OSDN Git Service

タイムラインの取得結果にレートリミットに関するメッセージが含まれていた場合はエラーとして扱う
authorKimura Youichi <kim.upsilon@bucyou.net>
Wed, 24 Jan 2024 03:26:48 +0000 (12:26 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Wed, 24 Jan 2024 03:26:48 +0000 (12:26 +0900)
CHANGELOG.txt
OpenTween.Tests/Api/GraphQL/HomeLatestTimelineRequestTest.cs
OpenTween.Tests/Resources/Responses/HomeLatestTimeline_RateLimit.json [new file with mode: 0644]
OpenTween/Api/GraphQL/ErrorResponse.cs
OpenTween/Api/GraphQL/HomeLatestTimelineRequest.cs

index 944406f..9c2b682 100644 (file)
@@ -6,6 +6,7 @@
  * FIX: ツイート検索のキーワードを後から変更すると検索結果が表示されない不具合を修正
  * FIX: Cookie使用時にステータスバーにRecentタブのレートリミットが表示されない不具合を修正
  * FIX: 取得したツイートの中身が空だった場合のエラー処理を改善
+ * FIX: タイムラインの取得結果にレートリミットに関するメッセージが含まれていた場合はエラーとして扱う
 
 ==== Ver 3.12.0(2024/01/20)
  * NEW: graphqlエンドポイントを使用したホームタイムラインの取得に対応
index df1fb6e..4bc2b56 100644 (file)
@@ -21,6 +21,7 @@
 
 using System.Threading.Tasks;
 using Moq;
+using OpenTween.Api.DataModel;
 using OpenTween.Connection;
 using Xunit;
 
@@ -92,5 +93,32 @@ namespace OpenTween.Api.GraphQL
             await request.Send(mock.Object);
             mock.VerifyAll();
         }
+
+        [Fact]
+        public async Task Send_RateLimitTest()
+        {
+            using var apiResponse = await TestUtils.CreateApiResponse("Resources/Responses/HomeLatestTimeline_RateLimit.json");
+
+            var mock = new Mock<IApiConnection>();
+            mock.Setup(x =>
+                    x.SendAsync(It.IsAny<IHttpRequest>())
+                )
+                .Callback<IHttpRequest>(x =>
+                {
+                    var request = Assert.IsType<GetRequest>(x);
+                    Assert.Equal(new("https://twitter.com/i/api/graphql/lAKISuk_McyDUlhS2Zmv4A/HomeLatestTimeline"), request.RequestUri);
+                })
+                .ReturnsAsync(apiResponse);
+
+            var request = new HomeLatestTimelineRequest();
+
+            var ex = await Assert.ThrowsAsync<TwitterApiException>(
+                () => request.Send(mock.Object)
+            );
+            var errorItem = Assert.Single(ex.Errors);
+            Assert.Equal(TwitterErrorCode.RateLimit, errorItem.Code);
+
+            mock.VerifyAll();
+        }
     }
 }
diff --git a/OpenTween.Tests/Resources/Responses/HomeLatestTimeline_RateLimit.json b/OpenTween.Tests/Resources/Responses/HomeLatestTimeline_RateLimit.json
new file mode 100644 (file)
index 0000000..4a651c3
--- /dev/null
@@ -0,0 +1,68 @@
+{
+  "data": {
+    "home": {
+      "home_timeline_urt": {
+        "instructions": [
+          {
+            "type": "TimelineAddEntries",
+            "entries": [
+              {
+                "entryId": "messageprompt-1682783911",
+                "sortIndex": "1749988213990096896",
+                "content": {
+                  "entryType": "TimelineTimelineItem",
+                  "__typename": "TimelineTimelineItem",
+                  "itemContent": {
+                    "itemType": "TimelineMessagePrompt",
+                    "__typename": "TimelineMessagePrompt",
+                    "content": {
+                      "contentType": "TimelineInlinePrompt",
+                      "headerText": "Unlock more posts by subscribing",
+                      "bodyText": "You have reached the limit for seeing posts today. Subscribe to see more posts every day.",
+                      "primaryButtonAction": {
+                        "text": "Subscribe",
+                        "action": {
+                          "url": "https://twitter.com/i/twitter_blue_sign_up",
+                          "dismissOnClick": false
+                        }
+                      }
+                    }
+                  },
+                  "clientEventInfo": {
+                    "component": "verified_prompt",
+                    "element": "message"
+                  }
+                }
+              },
+              {
+                "entryId": "cursor-top-1749988213990096897",
+                "sortIndex": "1749988213990096897",
+                "content": {
+                  "entryType": "TimelineTimelineCursor",
+                  "__typename": "TimelineTimelineCursor",
+                  "value": "DAABCgABGEk1AkAAJxEKAAIYSJVb2ltBzQgAAwAAAAEAAA",
+                  "cursorType": "Top"
+                }
+              },
+              {
+                "entryId": "cursor-bottom-1749988213990096895",
+                "sortIndex": "1749988213990096895",
+                "content": {
+                  "entryType": "TimelineTimelineCursor",
+                  "__typename": "TimelineTimelineCursor",
+                  "value": "DAABCgABGEk1Aj____0KAAIYSJVb2ltBzQgAAwAAAAIAAA",
+                  "cursorType": "Bottom"
+                }
+              }
+            ]
+          }
+        ],
+        "metadata": {
+          "scribeConfig": {
+            "page": "following"
+          }
+        }
+      }
+    }
+  }
+}
index 4f778a0..2a8e6d4 100644 (file)
@@ -30,6 +30,7 @@ using System.Threading.Tasks;
 using System.Xml;
 using System.Xml.Linq;
 using System.Xml.XPath;
+using OpenTween.Api.DataModel;
 
 namespace OpenTween.Api.GraphQL
 {
@@ -63,5 +64,25 @@ namespace OpenTween.Api.GraphQL
 
             throw new WebApiException(messageText, responseJson);
         }
+
+        public static void ThrowIfContainsRateLimitMessage(XElement rootElm)
+        {
+            var messageElm = rootElm.XPathSelectElement("//itemContent[itemType[text()='TimelineMessagePrompt']]");
+            if (messageElm == null)
+                return;
+
+            var bodyText = messageElm.XPathSelectElement("content/bodyText")?.Value ?? "";
+            if (bodyText.StartsWith("You have reached the limit"))
+            {
+                var error = new TwitterError
+                {
+                    Errors = new[]
+                    {
+                        new TwitterErrorItem { Code = TwitterErrorCode.RateLimit, Message = "" },
+                    },
+                };
+                throw new TwitterApiException(0, error, "");
+            }
+        }
     }
 }
index d11c0ca..63bea06 100644 (file)
@@ -72,6 +72,9 @@ namespace OpenTween.Api.GraphQL
             ErrorResponse.ThrowIfError(rootElm);
 
             var tweets = TimelineTweet.ExtractTimelineTweets(rootElm);
+            if (tweets.Length == 0)
+                ErrorResponse.ThrowIfContainsRateLimitMessage(rootElm);
+
             var cursorTop = rootElm.XPathSelectElement("//content[__typename[text()='TimelineTimelineCursor']][cursorType[text()='Top']]/value")?.Value;
             var cursorBottom = rootElm.XPathSelectElement("//content[__typename[text()='TimelineTimelineCursor']][cursorType[text()='Bottom']]/value")?.Value;