diff --git a/Jellyfin.Plugin.Template.sln b/Jellyfin.Plugin.ITunes.sln similarity index 85% rename from Jellyfin.Plugin.Template.sln rename to Jellyfin.Plugin.ITunes.sln index 241f725..267caf6 100644 --- a/Jellyfin.Plugin.Template.sln +++ b/Jellyfin.Plugin.ITunes.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Plugin.Template", "Jellyfin.Plugin.Template\Jellyfin.Plugin.Template.csproj", "{D921B930-CF91-406F-ACBC-08914DCD0D34}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Plugin.ITunes", "Jellyfin.Plugin.ITunes\Jellyfin.Plugin.ITunes.csproj", "{D921B930-CF91-406F-ACBC-08914DCD0D34}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Jellyfin.Plugin.Template/Configuration/PluginConfiguration.cs b/Jellyfin.Plugin.ITunes/Configuration/PluginConfiguration.cs similarity index 93% rename from Jellyfin.Plugin.Template/Configuration/PluginConfiguration.cs rename to Jellyfin.Plugin.ITunes/Configuration/PluginConfiguration.cs index 5ea6277..6832189 100644 --- a/Jellyfin.Plugin.Template/Configuration/PluginConfiguration.cs +++ b/Jellyfin.Plugin.ITunes/Configuration/PluginConfiguration.cs @@ -1,6 +1,6 @@ using MediaBrowser.Model.Plugins; -namespace Jellyfin.Plugin.Template.Configuration +namespace Jellyfin.Plugin.ITunes.Configuration { public enum SomeOptions { diff --git a/Jellyfin.Plugin.Template/Configuration/configPage.html b/Jellyfin.Plugin.ITunes/Configuration/configPage.html similarity index 100% rename from Jellyfin.Plugin.Template/Configuration/configPage.html rename to Jellyfin.Plugin.ITunes/Configuration/configPage.html diff --git a/Jellyfin.Plugin.ITunes/Dtos/AlbumResult.cs b/Jellyfin.Plugin.ITunes/Dtos/AlbumResult.cs new file mode 100644 index 0000000..db2e075 --- /dev/null +++ b/Jellyfin.Plugin.ITunes/Dtos/AlbumResult.cs @@ -0,0 +1,79 @@ +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.ITunes.Dtos +{ + public partial class ITunesAlbumDto + { + [JsonPropertyName("resultCount")] + public long ResultCount { get; set; } + + [JsonPropertyName("results")] + public Result[] Results { get; set; } + } + + public partial class Result + { + [JsonPropertyName("wrapperType")] + public string WrapperType { get; set; } + + [JsonPropertyName("collectionType")] + public string CollectionType { get; set; } + + [JsonPropertyName("artistId")] + public long ArtistId { get; set; } + + [JsonPropertyName("collectionId")] + public long CollectionId { get; set; } + + [JsonPropertyName("artistName")] + public string ArtistName { get; set; } + + [JsonPropertyName("collectionName")] + public string CollectionName { get; set; } + + [JsonPropertyName("collectionCensoredName")] + public string CollectionCensoredName { get; set; } + + [JsonPropertyName("artistViewUrl")] + public string ArtistViewUrl { get; set; } + + [JsonPropertyName("collectionViewUrl")] + public string CollectionViewUrl { get; set; } + + [JsonPropertyName("artworkUrl60")] + public string ArtworkUrl60 { get; set; } + + [JsonPropertyName("artworkUrl100")] + public string ArtworkUrl100 { get; set; } + + [JsonPropertyName("collectionPrice")] + public double CollectionPrice { get; set; } + + [JsonPropertyName("collectionExplicitness")] + public string CollectionExplicitness { get; set; } + + [JsonPropertyName("trackCount")] + public long TrackCount { get; set; } + + [JsonPropertyName("copyright")] + public string Copyright { get; set; } + + [JsonPropertyName("country")] + public string Country { get; set; } + + [JsonPropertyName("currency")] + public string Currency { get; set; } + + [JsonPropertyName("releaseDate")] + public string ReleaseDate { get; set; } + + [JsonPropertyName("primaryGenreName")] + public string PrimaryGenreName { get; set; } + + [JsonPropertyName("contentAdvisoryRating")] + public string ContentAdvisoryRating { get; set; } + + [JsonPropertyName("amgArtistId")] + public long? AmgArtistId { get; set; } + } +} diff --git a/Jellyfin.Plugin.ITunes/Jellyfin.Plugin.ITunes.csproj b/Jellyfin.Plugin.ITunes/Jellyfin.Plugin.ITunes.csproj new file mode 100644 index 0000000..c3602df --- /dev/null +++ b/Jellyfin.Plugin.ITunes/Jellyfin.Plugin.ITunes.csproj @@ -0,0 +1,32 @@ + + + + net5.0 + Jellyfin.Plugin.ITunes + 1.0.0.0 + 1.0.0.0 + + + + + + + + + + + + + + + + + + + + + + ../jellyfin.ruleset + + + diff --git a/Jellyfin.Plugin.Template/Plugin.cs b/Jellyfin.Plugin.ITunes/Plugin.cs similarity index 80% rename from Jellyfin.Plugin.Template/Plugin.cs rename to Jellyfin.Plugin.ITunes/Plugin.cs index 74ead75..d9994f0 100644 --- a/Jellyfin.Plugin.Template/Plugin.cs +++ b/Jellyfin.Plugin.ITunes/Plugin.cs @@ -1,18 +1,18 @@ using System; using System.Collections.Generic; -using Jellyfin.Plugin.Template.Configuration; +using Jellyfin.Plugin.ITunes.Configuration; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Serialization; -namespace Jellyfin.Plugin.Template +namespace Jellyfin.Plugin.ITunes { public class Plugin : BasePlugin, IHasWebPages { - public override string Name => "Template"; + public override string Name => "iTunes"; - public override Guid Id => Guid.Parse("eb5d7894-8eef-4b36-aa6f-5d124e828ce1"); + public override Guid Id => Guid.Parse("a9f62a44-fea5-46c3-ac26-55abba29c7c8"); public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) : base(applicationPaths, xmlSerializer) { diff --git a/Jellyfin.Plugin.ITunes/Providers/ItunesAlbumProvider.cs b/Jellyfin.Plugin.ITunes/Providers/ItunesAlbumProvider.cs new file mode 100644 index 0000000..5d7fde1 --- /dev/null +++ b/Jellyfin.Plugin.ITunes/Providers/ItunesAlbumProvider.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Json; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; +using Microsoft.Extensions.Logging; +using Jellyfin.Plugin.ITunes.Dtos; + +namespace Jellyfin.Plugin.ITunes.Providers +{ + public class ITunesAlbumProvider : IRemoteImageProvider, IHasOrder + { + private readonly IHttpClientFactory _httpClientFactory; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public ITunesAlbumProvider(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + } + + /// + public string Name => "iTunes"; + + /// + public int Order => 1; // After embedded provider + + /// + public bool Supports(BaseItem item) + => item is MusicAlbum; + + /// + public IEnumerable GetSupportedImages(BaseItem item) + { + return new List + { + ImageType.Primary + }; + } + + /// + public async Task GetImageResponse(string url, CancellationToken cancellationToken) + { + var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); + return await httpClient.GetAsync(new Uri(url), cancellationToken).ConfigureAwait(false); + } + + /// + public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) + { + var album = (MusicAlbum)item; + var list = new List(); + + if (!string.IsNullOrEmpty(album.Name)) + { + var searchQuery = album.Name; + + if (album.AlbumArtists.Count > 0) { + string[] terms = { + album.AlbumArtists[0], + album.Name + }; + searchQuery = String.Join(' ', terms); + } + + var encodedName = Uri.EscapeUriString(searchQuery); + + list.AddRange(await GetImagesInternal($"https://itunes.apple.com/search?term={encodedName}&media=music&entity=album", cancellationToken) + .ConfigureAwait(false)); + } + + return list; + } + + private async Task> GetImagesInternal(string url, CancellationToken cancellationToken) + { + List list = new List(); + + var iTunesAlbumDto = await _httpClientFactory + .CreateClient(NamedClient.Default) + .GetFromJsonAsync(new Uri(url)) + .ConfigureAwait(false);; + + if (iTunesAlbumDto != null) + { + foreach (Result result in iTunesAlbumDto.Results) + { + // The max artwork size is 3000x3000. Some might return less, but we can't predict that. + var image1400 = result.ArtworkUrl100.Replace("100x100bb","3000x3000bb"); + + list.Add( + new RemoteImageInfo + { + ProviderName = Name, + Url = image1400, + Type = ImageType.Primary, + ThumbnailUrl = result.ArtworkUrl100, + RatingType = RatingType.Score, + } + ); + } + } + else + { + return Array.Empty(); + } + + return list; + } + } +} diff --git a/Jellyfin.Plugin.Template/Jellyfin.Plugin.Template.csproj b/Jellyfin.Plugin.Template/Jellyfin.Plugin.Template.csproj deleted file mode 100644 index 5e75639..0000000 --- a/Jellyfin.Plugin.Template/Jellyfin.Plugin.Template.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - net5.0 - Jellyfin.Plugin.Template - 1.0.0.0 - 1.0.0.0 - - - - - - - - - - - - - diff --git a/jellyfin.ruleset b/jellyfin.ruleset new file mode 100644 index 0000000..45ab725 --- /dev/null +++ b/jellyfin.ruleset @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +