Example #1
0
        /// <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();
            });
        }
Example #2
0
        /// <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;
                }
            }
        }
Example #3
0
        /// <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();
            });
        }
Example #4
0
        /// <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));
        }
Example #5
0
        /// <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());
        }
Example #7
0
        /// <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());
        }
Example #8
0
        /// <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));
        }
Example #9
0
        /// <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);
        }
Example #10
0
        /// <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();
            }
        }
Example #11
0
        /// <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());
            }
        }
Example #13
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));
        }
        /// <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));
        }
Example #15
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);
                }
            }
        }
Example #16
0
        /// <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));
        }
Example #17
0
        /// <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);
        }
Example #18
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));
        }
Example #19
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(
                          "放送ページの取得に失敗しました。",
                          NicoString.LiveIdString(liveId));
            }

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

            return(CreateFromHtml(NicoString.LiveIdString(liveId), text));
        }
Example #20
0
        /// <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);
        }
Example #21
0
        /// <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);
        }
Example #22
0
        /// <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));
        }
Example #23
0
        /// <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));
        }
Example #24
0
        /// <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;
                }
            }
        }
Example #25
0
        /// <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);
            }
        }
Example #26
0
        /// <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);
        }