diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Constants.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Constants.cs
index 8528022..4ddeece 100644
--- a/Jellyfin.Plugin.TubeArchivistMetadata/Constants.cs
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/Constants.cs
@@ -14,5 +14,10 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
/// Plugin GUID.
///
public const string PluginGuid = "dc97d0c6-28b0-4242-afb4-5833ae1b3715";
+
+ ///
+ /// Providers name.
+ ///
+ public const string ProviderName = "TubeArchivist";
}
}
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Jellyfin.Plugin.TubeArchivistMetadata.csproj b/Jellyfin.Plugin.TubeArchivistMetadata/Jellyfin.Plugin.TubeArchivistMetadata.csproj
index 46ee0d1..2df209c 100644
--- a/Jellyfin.Plugin.TubeArchivistMetadata/Jellyfin.Plugin.TubeArchivistMetadata.csproj
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/Jellyfin.Plugin.TubeArchivistMetadata.csproj
@@ -13,6 +13,7 @@
+
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Plugin.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Plugin.cs
index 02b26a6..195d5a4 100644
--- a/Jellyfin.Plugin.TubeArchivistMetadata/Plugin.cs
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/Plugin.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Net.Http;
using Jellyfin.Plugin.TubeArchivistMetadata.Configuration;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Plugins;
@@ -23,6 +24,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
: base(applicationPaths, xmlSerializer)
{
Instance = this;
+ HttpClientHandler handler = new HttpClientHandler();
+ handler.AllowAutoRedirect = false;
+ handler.CheckCertificateRevocationList = true;
+ HttpClient = new HttpClient(handler);
+ HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Token", Instance?.Configuration.TubeArchivistApiKey);
}
///
@@ -36,6 +42,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
///
public static Plugin? Instance { get; private set; }
+ ///
+ /// Gets the HTTP client used globally in the plugin.
+ ///
+ public HttpClient HttpClient { get; }
+
///
public IEnumerable GetPages() => new[]
{
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs
new file mode 100644
index 0000000..34363ac
--- /dev/null
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+
+namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers
+{
+ ///
+ /// Image provider which interacts with TubeArchivist library.
+ ///
+ public class EpisodeImageProvider : IRemoteImageProvider
+ {
+ ///
+ /// Gets the provider name.
+ ///
+ public string Name => "TubeArchivist";
+
+ ///
+ public bool Supports(BaseItem item) => item is Episode;
+
+ ///
+ public IEnumerable GetSupportedImages(BaseItem item)
+ {
+ return new[] { ImageType.Primary };
+ }
+
+ ///
+ public async Task> GetImages(BaseItem item, CancellationToken cancellationToken)
+ {
+ var list = new List();
+ var taApi = TubeArchivistApi.GetInstance();
+ var videoTAId = item.Path.Split("/").Last().Split(".").First();
+ var video = await taApi.GetVideo(videoTAId).ConfigureAwait(true);
+
+ if (video != null)
+ {
+ list.Add(new RemoteImageInfo
+ {
+ ProviderName = Name,
+ Type = ImageType.Primary,
+ Url = video.VidThumbUrl
+ });
+ Console.WriteLine("ThumbURL: " + video.VidThumbUrl);
+ }
+
+ return list;
+ }
+
+ ///
+ public async Task GetImageResponse(string url, CancellationToken cancellationToken)
+ {
+ if (Plugin.Instance == null)
+ {
+ throw new DataException("Uninitialized plugin!");
+ }
+ else
+ {
+ return await Plugin.Instance.HttpClient.GetAsync(new Uri(Plugin.Instance.Configuration.TubeArchivistUrl + url), cancellationToken).ConfigureAwait(false);
+ }
+ }
+ }
+}
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs
new file mode 100644
index 0000000..cfce945
--- /dev/null
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+using Newtonsoft.Json;
+
+namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers
+{
+ ///
+ /// Metadata provider which interacts with TubeArchivist library.
+ ///
+ public class EpisodeMetadataProvider : IRemoteMetadataProvider
+ {
+ ///
+ /// Gets the provider name.
+ ///
+ public string Name => "TubeArchivist";
+
+ ///
+ public async Task> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
+ {
+ var result = new MetadataResult();
+ var taApi = TubeArchivistApi.GetInstance();
+ var videoTAId = info.Path.Split("/").Last().Split(".").First();
+ var video = await taApi.GetVideo(videoTAId).ConfigureAwait(true);
+ Console.WriteLine("Metadata video received: ");
+ Console.WriteLine(JsonConvert.SerializeObject(video));
+ Console.WriteLine("Media YT id: " + videoTAId);
+
+ if (video != null)
+ {
+ var peopleInfo = new List();
+ PeopleHelper.AddPerson(peopleInfo, new PersonInfo
+ {
+ Name = video.Channel.Name,
+ ImageUrl = video.Channel.ThumbUrl,
+ Type = PersonType.Actor,
+ });
+ result.HasMetadata = true;
+ result.Item = video.ToEpisode();
+ result.Provider = Name;
+ result.People = peopleInfo;
+ }
+
+ Console.WriteLine(result.Item.ProductionYear);
+ return result;
+ }
+
+ ///
+ public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
+ {
+ var results = new List();
+
+ var taApi = TubeArchivistApi.GetInstance();
+ var videoTAId = searchInfo.Path.Split("/").Last().Split(".").First();
+ var video = await taApi.GetVideo(videoTAId).ConfigureAwait(true);
+ if (video != null)
+ {
+ results.Add(video.ToSearchResult());
+ }
+
+ return results;
+ }
+
+ ///
+ public async Task GetImageResponse(string url, CancellationToken cancellationToken)
+ {
+ if (Plugin.Instance == null)
+ {
+ throw new DataException("Uninitialized plugin!");
+ }
+ else
+ {
+ return await Plugin.Instance.HttpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ }
+}
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel.cs b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel.cs
new file mode 100644
index 0000000..908d01f
--- /dev/null
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel.cs
@@ -0,0 +1,71 @@
+using Newtonsoft.Json;
+
+namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
+{
+ ///
+ /// A class representing TubeArchivist API channel data.
+ ///
+ public class Channel
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// URL of the channel banner image.
+ /// Channel description.
+ /// Channel YouTube id.
+ /// Channel name.
+ /// URL of the channel thumb image.
+ /// URL of the channel tvart image.
+ public Channel(
+ string bannerUrl,
+ string description,
+ string id,
+ string name,
+ string thumbUrl,
+ string tvartUrl)
+ {
+ this.BannerUrl = bannerUrl;
+ this.Description = description;
+ this.Id = id;
+ this.Name = name;
+ this.ThumbUrl = thumbUrl;
+ this.TvartUrl = tvartUrl;
+ }
+
+ ///
+ /// Gets or sets the URL of the channel banner image.
+ ///
+ [JsonProperty(PropertyName = "channel_banner_url")]
+ public string BannerUrl { get; set; }
+
+ ///
+ /// Gets or sets the channel description.
+ ///
+ [JsonProperty(PropertyName = "channel_description")]
+ public string Description { get; set; }
+
+ ///
+ /// Gets or sets the channel YouTube id.
+ ///
+ [JsonProperty(PropertyName = "channel_id")]
+ public string Id { get; set; }
+
+ ///
+ /// Gets or sets the channel name.
+ ///
+ [JsonProperty(PropertyName = "channel_name")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the URL of the channel thumb image.
+ ///
+ [JsonProperty(PropertyName = "channel_thumb_url")]
+ public string ThumbUrl { get; set; }
+
+ ///
+ /// Gets or sets the URL of the channel tvart image.
+ ///
+ [JsonProperty(PropertyName = "channel_tvart_url")]
+ public string TvartUrl { get; set; }
+ }
+}
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/ResponseContainer.cs b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/ResponseContainer.cs
new file mode 100644
index 0000000..753c10a
--- /dev/null
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/ResponseContainer.cs
@@ -0,0 +1,14 @@
+namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
+{
+ ///
+ /// Class representing the base common structure of TubeArchivist API responses.
+ ///
+ /// The contained data type.
+ public class ResponseContainer
+ {
+ ///
+ /// Gets or sets the contained data object.
+ ///
+ public T? Data { get; set; }
+ }
+}
diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/TubeArchivistApi.cs b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/TubeArchivistApi.cs
new file mode 100644
index 0000000..8242000
--- /dev/null
+++ b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/TubeArchivistApi.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Data;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
+{
+ ///
+ /// Class to interact with TubeArchivist API.
+ ///
+ public class TubeArchivistApi
+ {
+ private HttpClient client;
+ private static TubeArchivistApi _taApiInstance = null!;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// HTTP client to make requests to TubeArchivist API.
+ private TubeArchivistApi(HttpClient httpClient)
+ {
+ client = httpClient;
+ }
+
+ ///
+ /// Gets the instance of the class.
+ ///
+ /// The TubeArchivistApi instance.
+ public static TubeArchivistApi GetInstance()
+ {
+ if (_taApiInstance == null)
+ {
+ if (Plugin.Instance != null)
+ {
+ _taApiInstance = new TubeArchivistApi(Plugin.Instance.HttpClient);
+ }
+ else
+ {
+ throw new DataException("Uninitialized plugin!");
+ }
+ }
+
+ return _taApiInstance;
+ }
+
+ ///
+ /// Retrieves the given channel information from TubeArchivist.
+ ///
+ /// YouTube channel id.
+ /// A task.
+ public async Task GetChannel(string channelId)
+ {
+ ResponseContainer? channel = null;
+ Console.WriteLine(Plugin.Instance?.Configuration.TubeArchivistUrl);
+ Console.WriteLine(Plugin.Instance?.Configuration.TubeArchivistApiKey);
+
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", Plugin.Instance?.Configuration.TubeArchivistApiKey);
+
+ var channelsEndpoint = "/api/channel/";
+ var url = new Uri(Plugin.Instance?.Configuration.TubeArchivistUrl + channelsEndpoint + channelId);
+ var response = await client.GetAsync(url).ConfigureAwait(true);
+ Console.WriteLine(response.StatusCode);
+ while (response.StatusCode == HttpStatusCode.Moved)
+ {
+ Console.WriteLine("Received redirect to: " + response.Headers.Location);
+ response = await client.GetAsync(response.Headers.Location).ConfigureAwait(true);
+ }
+
+ Console.WriteLine(url + ": " + response.StatusCode);
+
+ if (response.IsSuccessStatusCode)
+ {
+ string rawData = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
+ channel = JsonConvert.DeserializeObject>(rawData);
+
+ Console.WriteLine("Channel null? " + channel == null);
+ Console.WriteLine("Channel: " + channel?.Data?.Name);
+ if (channel != null && channel.Data != null)
+ {
+ Console.WriteLine(JsonConvert.SerializeObject(channel));
+ }
+ }
+
+ return channel?.Data;
+ }
+
+ ///
+ /// Retrieves the given video information from TubeArchivist.
+ ///
+ /// YouTube video id.
+ /// A task.
+ public async Task