diff --git a/NiconicoToolkit.Shared/NiconicoToolkit.Shared.projitems b/NiconicoToolkit.Shared/NiconicoToolkit.Shared.projitems index 21d6c1b..aa1a0de 100644 --- a/NiconicoToolkit.Shared/NiconicoToolkit.Shared.projitems +++ b/NiconicoToolkit.Shared/NiconicoToolkit.Shared.projitems @@ -235,7 +235,10 @@ - + + + + @@ -243,7 +246,4 @@ - - - \ No newline at end of file diff --git a/NiconicoToolkit.Shared/Video/Watch/NV_Comment/CommentSubClient.cs b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/CommentSubClient.cs deleted file mode 100644 index 4aff71a..0000000 --- a/NiconicoToolkit.Shared/Video/Watch/NV_Comment/CommentSubClient.cs +++ /dev/null @@ -1,434 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading; -using System.Threading.Tasks; -using System.Text.Json; -using System.Linq; -#if WINDOWS_UWP -using Windows.Web.Http; -using Windows.Web.Http.Headers; -#else -using System.Net.Http; -using System.Net.Http.Headers; -#endif - -namespace NiconicoToolkit.Video.Watch.NV_Comment; - -public sealed class NvCommentSubClient -{ - private readonly NiconicoContext _context; - private readonly JsonSerializerOptions _option; - - public NvCommentSubClient(NiconicoContext context, JsonSerializerOptions option) - { - _context = context; - _option = option; - } - - - const string NVCommentApiUrl = "https://nvcomment.nicovideo.jp/v1/threads"; - - /// - /// 動画に投稿されたコメントを取得します。 - /// - /// VideoClient.VideoWatch.GetInitialWatchDataAsync() のレスポンスデータに含まれる NvComment を指定します。 - /// - /// - public async Task GetCommentsAsync(NvComment videoComment, CancellationToken ct = default) - { - string requestParamsJson = JsonSerializer.Serialize(new ThreadRequestContainer() - { - ThreadKey = videoComment.ThreadKey, - Params = new ThreadRequestContainer.ThreadRequestParams() - { - Targets = videoComment.Params.Targets, - Language = videoComment.Params.Language, - } - }); - return await _context.SendJsonAsAsync( - HttpMethod.Post, - NVCommentApiUrl, - requestParamsJson, - ct: ct - ); - } - - /// - /// 動画に投稿されたコメントを取得します。 - /// - /// - /// 取得対象とするコメント郡を指定します。参考:ThreadTargetIdConstants - /// - /// - /// - /// VideoClient.VideoWatch.GetInitialWatchDataAsync() のレスポンスデータに含まれる NvComment のデータを引数に渡してください。 - public async Task GetCommentsAsync(string threadKey, IEnumerable targets, string language, CancellationToken ct = default) - { - string requestParamsJson = JsonSerializer.Serialize(new ThreadRequestContainer() - { - ThreadKey = threadKey, - Params = new ThreadRequestContainer.ThreadRequestParams() - { - Targets = targets.ToList(), - Language = language, - } - }); - return await _context.SendJsonAsAsync( - HttpMethod.Post, - NVCommentApiUrl, - requestParamsJson, - ct: ct - ); - } - - /// - /// スレッドにコメントを送信するためのポストキーを取得します。 - /// - /// スレッドID。WatchApiResponse.WatchApiData.Comment.Threads から取得できます。 - /// - [RequireLogin] - public async Task GetPostKeyAsync(string threadId, CancellationToken ct = default) - { - return await _context.GetJsonAsAsync( - $"https://nvapi.nicovideo.jp/v1/comment/keys/post?threadId={threadId}", ct: ct - ); - } - - /// - /// 動画の指定スレッドに対してコメント投稿を送信します。 - /// - /// スレッドID。WatchApiResponse.WatchApiData.Comment.Threads から取得できます。 - /// 動画ID。stringのままでもVideoIdへの暗黙の型変換により指定可能です。 - /// 184などのコマンドを指定します - /// https://dic.nicovideo.jp/a/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89 - /// コメント本文。Uriエンコードは不要です。 - /// コメントする動画時間をマイクロ秒単位で指定します。動画秒数に対して1000を掛け算することでマイクロ秒へ変換できます。 - /// GetPostKeyAsync()を使用して予め取得してください。 - /// - /// - /// パラメータエラーによる失敗は全て INVALID_PARAMETER としてまとめられるため、何が間違いかは判別できません。 - [RequireLogin] - public async Task PostCommentAsync( - string threadId, - VideoId videoId, - IEnumerable commands, - string comment, - int vPosMs, - string postKey, - CancellationToken ct = default - ) - { - string requestParamsJson = JsonSerializer.Serialize(new ThreadPostRequest() - { - VideoId = videoId.ToString(), - Commands = commands.ToList(), - Body = comment, - VposMs = vPosMs, - PostKey = postKey, - }); - - return await _context.SendJsonAsAsync(HttpMethod.Post, - $"{NVCommentApiUrl}/{threadId}/comments", requestParamsJson, ct: ct); - } - - - [RequireLogin] - public async Task GetEasyPostKeyAsync(string threadId, CancellationToken ct = default) - { - return await _context.GetJsonAsAsync( - $"https://nvapi.nicovideo.jp/v1/comment/keys/post-easy?threadId={threadId}", ct: ct - ); - } - - [RequireLogin] - public async Task EasyPostCommentAsync( - string threadId, - VideoId videoId, - string comment, - int vPosMs, - string easyPostKey, - CancellationToken ct = default - ) - { - string requestParamsJson = JsonSerializer.Serialize(new ThreadEasyPostRequest() - { - VideoId = videoId.ToString(), - Body = comment, - VposMs = vPosMs, - EasyPostKey = easyPostKey, - }); - - return await _context.SendJsonAsAsync(HttpMethod.Post, - $"{NVCommentApiUrl}/{threadId}/easy-comments", requestParamsJson, ct: ct); - } - - [RequireLogin] - public async Task GetDeleteKeyAsync(string threadId, string fork, CancellationToken ct = default) - { - return await _context.GetJsonAsAsync( - $"https://nvapi.nicovideo.jp/v1/comment/keys/delete?threadId={threadId}&fork={fork}", ct: ct - ); - } - - [RequireLogin] - public async Task DeleteCommentAsync( - VideoId videoId, - string threadId, - string fork, - int commentNumber, - string language, - string deleteKey, - CancellationToken ct = default - ) - { - string requestParamsJson = JsonSerializer.Serialize(new ThreadDeleteRequest() - { - VideoId = videoId.ToString(), - Fork = fork, - DeleteKey = deleteKey, - Language = language, - Targets = new () { new () { Number = commentNumber }} - }); - - return await _context.SendJsonAsAsync(HttpMethod.Put, - $"{NVCommentApiUrl}/{threadId}/comment-comment-owner-deletions", requestParamsJson, ct: ct); - } -} - -public sealed class ThreadDeleteRequest -{ - [JsonPropertyName("videoId")] - public string VideoId { get; set; } - - [JsonPropertyName("deleteKey")] - public string DeleteKey { get; set; } - - [JsonPropertyName("language")] - public string Language { get; set; } - - [JsonPropertyName("targets")] - public List Targets { get; set; } - - [JsonPropertyName("fork")] - public string Fork { get; set; } - - public sealed class ThreadDeleteTarget - { - [JsonPropertyName("no")] - public int Number { get; set; } - - [JsonPropertyName("operation")] - public string Operation { get; set; } = "DELETE"; - } -} - -public sealed class ThreadDeleteResponse : ResponseWithMeta -{ - -} - - -public static class ThreadTargetForkConstants -{ - public const string Easy = "easy"; - public const string Main = "main"; - public const string Owner = "owner"; -} - - -public sealed class ThreadPostKeyResponse : ResponseWithMeta -{ - [JsonPropertyName("data")] - public ThreadPostKeyData? Data { get; set; } - - public sealed class ThreadPostKeyData - { - [JsonPropertyName("postKey")] - public string PostKey { get; set; } - } -} - -public sealed class ThreadPostRequest -{ - [JsonPropertyName("videoId")] - public string VideoId { get; set; } - - [JsonPropertyName("commands")] - public List Commands { get; set; } - - [JsonPropertyName("body")] - public string Body { get; set; } - - [JsonPropertyName("vposMs")] - public int VposMs { get; set; } - - [JsonPropertyName("postKey")] - public string PostKey { get; set; } -} - -public sealed class ThreadEasyPostRequest -{ - [JsonPropertyName("videoId")] - public string VideoId { get; set; } - - [JsonPropertyName("body")] - public string Body { get; set; } - - [JsonPropertyName("vposMs")] - public int VposMs { get; set; } - - [JsonPropertyName("postEasyKey")] - public string EasyPostKey { get; set; } -} - -public sealed class ThreadPostResponse : ResponseWithMeta -{ - [JsonPropertyName("data")] - public ThreadPostResponseData? Data { get; set; } - - public sealed class ThreadPostResponseData - { - [JsonPropertyName("id")] - public string Id { get; set; } - - [JsonPropertyName("no")] - public int Number { get; set; } - } -} - -public sealed class ThreadDeleteKeyResponse : ResponseWithMeta -{ - [JsonPropertyName("data")] - public ThreadDeleteKeyData? Data { get; set; } - - public sealed class ThreadDeleteKeyData - { - [JsonPropertyName("deleteKey")] - public string DeleteKey { get; set; } - } -} - -public sealed class ThreadEasyPostKeyResponse : ResponseWithMeta -{ - [JsonPropertyName("data")] - public ThreadEasyPostKeyData? Data { get; set; } - - public sealed class ThreadEasyPostKeyData - { - [JsonPropertyName("postEasyKey")] - public string EasyPostKey { get; set; } - } -} - -public class ThreadRequestContainer -{ - [JsonPropertyName("params")] - public ThreadRequestParams Params { get; set; } - - [JsonPropertyName("threadKey")] - public string ThreadKey { get; set; } - - [JsonPropertyName("additionals")] - public ThreadRequestAdditionals Additionals { get; set; } = new ThreadRequestAdditionals(); - - - public class ThreadRequestAdditionals - { - } - - public class ThreadRequestParams - { - [JsonPropertyName("targets")] - public List Targets { get; set; } - - [JsonPropertyName("language")] - public string Language { get; set; } - } -} - - -public class ThreadResponseContainer : ResponseWithMeta -{ - [JsonPropertyName("data")] - public ThreadResponseData Data { get; set; } -} - - -// Root myDeserializedClass = JsonSerializer.Deserialize(myJsonResponse); -public class Comment -{ - [JsonPropertyName("id")] - public string Id { get; set; } - - [JsonPropertyName("no")] - public int No { get; set; } - - [JsonPropertyName("vposMs")] - public int VposMs { get; set; } - - [JsonPropertyName("body")] - public string Body { get; set; } - - [JsonPropertyName("commands")] - public List Commands { get; set; } - - [JsonPropertyName("userId")] - public string UserId { get; set; } - - [JsonPropertyName("isPremium")] - public bool IsPremium { get; set; } - - [JsonPropertyName("score")] - public int Score { get; set; } - - [JsonPropertyName("postedAt")] - public DateTime PostedAt { get; set; } - - [JsonPropertyName("nicoruCount")] - public int NicoruCount { get; set; } - - [JsonPropertyName("nicoruId")] - public object NicoruId { get; set; } - - [JsonPropertyName("source")] - public string Source { get; set; } - - [JsonPropertyName("isMyPost")] - public bool IsMyPost { get; set; } -} - -public class ThreadResponseData -{ - [JsonPropertyName("globalComments")] - public List GlobalComments { get; set; } - - [JsonPropertyName("threads")] - public List Threads { get; set; } -} - -public class GlobalComment -{ - [JsonPropertyName("id")] - public string Id { get; set; } - - [JsonPropertyName("count")] - public int Count { get; set; } -} - -public class Thread -{ - [JsonPropertyName("id")] - public string Id { get; set; } - - [JsonPropertyName("fork")] - public string Fork { get; set; } - - [JsonPropertyName("commentCount")] - public int CommentCount { get; set; } - - [JsonPropertyName("comments")] - public List Comments { get; set; } -} - diff --git a/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Core.cs b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Core.cs new file mode 100644 index 0000000..86dcbc9 --- /dev/null +++ b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Core.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; +using System.Text.Json; +using System.Linq; +#if WINDOWS_UWP +using Windows.Web.Http; +using Windows.Web.Http.Headers; +#else +using System.Net.Http; +using System.Net.Http.Headers; +#endif + +namespace NiconicoToolkit.Video.Watch.NV_Comment; + +public sealed partial class NvCommentSubClient +{ + private readonly NiconicoContext _context; + private readonly JsonSerializerOptions _option; + + public NvCommentSubClient(NiconicoContext context, JsonSerializerOptions option) + { + _context = context; + _option = option; + } + + public const string NVCommentThreadsUrl = "https://nvcomment.nicovideo.jp/v1/threads"; + public const string NvApiCommentKeysUrl = "https://nvapi.nicovideo.jp/v1/comment/keys/"; +} + +public static class ThreadTargetForkConstants +{ + public const string Easy = "easy"; + public const string Main = "main"; + public const string Owner = "owner"; +} + + + + diff --git a/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Delete.cs b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Delete.cs new file mode 100644 index 0000000..fb37ca4 --- /dev/null +++ b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Delete.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using System.Threading; +#if WINDOWS_UWP +using Windows.Web.Http; +using Windows.Web.Http.Headers; +#else +using System.Net.Http; +using System.Net.Http.Headers; +#endif + +namespace NiconicoToolkit.Video.Watch.NV_Comment; + +public partial class NvCommentSubClient +{ + /// + /// 自らが投稿したコメントを削除する際のキーを取得します。 + /// + /// + /// fork または forkLabel を指定。参考:ThreadTargetForkConstants + /// + /// + [RequireLogin] + public async Task GetDeleteKeyAsync(string threadId, string fork, CancellationToken ct = default) + { + return await _context.GetJsonAsAsync( + $"{NvApiCommentKeysUrl}delete?threadId={threadId}&fork={fork}", ct: ct + ); + } + + + /// + /// 自らが投稿したコメントを削除します。IsMyPost が true のコメント番号を指定して削除します。 + /// + /// + /// + /// + /// コメントの番号("no") + /// + /// GetDeleteKeyAsync() によって得られる削除キーを指定します。 + /// + /// + [RequireLogin] + public async Task DeleteCommentAsync( + VideoId videoId, + string threadId, + string fork, + int commentNumber, + string language, + string deleteKey, + CancellationToken ct = default + ) + { + string requestParamsJson = JsonSerializer.Serialize(new ThreadDeleteRequest() + { + VideoId = videoId.ToString(), + Fork = fork, + DeleteKey = deleteKey, + Language = language, + Targets = new() { new() { Number = commentNumber } } + }); + + return await _context.SendJsonAsAsync(HttpMethod.Put, + $"{NVCommentThreadsUrl}/{threadId}/comment-comment-owner-deletions", requestParamsJson, ct: ct); + } +} + + + +public sealed class ThreadDeleteRequest +{ + [JsonPropertyName("videoId")] + public string VideoId { get; set; } + + [JsonPropertyName("deleteKey")] + public string DeleteKey { get; set; } + + [JsonPropertyName("language")] + public string Language { get; set; } + + [JsonPropertyName("targets")] + public List Targets { get; set; } + + [JsonPropertyName("fork")] + public string Fork { get; set; } + + public sealed class ThreadDeleteTarget + { + [JsonPropertyName("no")] + public int Number { get; set; } + + [JsonPropertyName("operation")] + public string Operation { get; set; } = "DELETE"; + } +} + +public sealed class ThreadDeleteResponse : ResponseWithMeta +{ + +} + diff --git a/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Get.cs b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Get.cs new file mode 100644 index 0000000..f80e1b6 --- /dev/null +++ b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Get.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using System.Threading; +using System.Text.Json.Serialization; +#if WINDOWS_UWP +using Windows.Web.Http; +using Windows.Web.Http.Headers; +#else +using System.Net.Http; +using System.Net.Http.Headers; +#endif + +namespace NiconicoToolkit.Video.Watch.NV_Comment; + +public partial class NvCommentSubClient +{ + + /// + /// 動画に投稿されたコメントを取得します。 + /// + /// VideoClient.VideoWatch.GetInitialWatchDataAsync() のレスポンスデータに含まれる NvComment を指定します。 + /// + /// + public async Task GetCommentsAsync(NvComment videoComment, CancellationToken ct = default) + { + string requestParamsJson = JsonSerializer.Serialize(new ThreadRequest() + { + ThreadKey = videoComment.ThreadKey, + Params = new ThreadRequest.ThreadRequestParams() + { + Targets = videoComment.Params.Targets, + Language = videoComment.Params.Language, + } + }); + return await _context.SendJsonAsAsync( + HttpMethod.Post, + NVCommentThreadsUrl, + requestParamsJson, + ct: ct + ); + } + + /// + /// 動画に投稿されたコメントを取得します。 + /// + /// VideoClient.VideoWatch.GetInitialWatchDataAsync() のレスポンスデータに含まれる NvComment を指定します。 + /// 取得対象とするコメントForkを指定します。参考:ThreadTargetIdConstants + /// + /// + /// VideoClient.VideoWatch.GetInitialWatchDataAsync() のレスポンスデータに含まれる NvComment のデータを引数に渡してください。 + public async Task GetCommentsAsync(NvComment videoComment, IEnumerable targetForks, CancellationToken ct = default) + { + var forks = targetForks.ToHashSet(); + string requestParamsJson = JsonSerializer.Serialize(new ThreadRequest() + { + ThreadKey = videoComment.ThreadKey, + Params = new ThreadRequest.ThreadRequestParams() + { + Targets = videoComment.Params.Targets.Where(x => forks.Contains(x.Fork)).ToList(), + Language = videoComment.Params.Language, + } + }); + return await _context.SendJsonAsAsync( + HttpMethod.Post, + NVCommentThreadsUrl, + requestParamsJson, + ct: ct + ); + } +} + + +class ThreadRequest +{ + [JsonPropertyName("params")] + public ThreadRequestParams Params { get; set; } + + [JsonPropertyName("threadKey")] + public string ThreadKey { get; set; } + + [JsonPropertyName("additionals")] + public ThreadRequestAdditionals Additionals { get; set; } = new ThreadRequestAdditionals(); + + + public class ThreadRequestAdditionals + { + } + + public class ThreadRequestParams + { + [JsonPropertyName("targets")] + public List Targets { get; set; } + + [JsonPropertyName("language")] + public string Language { get; set; } + } +} + + +public class ThreadResponse : ResponseWithMeta +{ + [JsonPropertyName("data")] + public ThreadResponseData Data { get; set; } + + + public class ThreadResponseData + { + [JsonPropertyName("globalComments")] + public List GlobalComments { get; set; } + + [JsonPropertyName("threads")] + public List Threads { get; set; } + } + + public class GlobalComment + { + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("count")] + public int Count { get; set; } + } + + public class Thread + { + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("fork")] + public string Fork { get; set; } + + [JsonPropertyName("commentCount")] + public int CommentCount { get; set; } + + [JsonPropertyName("comments")] + public List Comments { get; set; } + } + + public class Comment + { + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("no")] + public int No { get; set; } + + [JsonPropertyName("vposMs")] + public int VposMs { get; set; } + + [JsonPropertyName("body")] + public string Body { get; set; } + + [JsonPropertyName("commands")] + public List Commands { get; set; } + + [JsonPropertyName("userId")] + public string UserId { get; set; } + + [JsonPropertyName("isPremium")] + public bool IsPremium { get; set; } + + [JsonPropertyName("score")] + public int Score { get; set; } + + [JsonPropertyName("postedAt")] + public DateTime PostedAt { get; set; } + + [JsonPropertyName("nicoruCount")] + public int NicoruCount { get; set; } + + [JsonPropertyName("nicoruId")] + public object NicoruId { get; set; } + + [JsonPropertyName("source")] + public string Source { get; set; } + + [JsonPropertyName("isMyPost")] + public bool IsMyPost { get; set; } + } +} + diff --git a/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Post.cs b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Post.cs new file mode 100644 index 0000000..dbd70a7 --- /dev/null +++ b/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Post.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using System.Threading; +using System.Text.Json.Serialization; +#if WINDOWS_UWP +using Windows.Web.Http; +using Windows.Web.Http.Headers; +#else +using System.Net.Http; +using System.Net.Http.Headers; +#endif + +namespace NiconicoToolkit.Video.Watch.NV_Comment; + +public partial class NvCommentSubClient +{ + + /// + /// スレッドにコメントを送信するためのポストキーを取得します。 + /// + /// スレッドID。WatchApiResponse.WatchApiData.Comment.Threads から取得できます。 + /// + [RequireLogin] + public async Task GetPostKeyAsync(string threadId, CancellationToken ct = default) + { + return await _context.GetJsonAsAsync( + $"{NvApiCommentKeysUrl}post?threadId={threadId}", ct: ct + ); + } + + /// + /// 動画の指定スレッドに対してコメント投稿を送信します。 + /// + /// スレッドID。WatchApiResponse.WatchApiData.Comment.Threads から取得できます。 + /// 動画ID。stringのままでもVideoIdへの暗黙の型変換により指定可能です。 + /// 184などのコマンドを指定します + /// https://dic.nicovideo.jp/a/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89 + /// コメント本文。Uriエンコードは不要です。 + /// コメントする動画時間をマイクロ秒単位で指定します。動画秒数に対して1000を掛け算することでマイクロ秒へ変換できます。 + /// GetPostKeyAsync()を使用して予め取得してください。 + /// + /// + /// パラメータエラーによる失敗は全て INVALID_PARAMETER としてまとめられるため、何が間違いかは判別できません。 + [RequireLogin] + public async Task PostCommentAsync( + string threadId, + VideoId videoId, + IEnumerable commands, + string comment, + int vPosMs, + string postKey, + CancellationToken ct = default + ) + { + string requestParamsJson = JsonSerializer.Serialize(new ThreadPostRequest() + { + VideoId = videoId.ToString(), + Commands = commands.ToList(), + Body = comment, + VposMs = vPosMs, + PostKey = postKey, + }); + + return await _context.SendJsonAsAsync(HttpMethod.Post, + $"{NVCommentThreadsUrl}/{threadId}/comments", requestParamsJson, ct: ct); + } + + + [RequireLogin] + public async Task GetEasyPostKeyAsync(string threadId, CancellationToken ct = default) + { + return await _context.GetJsonAsAsync( + $"{NvApiCommentKeysUrl}post-easy?threadId={threadId}", ct: ct + ); + } + + [RequireLogin] + public async Task EasyPostCommentAsync( + string threadId, + VideoId videoId, + string comment, + int vPosMs, + string easyPostKey, + CancellationToken ct = default + ) + { + string requestParamsJson = JsonSerializer.Serialize(new ThreadEasyPostRequest() + { + VideoId = videoId.ToString(), + Body = comment, + VposMs = vPosMs, + EasyPostKey = easyPostKey, + }); + + return await _context.SendJsonAsAsync(HttpMethod.Post, + $"{NVCommentThreadsUrl}/{threadId}/easy-comments", requestParamsJson, ct: ct); + } +} + +public sealed class ThreadPostKeyResponse : ResponseWithMeta +{ + [JsonPropertyName("data")] + public ThreadPostKeyData? Data { get; set; } + + public sealed class ThreadPostKeyData + { + [JsonPropertyName("postKey")] + public string PostKey { get; set; } + } +} + +sealed class ThreadPostRequest +{ + [JsonPropertyName("videoId")] + public string VideoId { get; set; } + + [JsonPropertyName("commands")] + public List Commands { get; set; } + + [JsonPropertyName("body")] + public string Body { get; set; } + + [JsonPropertyName("vposMs")] + public int VposMs { get; set; } + + [JsonPropertyName("postKey")] + public string PostKey { get; set; } +} + +sealed class ThreadEasyPostRequest +{ + [JsonPropertyName("videoId")] + public string VideoId { get; set; } + + [JsonPropertyName("body")] + public string Body { get; set; } + + [JsonPropertyName("vposMs")] + public int VposMs { get; set; } + + [JsonPropertyName("postEasyKey")] + public string EasyPostKey { get; set; } +} + +public sealed class ThreadPostResponse : ResponseWithMeta +{ + [JsonPropertyName("data")] + public ThreadPostResponseData? Data { get; set; } + + public sealed class ThreadPostResponseData + { + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("no")] + public int Number { get; set; } + } +} + +public sealed class ThreadDeleteKeyResponse : ResponseWithMeta +{ + [JsonPropertyName("data")] + public ThreadDeleteKeyData? Data { get; set; } + + public sealed class ThreadDeleteKeyData + { + [JsonPropertyName("deleteKey")] + public string DeleteKey { get; set; } + } +} + +public sealed class ThreadEasyPostKeyResponse : ResponseWithMeta +{ + [JsonPropertyName("data")] + public ThreadEasyPostKeyData? Data { get; set; } + + public sealed class ThreadEasyPostKeyData + { + [JsonPropertyName("postEasyKey")] + public string EasyPostKey { get; set; } + } +} + diff --git a/NuSpec/build_nuget.cmd b/NuSpec/build_nuget.cmd index de067e3..5874570 100644 --- a/NuSpec/build_nuget.cmd +++ b/NuSpec/build_nuget.cmd @@ -1 +1 @@ -nuget pack Package.nuspec -outputDirectory "C:\Users\tor4k\local_nuget" -p version=0.3.1 \ No newline at end of file +nuget pack Package.nuspec -outputDirectory "C:\Users\tor4k\local_nuget" -p version=0.3.2 \ No newline at end of file diff --git a/Test/NiconicoToolkit.Shared.Test/VideoWatchTest.cs b/Test/NiconicoToolkit.Shared.Test/VideoWatchTest.cs index 9ee5eaf..31bd259 100644 --- a/Test/NiconicoToolkit.Shared.Test/VideoWatchTest.cs +++ b/Test/NiconicoToolkit.Shared.Test/VideoWatchTest.cs @@ -177,9 +177,8 @@ public async Task NvGetCommentWithoutEasyPostAsync(string videoId) var nvComment = res.WatchApiResponse.WatchApiData.Comment.NvComment; var commentRes = await _context.Video.NvComment.GetCommentsAsync( - nvComment.ThreadKey, - nvComment.Params.Targets.Where(x => x.Fork != ThreadTargetForkConstants.Easy), - nvComment.Params.Language + nvComment, + new[] { ThreadTargetForkConstants.Owner, ThreadTargetForkConstants.Main } ); Assert.IsNotNull(commentRes.Data); @@ -283,7 +282,7 @@ public async Task NvDeleteCommentAsync(string videoId) var comment = res.WatchApiResponse.WatchApiData.Comment; var nvComment = comment.NvComment; - var commentRes = await _context.Video.NvComment.GetCommentsAsync(nvComment.ThreadKey, nvComment.Params.Targets.Where(x => x.Fork == ThreadTargetForkConstants.Easy), nvComment.Params.Language); + var commentRes = await _context.Video.NvComment.GetCommentsAsync(nvComment, new[] { ThreadTargetForkConstants.Easy }); var postedThread = commentRes.Data.Threads.FirstOrDefault(x => x.Fork == ThreadTargetForkConstants.Easy); var myPostComments = postedThread.Comments.Where(x => x.IsMyPost); int deleteTargetCommentNumber = -1;