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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+