OSDN Git Service

TwitterGraphqlCursorクラスを追加
authorKimura Youichi <kim.upsilon@bucyou.net>
Fri, 3 May 2024 14:43:51 +0000 (23:43 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Fri, 3 May 2024 21:12:44 +0000 (06:12 +0900)
22 files changed:
OpenTween.Tests/Api/GraphQL/HomeLatestTimelineRequestTest.cs
OpenTween.Tests/Api/GraphQL/LikesRequestTest.cs
OpenTween.Tests/Api/GraphQL/ListLatestTweetsTimelineRequestTest.cs
OpenTween.Tests/Api/GraphQL/SearchTimelineRequestTest.cs
OpenTween.Tests/Api/GraphQL/TimelineResponseTest.cs
OpenTween.Tests/Api/GraphQL/UserTweetsAndRepliesRequestTest.cs
OpenTween.Tests/Api/TwitterV2/NotificationsMentionsRequestTest.cs
OpenTween/Api/GraphQL/HomeLatestTimelineRequest.cs
OpenTween/Api/GraphQL/LikesRequest.cs
OpenTween/Api/GraphQL/ListLatestTweetsTimelineRequest.cs
OpenTween/Api/GraphQL/SearchTimelineRequest.cs
OpenTween/Api/GraphQL/TimelineResponse.cs
OpenTween/Api/GraphQL/TimelineResponseParser.cs
OpenTween/Api/GraphQL/TwitterGraphqlCursor.cs [new file with mode: 0644]
OpenTween/Api/GraphQL/UserTweetsAndRepliesRequest.cs
OpenTween/Api/TwitterV2/NotificationsMentionsRequest.cs
OpenTween/Models/FavoritesTabModel.cs
OpenTween/Models/HomeTabModel.cs
OpenTween/Models/ListTimelineTabModel.cs
OpenTween/Models/MentionsTabModel.cs
OpenTween/Models/PublicSearchTabModel.cs
OpenTween/Models/UserTimelineTabModel.cs

index 4bc2b56..ce18d24 100644 (file)
@@ -57,8 +57,8 @@ namespace OpenTween.Api.GraphQL
 
             var response = await request.Send(mock.Object);
             Assert.Single(response.Tweets);
-            Assert.Equal("DAABCgABGENe-W5AJxEKAAIWeWboXhcQAAgAAwAAAAEAAA", response.CursorTop);
-            Assert.Equal("DAABCgABGENe-W4__5oKAAIWK_5v3BcQAAgAAwAAAAIAAA", response.CursorBottom);
+            Assert.Equal("DAABCgABGENe-W5AJxEKAAIWeWboXhcQAAgAAwAAAAEAAA", response.CursorTop?.Value);
+            Assert.Equal("DAABCgABGENe-W4__5oKAAIWK_5v3BcQAAgAAwAAAAIAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -87,7 +87,7 @@ namespace OpenTween.Api.GraphQL
             var request = new HomeLatestTimelineRequest
             {
                 Count = 20,
-                Cursor = "aaa",
+                Cursor = new("aaa"),
             };
 
             await request.Send(mock.Object);
index accc445..704adf4 100644 (file)
@@ -57,8 +57,8 @@ namespace OpenTween.Api.GraphQL
 
             var response = await request.Send(mock.Object);
             Assert.Single(response.Tweets);
-            Assert.Equal("DAAHCgABGEs2Ve9AAAELAAIAAAATMTc4OTA3OTU2MDM5NDcxNTMyMggAAwAAAAEAAA", response.CursorTop);
-            Assert.Equal("DAAHCgABGEs2Ve8___8LAAIAAAATMTc4OTA3OTU2MDM5NDcxNTMyMggAAwAAAAIAAA", response.CursorBottom);
+            Assert.Equal("DAAHCgABGEs2Ve9AAAELAAIAAAATMTc4OTA3OTU2MDM5NDcxNTMyMggAAwAAAAEAAA", response.CursorTop?.Value);
+            Assert.Equal("DAAHCgABGEs2Ve8___8LAAIAAAATMTc4OTA3OTU2MDM5NDcxNTMyMggAAwAAAAIAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -85,7 +85,7 @@ namespace OpenTween.Api.GraphQL
             {
                 UserId = "12345",
                 Count = 20,
-                Cursor = "aaa",
+                Cursor = new("aaa"),
             };
 
             await request.Send(mock.Object);
index 4cb9c95..e68cd8a 100644 (file)
@@ -56,8 +56,8 @@ namespace OpenTween.Api.GraphQL
 
             var response = await request.Send(mock.Object);
             Assert.Single(response.Tweets);
-            Assert.Equal("DAABCgABF0HfRMjAJxEKAAIWes8rE1oQAAgAAwAAAAEAAA", response.CursorTop);
-            Assert.Equal("DAABCgABF0HfRMi__7QKAAIVAxUYmFWQAwgAAwAAAAIAAA", response.CursorBottom);
+            Assert.Equal("DAABCgABF0HfRMjAJxEKAAIWes8rE1oQAAgAAwAAAAEAAA", response.CursorTop?.Value);
+            Assert.Equal("DAABCgABF0HfRMi__7QKAAIVAxUYmFWQAwgAAwAAAAIAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -86,7 +86,7 @@ namespace OpenTween.Api.GraphQL
             var request = new ListLatestTweetsTimelineRequest(listId: "1675863884757110790")
             {
                 Count = 20,
-                Cursor = "aaa",
+                Cursor = new("aaa"),
             };
 
             await request.Send(mock.Object);
index 7e960eb..72ac3ce 100644 (file)
@@ -56,8 +56,8 @@ namespace OpenTween.Api.GraphQL
 
             var response = await request.Send(mock.Object);
             Assert.Single(response.Tweets);
-            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAABCAADAAAAAAgABAAAAAAKAAUX8j3ezIAnEAoABhfyPd7Mf9jwAAA", response.CursorTop);
-            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAACCAADAAAAAAgABAAAAAAKAAUX8j3ezIAnEAoABhfyPd7Mf9jwAAA", response.CursorBottom);
+            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAABCAADAAAAAAgABAAAAAAKAAUX8j3ezIAnEAoABhfyPd7Mf9jwAAA", response.CursorTop?.Value);
+            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAACCAADAAAAAAgABAAAAAAKAAUX8j3ezIAnEAoABhfyPd7Mf9jwAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -78,8 +78,8 @@ namespace OpenTween.Api.GraphQL
 
             var response = await request.Send(mock.Object);
             Assert.Empty(response.Tweets);
-            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAABCAADAAAAAQgABAAAAAAKAAUX8j3ezIBOIAoABhfyPd7Mf9jwAAA", response.CursorTop);
-            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAACCAADAAAAAQgABAAAAAAKAAUX8j3ezIBOIAoABhfyPd7Mf9jwAAA", response.CursorBottom);
+            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAABCAADAAAAAQgABAAAAAAKAAUX8j3ezIBOIAoABhfyPd7Mf9jwAAA", response.CursorTop?.Value);
+            Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAACCAADAAAAAQgABAAAAAAKAAUX8j3ezIBOIAoABhfyPd7Mf9jwAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -108,7 +108,7 @@ namespace OpenTween.Api.GraphQL
             var request = new SearchTimelineRequest(rawQuery: "#OpenTween")
             {
                 Count = 20,
-                Cursor = "aaa",
+                Cursor = new("aaa"),
             };
 
             await request.Send(mock.Object);
index 4a793df..bf6b64d 100644 (file)
@@ -31,7 +31,7 @@ namespace OpenTween.Api.GraphQL
         {
             using var apiResponse = await TestUtils.CreateApiResponse("Resources/Responses/SearchTimeline_SimpleTweet.json");
             var tweets = TimelineTweet.ExtractTimelineTweets(await apiResponse.ReadAsJsonXml());
-            var timelineResponse = new TimelineResponse(tweets, "", "");
+            var timelineResponse = new TimelineResponse(tweets, new(""), new(""));
 
             var statuses = timelineResponse.ToTwitterStatuses();
             Assert.Single(statuses);
index 50264c6..a989361 100644 (file)
@@ -56,8 +56,8 @@ namespace OpenTween.Api.GraphQL
 
             var response = await request.Send(mock.Object);
             Assert.Single(response.Tweets);
-            Assert.Equal("DAABCgABF_tTnZvAJxEKAAIWes8rE1oQAAgAAwAAAAEAAA", response.CursorTop);
-            Assert.Equal("DAABCgABF_tTnZu__-0KAAIWZa6KTRoAAwgAAwAAAAIAAA", response.CursorBottom);
+            Assert.Equal("DAABCgABF_tTnZvAJxEKAAIWes8rE1oQAAgAAwAAAAEAAA", response.CursorTop?.Value);
+            Assert.Equal("DAABCgABF_tTnZu__-0KAAIWZa6KTRoAAwgAAwAAAAIAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -86,7 +86,7 @@ namespace OpenTween.Api.GraphQL
             var request = new UserTweetsAndRepliesRequest(userId: "40480664")
             {
                 Count = 20,
-                Cursor = "aaa",
+                Cursor = new("aaa"),
             };
 
             await request.Send(mock.Object);
index d65c7ae..ef264e3 100644 (file)
@@ -59,8 +59,8 @@ namespace OpenTween.Api.TwitterV2
             Assert.Equal("1748671085438988794", status.IdStr);
             Assert.Equal("40480664", status.User.IdStr);
 
-            Assert.Equal("DAABDAABCgABAAAAAC4B0ZQIAAIAAAACCAADm5udsQgABCaolIMACwACAAAAC0FZMG1xVjB6VEZjAAA", response.CursorTop);
-            Assert.Equal("DAACDAABCgABAAAAAC4B0ZQIAAIAAAACCAADm5udsQgABCaolIMACwACAAAAC0FZMG1xVjB6VEZjAAA", response.CursorBottom);
+            Assert.Equal("DAABDAABCgABAAAAAC4B0ZQIAAIAAAACCAADm5udsQgABCaolIMACwACAAAAC0FZMG1xVjB6VEZjAAA", response.CursorTop?.Value);
+            Assert.Equal("DAACDAABCgABAAAAAC4B0ZQIAAIAAAACCAADm5udsQgABCaolIMACwACAAAAC0FZMG1xVjB6VEZjAAA", response.CursorBottom?.Value);
 
             mock.VerifyAll();
         }
@@ -88,7 +88,7 @@ namespace OpenTween.Api.TwitterV2
             var request = new NotificationsMentionsRequest()
             {
                 Count = 20,
-                Cursor = "aaa",
+                Cursor = new("aaa"),
             };
 
             await request.Send(mock.Object);
index e9fb72e..f848810 100644 (file)
@@ -25,6 +25,7 @@ using System;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using OpenTween.Connection;
+using OpenTween.Models;
 
 namespace OpenTween.Api.GraphQL
 {
@@ -36,16 +37,18 @@ namespace OpenTween.Api.GraphQL
 
         public int Count { get; set; } = 20;
 
-        public string? Cursor { get; set; }
+        public TwitterGraphqlCursor? Cursor { get; set; }
 
         public Dictionary<string, string> CreateParameters()
         {
+            var cursorStr = this.Cursor?.Value;
+
             return new()
             {
                 ["variables"] = "{" +
                     $@"""includePromotedContent"":true,""latestControlAvailable"":true,""requestContext"":""launch""," +
                     $@"""count"":{this.Count}" +
-                    (this.Cursor != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(this.Cursor)}""" : "") +
+                    (cursorStr != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(cursorStr)}""" : "") +
                     "}",
                 ["features"] = """
                     {"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_media_download_video_enabled":false,"responsive_web_enhance_cards_enabled":false}
index deda28a..d919769 100644 (file)
@@ -38,10 +38,12 @@ namespace OpenTween.Api.GraphQL
 
         public int Count { get; set; } = 20;
 
-        public string? Cursor { get; set; }
+        public TwitterGraphqlCursor? Cursor { get; set; }
 
         public Dictionary<string, string> CreateParameters()
         {
+            var cursorStr = this.Cursor?.Value;
+
             return new()
             {
                 ["variables"] = "{" +
@@ -52,7 +54,7 @@ namespace OpenTween.Api.GraphQL
                     $@"""withBirdwatchNotes"":false," +
                     $@"""withVoice"":true," +
                     $@"""withV2Timeline"":true" +
-                    (this.Cursor != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(this.Cursor)}""" : "") +
+                    (cursorStr != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(cursorStr)}""" : "") +
                     "}",
                 ["features"] = """
                     {"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_media_download_video_enabled":false,"responsive_web_enhance_cards_enabled":false}
index 29d0614..81c0ccc 100644 (file)
@@ -38,19 +38,21 @@ namespace OpenTween.Api.GraphQL
 
         public int Count { get; set; } = 20;
 
-        public string? Cursor { get; set; }
+        public TwitterGraphqlCursor? Cursor { get; set; }
 
         public ListLatestTweetsTimelineRequest(string listId)
             => this.ListId = listId;
 
         public Dictionary<string, string> CreateParameters()
         {
+            var cursorStr = this.Cursor?.Value;
+
             return new()
             {
                 ["variables"] = "{" +
                     $@"""listId"":""{JsonUtils.EscapeJsonString(this.ListId)}""," +
                     $@"""count"":{this.Count}" +
-                    (this.Cursor != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(this.Cursor)}""" : "") +
+                    (cursorStr != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(cursorStr)}""" : "") +
                     "}",
                 ["features"] = "{" +
                     @"""rweb_lists_timeline_redesign_enabled"":true," +
index 9587d80..2f00249 100644 (file)
@@ -38,20 +38,22 @@ namespace OpenTween.Api.GraphQL
 
         public int Count { get; set; } = 20;
 
-        public string? Cursor { get; set; }
+        public TwitterGraphqlCursor? Cursor { get; set; }
 
         public SearchTimelineRequest(string rawQuery)
             => this.RawQuery = rawQuery;
 
         public Dictionary<string, string> CreateParameters()
         {
+            var cursorStr = this.Cursor?.Value;
+
             return new()
             {
                 ["variables"] = "{" +
                     $@"""rawQuery"":""{JsonUtils.EscapeJsonString(this.RawQuery)}""," +
                     $@"""count"":{this.Count}," +
                     $@"""product"":""Latest""" +
-                    (this.Cursor != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(this.Cursor)}""" : "") +
+                    (cursorStr != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(cursorStr)}""" : "") +
                     "}",
                 ["features"] = "{" +
                     @"""responsive_web_graphql_exclude_directive_enabled"":true," +
index a2729df..fbf5964 100644 (file)
@@ -28,8 +28,8 @@ namespace OpenTween.Api.GraphQL
 {
     public record TimelineResponse(
         TimelineTweet[] Tweets,
-        string? CursorTop,
-        string? CursorBottom
+        TwitterGraphqlCursor? CursorTop,
+        TwitterGraphqlCursor? CursorBottom
     )
     {
         public TwitterStatus[] ToTwitterStatuses()
index 8fe315f..3e1e590 100644 (file)
@@ -36,8 +36,15 @@ namespace OpenTween.Api.GraphQL
             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;
+            var cursorTopStr = rootElm.XPathSelectElement("//content[__typename[text()='TimelineTimelineCursor']][cursorType[text()='Top']]/value")?.Value;
+            var cursorTop = cursorTopStr != null
+                ? new TwitterGraphqlCursor(cursorTopStr)
+                : null;
+
+            var cursorBottomStr = rootElm.XPathSelectElement("//content[__typename[text()='TimelineTimelineCursor']][cursorType[text()='Bottom']]/value")?.Value;
+            var cursorBottom = cursorBottomStr != null
+                ? new TwitterGraphqlCursor(cursorBottomStr)
+                : null;
 
             return new(tweets, cursorTop, cursorBottom);
         }
diff --git a/OpenTween/Api/GraphQL/TwitterGraphqlCursor.cs b/OpenTween/Api/GraphQL/TwitterGraphqlCursor.cs
new file mode 100644 (file)
index 0000000..88bdbdc
--- /dev/null
@@ -0,0 +1,29 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2024 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#nullable enable
+
+namespace OpenTween.Api.GraphQL
+{
+    public record TwitterGraphqlCursor(
+        string Value
+    );
+}
index c138868..790a0ac 100644 (file)
@@ -38,13 +38,15 @@ namespace OpenTween.Api.GraphQL
 
         public int Count { get; set; } = 20;
 
-        public string? Cursor { get; set; }
+        public TwitterGraphqlCursor? Cursor { get; set; }
 
         public UserTweetsAndRepliesRequest(string userId)
             => this.UserId = userId;
 
         public Dictionary<string, string> CreateParameters()
         {
+            var cursorStr = this.Cursor?.Value;
+
             return new()
             {
                 ["variables"] = "{" +
@@ -54,7 +56,7 @@ namespace OpenTween.Api.GraphQL
                     $@"""withCommunity"":true," +
                     $@"""withVoice"":true," +
                     $@"""withV2Timeline"":true" +
-                    (this.Cursor != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(this.Cursor)}""" : "") +
+                    (cursorStr != null ? $@",""cursor"":""{JsonUtils.EscapeJsonString(cursorStr)}""" : "") +
                     "}",
                 ["features"] = """
                     {"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"responsive_web_home_pinned_timelines_enabled":true,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":false,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_media_download_video_enabled":false,"responsive_web_enhance_cards_enabled":false}
index 8f08a5e..22e28e9 100644 (file)
@@ -46,7 +46,7 @@ namespace OpenTween.Api.TwitterV2
 
         public int Count { get; set; } = 100;
 
-        public string? Cursor { get; set; }
+        public TwitterGraphqlCursor? Cursor { get; set; }
 
         public Dictionary<string, string> CreateParameters()
         {
@@ -86,8 +86,8 @@ namespace OpenTween.Api.TwitterV2
                 ["count"] = this.Count.ToString(CultureInfo.InvariantCulture),
             };
 
-            if (!MyCommon.IsNullOrEmpty(this.Cursor))
-                param["cursor"] = this.Cursor;
+            if (this.Cursor != null)
+                param["cursor"] = this.Cursor.Value;
 
             return param;
         }
@@ -151,8 +151,15 @@ namespace OpenTween.Api.TwitterV2
                 statuses.Add(tweet);
             }
 
-            var cursorTop = rootElm.XPathSelectElement("//content/operation/cursor[cursorType[text()='Top']]/value")?.Value;
-            var cursorBottom = rootElm.XPathSelectElement("//content/operation/cursor[cursorType[text()='Bottom']]/value")?.Value;
+            var cursorTopStr = rootElm.XPathSelectElement("//content/operation/cursor[cursorType[text()='Top']]/value")?.Value;
+            var cursorTop = cursorTopStr != null
+                ? new TwitterGraphqlCursor(cursorTopStr)
+                : null;
+
+            var cursorBottomStr = rootElm.XPathSelectElement("//content/operation/cursor[cursorType[text()='Bottom']]/value")?.Value;
+            var cursorBottom = cursorBottomStr != null
+                ? new TwitterGraphqlCursor(cursorBottomStr)
+                : null;
 
             return new(statuses.ToArray(), cursorTop, cursorBottom);
         }
@@ -180,8 +187,8 @@ namespace OpenTween.Api.TwitterV2
 
         public readonly record struct NotificationsResponse(
             TwitterStatus[] Statuses,
-            string? CursorTop,
-            string? CursorBottom
+            TwitterGraphqlCursor? CursorTop,
+            TwitterGraphqlCursor? CursorBottom
         );
     }
 }
index fc6d502..adf87fe 100644 (file)
@@ -32,6 +32,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -45,9 +46,9 @@ namespace OpenTween.Models
 
         public PostId? OldestId { get; set; }
 
-        public string? CursorTop { get; set; }
+        public TwitterGraphqlCursor? CursorTop { get; set; }
 
-        public string? CursorBottom { get; set; }
+        public TwitterGraphqlCursor? CursorBottom { get; set; }
 
         public FavoritesTabModel()
             : this(MyCommon.DEFAULTTAB.FAV)
index 583b5cb..5e7074d 100644 (file)
@@ -34,6 +34,7 @@ using System.Linq;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -47,9 +48,9 @@ namespace OpenTween.Models
 
         public PostId? OldestId { get; set; }
 
-        public string? CursorTop { get; set; }
+        public TwitterGraphqlCursor? CursorTop { get; set; }
 
-        public string? CursorBottom { get; set; }
+        public TwitterGraphqlCursor? CursorBottom { get; set; }
 
         public int TweetsPerHour => this.tweetsPerHour;
 
index 08ffceb..046a6d8 100644 (file)
@@ -32,6 +32,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -47,9 +48,9 @@ namespace OpenTween.Models
 
         public PostId? OldestId { get; set; }
 
-        public string? CursorTop { get; set; }
+        public TwitterGraphqlCursor? CursorTop { get; set; }
 
-        public string? CursorBottom { get; set; }
+        public TwitterGraphqlCursor? CursorBottom { get; set; }
 
         public ListTimelineTabModel(string tabName, ListElement list)
             : base(tabName)
index 7e97bba..45ab1a7 100644 (file)
@@ -32,6 +32,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -45,9 +46,9 @@ namespace OpenTween.Models
 
         public PostId? OldestId { get; set; }
 
-        public string? CursorTop { get; set; }
+        public TwitterGraphqlCursor? CursorTop { get; set; }
 
-        public string? CursorBottom { get; set; }
+        public TwitterGraphqlCursor? CursorBottom { get; set; }
 
         public MentionsTabModel()
             : this(MyCommon.DEFAULTTAB.REPLY)
index 97e359c..db223d2 100644 (file)
@@ -32,6 +32,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -47,9 +48,9 @@ namespace OpenTween.Models
 
         public PostId? SinceId { get; set; }
 
-        public string? CursorTop { get; set; }
+        public TwitterGraphqlCursor? CursorTop { get; set; }
 
-        public string? CursorBottom { get; set; }
+        public TwitterGraphqlCursor? CursorBottom { get; set; }
 
         public string SearchWords
         {
index eda890d..168dc9f 100644 (file)
@@ -32,6 +32,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -49,9 +50,9 @@ namespace OpenTween.Models
 
         public PostId? OldestId { get; set; }
 
-        public string? CursorTop { get; set; }
+        public TwitterGraphqlCursor? CursorTop { get; set; }
 
-        public string? CursorBottom { get; set; }
+        public TwitterGraphqlCursor? CursorBottom { get; set; }
 
         public UserTimelineTabModel(string tabName, string screenName)
             : base(tabName)