• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

dev


Commit MetaInfo

Revisionfb6b145f56bc25197c355fac6551a72178e249ff (tree)
Time2013-05-06 20:15:29
AuthorKimura Youichi <kim.upsilon@bucy...>
CommiterKimura Youichi

Log Message

関連発言の取得で related_result の結果だけでなく in_reply_to も辿るように変更

protected な発言で related_result が機能しない問題への対策

Change Summary

Incremental Difference

--- a/OpenTween.Tests/TwitterTest.cs
+++ b/OpenTween.Tests/TwitterTest.cs
@@ -63,5 +63,30 @@ namespace OpenTween
6363 return Twitter.ThirdPartyStatusUrlRegex.Matches(url).Cast<Match>()
6464 .Select(x => x.Groups["StatusId"].Value).ToArray();
6565 }
66+
67+ [Test]
68+ public void FindTopOfReplyChainTest()
69+ {
70+ var posts = new Dictionary<long, PostClass>
71+ {
72+ {950L, new PostClass { StatusId = 950L, InReplyToStatusId = 0L }}, // このツイートが末端
73+ {987L, new PostClass { StatusId = 987L, InReplyToStatusId = 950L }},
74+ {999L, new PostClass { StatusId = 999L, InReplyToStatusId = 987L }},
75+ {1000L, new PostClass { StatusId = 1000L, InReplyToStatusId = 999L }},
76+ };
77+ Assert.That(Twitter.FindTopOfReplyChain(posts, 1000L).StatusId, Is.EqualTo(950L));
78+ Assert.That(Twitter.FindTopOfReplyChain(posts, 950L).StatusId, Is.EqualTo(950L));
79+ Assert.That(() => Twitter.FindTopOfReplyChain(posts, 500L), Throws.ArgumentException);
80+
81+ posts = new Dictionary<long, PostClass>
82+ {
83+ // 1200L は posts の中に存在しない
84+ {1210L, new PostClass { StatusId = 1210L, InReplyToStatusId = 1200L }},
85+ {1220L, new PostClass { StatusId = 1220L, InReplyToStatusId = 1210L }},
86+ {1230L, new PostClass { StatusId = 1230L, InReplyToStatusId = 1220L }},
87+ };
88+ Assert.That(Twitter.FindTopOfReplyChain(posts, 1230L).StatusId, Is.EqualTo(1210L));
89+ Assert.That(Twitter.FindTopOfReplyChain(posts, 1210L).StatusId, Is.EqualTo(1210L));
90+ }
6691 }
6792 }
--- a/OpenTween/Resources/ChangeLog.txt
+++ b/OpenTween/Resources/ChangeLog.txt
@@ -6,6 +6,7 @@
66 * NEW: Favstarなどサードパーティ製サービスのパーマリンクURLも関連発言表示の対象に追加
77 * FIX: スペースが含まれているURLをブラウザで開こうとするとURLが分断されて複数のタブが開いてしまう問題を修正 (thx @5px!)
88 * FIX: 画面更新時にInvalidOperationExceptionのエラーが発生する不具合を修正
9+ * FIX: 関連発言表示が非公開アカウントのツイートに対して機能しない問題を修正
910
1011 ==== Ver 1.0.9(2013/04/07)
1112 * CHG: APIレートリミット関連の実装を修正
--- a/OpenTween/Twitter.cs
+++ b/OpenTween/Twitter.cs
@@ -2459,27 +2459,30 @@ namespace OpenTween
24592459 return CreatePostsFromJson(content, MyCommon.WORKERTYPE.List, tab, read, count, ref tab.OldestId);
24602460 }
24612461
2462-
2463- private PostClass CheckReplyToPost(List<PostClass> relPosts)
2462+ /// <summary>
2463+ /// startStatusId からリプライ先の発言を辿る。発言は posts 以外からは検索しない。
2464+ /// </summary>
2465+ /// <returns>posts の中から検索されたリプライチェインの末端</returns>
2466+ internal static PostClass FindTopOfReplyChain(IDictionary<Int64, PostClass> posts, Int64 startStatusId)
24642467 {
2465- var tmpPost = relPosts[0];
2466- PostClass lastPost = null;
2467- while (tmpPost != null)
2468- {
2469- if (tmpPost.InReplyToStatusId == 0) return null;
2470- lastPost = tmpPost;
2471- var replyToPost = from p in relPosts
2472- where p.StatusId == tmpPost.InReplyToStatusId
2473- select p;
2474- tmpPost = replyToPost.FirstOrDefault();
2475- }
2476- return lastPost;
2468+ if (!posts.ContainsKey(startStatusId))
2469+ throw new ArgumentException("startStatusId (" + startStatusId + ") が posts の中から見つかりませんでした。");
2470+
2471+ var nextPost = posts[startStatusId];
2472+ while (nextPost.InReplyToStatusId != 0)
2473+ {
2474+ if (!posts.ContainsKey(nextPost.InReplyToStatusId))
2475+ break;
2476+ nextPost = posts[nextPost.InReplyToStatusId];
2477+ }
2478+
2479+ return nextPost;
24772480 }
24782481
24792482 public string GetRelatedResult(bool read, TabClass tab)
24802483 {
24812484 var rslt = "";
2482- var relPosts = new List<PostClass>();
2485+ var relPosts = new Dictionary<Int64, PostClass>();
24832486 if (tab.RelationTargetPost.TextFromApi.Contains("@") && tab.RelationTargetPost.InReplyToStatusId == 0)
24842487 {
24852488 //検索結果対応
@@ -2495,23 +2498,89 @@ namespace OpenTween
24952498 tab.RelationTargetPost = p;
24962499 }
24972500 }
2498- relPosts.Add(tab.RelationTargetPost.Clone());
2499- var tmpPost = relPosts[0];
2501+ relPosts.Add(tab.RelationTargetPost.StatusId, tab.RelationTargetPost.Clone());
2502+
2503+ // 一周目: 非公式な related_results API を使用してリプライチェインを辿る
2504+ var nextPost = relPosts[tab.RelationTargetPost.StatusId];
2505+ var loopCount = 1;
25002506 do
25012507 {
2502- rslt = this.GetRelatedResultsApi(read, tmpPost, tab, relPosts);
2508+ rslt = this.GetRelatedResultsApi(nextPost, relPosts);
25032509 if (!string.IsNullOrEmpty(rslt)) break;
2504- tmpPost = CheckReplyToPost(relPosts);
2505- } while (tmpPost != null);
2510+ nextPost = FindTopOfReplyChain(relPosts, nextPost.StatusId);
2511+ } while (nextPost.InReplyToStatusId != 0 && loopCount++ <= 5);
2512+
2513+ // 二周目: in_reply_to_status_id を使用してリプライチェインを辿る
2514+ nextPost = FindTopOfReplyChain(relPosts, tab.RelationTargetPost.StatusId);
2515+ loopCount = 1;
2516+ while (nextPost.InReplyToStatusId != 0 && loopCount++ <= 20)
2517+ {
2518+ var inReplyToId = nextPost.InReplyToStatusId;
2519+
2520+ var inReplyToPost = TabInformations.GetInstance()[inReplyToId];
2521+ if (inReplyToPost != null)
2522+ {
2523+ inReplyToPost = inReplyToPost.Clone();
2524+ }
2525+ else
2526+ {
2527+ var errorText = this.GetStatusApi(read, inReplyToId, ref inReplyToPost);
2528+ if (!string.IsNullOrEmpty(errorText))
2529+ {
2530+ rslt = errorText;
2531+ break;
2532+ }
2533+ }
2534+
2535+ relPosts.Add(inReplyToPost.StatusId, inReplyToPost);
2536+
2537+ nextPost = FindTopOfReplyChain(relPosts, nextPost.StatusId);
2538+ }
2539+
2540+ //MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
2541+ var text = tab.RelationTargetPost.Text;
2542+ var ma = Twitter.StatusUrlRegex.Matches(text).Cast<Match>()
2543+ .Concat(Twitter.ThirdPartyStatusUrlRegex.Matches(text).Cast<Match>());
2544+ foreach (var _match in ma)
2545+ {
2546+ Int64 _statusId;
2547+ if (Int64.TryParse(_match.Groups["StatusId"].Value, out _statusId))
2548+ {
2549+ if (relPosts.ContainsKey(_statusId))
2550+ continue;
2551+
2552+ PostClass p = null;
2553+ var _post = TabInformations.GetInstance()[_statusId];
2554+ if (_post == null)
2555+ {
2556+ this.GetStatusApi(read, _statusId, ref p);
2557+ }
2558+ else
2559+ {
2560+ p = _post.Clone();
2561+ }
2562+
2563+ if (p != null)
2564+ relPosts.Add(p.StatusId, p);
2565+ }
2566+ }
2567+
2568+ relPosts.Values.ToList().ForEach(p =>
2569+ {
2570+ if (p.IsMe && !read && this._readOwnPost)
2571+ p.IsRead = true;
2572+ else
2573+ p.IsRead = read;
2574+
2575+ p.RelTabName = tab.TabName;
2576+ TabInformations.GetInstance().AddPost(p);
2577+ });
25062578
2507- relPosts.ForEach(p => TabInformations.GetInstance().AddPost(p));
25082579 return rslt;
25092580 }
25102581
2511- private string GetRelatedResultsApi(bool read,
2512- PostClass post,
2513- TabClass tab,
2514- List<PostClass> relatedPosts)
2582+ private string GetRelatedResultsApi(PostClass post,
2583+ IDictionary<Int64, PostClass> relatedPosts)
25152584 {
25162585 if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return "";
25172586
@@ -2564,100 +2633,18 @@ namespace OpenTween
25642633 return "Invalid Json!";
25652634 }
25662635
2567- var targetItem = post;
2568- if (targetItem == null)
2569- {
2570- return "";
2571- }
2572- else
2573- {
2574- targetItem = targetItem.Clone();
2575- }
2576- targetItem.RelTabName = tab.TabName;
2577- TabInformations.GetInstance().AddPost(targetItem);
2578-
2579- PostClass replyToItem = null;
2580- var replyToUserName = targetItem.InReplyToUser;
2581- if (targetItem.InReplyToStatusId > 0 && TabInformations.GetInstance()[targetItem.InReplyToStatusId] != null)
2582- {
2583- replyToItem = TabInformations.GetInstance()[targetItem.InReplyToStatusId].Clone();
2584- replyToItem.IsRead = read;
2585- if (replyToItem.IsMe && !read && _readOwnPost) replyToItem.IsRead = true;
2586- replyToItem.RelTabName = tab.TabName;
2587- }
2588-
2589- var replyAdded = false;
25902636 foreach (var relatedData in items)
25912637 {
25922638 foreach (var result in relatedData.Results)
25932639 {
25942640 var item = CreatePostsFromStatusData(result.Status);
25952641 if (item == null) continue;
2596- if (targetItem.InReplyToStatusId == item.StatusId)
2597- {
2598- replyToItem = null;
2599- replyAdded = true;
2600- }
2601- item.IsRead = read;
2602- if (item.IsMe && !read && _readOwnPost) item.IsRead = true;
2603- if (tab != null) item.RelTabName = tab.TabName;
26042642 //非同期アイコン取得&StatusDictionaryに追加
2605- relatedPosts.Add(item);
2606- }
2607- }
2608- if (replyToItem != null)
2609- {
2610- relatedPosts.Add(replyToItem);
2611- }
2612- else if (targetItem.InReplyToStatusId > 0 && !replyAdded)
2613- {
2614- PostClass p = null;
2615- var rslt = "";
2616- rslt = GetStatusApi(read, targetItem.InReplyToStatusId, ref p);
2617- if (string.IsNullOrEmpty(rslt))
2618- {
2619- p.IsRead = read;
2620- p.RelTabName = tab.TabName;
2621- relatedPosts.Add(p);
2643+ if (!relatedPosts.ContainsKey(item.StatusId))
2644+ relatedPosts.Add(item.StatusId, item);
26222645 }
2623- return rslt;
26242646 }
26252647
2626- //発言者・返信先ユーザーの直近10発言取得
2627- //var rslt = this.GetUserTimelineApi(read, 10, "", tab);
2628- //if (!string.IsNullOrEmpty(rslt)) return rslt;
2629- //if (!string.IsNullOrEmpty(replyToUserName))
2630- // rslt = this.GetUserTimelineApi(read, 10, replyToUserName, tab);
2631- //}
2632- //return rslt;
2633-
2634- //MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
2635- var text = tab.RelationTargetPost.Text;
2636- var ma = Twitter.StatusUrlRegex.Matches(text).Cast<Match>()
2637- .Concat(Twitter.ThirdPartyStatusUrlRegex.Matches(text).Cast<Match>());
2638- foreach (var _match in ma)
2639- {
2640- Int64 _statusId;
2641- if (Int64.TryParse(_match.Groups["StatusId"].Value, out _statusId))
2642- {
2643- PostClass p = null;
2644- var _post = TabInformations.GetInstance()[_statusId];
2645- if (_post == null)
2646- {
2647- var rslt = this.GetStatusApi(read, _statusId, ref p);
2648- }
2649- else
2650- {
2651- p = _post.Clone();
2652- }
2653- if (p != null)
2654- {
2655- p.IsRead = read;
2656- p.RelTabName = tab.TabName;
2657- relatedPosts.Add(p);
2658- }
2659- }
2660- }
26612648 return "";
26622649 }
26632650