/// <summary> /// playerstatusの取得を開始します。 /// </summary> private static void BeginGetPlayerStatus(long liveId, InternalData internalData, AutoResetEvent ev) { WebUtil.RequestHttpAsync( NicoString.GetPlayerStatusUrl(liveId), null, internalData.Cookie, (result, data) => { try { // ステータスがおかしければエラーとします。 var v = PlayerStatus.CreateFromXml(liveId, NicoUtil.GetXml(data)); internalData.LiveStreamInfo.PlayerStatus = v; } catch (Exception ex) { internalData.Exception = ex; } ev.Set(); }); }
/// <summary> /// コンストラクタ /// </summary> private PublishStatus(long liveId, XmlNode node) : base(node, "getpublishstatus", NicoString.LiveIdString(liveId)) { this.Stream = new StreamType(); this.User = new UserType(); this.RTMP = new RTMPType(); foreach (var childObj in RootNode.ChildNodes) { var child = (XmlNode)childObj; switch (child.Name) { case "stream": this.Stream = new StreamType(child); break; case "user": this.User = new UserType(child); break; case "rtmp": this.RTMP = new RTMPType(child); break; } } }
/// <summary> /// publishstatusの取得を開始します。 /// </summary> private static void BeginGetPublishStatus(long liveId, InternalData internalData, AutoResetEvent ev) { WebUtil.RequestHttpAsync( NicoString.GetPublishStatusUrl(liveId), null, internalData.Cookie, (result, data) => { try { // publishstatusは放送主でないと取得できません。 var v = PublishStatus.CreateFromXml(liveId, NicoUtil.GetXml(data)); internalData.LiveStreamInfo.PublishStatus = v; } catch (Exception ex) { internalData.Exception = ex; } ev.Set(); }); }
/// <summary> /// アリーナのコメントサーバー情報を取得します。 /// </summary> public CommentRoomInfo GetArenaInfo(PlayerStatus playerStatus) { var roomLabel = playerStatus.User.RoomLabel; var ms = playerStatus.MS; if (playerStatus.Stream.ProviderType != ProviderType.Channel) { throw new NicoLiveException( "チャンネル生放送以外には対応していません。"); } // メッセージサーバーのURLから番号を取得します。 var msAddrNum = NicoString.GetMessageServerNumber(ms.Address); if (msAddrNum < 0) { return(new CommentRoomInfo( roomLabel, ms.Address, ms.Port, ms.Thread)); } return(new CommentRoomInfo( roomLabel, ms.Address, ms.Port, ms.Thread)); }
/// <summary> /// 放送情報の取得を開始します。 /// </summary> private static void BeginGetLiveInfo(long liveId, InternalData internalData, AutoResetEvent ev) { WebUtil.RequestHttpTextAsync( NicoString.GetLiveUrl(liveId), null, internalData.Cookie, Encoding.UTF8, (result, text) => { try { // 放送情報が取得できなければエラーとします。 var v = LiveInfo.CreateFromHtml( string.Format("lv{0}", liveId), text); internalData.LiveStreamInfo.LiveInfo = v; } catch (Exception ex) { internalData.Exception = ex; } ev.Set(); }); }
/// <summary> /// 全コメントルームのポート情報などを取得します。 /// </summary> public CommentRoomInfo[] GetAllRoomInfo(PlayerStatus playerStatus, int communityLevel) { var arenaInfo = GetArenaInfo(playerStatus); var arenaAddrNum = NicoString.GetMessageServerNumber( arenaInfo.Address); if (arenaInfo.RoomLabel != "先頭のルーム") { return(new CommentRoomInfo[] { arenaInfo }); } return(LiveRoomDataList.Select(data => { var carry = 0; var msAddr = CommentServerAddress( arenaAddrNum + data.Offset, out carry); var msPort = CommentServerPort(arenaInfo.Port + carry); return new CommentRoomInfo( data.Name, msAddr, msPort, arenaInfo.Thread + data.Offset); }).ToArray()); }
/// <summary> /// 全コメントルームのポート情報などを取得します。 /// </summary> public CommentRoomInfo[] GetAllRoomInfo(PlayerStatus playerStatus, int communityLevel) { var result = new List <CommentRoomInfo>(); var arenaInfo = GetArenaInfo(playerStatus); // ルーム数を取得します。 var roomCount = ( communityLevel > 0 ? CommunityLevelTable.GetNumberOfSeet(communityLevel) / 500 : 1); result.Add(arenaInfo); var arenaInfoAddrNum = NicoString.GetMessageServerNumber( arenaInfo.Address); for (var i = 1; i < roomCount; ++i) { var carry = 0; var msPort = CommentServerPort(arenaInfo.Port + i, out carry); var msAddr = CommentServerAddress(arenaInfoAddrNum + carry); // 各立ち見席の情報を設定します。 var roomInfo = new CommentRoomInfo( "立ち見" + (char)((int)'A' + (i - 1)) + "列", msAddr, msPort, arenaInfo.Thread + i); result.Add(roomInfo); } return(result.ToArray()); }
/// <summary> /// アリーナのコメントサーバー情報を取得します。 /// </summary> public CommentRoomInfo GetArenaInfo(PlayerStatus playerStatus) { var arenaName = playerStatus.Stream.DefaultCommunity; var roomLabel = playerStatus.User.RoomLabel; var ms = playerStatus.MS; var offset = 0; if (playerStatus.Stream.ProviderType != ProviderType.Community) { throw new NicoLiveException( "ユーザー生放送以外には対応していません。"); } // メッセージサーバーのURLから番号を取得します。 var msAddrNum = NicoString.GetMessageServerNumber(ms.Address); if (msAddrNum < 0) { return(new CommentRoomInfo( roomLabel, ms.Address, ms.Port, ms.Thread)); } // アリーナ席へのオフセットを取得します。 if (roomLabel.IndexOf("A") >= 0) { offset = 1; } else if (roomLabel.IndexOf("B") >= 0) { offset = 2; } else if (roomLabel.IndexOf("C") >= 0) { offset = 3; } else { offset = 0; } var carry = 0; var msPort = CommentServerPort(ms.Port - offset, out carry); var msAddr = CommentServerAddress(msAddrNum + carry); // サーバーアドレス番号はポート番号のオーバーフローによって // 上下します。 // - ポート番号が2805以下なら、アドレス番号は1下がる // - ポート番号が2814以上なら、アドレス番号は1上がる return(new CommentRoomInfo( arenaName, msAddr, msPort, ms.Thread - offset)); }
/// <summary> /// 指定のブラウザのクッキーを使って、ログインします。 /// </summary> public static CookieContainer LoginWithBrowser(BrowserType browser, bool validate) { #if !RGN_NOT_USE_COOKIEGETTERSHARP try { var enumType = typeof(Ragnarok.Net.CookieGetter.BrowserType); var browserType = (Ragnarok.Net.CookieGetter.BrowserType)browser; if (!Enum.IsDefined(enumType, browserType)) { throw new ArgumentException( "ブラウザの種類が正しくありません。", "browser"); } var cookieGetter = CookieGetter.CreateInstance(browserType); if (cookieGetter == null) { Log.Error( "クッキーの取得オブジェクトの作成に失敗しました。"); return(null); } // 与えられたブラウザのログインクッキーを取得します。 var cookie = cookieGetter.GetCookie( new Uri(NicoString.GetLiveTopUrl()), "user_session"); if (cookie == null) { return(null); } var cc = new CookieContainer(); cc.Add(cookie); // 本当にこのクッキーでログインできるか確認します。 if (validate) { var account = CookieValidator.Validate(cc); if (account == null) { return(null); } } return(cc); } catch (Exception) { /*Log.ErrorMessage(ex, * "クッキーの取得に失敗しました。");*/ } #endif return(null); }
/// <summary> /// アラート情報の取得を開始します。 /// </summary> protected void StartReceiveAlert() { lock (SyncRoot) { // アラート情報の受信を開始するためのメッセージです。 var message = NicoString.MakeThreadStart( this.alertInfo.MS.ThreadId, 1); var buffer = Encoding.UTF8.GetBytes(message); this.socket.Send(buffer); StartReceiveAlertLoop(); } }
/// <summary> /// ニコ生のコメントサーバーはアドレス番号が101-104をループする。 /// </summary> public string CommentServerAddress(int number) { while (number < 101) { number += 4; } while (number > 104) { number -= 4; } return(NicoString.GetCommunityMessageServerAddress(number)); }
/// <summary> /// アドレスやポート番号が記述されたXMLファイルから情報を取得します。 /// </summary> public static CommentRoomInfo[] GetAllRoomInfoFromXml(string filepath) { if (string.IsNullOrEmpty(filepath)) { throw new ArgumentNullException("filepath"); } using (var stream = new FileStream(filepath, FileMode.Open)) { var doc = XDocument.Load(stream); var addrNode = doc.XPathSelectElement("/live/ms/addr"); if (addrNode == null || string.IsNullOrEmpty(addrNode.Value)) { throw new ArgumentException("addr要素が見つかりません。"); } var startAddrNum = NicoString.GetMessageServerNumber(addrNode.Value); var portNode = doc.XPathSelectElement("/live/ms/port"); if (portNode == null || string.IsNullOrEmpty(portNode.Value)) { throw new ArgumentException("addr要素が見つかりません。"); } var startPort = int.Parse(portNode.Value); var tidListNode = doc.XPathSelectElements("/live/tid_list"); if (!tidListNode.Any()) { throw new ArgumentException("tid_list要素が見つかりません。"); } return(tidListNode.Elements("tid") .Select(_ => _.Value) .Where(_ => !string.IsNullOrEmpty(_)) .Select(_ => int.Parse(_)) .SelectWithIndex((tid, i) => { /*var name = (i < LiveRoomDataList.Count() ? * LiveRoomDataList[i].Name : "不明(" + i + ")");*/ int carry; var addr = CommentServerAddress(startAddrNum + i, out carry); var port = CommentServerPort(startPort + carry); return new CommentRoomInfo(i.ToString(), addr, port, tid); }) .ToArray()); } }
/// <summary> /// ニコニコ生放送の情報を取得します。 /// </summary> public static PlayerStatus Create(long liveId, CookieContainer cc) { // 生放送IDから放送情報を取得します。 var node = LiveUtil.GetXml( NicoString.GetPlayerStatusUrl(liveId), cc); if (node == null) { throw new NicoLiveException( LiveStatusCode.NetworkError, LiveUtil.LiveIdString(liveId)); } return(CreateFromXml(liveId, node)); }
/// <summary> /// アリーナのコメントサーバー情報を取得します。 /// </summary> public CommentRoomInfo GetArenaInfo(PlayerStatus playerStatus) { var roomLabel = playerStatus.User.RoomLabel; var ms = playerStatus.MS; if (playerStatus.Stream.ProviderType != ProviderType.Official) { throw new NicoLiveException( "公式生放送以外には対応していません。"); } // メッセージサーバーのURLから番号を取得します。 var msAddrNum = NicoString.GetMessageServerNumber(ms.Address); if (msAddrNum < 0) { return(new CommentRoomInfo( roomLabel, ms.Address, ms.Port, ms.Thread)); } // アリーナへのオフセットを取得します。 OfficialLiveRoomData data; if (!LiveRoomDataDic.TryGetValue(roomLabel, out data)) { return(new CommentRoomInfo( roomLabel, ms.Address, ms.Port, ms.Thread)); } var carry = 0; var msAddr = CommentServerAddress(msAddrNum - data.Offset, out carry); var msPort = CommentServerPort(ms.Port + carry); // サーバーポート番号はアドレス番号のオーバーフローによって // 上下します。 return(new CommentRoomInfo( "先頭のルーム", msAddr, msPort, ms.Thread - data.Offset)); }
/// <summary> /// サーバーのメッセージ処理を開始します。 /// </summary> /// <remarks> /// これ以後、メッセージが受信されるようになります。 /// </remarks> public void StartReceiveMessage(int resFrom, int timeout, DateTime?when = null) { using (var result = this.startingMessageLock.Lock()) { if (result == null) { throw new NicoLiveException( "メッセージの受信開始処理をすでに行っています。"); } using (new DebugLock(SyncRoot)) { // 送信するメッセージの組み立て var message = string.Empty; if (when == null) { // 通常のコメント取得 message = NicoString.MakeThreadStart( ThreadId, resFrom); } else { // 過去ログの取得 var waybackkey = LiveUtil.GetWaybackKey( ThreadId, this.commentClient.CookieContainer); message = NicoString.MakeThreadStart( ThreadId, resFrom, this.commentClient.UserId, waybackkey, when.Value); } // メッセージの受信を開始します。 this.startMessageEvent.Reset(); SendMessageSync(message); } // startMessageEventがシグナル状態にならなかった場合、 // サーバーからのメッセージ受信に失敗しています。 if (!this.startMessageEvent.WaitOne(timeout)) { throw new NicoLiveException( "メッセージの受信開始処理に失敗しました。", this.commentClient.LiveIdString); } } }
/// <summary> /// コメントサーバーはアドレス番号が101-104をループする。 /// </summary> public static string CommentServerAddress(int number, out int carry) { carry = 0; while (number < 101) { carry -= 1; number += 4; } while (number > 104) { carry += 1; number -= 4; } return(NicoString.GetOfficialMessageServerAddress(number)); }
/// <summary> /// 現在放送中の放送アドレスを放送ページから取得します。 /// </summary> private static string GetCurrentLiveUrlFromLive(int communityId, CookieContainer cc) { try { var responseText = WebUtil.RequestHttpText( NicoString.GetLiveUrl("co" + communityId), null, cc, Encoding.UTF8); if (string.IsNullOrEmpty(responseText)) { return(null); } if (!HarajukuNowOnAirRegex.IsMatch(responseText) && !QwatchNowOnAirRegex.IsMatch(responseText)) { // 放送中ではありません。 return(null); } var m = CurrentLiveRegexLivePage.Match(responseText); if (!m.Success) { // 放送IDが見つかりません。 return(null); } var liveId = long.Parse(m.Groups[1].Value); return(NicoString.GetLiveUrl(liveId)); } catch (Exception ex) { Util.ThrowIfFatal(ex); Log.ErrorException(ex, "co{0}: 放送ページの取得に失敗しました。", communityId); } return(null); }
/// <summary> /// Urlからコミュニティ情報を取得します。 /// </summary> /// <exception cref="System.TimeoutException" /> /// <exception cref="System.Net.WebException" /> public static CommunityInfo Create(int id, CookieContainer cc) { // ページを取得します。 var responseData = WebUtil.RequestHttp( NicoString.GetCommunityUrl(id), null, cc); // 失敗;; コミュニティエラー時はレスポンスが空になります。 if (responseData == null) { throw new NicoLiveException( "コミュニティページの取得に失敗しました。", LiveUtil.CommunityIdString(id)); } var text = Encoding.UTF8.GetString(responseData); return(CreateFromHtml(id, text)); }
/// <summary> /// Urlから生放送情報を取得します。 /// </summary> public static LiveInfo Create(long liveId, CookieContainer cc) { // urlを取得します。 var responseData = WebUtil.RequestHttp( NicoString.GetLiveUrl(liveId), null, cc); // 失敗;; エラー時はレスポンスが空になります。 if (responseData == null) { throw new NicoException( "放送ページの取得に失敗しました。", NicoString.LiveIdString(liveId)); } var text = Encoding.UTF8.GetString(responseData); return(CreateFromHtml(NicoString.LiveIdString(liveId), text)); }
/// <summary> /// ニコニコに直接ログインします。 /// </summary> public static CookieContainer LoginDirect(string mail, string password) { if (string.IsNullOrEmpty(mail) || string.IsNullOrEmpty(password)) { Log.Error( "ログイン出来ません。" + Environment.NewLine + "メールアドレスとパスワードを設定してください。"); return(null); } try { var cc = new CookieContainer(); // ニコニコにログインします。 var text = WebUtil.RequestHttpText( NicoString.GetLoginUrl(), NicoString.MakeLoginData(mail, password), cc, Encoding.UTF8); if (string.IsNullOrEmpty(text) || text.IndexOf(NicoString.LoginErrorText()) >= 0) { Log.Error("ログインに失敗しました。"); return(null); } return(cc); } catch (Exception ex) { Log.ErrorException(ex, "直接ログインに失敗しました。"); } return(null); }
/// <summary> /// 現在放送中の放送アドレスをコミュニティから取得します。 /// </summary> private static string GetCurrentLiveUrlFromCommunity(int communityId, CookieContainer cc) { try { var responseText = WebUtil.RequestHttpText( NicoString.GetCommunityUrl(communityId), null, cc, Encoding.UTF8); if (string.IsNullOrEmpty(responseText)) { return(null); } var m = CurrentLiveCommunityPageRegex.Match(responseText); if (!m.Success) { return(null); } var liveId = long.Parse(m.Groups[1].Value); return(NicoString.GetLiveUrl(liveId)); } catch (WebException) { // クローズコミュニティの場合はこの例外が発生します。 } catch (Exception ex) { Util.ThrowIfFatal(ex); Log.ErrorException(ex, "co{0}: コミュニティページの取得に失敗しました。", communityId); } return(null); }
/// <summary> /// 動画番号が含まれる文字列から情報を作成します。 /// </summary> public static VideoData CreateFromPage(string videoStr, CookieContainer cc) { if (string.IsNullOrEmpty(videoStr)) { throw new ArgumentNullException("videoStr"); } if (cc == null) { throw new ArgumentNullException("cc"); } var videoId = VideoUtil.GetVideoId(videoStr); if (string.IsNullOrEmpty(videoId)) { throw new NicoVideoException( $"{videoStr}: 不正な動画IDです。"); } // urlを取得します。 var responseData = WebUtil.RequestHttp( NicoString.GetVideoUrl(videoId), null, cc); // 失敗;; エラー時はレスポンスが空になります。 if (responseData == null) { throw new NicoVideoException( "放送ページの取得に失敗しました。", videoId); } var text = Encoding.UTF8.GetString(responseData); return(CreateFromPageHtml(text)); }
/// <summary> /// 過去コメントの取得に使うWaybackKeyを取得します。 /// </summary> public static string GetWaybackKey(int threadId, CookieContainer cc) { var responseText = WebUtil.RequestHttpText( NicoString.GetWaybackKeyUrl(threadId), null, cc, Encoding.UTF8); if (string.IsNullOrEmpty(responseText)) { return(null); } // waybackkeyは=の後に入っています。 var index = responseText.IndexOf('='); if (index < 0 || index + 1 >= responseText.Length) { return(null); } return(responseText.Substring(index + 1)); }
/// <summary> /// コンストラクタ /// </summary> private Heartbeat(long liveId, XmlNode node) : base(node, "heartbeat", NicoString.LiveIdString(liveId)) { foreach (var childObj in RootNode.ChildNodes) { var child = (XmlNode)childObj; var value = child.InnerText; switch (child.Name) { case "watchCount": this.WatchCount = StrUtil.ToInt(value, -1); break; case "commentCount": this.CommentCount = StrUtil.ToInt(value, -1); break; case "ticket": this.Ticket = value; break; } } }
/// <summary> /// 放送主コメントの投稿処理を行います。 /// </summary> private void UpdateOwnerComment() { try { var publishStatus = this.publishStatus; if (publishStatus == null) { return; } // コメントを取り出します。 var comment = DequeueOwnerComment(DateTime.Now); if (comment == null) { return; } // 実際の投稿処理を行います。 WebUtil.RequestHttpAsync( NicoString.GetBroadcastCommentUrl(this.LiveId), NicoString.MakeBroadcastCommentData( comment.Text, comment.Mail, comment.Name, publishStatus.Stream.Token), this.cookieContainer, OwnerCommentSentDone); } catch (Exception ex) { Log.ErrorException(this, ex, "放送主コメントの投稿に失敗しました。"); OwnerCommentSentDone(null, null); } }
/// <summary> /// html形式のコミュニティページからコミュニティ情報を作成します。 /// </summary> public static CommunityInfo CreateFromHtml(int id, string pageStr) { var community = new CommunityInfo(); if (string.IsNullOrEmpty(pageStr)) { throw new NicoProviderException( "与えられたページがありません。", NicoString.CommunityIdString(id)); } var m = Regex.Match(pageStr, @"<img src=""http://icon\.nimg\.jp/community/\d+/co([0-9]+)\.jpg\?[0-9]+"""); if (!m.Success) { throw new NicoProviderException( "コミュニティIDを取得できませんでした。", NicoString.CommunityIdString(id)); } community.Id = int.Parse(m.Groups[1].Value); m = Regex.Match(pageStr, @"<title>\s*(.*)\s*-?\s*ニコニコ[^<]*?\s*</title>"); if (!m.Success) { throw new NicoProviderException( "コミュニティタイトルを取得できませんでした。", NicoString.CommunityIdString(id)); } community.Title = WebUtil.DecodeHtmlText(m.Groups[1].Value); m = Regex.Match(pageStr, @"<div class=""cnt2"" style=""[^""]+?"">\s*" + @"((.|\s)*?)\s*</div></div></div>\s*" + @"<!-- subbox profile -->"); if (!m.Success) { m = Regex.Match(pageStr, @"<div id=""community_description""><!-- ID は暫定 -->\s*" + @"()</div>\s*</div>\s*<div id=""cbox_news"">"); if (!m.Success) { throw new NicoProviderException( "コミュニティプロフィールを取得できませんでした。", NicoString.CommunityIdString(id)); } } community.Description = WebUtil.DecodeHtmlText(m.Groups[1].Value); // <td nowrap>レベル:</td> // <td> // <strong>13</strong> m = Regex.Match(pageStr, @"<td nowrap>レベル:</td>\s*<td>\s*<strong>([0-9]+)</strong>"); if (!m.Success) { throw new NicoProviderException( "コミュニティのレベルを取得できませんでした。", NicoString.CommunityIdString(id)); } community.Level = int.Parse(m.Groups[1].Value); // <td nowrap>メンバー:</td> // <td> // <strong>87</strong> m = Regex.Match(pageStr, @"<td nowrap>メンバー:</td>\s*<td>\s*<strong>([0-9]+)</strong>"); if (!m.Success) { throw new NicoProviderException( "コミュニティの参加メンバー数を取得できませんでした。", NicoString.CommunityIdString(id)); } community.NumberOfMembers = int.Parse(m.Groups[1].Value); m = Regex.Match(pageStr, @"オーナー:<a href=""http://www\.nicovideo\.jp/user/([0-9]+)"" " + @"style=""color:#FFF;"" target=""_blank"">\s*" + @"<strong>([^<]+)</strong></a>"); if (!m.Success) { throw new NicoProviderException( "コミュニティのオーナーを取得できませんでした。", NicoString.CommunityIdString(id)); } community.OwnerId = int.Parse(m.Groups[1].Value); community.OwnerName = WebUtil.DecodeHtmlText(m.Groups[2].Value); m = Regex.Match(pageStr, @"開設日:<strong>(\d+)年(\d+)月(\d+)日</strong>"); if (!m.Success) { throw new NicoProviderException( "コミュニティの開設日が取得できませんでした。", NicoString.CommunityIdString(id)); } community.OpenDate = new DateTime( int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value), int.Parse(m.Groups[3].Value)); return(community); }