Beispiel #1
0
        /// <summary>
        /// コンストラクタ
        /// </summary>
        private PublishStatus(long liveId, XmlNode node)
            : base(node, "getpublishstatus", LiveUtil.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;
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// コメントサーバーに接続します。
        /// </summary>
        /// <remarks>
        /// 接続失敗時には例外が返されます。
        /// </remarks>
        public void Connect(PlayerStatus playerStatus, CookieContainer cc,
                            bool currentRoomOnly, TimeSpan timeout)
        {
            lock (ConnectLock)
            {
                if (playerStatus == null)
                {
                    throw new ArgumentNullException("playerStatus");
                }

                // 例外が発生する可能性があります。
                var streamInfo = LiveUtil.GetLiveStreamInfo(playerStatus, cc);

                // 各コメントルームの情報を取得します。
                var roomInfoList = GetAllRoomInfo(
                    streamInfo.PlayerStatus,
                    streamInfo.LiveInfo.CommunityLevel);
                var currentRoomIndex = FindRoomIndex(
                    playerStatus.MS.Port, roomInfoList);
                var roomList = new List <CommentRoom>();

                // 各コメントルームに接続します。
                for (var i = 0; i < roomInfoList.Count(); ++i)
                {
                    if (currentRoomOnly && i != currentRoomIndex)
                    {
                        roomList.Add(null);
                        continue;
                    }

                    var room = new CommentRoom(this, roomInfoList[i], i);
                    // 接続に失敗した場合、例外が返ります。
                    room.Connect(cc, timeout);
                    roomList.Add(room);
                }

                Disconnect();
                lock (SyncRoot)
                {
                    this.connectedRoomCount = 0;
                    this.playerStatus       = streamInfo.PlayerStatus;
                    this.publishStatus      = streamInfo.PublishStatus;
                    this.liveInfo           = streamInfo.LiveInfo;
                    this.roomList           = roomList;
                    this.currentRoomIndex   = currentRoomIndex;
                    this.cookieContainer    = cc;
                }

                // フィールド値を設定した後に、OnConnectedRoomを呼びます。
                foreach (var room in ClonedCommentRoomList)
                {
                    OnConnectedRoom(room);
                }

                // 接続時のイベントを発生させます。
                FireConnected();
            }
        }
Beispiel #3
0
        /// <summary>
        /// アラートメッセージを処理します。
        /// </summary>
        private void HandleMessage(string message)
        {
            var doc = new XmlDocument();

            doc.LoadXml(message);

            var node = doc.DocumentElement;

            if (node.Name != "chat")
            {
                return;
            }

            Log.Trace("Alert {0}", node.InnerText);

            // 内部テキストは
            //   [放送ID],[チャンネル/コミュニティID/official],[ユーザーID]
            // となっています。
            var values = node.InnerText.Split(',');

            if (values.Length < 3)
            {
                return;
            }

            // 放送IDを取得します。
            var liveId = StrUtil.ToInt(values[0], 0);

            if (liveId <= 0)
            {
                return;
            }

            // 提供者を取得します。
            var providerData = LiveUtil.ParseProvider(values[1]);

            if (providerData == null)
            {
                return;
            }

            // ユーザー情報を取得します。
            var userId = StrUtil.ToInt(values[2], -1);

            // IDが重複して送られてくることがあるので、
            // すでに受信した放送IDならば無視します。
            if (!IsContainsLiveId(liveId))
            {
                var e = new LiveAlertedEventArgs(
                    liveId, providerData, userId);
                OnLiveAlerted(e);

                AddLiveIdToHistoryBuffer(liveId);
            }
        }
Beispiel #4
0
        /// <summary>
        /// ニコニコ生放送の情報を取得します。
        /// </summary>
        public static PlayerStatus Create(string liveStr, CookieContainer cc)
        {
            var liveId = LiveUtil.GetLiveId(liveStr);

            if (liveId < 0)
            {
                throw new NicoLiveException(LiveStatusCode.InvalidLiveId);
            }

            return(Create(liveId, cc));
        }
Beispiel #5
0
        /// <summary>
        /// アラート情報を作成します。
        /// </summary>
        public static AlertInfo Create()
        {
            var node = LiveUtil.GetXml(
                "http://live.nicovideo.jp/api/getalertinfo",
                null);

            if (node == null)
            {
                throw new NicoLiveException(LiveStatusCode.NetworkError);
            }

            return(new AlertInfo(node));
        }
Beispiel #6
0
        /// <summary>
        /// コミュニティ番号が含まれる文字列から情報を作成します。
        /// </summary>
        public static CommunityInfo Create(string communityStr,
                                           CookieContainer cc)
        {
            var id = LiveUtil.GetCommunityId(communityStr);

            if (id < 0)
            {
                throw new NicoLiveException(
                          "コミュニティIDが取得できませんでした。");
            }

            return(Create(id, cc));
        }
Beispiel #7
0
        /// <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));
        }
