account.Initialize(accountSettings2, settingCommon2);
Assert.Equal(22222L, account.UserId);
}
+
+ [Fact]
+ public void Query_V1_Test()
+ {
+ var accountKey = Guid.NewGuid();
+ using var account = new TwitterAccount(accountKey);
+
+ var accountSettings = new UserAccount
+ {
+ UniqueKey = accountKey,
+ TwitterAuthType = APIAuthType.OAuth1,
+ Token = "aaaaa",
+ TokenSecret = "aaaaa",
+ UserId = 11111L,
+ Username = "tetete",
+ };
+ var settingCommon = new SettingCommon();
+ account.Initialize(accountSettings, settingCommon);
+
+ Assert.IsType<TwitterV1Query>(account.Query);
+ }
+
+ [Fact]
+ public void Query_Graphql_Test()
+ {
+ var accountKey = Guid.NewGuid();
+ using var account = new TwitterAccount(accountKey);
+
+ var accountSettings = new UserAccount
+ {
+ UniqueKey = accountKey,
+ TwitterAuthType = APIAuthType.TwitterComCookie,
+ TwitterComCookie = "auth_token=foo; ct0=bar",
+ UserId = 11111L,
+ Username = "tetete",
+ };
+ var settingCommon = new SettingCommon();
+ account.Initialize(accountSettings, settingCommon);
+
+ Assert.IsType<TwitterGraphqlQuery>(account.Query);
+ }
}
}
public override async Task RefreshAsync(ISocialAccount account, bool backward, IProgress<string> progress)
{
- if (account is not TwitterAccount twAccount)
- throw new ArgumentException($"Invalid account type: {account.GetType()}", nameof(account));
-
progress.Report(string.Format(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText5, backward ? -1 : 1));
var firstLoad = !this.IsFirstLoadCompleted;
var count = Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Timeline, backward, firstLoad);
var cursor = backward ? this.CursorBottom : this.CursorTop;
- var response = await twAccount.Legacy.GetHomeTimelineApi(count, cursor, firstLoad)
+ var response = await account.Query.GetHomeTimeline(count, cursor, firstLoad)
.ConfigureAwait(false);
foreach (var post in response.Posts)
public IApiConnection Connection { get; }
+ public ISocialProtocolQuery Query { get; }
+
public bool IsDisposed { get; }
public void Initialize(UserAccount accountSettings, SettingCommon settingCommon);
--- /dev/null
+// 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
+
+using System.Threading.Tasks;
+using OpenTween.Models;
+
+namespace OpenTween.SocialProtocol
+{
+ public interface ISocialProtocolQuery
+ {
+ public Task<TimelineResponse> GetHomeTimeline(int count, IQueryCursor? cursor, bool firstLoad);
+ }
+}
public Guid UniqueKey { get; }
+ public ISocialProtocolQuery Query { get; private set; }
+
public bool IsDisposed { get; private set; }
public TwitterAccountState AccountState { get; private set; } = new();
=> this.Legacy.Api.Connection;
public TwitterAccount(Guid uniqueKey)
- => this.UniqueKey = uniqueKey;
+ {
+ this.UniqueKey = uniqueKey;
+ this.Query = this.CreateQueryInstance(APIAuthType.None);
+ }
public void Initialize(UserAccount accountSettings, SettingCommon settingCommon)
{
var credential = accountSettings.GetTwitterCredential();
this.AccountState = new TwitterAccountState(accountSettings.UserId, accountSettings.Username);
+ this.Query = this.CreateQueryInstance(credential.AuthType);
+
this.twLegacy.Initialize(credential, this.AccountState);
this.twLegacy.RestrictFavCheck = settingCommon.RestrictFavCheck;
}
this.twLegacy.Dispose();
this.IsDisposed = true;
}
+
+ private ISocialProtocolQuery CreateQueryInstance(APIAuthType authType)
+ {
+ return authType switch
+ {
+ APIAuthType.TwitterComCookie => new TwitterGraphqlQuery(this),
+ _ => new TwitterV1Query(this),
+ };
+ }
}
}
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
+// (c) 2008-2011 Moz (@syo68k)
+// (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
+// (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
+// (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
+// (c) 2011 Egtra (@egtra) <http://dev.activebasic.com/egtra/>
+// (c) 2013 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
+
+using System.Threading.Tasks;
+using OpenTween.Api.GraphQL;
+using OpenTween.Models;
+
+namespace OpenTween.SocialProtocol.Twitter
+{
+ public class TwitterGraphqlQuery : ISocialProtocolQuery
+ {
+ private readonly TwitterAccount account;
+
+ public TwitterGraphqlQuery(TwitterAccount account)
+ {
+ this.account = account;
+ }
+
+ public async Task<TimelineResponse> GetHomeTimeline(int count, IQueryCursor? cursor, bool firstLoad)
+ {
+ this.account.Legacy.CheckAccountState();
+
+ var request = new HomeLatestTimelineRequest
+ {
+ Count = count,
+ Cursor = cursor?.As<TwitterGraphqlCursor>(),
+ };
+
+ var response = await request.Send(this.account.Connection)
+ .ConfigureAwait(false);
+
+ var statuses = response.ToTwitterStatuses();
+ var cursorTop = response.CursorTop;
+ var cursorBottom = response.CursorBottom;
+
+ var posts = this.account.Legacy.CreatePostsFromJson(statuses, firstLoad);
+ posts = this.account.Legacy.FilterNoRetweetUserPosts(posts);
+
+ return new(posts, cursorTop, cursorBottom);
+ }
+ }
+}
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
+// (c) 2008-2011 Moz (@syo68k)
+// (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
+// (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
+// (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
+// (c) 2011 Egtra (@egtra) <http://dev.activebasic.com/egtra/>
+// (c) 2013 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
+
+using System.Linq;
+using System.Threading.Tasks;
+using OpenTween.Models;
+
+namespace OpenTween.SocialProtocol.Twitter
+{
+ public class TwitterV1Query : ISocialProtocolQuery
+ {
+ private readonly TwitterAccount account;
+
+ public TwitterV1Query(TwitterAccount account)
+ {
+ this.account = account;
+ }
+
+ public async Task<TimelineResponse> GetHomeTimeline(int count, IQueryCursor? cursor, bool firstLoad)
+ {
+ this.account.Legacy.CheckAccountState();
+
+ TwitterStatusId? maxId = null, sinceId = null;
+
+ if (cursor is QueryCursor<TwitterStatusId> statusIdCursor)
+ {
+ if (statusIdCursor.Type == CursorType.Top)
+ sinceId = statusIdCursor.Value;
+ else if (statusIdCursor.Type == CursorType.Bottom)
+ maxId = statusIdCursor.Value;
+ }
+
+ var statuses = await this.account.Legacy.Api.StatusesHomeTimeline(count, maxId, sinceId)
+ .ConfigureAwait(false);
+
+ IQueryCursor? cursorTop = null, cursorBottom = null;
+
+ if (statuses.Length > 0)
+ {
+ var (min, max) = statuses.Select(x => new TwitterStatusId(x.IdStr)).MinMax();
+ cursorTop = new QueryCursor<TwitterStatusId>(CursorType.Top, max);
+ cursorBottom = new QueryCursor<TwitterStatusId>(CursorType.Bottom, min);
+ }
+
+ var posts = this.account.Legacy.CreatePostsFromJson(statuses, firstLoad);
+ posts = this.account.Legacy.FilterNoRetweetUserPosts(posts);
+
+ return new(posts, cursorTop, cursorBottom);
+ }
+ }
+}
return Math.Min(count, GetMaxApiResultCount(type));
}
- public async Task<TimelineResponse> GetHomeTimelineApi(int count, IQueryCursor? cursor, bool firstLoad)
- {
- this.CheckAccountState();
-
- TwitterStatus[] statuses;
- IQueryCursor? cursorTop = null, cursorBottom = null;
-
- if (this.Api.AuthType == APIAuthType.TwitterComCookie)
- {
- var request = new HomeLatestTimelineRequest
- {
- Count = count,
- Cursor = cursor?.As<TwitterGraphqlCursor>(),
- };
- var response = await request.Send(this.Api.Connection)
- .ConfigureAwait(false);
-
- statuses = response.ToTwitterStatuses();
-
- cursorTop = response.CursorTop;
- cursorBottom = response.CursorBottom;
- }
- else
- {
- TwitterStatusId? maxId = null, sinceId = null;
-
- if (cursor is QueryCursor<TwitterStatusId> statusIdCursor)
- {
- if (statusIdCursor.Type == CursorType.Top)
- sinceId = statusIdCursor.Value;
- else if (statusIdCursor.Type == CursorType.Bottom)
- maxId = statusIdCursor.Value;
- }
-
- statuses = await this.Api.StatusesHomeTimeline(count, maxId, sinceId)
- .ConfigureAwait(false);
-
- if (statuses.Length > 0)
- {
- var (min, max) = statuses.Select(x => new TwitterStatusId(x.IdStr)).MinMax();
- cursorTop = new QueryCursor<TwitterStatusId>(CursorType.Top, max);
- cursorBottom = new QueryCursor<TwitterStatusId>(CursorType.Bottom, min);
- }
- }
-
- var posts = this.CreatePostsFromJson(statuses, firstLoad);
- posts = this.FilterNoRetweetUserPosts(posts);
-
- return new(posts, cursorTop, cursorBottom);
- }
-
public async Task GetMentionsTimelineApi(MentionsTabModel tab, bool more, bool firstLoad)
{
this.CheckAccountState();
return post;
}
- private PostClass[] CreatePostsFromJson(TwitterStatus[] statuses, bool firstLoad)
+ internal PostClass[] CreatePostsFromJson(TwitterStatus[] statuses, bool firstLoad)
{
var posts = statuses.Select(x => this.CreatePostsFromStatusData(x, firstLoad)).ToArray();
return posts;
}
- private PostClass[] FilterNoRetweetUserPosts(PostClass[] posts)
+ internal PostClass[] FilterNoRetweetUserPosts(PostClass[] posts)
=> posts.Where(x => x.RetweetedByUserId == null || !this.Api.AccountState.NoRetweetUserIds.Contains(x.RetweetedByUserId.Value)).ToArray();
public async Task GetListStatus(ListTimelineTabModel tab, bool more, bool firstLoad)
public string[] GetHashList()
=> this.postFactory.GetReceivedHashtags();
- private void CheckAccountState()
+ internal void CheckAccountState()
{
if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid)
throw new WebApiException("Auth error. Check your account");