Skip to content

Commit

Permalink
Merge branch 'develop' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
upsilon committed Jun 10, 2024
2 parents b954c0f + e8df69d commit c3ee35e
Show file tree
Hide file tree
Showing 252 changed files with 11,882 additions and 4,393 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ env:
jobs:
build:
uses: ./.github/workflows/build.yml
with:
msbuild_args: /p:ContinuousIntegrationBuild=true

test:
runs-on: windows-2022
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
更新履歴

==== Ver 3.14.0(2024/06/11)
* NEW: メインアカウント以外のホームタイムライン表示に対応
- タブ単位で切り替わるマルチアカウント機能です
- 投稿欄やふぁぼ・RT等の機能も表示中のタブに連動して使用するアカウントが変わります
- 現時点ではメインアカウント以外のタブ設定は次回起動時に保持されません
* NEW: Misskeyアカウントのホームタイムライン表示・投稿に対応しました
- 現時点では Misskey アカウントをメインに設定することはできません
- MFMの表示には対応していません
* NEW: Twemoji 15.1.0 に対応しました
- Unicode 15.1 で追加された絵文字が表示されるようになります
* NEW: WebP画像の表示に対応しました
- プロフィール画像やサムネイル画像にWebPが使われている場合も表示が可能になります
- 「WebP画像拡張機能」がインストールされている環境でのみ動作します
* CHG: 設定画面でのアカウント一覧の表示形式を変更
* CHG: 新規アカウント追加時のダイアログの構成を変更
* CHG: 新規タブの初回に読み込まれた発言を既読状態にする(起動時の初回の読み込みと同じ動作となる)
* CHG: ドメインに x.com が使われている引用ツイートの展開・投稿に対応
* CHG: 不具合調査のために追加していた発言一覧の定期更新タスクの待機時間チェックを削除
* FIX: 発言の削除中にタブを切り替えるとエラーが発生する不具合を修正 (thx @Tan90909090!)
* FIX: 発言一覧のプロフィール画像の読み込みでエラーが発生すると無限ループが生じる不具合を修正
* FIX: 発言詳細欄からプロフィール画像の再読み込みを行う機能が動作していない不具合を修正
* FIX: DMの添付画像の読み込み時に発生したエラーが適切に処理されない不具合を修正 (thx @wahho!)

==== Ver 3.13.0(2024/01/27)
* NEW: Cookie使用時のReplyタブの更新に対応(/statuses/mentions_timeline.json 廃止に伴う対応)
* NEW: Cookie使用時のFavoritesタブの更新に対応
Expand Down
5 changes: 5 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<DefineConstants Condition="'$(ContinuousIntegrationBuild)' == 'true'">$(DefineConstants);CI_BUILD</DefineConstants>
</PropertyGroup>
</Project>
3 changes: 2 additions & 1 deletion OpenTween.Tests/Api/GraphQL/CreateTweetRequestTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using System.Threading.Tasks;
using Moq;
using OpenTween.Connection;
using OpenTween.Models;
using Xunit;

namespace OpenTween.Api.GraphQL
Expand Down Expand Up @@ -78,7 +79,7 @@ public async Task Send_ReplyTest()
{
TweetText = "tetete",
InReplyToTweetId = new("12345"),
ExcludeReplyUserIds = new[] { "11111", "22222" },
ExcludeReplyUserIds = new TwitterUserId[] { new("11111"), new("22222") },
};
await request.Send(mock.Object);
mock.VerifyAll();
Expand Down
6 changes: 3 additions & 3 deletions OpenTween.Tests/Api/GraphQL/HomeLatestTimelineRequestTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ public async Task Send_Test()

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.Value);
Assert.Equal("DAABCgABGENe-W4__5oKAAIWK_5v3BcQAAgAAwAAAAIAAA", response.CursorBottom?.Value.Value);

mock.VerifyAll();
}
Expand Down Expand Up @@ -87,7 +87,7 @@ public async Task Send_RequestCursor_Test()
var request = new HomeLatestTimelineRequest
{
Count = 20,
Cursor = "aaa",
Cursor = new("aaa"),
};

await request.Send(mock.Object);
Expand Down
10 changes: 5 additions & 5 deletions OpenTween.Tests/Api/GraphQL/LikesRequestTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ public async Task Send_Test()