Beispiel #8
0
        /// <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);
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// PostKeyを取得します。
        /// </summary>
        private string GetPostKey()
        {
            try
            {
                var newBlockNo = (this.lastRes + 1) / 100;

                /*// postkeyがあって、blocknoも変わっていなければ、
                 * // postkeyを新たに取得する必要はありません。
                 * if (!string.IsNullOrEmpty(this.postKey) &&
                 *  newBlockNo == this.prevBlockNo)
                 * {
                 *  return this.postKey;
                 * }*/

                // postkeyを短時間で取得し続けるとコメント投稿が不可能になって
                // しまうため、このような時間制限をつけます。
                // また、前回投稿よりきっちり3秒後にblocknoが変わった場合でも
                // 正しいpostkeyが取得できるよう、
                // 猶予時間を(3.0 - 0.1)秒 としています。
                var waitTime = MinimumWaitTimeForPost - TimeSpan.FromSeconds(0.1);
                var now      = DateTime.Now;
                if (now < this.lastGetPostKey + waitTime)
                {
                    return(this.postKey);
                }

                // エラー時にも対応できるよう、取得時間は先に設定します。
                this.lastGetPostKey = now;

                // 新たにpostkeyを取得。
                this.postKey = LiveUtil.GetPostKey(
                    this.ThreadId,
                    newBlockNo,
                    this.commentClient.CookieContainer);
            }
            catch (Exception ex)
            {
                Log.ErrorException(ex,
                                   "postkeyの取得に失敗しました。");

                this.postKey = null;
            }

            return(this.postKey);
        }
Beispiel #10
0
        /// <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));
        }
Beispiel #11
0
        /// <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(
                          "放送ページの取得に失敗しました。",
                          LiveUtil.LiveIdString(liveId));
            }

            var text = Encoding.UTF8.GetString(responseData);

            return(CreateFromHtml(LiveUtil.LiveIdString(liveId), text));
        }
Beispiel #12
0
        /// <summary>
        /// コンストラクタ
        /// </summary>
        private Heartbeat(long liveId, XmlNode node)
            : base(node, "heartbeat", LiveUtil.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;
                }
            }
        }
Beispiel #13
0
        /// <summary>
        /// html形式のコミュニティページからコミュニティ情報を作成します。
        /// </summary>
        public static CommunityInfo CreateFromHtml(int id, string pageStr)
        {
            var community = new CommunityInfo();

            if (string.IsNullOrEmpty(pageStr))
            {
                throw new NicoLiveException(
                          "与えられたページがありません。",
                          LiveUtil.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 NicoLiveException(
                          "コミュニティIDを取得できませんでした。",
                          LiveUtil.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 NicoLiveException(
                          "コミュニティタイトルを取得できませんでした。",
                          LiveUtil.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 NicoLiveException(
                              "コミュニティプロフィールを取得できませんでした。",
                              LiveUtil.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 NicoLiveException(
                          "コミュニティのレベルを取得できませんでした。",
                          LiveUtil.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 NicoLiveException(
                          "コミュニティの参加メンバー数を取得できませんでした。",
                          LiveUtil.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 NicoLiveException(
                          "コミュニティのオーナーを取得できませんでした。",
                          LiveUtil.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 NicoLiveException(
                          "コミュニティの開設日が取得できませんでした。",
                          LiveUtil.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);
        }
Beispiel #14
0
        /// <summary>
        /// html形式の生放送ページから生放送情報を作成します。
        /// </summary>
        public static LiveInfo CreateFromHtml(string idString, string pageStr)
        {
            var live = new LiveInfo();

            if (string.IsNullOrEmpty(pageStr))
            {
                throw new NicoLiveException(
                          "ページが空です。",
                          idString);
            }

            var m = ProviderInfoRegex.Match(pageStr);

            if (!m.Success)
            {
                throw new NicoLiveException(
                          "放送の提供元情報を取得できませんでした。",
                          idString);
            }
            var provider = LiveUtil.ParseProvider(m.Groups[1].Value);

            m = VideoInfoRegex.Match(pageStr);
            if (!m.Success)
            {
                throw new NicoLiveException(
                          "生放送情報を取得できませんでした。",
                          idString);
            }

            var infoStr = m.Groups[1].Value;

            m = IdRegex.Match(infoStr);
            if (!m.Success)
            {
                throw new NicoException(
                          "生放送IDを取得できませんでした。",
                          idString);
            }
            live.Id = int.Parse(m.Groups[1].Value);

            m = TitleRegex.Match(infoStr);
            if (!m.Success)
            {
                throw new NicoException(
                          "生放送タイトルを取得できませんでした。",
                          idString);
            }
            live.Title = m.Groups[1].Value
                         .Replace("\\'", "'");

            m = DescriptionRegex.Match(infoStr);
            if (!m.Success)
            {
                throw new NicoLiveException(
                          "生放送概要を取得できませんでした。",
                          idString);
            }
            live.Description = m.Groups[1].Value
                               .Replace("\\'", "'")
                               .Replace("\\r\\n", "\n");

            switch (provider.ProviderType)
            {
            case ProviderType.Community:
                SetCommunityInfo(live, pageStr);
                break;

            case ProviderType.Channel:
                SetChannelInfo(live, pageStr);
                break;

            case ProviderType.Official:
                SetOfficialInfo(live, pageStr);
                break;

            default:
                throw new NotImplementedException(
                          "実装されていない放送提供元です。");
            }

            return(live);
        }