/// <summary> /// 渡された BbsThread の子たちをスレッドを表示する XmlElement を返します。 /// toolong が true の場合、子のスレッドは省略されます。 /// </summary> protected XmlNode GetThread(BbsThread bt, bool toolong){ XmlElement result = Html.Create("ul", "tree"); XmlElement rootLi = Html.Create("li", "root"); result.AppendChild(rootLi); XmlElement ia = MakeInthreadAnchor(bt); rootLi.AppendChild(ia); rootLi.AppendChild(Html.Space); if(bt.CommentTo != null){ XmlElement commentToP = GetCommentToDesc(bt); rootLi.PrependChild(commentToP); } if(toolong){ rootLi.AppendChild(Html.P("threadabort", "(このスレッドは長すぎるため、省略されました)")); } else { XmlElement secondUl = Html.Create("ul"); rootLi.AppendChild(secondUl); for(int i=0; i < bt.Articles.Length; i++){ Article a = bt.Articles[i]; XmlElement secondLi = Html.Create("li"); secondLi.AppendChild(MakeTree(a)); secondUl.AppendChild(secondLi); } } return result; }
// パブリックメソッド // データのロード /// <summary> /// XmlDocument からデータをロードします。 /// </summary> public void Load(XmlDocument x){ XmlNodeList xnl = x.DocumentElement.GetElementsByTagName(MessageElementName); Dictionary<int, Article> articleDict = new Dictionary<int, Article>(); Dictionary<string, BbsThread> threadDict = new Dictionary<string, BbsThread>(); // 古い順に読む for(int i=xnl.Count-1; i >=0 ; i--){ Article a = new Article(xnl[i] as XmlElement); int parent = a.Parent; if(parent > 0 && articleDict.ContainsKey(parent)){ // 親がいる Article parentArticle = articleDict[parent]; a.Thread = parentArticle.Thread; parentArticle.AddChild(a); } else { // 親がいない if(a.CommentTo != null){ // 同じコメントのスレッドあるか? string key = a.CommentTo.OriginalString; if(threadDict.ContainsKey(key)){ BbsThread bt = threadDict[key]; bt.AddArticle(a); a.Thread = bt; } else { BbsThread bt = new BbsThread(a); a.Thread = bt; threadDict.Add(key, bt); } } else { BbsThread bt = new BbsThread(a); a.Thread = bt; threadDict.Add(a.Id.ToString(), bt); } } articleDict.Add(a.Id, a); } foreach(Article a in articleDict.Values){ Rows.Add(new Object[]{ a.Id, a.Date, a.CommentTo, a, }); } myThreadList = new BbsThread[threadDict.Count]; threadDict.Values.CopyTo(myThreadList, 0); Array.ForEach(myThreadList, item=>{item.Set();}); Array.Sort(myThreadList); }
/// <summary> /// コメントであることを説明する文言を含むp要素を取得します。 /// </summary> protected XmlElement GetCommentToDesc(BbsThread bt){ XmlElement a = GetCommentToLink(bt.CommentTo); XmlElement p = Html.P(BbsAction.NavDescClass, "これは「", a, "」に関連するコメントです。"); return p; }
// スレッド全記事表示のリンクを生成します。 protected XmlElement MakeInthreadAnchor(BbsThread bt){ string inthreadLinkText = string.Format("全読: [{0}]{1}からのスレッド({2}件)]", bt.Id, bt.FirstArticle.Subject, bt.Count); Uri linkUri = Bbs.BasePath.Combine(BbsViewInThread.Id, bt.Id); return Html.A(linkUri, null, inthreadLinkText); }
/// <summary> /// 渡された BbsThread の子たちをスレッドを表示する XmlElement を返します。 /// </summary> protected XmlNode GetThread(BbsThread bt){ return GetThread(bt, false); }
/// <summary> /// スレ一覧をダウンロードする /// </summary> public void Download() { Threads.Clear(); var content = ""; var subjectAddress = ""; if (GlobalConf.UseBg20 && HostName.EndsWith(".2ch.net")) { subjectAddress = String.Format("http://bg20.2ch.net/test/p.so/{0}/{1}/", HostName, BoardDir); } else { subjectAddress = String.Format("http://{0}/{1}/subject.txt", HostName, BoardDir); } var sp = new Stopwatch(); sp.Start(); using (var client = new WebClient()) { client.Headers.Add(HttpRequestHeader.UserAgent, GlobalConf.UserAgent); content = client.DownloadString(subjectAddress); } sp.Stop(); Debug.WriteLine("subject.txt loaded: taken " + sp.ElapsedMilliseconds / 1000.0 + "sec."); var lines = content.Split('\n'); foreach (var line in lines) { var match = Regex.Match(line, "(?<epoch>\\d+)\\.dat<>(?<name>.+)\\((?<resnum>\\d+)\\)", RegexOptions.Compiled); if (!match.Success) continue; var thread = new BbsThread { Epoch = long.Parse(match.Groups["epoch"].Value), Name = match.Groups["name"].Value, ResNum = int.Parse(match.Groups["resnum"].Value) }; Threads.Add(thread); } }