feat: add tmdb backdrop

This commit is contained in:
cxfksword 2023-01-17 15:06:04 +08:00
parent 194cb3471c
commit 8cb221a204
8 changed files with 137 additions and 31 deletions

View File

@ -1,13 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Moq" Version="4.18.2" />
@ -15,11 +12,9 @@
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Jellyfin.Plugin.MetaShark\Jellyfin.Plugin.MetaShark.csproj" >
<ExcludeAssets></ExcludeAssets>
<ProjectReference Include="..\Jellyfin.Plugin.MetaShark\Jellyfin.Plugin.MetaShark.csproj">
<ExcludeAssets />
</ProjectReference>
</ItemGroup>
</Project>
</Project>

View File

@ -0,0 +1,60 @@
using Jellyfin.Plugin.MetaShark.Api;
using Jellyfin.Plugin.MetaShark.Core;
using Jellyfin.Plugin.MetaShark.Providers;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Moq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Jellyfin.Plugin.MetaShark.Test
{
[TestClass]
public class MovieImageProviderTest
{
ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
builder.AddSimpleConsole(options =>
{
options.IncludeScopes = true;
options.SingleLine = true;
options.TimestampFormat = "hh:mm:ss ";
}));
[TestMethod]
public void TestGetMovieImage()
{
var info = new MediaBrowser.Controller.Entities.Movies.Movie()
{
Name = "机动战士高达 逆袭的夏亚",
PreferredMetadataLanguage = "zh",
ProviderIds = new Dictionary<string, string> { { BaseProvider.DoubanProviderId, "1401536" }, { MetadataProvider.Tmdb.ToString(), "16157" } }
};
var doubanApi = new DoubanApi(loggerFactory);
var tmdbApi = new TmdbApi(loggerFactory);
var omdbApi = new OmdbApi(loggerFactory);
var httpClientFactory = new DefaultHttpClientFactory();
var libraryManagerStub = new Mock<ILibraryManager>();
var httpContextAccessorStub = new Mock<IHttpContextAccessor>();
Task.Run(async () =>
{
var provider = new MovieImageProvider(httpClientFactory, loggerFactory, libraryManagerStub.Object, httpContextAccessorStub.Object, doubanApi, tmdbApi, omdbApi);
var result = await provider.GetImages(info, CancellationToken.None);
Assert.IsNotNull(result);
var str = result.ToJson();
Console.WriteLine(result.ToJson());
}).GetAwaiter().GetResult();
}
}
}

View File

@ -54,6 +54,14 @@ namespace Jellyfin.Plugin.MetaShark.Test
parseResult = NameParser.Parse(fileName);
Console.WriteLine(parseResult.ToJson());
// 只中文
fileName = "机动战士高达 逆袭的夏亚";
parseResult = NameParser.Parse(fileName);
Console.WriteLine(parseResult.ToJson());
fileName = "秒速5厘米";
parseResult = NameParser.Parse(fileName);
Console.WriteLine(parseResult.ToJson());
// 标题加年份
@ -98,6 +106,9 @@ namespace Jellyfin.Plugin.MetaShark.Test
// anime混合中日文
fileName = "[异域-11番小队][罗马浴场 THERMAE_ROMAE][1-6+SP][BDRIP][720P][X264-10bit_AAC]";
var anitomyResult = AnitomySharp.AnitomySharp.Parse(fileName);
Console.WriteLine(anitomyResult.ToJson());
parseResult = NameParser.Parse(fileName);
Console.WriteLine(parseResult.ToJson());
@ -121,9 +132,6 @@ namespace Jellyfin.Plugin.MetaShark.Test
// 只英文
fileName = "She-Hulk.Attorney.At.Law.S01E01.1080p.WEBRip.x265-RARBG";
var anitomyResult = AnitomySharp.AnitomySharp.Parse(fileName);
Console.WriteLine(anitomyResult.ToJson());
parseResult = NameParser.Parse(fileName);
Console.WriteLine(parseResult.ToJson());