var request = new LikesRequest
{
UserId = "12345",
UserId = new("12345"),
Count = 20,
};

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.Value);
Assert.Equal("DAAHCgABGEs2Ve8___8LAAIAAAATMTc4OTA3OTU2MDM5NDcxNTMyMggAAwAAAAIAAA", response.CursorBottom?.Value.Value);

mock.VerifyAll();
}
Expand All @@ -83,9 +83,9 @@ public async Task Send_RequestCursor_Test()

var request = new LikesRequest
{
UserId = "12345",
UserId = new("12345"),
Count = 20,
Cursor = "aaa",
Cursor = new("aaa"),
};

await request.Send(mock.Object);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public async Task Send_Test()

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.Value);
Assert.Equal("DAABCgABF0HfRMi__7QKAAIVAxUYmFWQAwgAAwAAAAIAAA", response.CursorBottom?.Value.Value);

mock.VerifyAll();
}
Expand Down Expand Up @@ -86,7 +86,7 @@ public async Task Send_RequestCursor_Test()
var request = new ListLatestTweetsTimelineRequest(listId: "1675863884757110790")
{
Count = 20,
Cursor = "aaa",
Cursor = new("aaa"),
};

await request.Send(mock.Object);
Expand Down
10 changes: 5 additions & 5 deletions OpenTween.Tests/Api/GraphQL/SearchTimelineRequestTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public async Task Send_Test()

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.Value);
Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAACCAADAAAAAAgABAAAAAAKAAUX8j3ezIAnEAoABhfyPd7Mf9jwAAA", response.CursorBottom?.Value.Value);

mock.VerifyAll();
}
Expand All @@ -78,8 +78,8 @@ public async Task Send_ReplaceCursorTest()

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.Value);
Assert.Equal("DAADDAABCgABFnlh4hraMAYKAAIOTm0DEhTAAQAIAAIAAAACCAADAAAAAQgABAAAAAAKAAUX8j3ezIBOIAoABhfyPd7Mf9jwAAA", response.CursorBottom?.Value.Value);

mock.VerifyAll();
}
Expand Down Expand Up @@ -108,7 +108,7 @@ public async Task Send_RequestCursor_Test()
var request = new SearchTimelineRequest(rawQuery: "#OpenTween")
{
Count = 20,
Cursor = "aaa",
Cursor = new("aaa"),
};

await request.Send(mock.Object);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@
// Boston, MA 02110-1301, USA.

using System.Threading.Tasks;
using OpenTween.Models;
using Xunit;

namespace OpenTween.Api.GraphQL
{
public class TimelineResponseTest
public class TimelineGraphqlResponseTest
{
[Fact]
public async Task ToTwitterStatuses_Test()
{
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 TimelineGraphqlResponse(tweets, new(CursorType.Top, new("")), new(CursorType.Bottom, new("")));

var statuses = timelineResponse.ToTwitterStatuses();
Assert.Single(statuses);
Expand Down
56 changes: 33 additions & 23 deletions OpenTween.Tests/Api/GraphQL/TimelineTweetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ public void ToStatus_WithTwitterPostFactory_SimpleTweet_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_SimpleTweet.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1613784711020826626", post.StatusId.Id);
Assert.Equal(40480664L, post.UserId);
Assert.Equal(new TwitterUserId("40480664"), post.UserId);
Assert.False(post.IsPromoted);
}

Expand All @@ -86,11 +86,11 @@ public void ToStatus_WithTwitterPostFactory_TweetWithMedia_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_TweetWithMedia.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1614587968567783424", post.StatusId.Id);
Assert.Equal(40480664L, post.UserId);
Assert.Equal(new TwitterUserId("40480664"), post.UserId);
Assert.Equal(2, post.Media.Count);
Assert.Equal("https://pbs.twimg.com/media/FmgrJiEaAAEU42G.png", post.Media[0].Url);
Assert.Equal("OpenTweenで @opentween のツイート一覧を表示しているスクショ", post.Media[0].AltText);
Expand All @@ -104,13 +104,13 @@ public void ToStatus_WithTwitterPostFactory_RetweetedTweet_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_RetweetedTweet.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1617128268548964354", post.StatusId.Id);
Assert.Equal(40480664L, post.RetweetedByUserId);
Assert.Equal(new TwitterUserId("40480664"), post.RetweetedByUserId);
Assert.Equal("1617126084138659840", post.RetweetedId!.Id);
Assert.Equal(514241801L, post.UserId);
Assert.Equal(new TwitterUserId("514241801"), post.UserId);
}

[Fact]
Expand All @@ -119,11 +119,11 @@ public void ToStatus_WithTwitterPostFactory_TweetWithVisibility_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_TweetWithVisibility.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1602775353088524288", post.StatusId.Id);
Assert.Equal(357750891L, post.UserId);
Assert.Equal(new TwitterUserId("357750891"), post.UserId);
}

