mirror of
https://github.com/jellyfin/jellyfin-plugin-fanart.git
synced 2024-11-26 23:20:31 +00:00
commit
362fd96399
@ -1,23 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Jellyfin.Plugin.Fanart</RootNamespace>
|
||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.*" />
|
||||
<PackageReference Include="Jellyfin.Model" Version="10.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Configuration\configPage.html" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Configuration\configPage.html" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Jellyfin.Plugin.Fanart</RootNamespace>
|
||||
<AssemblyVersion>1.1.0</AssemblyVersion>
|
||||
<FileVersion>1.1.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.*" />
|
||||
<PackageReference Include="Jellyfin.Model" Version="10.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Configuration\configPage.html" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Configuration\configPage.html" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -10,18 +10,24 @@ namespace Jellyfin.Plugin.Fanart
|
||||
{
|
||||
public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
|
||||
{
|
||||
public override string Name => "Fanart";
|
||||
public override Guid Id => Guid.Parse("170a157f-ac6c-437a-abdd-ca9c25cebd39");
|
||||
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) : base(applicationPaths, xmlSerializer)
|
||||
public const string ApiKey = "184e1a2b1fe3b94935365411f919f638";
|
||||
public const string BaseUrl = "https://webservice.fanart.tv/v3/{2}/{1}?api_key={0}";
|
||||
|
||||
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||
: base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Fanart";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Guid Id { get; } = new Guid("170a157f-ac6c-437a-abdd-ca9c25cebd39");
|
||||
|
||||
public static Plugin Instance { get; private set; }
|
||||
|
||||
public static string ApiKey = "184e1a2b1fe3b94935365411f919f638";
|
||||
public static string BaseUrl = "https://webservice.fanart.tv/v3/{2}/{1}?api_key={0}";
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PluginPageInfo> GetPages()
|
||||
{
|
||||
return new[]
|
||||
|
@ -13,7 +13,6 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
@ -21,29 +20,28 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
public class AlbumProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
public AlbumProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
|
||||
public AlbumProvider(IServerConfigurationManager config, IHttpClient httpClient, IJsonSerializer jsonSerializer)
|
||||
{
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_fileSystem = fileSystem;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
public string Name => ProviderName;
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fanart";
|
||||
|
||||
public static string ProviderName => "Fanart";
|
||||
/// <inheritdoc />
|
||||
public int Order => 1; // After embedded provider
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(BaseItem item)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
}
|
||||
=> item is MusicAlbum;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
@ -53,6 +51,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var album = (MusicAlbum)item;
|
||||
@ -104,6 +103,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
@ -111,10 +111,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0)
|
||||
@ -145,7 +147,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateImages(List<RemoteImageInfo> list,
|
||||
private void PopulateImages(
|
||||
List<RemoteImageInfo> list,
|
||||
List<ArtistProvider.ArtistImage> images,
|
||||
ImageType type,
|
||||
int width,
|
||||
@ -175,7 +178,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Language = i.lang
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Integer, _usCulture, out var likes))
|
||||
if (!string.IsNullOrEmpty(likesString)
|
||||
&& int.TryParse(likesString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
@ -186,9 +190,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return null;
|
||||
}).Where(i => i != null));
|
||||
}
|
||||
// After embedded provider
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
|
@ -24,14 +24,11 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
public class ArtistProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
internal static ArtistProvider Current;
|
||||
|
||||
public ArtistProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
|
||||
{
|
||||
_config = config;
|
||||
@ -42,15 +39,19 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public string Name => ProviderName;
|
||||
internal static ArtistProvider Current { get; private set; }
|
||||
|
||||
public static string ProviderName => "Fanart";
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fanart";
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Order => 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(BaseItem item)
|
||||
{
|
||||
return item is MusicArtist;
|
||||
}
|
||||
=> item is MusicArtist;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
@ -63,6 +64,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var artist = (MusicArtist)item;
|
||||
@ -103,6 +105,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
@ -110,10 +113,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0)
|
||||
@ -139,7 +144,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
PopulateImages(list, obj.musicarts, ImageType.Art, 500, 281);
|
||||
}
|
||||
|
||||
private void PopulateImages(List<RemoteImageInfo> list,
|
||||
private void PopulateImages(
|
||||
List<RemoteImageInfo> list,
|
||||
List<ArtistImage> images,
|
||||
ImageType type,
|
||||
int width,
|
||||
@ -169,7 +175,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Language = i.lang
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Integer, _usCulture, out var likes))
|
||||
if (!string.IsNullOrEmpty(likesString)
|
||||
&& int.TryParse(likesString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
@ -181,8 +188,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
}).Where(i => i != null));
|
||||
}
|
||||
|
||||
public int Order => 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
@ -198,12 +204,10 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
var fileInfo = _fileSystem.GetFileSystemInfo(jsonPath);
|
||||
|
||||
if (fileInfo.Exists)
|
||||
if (fileInfo.Exists
|
||||
&& (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
||||
{
|
||||
if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return DownloadArtistJson(musicBrainzId, cancellationToken);
|
||||
@ -219,7 +223,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var url = string.Format(Plugin.BaseUrl, Plugin.ApiKey, musicBrainzId, "music");
|
||||
var url = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
Plugin.BaseUrl,
|
||||
Plugin.ApiKey,
|
||||
musicBrainzId,
|
||||
"music");
|
||||
|
||||
var clientKey = Plugin.Instance.Configuration.PersonalApiKey;
|
||||
if (!string.IsNullOrWhiteSpace(clientKey))
|
||||
@ -233,21 +242,19 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
try
|
||||
{
|
||||
using (var httpResponse = await _httpClient.SendAsync(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = true
|
||||
|
||||
}, "GET").ConfigureAwait(false))
|
||||
{
|
||||
using (var response = httpResponse.Content)
|
||||
using (var httpResponse = await _httpClient.SendAsync(
|
||||
new HttpRequestOptions
|
||||
{
|
||||
using (var saveFileStream = _fileSystem.GetFileStream(jsonPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||
{
|
||||
await response.CopyToAsync(saveFileStream).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = true
|
||||
|
||||
},
|
||||
"GET").ConfigureAwait(false))
|
||||
using (var response = httpResponse.Content)
|
||||
using (var saveFileStream = _fileSystem.GetFileStream(jsonPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||
{
|
||||
await response.CopyToAsync(saveFileStream).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpException ex)
|
||||
@ -295,35 +302,50 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return Path.Combine(dataPath, "fanart.json");
|
||||
}
|
||||
|
||||
|
||||
public class ArtistImage
|
||||
{
|
||||
public string id { get; set; }
|
||||
|
||||
public string url { get; set; }
|
||||
|
||||
public string likes { get; set; }
|
||||
|
||||
public string disc { get; set; }
|
||||
|
||||
public string size { get; set; }
|
||||
|
||||
public string lang { get; set; }
|
||||
}
|
||||
|
||||
public class Album
|
||||
{
|
||||
public string release_group_id { get; set; }
|
||||
|
||||
public List<ArtistImage> cdart { get; set; }
|
||||
|
||||
public List<ArtistImage> albumcover { get; set; }
|
||||
}
|
||||
|
||||
public class ArtistResponse
|
||||
{
|
||||
public string name { get; set; }
|
||||
|
||||
public string mbid_id { get; set; }
|
||||
|
||||
public List<ArtistImage> artistthumb { get; set; }
|
||||
|
||||
public List<ArtistImage> artistbackground { get; set; }
|
||||
|
||||
public List<ArtistImage> hdmusiclogo { get; set; }
|
||||
|
||||
public List<ArtistImage> musicbanner { get; set; }
|
||||
|
||||
public List<ArtistImage> musiclogo { get; set; }
|
||||
|
||||
public List<ArtistImage> musicarts { get; set; }
|
||||
|
||||
public List<ArtistImage> hdmusicarts { get; set; }
|
||||
|
||||
public List<Album> albums { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -23,33 +23,30 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
public class MovieProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
||||
internal static MovieProvider Current;
|
||||
|
||||
public MovieProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json)
|
||||
{
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_fileSystem = fileSystem;
|
||||
_json = json;
|
||||
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public string Name => ProviderName;
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fanart";
|
||||
|
||||
public static string ProviderName => "Fanart";
|
||||
/// <inheritdoc />
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(BaseItem item)
|
||||
{
|
||||
return item is Movie || item is BoxSet || item is MusicVideo;
|
||||
}
|
||||
=> item is Movie || item is BoxSet || item is MusicVideo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
@ -64,6 +61,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var baseItem = item;
|
||||
@ -90,7 +88,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
try
|
||||
{
|
||||
AddImages(list, path, cancellationToken);
|
||||
AddImages(list, path);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@ -114,6 +112,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
@ -121,23 +120,25 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0);
|
||||
}
|
||||
|
||||
private void AddImages(List<RemoteImageInfo> list, string path, CancellationToken cancellationToken)
|
||||
private void AddImages(List<RemoteImageInfo> list, string path)
|
||||
{
|
||||
var root = _json.DeserializeFromFile<RootObject>(path);
|
||||
|
||||
AddImages(list, root, cancellationToken);
|
||||
AddImages(list, root);
|
||||
}
|
||||
|
||||
private void AddImages(List<RemoteImageInfo> list, RootObject obj, CancellationToken cancellationToken)
|
||||
private void AddImages(List<RemoteImageInfo> list, RootObject obj)
|
||||
{
|
||||
PopulateImages(list, obj.hdmovieclearart, ImageType.Art, 1000, 562);
|
||||
PopulateImages(list, obj.hdmovielogo, ImageType.Logo, 800, 310);
|
||||
@ -176,7 +177,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Language = i.lang
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Integer, _usCulture, out var likes))
|
||||
if (!string.IsNullOrEmpty(likesString)
|
||||
&& int.TryParse(likesString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
@ -188,8 +190,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
}).Where(i => i != null));
|
||||
}
|
||||
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
@ -224,7 +225,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return dataPath;
|
||||
}
|
||||
|
||||
public string GetJsonPath(string id)
|
||||
private string GetJsonPath(string id)
|
||||
{
|
||||
var movieDataPath = GetMovieDataPath(_config.ApplicationPaths, id);
|
||||
return Path.Combine(movieDataPath, "fanart.json");
|
||||
@ -240,7 +241,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var url = string.Format(Plugin.BaseUrl, Plugin.ApiKey, id, "movies");
|
||||
var url = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
Plugin.BaseUrl,
|
||||
Plugin.ApiKey,
|
||||
id,
|
||||
"movies");
|
||||
|
||||
var clientKey = Plugin.Instance.Configuration.PersonalApiKey;
|
||||
if (!string.IsNullOrWhiteSpace(clientKey))
|
||||
@ -254,21 +260,19 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
try
|
||||
{
|
||||
using (var httpResponse = await _httpClient.SendAsync(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = true
|
||||
|
||||
}, "GET").ConfigureAwait(false))
|
||||
{
|
||||
using (var response = httpResponse.Content)
|
||||
using (var httpResponse = await _httpClient.SendAsync(
|
||||
new HttpRequestOptions
|
||||
{
|
||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||
{
|
||||
await response.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = true
|
||||
|
||||
},
|
||||
"GET").ConfigureAwait(false))
|
||||
using (var response = httpResponse.Content)
|
||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||
{
|
||||
await response.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpException exception)
|
||||
@ -291,12 +295,10 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
var fileInfo = _fileSystem.GetFileSystemInfo(path);
|
||||
|
||||
if (fileInfo.Exists)
|
||||
if (fileInfo.Exists
|
||||
&& (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
||||
{
|
||||
if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return DownloadMovieJson(id, cancellationToken);
|
||||
@ -305,24 +307,38 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
public class Image
|
||||
{
|
||||
public string id { get; set; }
|
||||
|
||||
public string url { get; set; }
|
||||
|
||||
public string lang { get; set; }
|
||||
|
||||
public string likes { get; set; }
|
||||
}
|
||||
|
||||
public class RootObject
|
||||
{
|
||||
public string name { get; set; }
|
||||
|
||||
public string tmdb_id { get; set; }
|
||||
|
||||
public string imdb_id { get; set; }
|
||||
|
||||
public List<Image> hdmovielogo { get; set; }
|
||||
|
||||
public List<Image> moviedisc { get; set; }
|
||||
|
||||
public List<Image> movielogo { get; set; }
|
||||
|
||||
public List<Image> movieposter { get; set; }
|
||||
|
||||
public List<Image> hdmovieclearart { get; set; }
|
||||
|
||||
public List<Image> movieart { get; set; }
|
||||
|
||||
public List<Image> moviebackground { get; set; }
|
||||
|
||||
public List<Image> moviebanner { get; set; }
|
||||
|
||||
public List<Image> moviethumb { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,12 @@ using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
@ -23,29 +21,26 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
public class SeasonProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
||||
public SeasonProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json)
|
||||
public SeasonProvider(IHttpClient httpClient, IJsonSerializer json)
|
||||
{
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_fileSystem = fileSystem;
|
||||
_json = json;
|
||||
}
|
||||
|
||||
public string Name => ProviderName;
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fanart";
|
||||
|
||||
public static string ProviderName => "Fanart";
|
||||
/// <inheritdoc />
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(BaseItem item)
|
||||
{
|
||||
return item is Season;
|
||||
}
|
||||
=> item is Season;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
@ -57,6 +52,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
@ -112,6 +108,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
@ -119,10 +116,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0)
|
||||
@ -144,7 +143,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
PopulateImages(list, obj.showbackground, ImageType.Backdrop, 1920, 1080, seasonNumber);
|
||||
}
|
||||
|
||||
private void PopulateImages(List<RemoteImageInfo> list,
|
||||
private void PopulateImages(
|
||||
List<RemoteImageInfo> list,
|
||||
List<SeriesProvider.Image> images,
|
||||
ImageType type,
|
||||
int width,
|
||||
@ -161,10 +161,10 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
var url = i.url;
|
||||
var season = i.season;
|
||||
|
||||
if (!string.IsNullOrEmpty(url) &&
|
||||
!string.IsNullOrEmpty(season) &&
|
||||
int.TryParse(season, NumberStyles.Integer, _usCulture, out var imageSeasonNumber) &&
|
||||
seasonNumber == imageSeasonNumber)
|
||||
if (!string.IsNullOrEmpty(url)
|
||||
&& !string.IsNullOrEmpty(season)
|
||||
&& int.TryParse(season, NumberStyles.Integer, CultureInfo.InvariantCulture, out var imageSeasonNumber)
|
||||
&& seasonNumber == imageSeasonNumber)
|
||||
{
|
||||
var likesString = i.likes;
|
||||
|
||||
@ -179,7 +179,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Language = i.lang
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Integer, _usCulture, out var likes))
|
||||
if (!string.IsNullOrEmpty(likesString)
|
||||
&& int.TryParse(likesString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
@ -191,8 +192,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
}).Where(i => i != null));
|
||||
}
|
||||
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
|
@ -6,14 +6,12 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.Fanart.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
@ -26,13 +24,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
public class SeriesProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
||||
internal static SeriesProvider Current { get; private set; }
|
||||
private readonly SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
public SeriesProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json)
|
||||
{
|
||||
@ -44,15 +41,19 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public string Name => ProviderName;
|
||||
internal static SeriesProvider Current { get; private set; }
|
||||
|
||||
public static string ProviderName => "Fanart";
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fanart";
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(BaseItem item)
|
||||
{
|
||||
return item is Series;
|
||||
}
|
||||
=> item is Series;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
@ -66,6 +67,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
@ -93,7 +95,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
try
|
||||
{
|
||||
AddImages(list, path, cancellationToken);
|
||||
AddImages(list, path);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@ -117,6 +119,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
@ -124,24 +127,26 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0)
|
||||
.ThenByDescending(i => i.VoteCount ?? 0);
|
||||
}
|
||||
|
||||
private void AddImages(List<RemoteImageInfo> list, string path, CancellationToken cancellationToken)
|
||||
private void AddImages(List<RemoteImageInfo> list, string path)
|
||||
{
|
||||
var root = _json.DeserializeFromFile<RootObject>(path);
|
||||
|
||||
AddImages(list, root, cancellationToken);
|
||||
AddImages(list, root);
|
||||
}
|
||||
|
||||
private void AddImages(List<RemoteImageInfo> list, RootObject obj, CancellationToken cancellationToken)
|
||||
private void AddImages(List<RemoteImageInfo> list, RootObject obj)
|
||||
{
|
||||
PopulateImages(list, obj.hdtvlogo, ImageType.Logo, 800, 310);
|
||||
PopulateImages(list, obj.hdclearart, ImageType.Art, 1000, 562);
|
||||
@ -154,7 +159,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
PopulateImages(list, obj.tvposter, ImageType.Primary, 1000, 1426);
|
||||
}
|
||||
|
||||
private void PopulateImages(List<RemoteImageInfo> list,
|
||||
private void PopulateImages(
|
||||
List<RemoteImageInfo> list,
|
||||
List<Image> images,
|
||||
ImageType type,
|
||||
int width,
|
||||
@ -189,7 +195,8 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
Language = i.lang
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Integer, _usCulture, out var likes))
|
||||
if (!string.IsNullOrEmpty(likesString)
|
||||
&& int.TryParse(likesString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
@ -201,8 +208,7 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
}).Where(i => i != null));
|
||||
}
|
||||
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
@ -243,7 +249,6 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
return Path.Combine(dataPath, "fanart.json");
|
||||
}
|
||||
|
||||
private readonly SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1, 1);
|
||||
internal async Task EnsureSeriesJson(string tvdbId, CancellationToken cancellationToken)
|
||||
{
|
||||
var path = GetJsonPath(tvdbId);
|
||||
@ -281,7 +286,12 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var url = string.Format(Plugin.BaseUrl, Plugin.ApiKey, tvdbId, "tv");
|
||||
var url = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
Plugin.BaseUrl,
|
||||
Plugin.ApiKey,
|
||||
tvdbId,
|
||||
"tv");
|
||||
|
||||
var clientKey = Plugin.Instance.Configuration.PersonalApiKey;
|
||||
if (!string.IsNullOrWhiteSpace(clientKey))
|
||||
@ -295,21 +305,19 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
|
||||
try
|
||||
{
|
||||
using (var httpResponse = await _httpClient.SendAsync(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = true
|
||||
|
||||
}, "GET").ConfigureAwait(false))
|
||||
{
|
||||
using (var response = httpResponse.Content)
|
||||
using (var httpResponse = await _httpClient.SendAsync(
|
||||
new HttpRequestOptions
|
||||
{
|
||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||
{
|
||||
await response.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken,
|
||||
BufferContent = true
|
||||
|
||||
},
|
||||
"GET").ConfigureAwait(false))
|
||||
using (var response = httpResponse.Content)
|
||||
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true))
|
||||
{
|
||||
await response.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (HttpException exception)
|
||||
@ -329,27 +337,44 @@ namespace Jellyfin.Plugin.Fanart.Providers
|
||||
public class Image
|
||||
{
|
||||
public string id { get; set; }
|
||||
|
||||
public string url { get; set; }
|
||||
|
||||
public string lang { get; set; }
|
||||
|
||||
public string likes { get; set; }
|
||||
|
||||
public string season { get; set; }
|
||||
}
|
||||
|
||||
public class RootObject
|
||||
{
|
||||
public string name { get; set; }
|
||||
|
||||
public string thetvdb_id { get; set; }
|
||||
|
||||
public List<Image> clearlogo { get; set; }
|
||||
|
||||
public List<Image> hdtvlogo { get; set; }
|
||||
|
||||
public List<Image> clearart { get; set; }
|
||||
|
||||
public List<Image> showbackground { get; set; }
|
||||
|
||||
public List<Image> tvthumb { get; set; }
|
||||
|
||||
public List<Image> seasonposter { get; set; }
|
||||
|
||||
public List<Image> seasonthumb { get; set; }
|
||||
|
||||
public List<Image> hdclearart { get; set; }
|
||||
|
||||
public List<Image> tvbanner { get; set; }
|
||||
|
||||
public List<Image> characterart { get; set; }
|
||||
|
||||
public List<Image> tvposter { get; set; }
|
||||
|
||||
public List<Image> seasonbanner { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
name: "jellyfin-plugin-fanart"
|
||||
guid: "170a157f-ac6c-437a-abdd-ca9c25cebd39"
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
nicename: "Fanart"
|
||||
description: "Scrape poster images from fanart.tv"
|
||||
overview: "Scrape poster images for movies, shows, and artists in your library."
|
||||
|
Loading…
Reference in New Issue
Block a user