chore: merge upstream master and fix conflicts
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
{
|
||||
/// <summary>
|
||||
/// A class representing TubeArchivist API custom playlist creation request.
|
||||
/// </summary>
|
||||
public class CustomPlaylistCreation
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CustomPlaylistCreation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="playlistName">The name of the new custom playlist to create.</param>
|
||||
public CustomPlaylistCreation(string playlistName)
|
||||
{
|
||||
this.PlaylistName = playlistName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the new custom playlist to create.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_name")]
|
||||
public string PlaylistName { get; set; }
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum representing the possible actions to execute on a TubeArchivist custom playlist video.
|
||||
/// </summary>
|
||||
public enum CustomPlaylistAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new custom playlist video.
|
||||
/// </summary>
|
||||
Create,
|
||||
|
||||
/// <summary>
|
||||
/// Removea custom playlist video.
|
||||
/// </summary>
|
||||
Remove,
|
||||
|
||||
/// <summary>
|
||||
/// Move a custom playlist video to the top of the list.
|
||||
/// </summary>
|
||||
Top,
|
||||
|
||||
/// <summary>
|
||||
/// Move a custom playlist video to the bottom of the list.
|
||||
/// </summary>
|
||||
Bottom,
|
||||
|
||||
/// <summary>
|
||||
/// Move a custom playlist video up in the list.
|
||||
/// </summary>
|
||||
Up,
|
||||
|
||||
/// <summary>
|
||||
/// Move a custom playlist video down in the list.
|
||||
/// </summary>
|
||||
Down
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class representing TubeArchivist API custom playlist entry operation request.
|
||||
/// </summary>
|
||||
public class CustomPlaylistEntryAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CustomPlaylistEntryAction"/> class.
|
||||
/// </summary>
|
||||
/// <param name="action">The standard action to create a new entry.</param>
|
||||
/// <param name="videoId">The entry YoutubeId.</param>
|
||||
public CustomPlaylistEntryAction(
|
||||
CustomPlaylistAction action,
|
||||
string videoId)
|
||||
{
|
||||
this.Action = action.ToString().ToLower(CultureInfo.CurrentCulture);
|
||||
this.VideoId = videoId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the standard action to create a new entry.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "action")]
|
||||
public string Action { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the entry YoutubeId.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "video_id")]
|
||||
public string VideoId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum representing whether the playlist on TubeArchivist belongs from YouTube or is created by the user.
|
||||
/// </summary>
|
||||
public enum PlaylistType
|
||||
{
|
||||
/// <summary>
|
||||
/// Playlist belongs from YouTube.
|
||||
/// </summary>
|
||||
Regular,
|
||||
|
||||
/// <summary>
|
||||
/// Playlist created by the user.
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class representing TubeArchivist API playlist data.
|
||||
/// </summary>
|
||||
public class Playlist
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Playlist"/> class.
|
||||
/// </summary>
|
||||
/// <param name="isActive">URL of the channel banner image.</param>
|
||||
/// <param name="channel">Playlist channel name.</param>
|
||||
/// <param name="channelId">Playlist channel YouTube id.</param>
|
||||
/// <param name="description">Playlist description.</param>
|
||||
/// <param name="entries">Playlist videos.</param>
|
||||
/// <param name="id">Playlist YouTube id.</param>
|
||||
/// <param name="name">Playlist name.</param>
|
||||
/// <param name="thumbnailUrl">URL of the playlist thumbnail.</param>
|
||||
/// <param name="type">Type of the playlist. See <see cref="PlaylistType"/>.</param>
|
||||
public Playlist(
|
||||
bool isActive,
|
||||
string channel,
|
||||
string channelId,
|
||||
string description,
|
||||
Collection<PlaylistEntry> entries,
|
||||
string id,
|
||||
string name,
|
||||
string thumbnailUrl, // TODO: Check if settable on Jellyfin
|
||||
PlaylistType type)
|
||||
{
|
||||
this.IsActive = isActive;
|
||||
this.Channel = channel;
|
||||
this.ChannelId = channelId;
|
||||
this.Description = description;
|
||||
this.Entries = entries;
|
||||
this.Id = id;
|
||||
this.Name = name;
|
||||
this.ThumbnailUrl = thumbnailUrl;
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the playlist is active or not.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_active")]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist channel name.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_channel")]
|
||||
public string Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist channel YouTube id.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_channel_id")]
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist description.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the playlist videos.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_entries")]
|
||||
public Collection<PlaylistEntry> Entries { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist YouTube id.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist name.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist thumbnail URL.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "playlist_thumbnail")]
|
||||
public string ThumbnailUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist type.
|
||||
/// </summary>
|
||||
/// <value>One of the <see cref="PlaylistType"/> values indicating the playlist's type.</value>
|
||||
[JsonProperty(PropertyName = "playlist_type")]
|
||||
public PlaylistType Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using ICU4N.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
{
|
||||
/// <summary>
|
||||
/// A class representing TubeArchivist API playlist entries data.
|
||||
/// </summary>
|
||||
public class PlaylistEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaylistEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="youtubeId">Video YouTube id.</param>
|
||||
/// <param name="title">Video title.</param>
|
||||
/// <param name="uploader">Video uploader.</param>
|
||||
/// <param name="index">Video index in the playlist.</param>
|
||||
/// <param name="isDownloaded">A value indicating whether the video has been already downloaded or not.</param>
|
||||
public PlaylistEntry(
|
||||
string youtubeId,
|
||||
string title,
|
||||
string uploader,
|
||||
int index,
|
||||
bool isDownloaded)
|
||||
{
|
||||
this.YoutubeId = youtubeId;
|
||||
this.Title = title;
|
||||
this.Uploader = uploader;
|
||||
this.Index = index;
|
||||
this.IsDownloaded = isDownloaded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video YouTube id.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "youtube_id")]
|
||||
public string YoutubeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video title.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video uploader.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "uploader")]
|
||||
public string Uploader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video index in the playlist.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "idx")]
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the video has been already downloaded or not.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "downloaded")]
|
||||
public bool IsDownloaded { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.TubeArchivistMetadata.Utilities;
|
||||
using MediaBrowser.Model.Playlists;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -150,7 +152,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send video playback progress to TubeArchivist.
|
||||
/// Sends video playback progress to TubeArchivist.
|
||||
/// </summary>
|
||||
/// <param name="videoId">Video id.</param>
|
||||
/// <param name="progress">Progress in seconds.</param>
|
||||
@@ -167,7 +169,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send video playback progress to TubeArchivist.
|
||||
/// Sends video playback progress to TubeArchivist.
|
||||
/// </summary>
|
||||
/// <param name="videoId">Video id.</param>
|
||||
/// <returns>Video playback progress data.</returns>
|
||||
@@ -186,7 +188,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set video/channel/playlist as watched on TubeArchivist.
|
||||
/// Sets video/channel/playlist as watched on TubeArchivist.
|
||||
/// </summary>
|
||||
/// <param name="itemId">Video/channel/playlist id.</param>
|
||||
/// <param name="isWatched">Whether the item has been watched or not.</param>
|
||||
@@ -201,5 +203,93 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
||||
|
||||
return response.StatusCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the playlists from TubeArchivist.
|
||||
/// </summary>
|
||||
/// <returns>A task.</returns>
|
||||
public async Task<ISet<Playlist>?> GetPlaylists()
|
||||
{
|
||||
ResponseContainer<ISet<Playlist>?>? playlists = null;
|
||||
|
||||
var playlistsEndpoint = "/api/playlist/";
|
||||
var url = new Uri(Utils.SanitizeUrl(Plugin.Instance?.Configuration.TubeArchivistUrl + playlistsEndpoint));
|
||||
var response = await client.GetAsync(url).ConfigureAwait(true);
|
||||
while (response.StatusCode == HttpStatusCode.Moved)
|
||||
{
|
||||
url = response.Headers.Location;
|
||||
_logger.LogInformation("{Message}", "Received redirect to: " + url);
|
||||
response = await client.GetAsync(url).ConfigureAwait(true);
|
||||
}
|
||||
|
||||
_logger.LogInformation("{Message}", url + ": " + response.StatusCode);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string rawData = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
|
||||
playlists = JsonConvert.DeserializeObject<ResponseContainer<ISet<Playlist>?>>(rawData);
|
||||
}
|
||||
|
||||
return playlists?.Data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new custom playlist.
|
||||
/// </summary>
|
||||
/// <param name="creationRequest">Playlist creation request.</param>
|
||||
/// <returns>The created <see cref="Playlist"/>.</returns>
|
||||
public async Task<Playlist?> CreateCustomPlaylist(CustomPlaylistCreation creationRequest)
|
||||
{
|
||||
Playlist? playlist = null;
|
||||
var customPlaylistEndpoint = $"/api/playlist/custom/";
|
||||
var url = new Uri(Utils.SanitizeUrl(Plugin.Instance!.Configuration.TubeArchivistUrl + customPlaylistEndpoint));
|
||||
var body = JsonConvert.SerializeObject(creationRequest);
|
||||
_logger.LogInformation("{Message}", body);
|
||||
|
||||
var response = await client.PostAsync(url, new StringContent(body, Encoding.UTF8, "application/json")).ConfigureAwait(true);
|
||||
_logger.LogInformation("POST {Message}", url + ": " + response.StatusCode);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string rawData = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
|
||||
playlist = JsonConvert.DeserializeObject<Playlist>(rawData);
|
||||
}
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new custom playlist.
|
||||
/// </summary>
|
||||
/// <param name="playlistId">Playlist id.</param>
|
||||
/// <param name="entryAction">Playlist creation request.</param>
|
||||
/// <returns>The response <see cref="HttpStatusCode"/>.</returns>
|
||||
public async Task<HttpStatusCode> CustomPlaylistEntryAction(string playlistId, CustomPlaylistEntryAction entryAction)
|
||||
{
|
||||
var customPlaylistEndpoint = $"/api/playlist/custom/";
|
||||
var url = new Uri(Utils.SanitizeUrl(Plugin.Instance!.Configuration.TubeArchivistUrl + customPlaylistEndpoint + playlistId));
|
||||
var body = JsonConvert.SerializeObject(entryAction);
|
||||
_logger.LogDebug("CustomPlaylistEntryAction body: {Message}", body);
|
||||
|
||||
var response = await client.PostAsync(url, new StringContent(body, Encoding.UTF8, "application/json")).ConfigureAwait(true);
|
||||
_logger.LogDebug("Response code: {Message}", response.StatusCode);
|
||||
|
||||
return response.StatusCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a playlist.
|
||||
/// </summary>
|
||||
/// <param name="playlistId">Playlist id.</param>
|
||||
/// <returns>Whether the playlist has been deleted successfully or not.</returns>
|
||||
public async Task<bool> DeletePlaylist(string playlistId)
|
||||
{
|
||||
var deletePlaylistEndpoint = $"/api/playlist/";
|
||||
var url = new Uri(Utils.SanitizeUrl(Plugin.Instance!.Configuration.TubeArchivistUrl + deletePlaylistEndpoint + playlistId));
|
||||
var response = await client.DeleteAsync(url).ConfigureAwait(true);
|
||||
_logger.LogDebug("Response code: {Message}", response.StatusCode);
|
||||
|
||||
return response.StatusCode == HttpStatusCode.NoContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user