[Fact]
Expand All @@ -132,11 +132,11 @@ public void ToStatus_WithTwitterPostFactory_SelfThread_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_SelfThread.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1511751702684499968", post.StatusId.Id);
Assert.Equal(40480664L, post.UserId);
Assert.Equal(new TwitterUserId("40480664"), post.UserId);
}

[Fact]
Expand All @@ -145,8 +145,8 @@ public void ToStatus_WithTwitterPostFactory_QuotedTweet_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_QuotedTweet.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1588614645866147840", post.StatusId.Id);
var quotedPostId = Assert.Single(post.QuoteStatusIds);
Expand All @@ -159,8 +159,8 @@ public void ToStatus_WithTwitterPostFactory_QuotedTweet_Tombstone_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_QuotedTweet_Tombstone.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1614653321310253057", post.StatusId.Id);
var quotedPostId = Assert.Single(post.QuoteStatusIds);
Expand All @@ -173,11 +173,11 @@ public void ToStatus_WithTwitterPostFactory_PromotedTweet_Test()
var rootElm = this.LoadResponseDocument("TimelineTweet_PromotedTweet.json");
var timelineTweet = new TimelineTweet(rootElm);
var status = timelineTweet.ToTwitterStatus();
var postFactory = new TwitterPostFactory(this.CreateTabInfo());
var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>());
var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);

Assert.Equal("1674737917363888129", post.StatusId.Id);
Assert.Equal(2941313791L, post.UserId);
Assert.Equal(new TwitterUserId("2941313791"), post.UserId);
Assert.True(post.IsPromoted);
Assert.Matches(new Regex(@"^\[Promoted\]\n"), post.TextFromApi);
}
Expand All @@ -195,6 +195,16 @@ public void ToStatus_TweetTombstone_Test()
Assert.Equal("This Post is from a suspended account. Learn more", ex.Message);
}

[Fact]
public void ToStatus_MissingLegacy_Test()
{
// legacy プロパティが欠けておりツイートの表示に必要な情報が不足している場合
var rootElm = this.LoadResponseDocument("TimelineTweet_MissingLegacy.json");
var timelineTweet = new TimelineTweet(rootElm);

Assert.False(timelineTweet.IsAvailable);
}

[Fact]
public void ToStatus_EmptyTweet_Test()
{
Expand Down
11 changes: 6 additions & 5 deletions OpenTween.Tests/Api/GraphQL/UserTweetsAndRepliesRequestTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using System.Threading.Tasks;
using Moq;
using OpenTween.Connection;
using OpenTween.Models;
using Xunit;

namespace OpenTween.Api.GraphQL
Expand Down Expand Up @@ -49,15 +50,15 @@ public async Task Send_Test()
})
.ReturnsAsync(apiResponse);

var request = new UserTweetsAndRepliesRequest(userId: "40480664")
var request = new UserTweetsAndRepliesRequest(userId: new("40480664"))
{
Count = 20,
};

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.Value);
Assert.Equal("DAABCgABF_tTnZu__-0KAAIWZa6KTRoAAwgAAwAAAAIAAA", response.CursorBottom?.Value.Value);

mock.VerifyAll();
}
Expand All @@ -83,10 +84,10 @@ public async Task Send_RequestCursor_Test()
})
.ReturnsAsync(apiResponse);

var request = new UserTweetsAndRepliesRequest(userId: "40480664")
var request = new UserTweetsAndRepliesRequest(userId: new("40480664"))
{
Count = 20,
Cursor = "aaa",
Cursor = new("aaa"),
};

await request.Send(mock.Object);
Expand Down
Loading

0 comments on commit c3ee35e

Please sign in to comment.