View File

@ -79,8 +79,8 @@ namespace Jellyfin.Plugin.MetaShark.Api
Regex regFamily = new Regex(@"家庭成员: \n(.+?)\n", RegexOptions.Compiled);
Regex regCelebrityImdb = new Regex(@"imdb编号:\s+?(nm\d+)", RegexOptions.Compiled);
// 默认1秒请求1次
private TimeLimiter _defaultTimeConstraint = TimeLimiter.GetFromMaxCountByInterval(1, TimeSpan.FromMilliseconds(1000));
// 默认500毫秒请求1次
private TimeLimiter _defaultTimeConstraint = TimeLimiter.GetFromMaxCountByInterval(1, TimeSpan.FromMilliseconds(500));
// 未登录最多1分钟10次请求不然5分钟后会被封ip
private TimeLimiter _guestTimeConstraint = TimeLimiter.Compose(new CountByIntervalAwaitableConstraint(10, TimeSpan.FromMinutes(1)), new CountByIntervalAwaitableConstraint(1, TimeSpan.FromMilliseconds(5000)));
// 登录后最多1分钟20次请求不然会触发机器人检验

View File

@ -35,6 +35,8 @@ public class PluginConfiguration : BasePluginConfiguration
public bool EnableTmdbSearch { get; set; } = false;
public bool EnableTmdbBackdrop { get; set; } = false;
public string TmdbApiKey { get; set; } = string.Empty;
public string TmdbHost { get; set; } = string.Empty;

View File

@ -69,6 +69,14 @@
</label>
<div class="fieldDescription">勾选后识别时会同时返回TheMovieDb搜索结果</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label class="emby-checkbox-label" for="EnableTmdbBackdrop">
<input id="EnableTmdbBackdrop" name="EnableTmdbBackdrop" type="checkbox"
is="emby-checkbox" />
<span>使用TheMovieDb补全背景图</span>
</label>
<div class="fieldDescription">勾选后当影片在豆瓣找不到背景图时改使用TheMovieDb的补全</div>
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="TmdbApiKey">Api Key</label>
<input id="TmdbApiKey" name="TmdbApiKey" type="text" is="emby-input" />
@ -104,6 +112,7 @@
document.querySelector('#EnableDoubanAvoidRiskControl').checked = config.EnableDoubanAvoidRiskControl;
document.querySelector('#EnableTmdb').checked = config.EnableTmdb;
document.querySelector('#EnableTmdbSearch').checked = config.EnableTmdbSearch;
document.querySelector('#EnableTmdbBackdrop').checked = config.EnableTmdbBackdrop;
document.querySelector('#TmdbApiKey').value = config.TmdbApiKey;
document.querySelector('#TmdbHost').value = config.TmdbHost;
@ -121,6 +130,7 @@
config.EnableDoubanAvoidRiskControl = document.querySelector('#EnableDoubanAvoidRiskControl').checked;
config.EnableTmdb = document.querySelector('#EnableTmdb').checked;
config.EnableTmdbSearch = document.querySelector('#EnableTmdbSearch').checked;
config.EnableTmdbBackdrop = document.querySelector('#EnableTmdbBackdrop').checked;
config.TmdbApiKey = document.querySelector('#TmdbApiKey').value;
config.TmdbHost = document.querySelector('#TmdbHost').value;
ApiClient.updatePluginConfiguration(TemplateConfig.pluginUniqueId, config).then(function (result) {

View File

@ -13,7 +13,7 @@ namespace Jellyfin.Plugin.MetaShark.Core
private static readonly Regex yearReg = new Regex(@"[12][890][0-9][0-9]", RegexOptions.Compiled);
private static readonly Regex seasonSuffixReg = new Regex(@"[ .]S\d{1,2}$", RegexOptions.Compiled);
private static readonly Regex unusedReg = new Regex(@"\[.+?\]|\(.+?\)", RegexOptions.Compiled);
private static readonly Regex unusedReg = new Regex(@"\[.+?\]|\(.+?\)|【.+?】", RegexOptions.Compiled);
public static ParseNameResult Parse(string fileName, bool isTvSeries = false)
{
@ -25,15 +25,16 @@ namespace Jellyfin.Plugin.MetaShark.Core
{
case AnitomySharp.Element.ElementCategory.ElementAnimeTitle:
// 处理混合中英文的标题中文一般在最前面如V字仇杀队.V.for.Vendetta
char[] seperatorChars = { ' ', '.' };
var firstSpaceIndex = item.Value.IndexOfAny(seperatorChars);
char[] delimiters = { ' ', '.' };
var firstSpaceIndex = item.Value.IndexOfAny(delimiters);
if (firstSpaceIndex > 0)
{
var firstString = item.Value.Substring(0, firstSpaceIndex);
if (firstString.HasChinese())
var lastString = item.Value.Substring(firstSpaceIndex + 1);
if (firstString.HasChinese() && !lastString.HasChinese())
{
parseResult.ChineseName = CleanName(firstString);
parseResult.Name = CleanName(item.Value.Substring(firstSpaceIndex + 1));
parseResult.Name = CleanName(lastString);
}
else
{

View File

@ -62,7 +62,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
{
return Enumerable.Empty<RemoteImageInfo>();
}
var backdropImgs = await GetBackdrop(sid, cancellationToken);
var backdropImgs = await GetBackdrop(item, cancellationToken);
var res = new List<RemoteImageInfo> {
new RemoteImageInfo
@ -139,28 +139,58 @@ namespace Jellyfin.Plugin.MetaShark.Providers
/// <summary>
/// Query for a background photo
/// </summary>
/// <param name="sid">a subject/movie id</param>
/// <param name="cancellationToken">Instance of the <see cref="CancellationToken"/> interface.</param>
private async Task<IEnumerable<RemoteImageInfo>> GetBackdrop(string sid, CancellationToken cancellationToken)
private async Task<IEnumerable<RemoteImageInfo>> GetBackdrop(BaseItem item, CancellationToken cancellationToken)
{
this.Log("GetBackdrop of sid: {0}", sid);
var photo = await this._doubanApi.GetWallpaperBySidAsync(sid, cancellationToken);
var sid = item.GetProviderId(DoubanProviderId);
var tmdbId = item.GetProviderId(MetadataProvider.Tmdb);
var list = new List<RemoteImageInfo>();
if (photo == null)
// 从豆瓣获取背景图
if (!string.IsNullOrEmpty(sid))
{
var photo = await this._doubanApi.GetWallpaperBySidAsync(sid, cancellationToken);
if (photo != null && photo.Count > 0)
{
this.Log("GetBackdrop from douban sid: {0}", sid);
list = photo.Where(x => x.Width > x.Height * 1.3).Select(x =>
{
return new RemoteImageInfo
{
ProviderName = Name,
Url = x.Large,
Type = ImageType.Backdrop,
};
}).ToList();
}
}
if (list.Count > 0)
{
return list;
}
return photo.Where(x => x.Width > x.Height * 1.3).Select(x =>
// 从TheMovieDb获取背景图
if (config.EnableTmdbBackdrop && !string.IsNullOrEmpty(tmdbId))
{
return new RemoteImageInfo
var language = item.GetPreferredMetadataLanguage();
var movie = await _tmdbApi
.GetMovieAsync(tmdbId.ToInt(), language, language, cancellationToken)
.ConfigureAwait(false);
if (movie != null && !string.IsNullOrEmpty(movie.BackdropPath))
{
ProviderName = Name,
Url = x.Large,
Type = ImageType.Backdrop,
};
});
this.Log("GetBackdrop from tmdb id: {0}", tmdbId);
list.Add(new RemoteImageInfo
{
ProviderName = Name,
Url = _tmdbApi.GetBackdropUrl(movie.BackdropPath),
Type = ImageType.Backdrop,
});
}
}
return list;
}
}