Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
|
945930d75e | |
|
b2264405d5 | |
|
4ae795d503 |
|
@ -4,7 +4,7 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 6.0.x
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
project: Jellyfin.Plugin.MetaShark/Jellyfin.Plugin.MetaShark.csproj
|
project: Jellyfin.Plugin.MetaShark/Jellyfin.Plugin.MetaShark.csproj
|
||||||
artifact: metashark
|
artifact: metashark
|
||||||
|
@ -36,9 +36,9 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
dotnet restore ${{ env.project }} --no-cache
|
dotnet restore ${{ env.project }} --no-cache
|
||||||
dotnet publish --nologo --no-restore --configuration=Release --framework=net8.0 ${{ env.project }}
|
dotnet publish --nologo --no-restore --configuration=Release --framework=net6.0 ${{ env.project }}
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
cp ./Jellyfin.Plugin.MetaShark/bin/Release/net8.0/Jellyfin.Plugin.MetaShark.dll ./artifacts/
|
cp ./Jellyfin.Plugin.MetaShark/bin/Release/net6.0/Jellyfin.Plugin.MetaShark.dll ./artifacts/
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
- uses: actions/setup-dotnet@v3
|
- uses: actions/setup-dotnet@v3
|
||||||
id: dotnet
|
id: dotnet
|
||||||
with:
|
with:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 6.0.x
|
||||||
- name: Change default dotnet version
|
- name: Change default dotnet version
|
||||||
run: |
|
run: |
|
||||||
echo '{"sdk":{"version": "${{ steps.dotnet.outputs.dotnet-version }}"}}' > ./global.json
|
echo '{"sdk":{"version": "${{ steps.dotnet.outputs.dotnet-version }}"}}' > ./global.json
|
||||||
|
|
|
@ -5,7 +5,7 @@ on:
|
||||||
tags: ["*"]
|
tags: ["*"]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 6.0.x
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
project: Jellyfin.Plugin.MetaShark/Jellyfin.Plugin.MetaShark.csproj
|
project: Jellyfin.Plugin.MetaShark/Jellyfin.Plugin.MetaShark.csproj
|
||||||
artifact: metashark
|
artifact: metashark
|
||||||
|
@ -41,9 +41,9 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
dotnet restore ${{ env.project }} --no-cache
|
dotnet restore ${{ env.project }} --no-cache
|
||||||
dotnet publish --nologo --no-restore --configuration=Release --framework=net8.0 -p:Version=${{steps.vars.outputs.VERSION}} ${{ env.project }}
|
dotnet publish --nologo --no-restore --configuration=Release --framework=net6.0 -p:Version=${{steps.vars.outputs.VERSION}} ${{ env.project }}
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
zip -j ./artifacts/${{ env.artifact }}_${{steps.vars.outputs.VERSION}}.zip ./Jellyfin.Plugin.MetaShark/bin/Release/net8.0/Jellyfin.Plugin.MetaShark.dll
|
zip -j ./artifacts/${{ env.artifact }}_${{steps.vars.outputs.VERSION}}.zip ./Jellyfin.Plugin.MetaShark/bin/Release/net6.0/Jellyfin.Plugin.MetaShark.dll
|
||||||
- name: Generate manifest
|
- name: Generate manifest
|
||||||
run: python3 ./scripts/generate_manifest.py ./artifacts/${{ env.artifact }}_${{steps.vars.outputs.VERSION}}.zip ${GITHUB_REF#refs/*/}
|
run: python3 ./scripts/generate_manifest.py ./artifacts/${{ env.artifact }}_${{steps.vars.outputs.VERSION}}.zip ${GITHUB_REF#refs/*/}
|
||||||
env:
|
env:
|
||||||
|
@ -54,7 +54,7 @@ jobs:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: ./artifacts/${{ env.artifact }}_*.zip
|
file: ./artifacts/${{ env.artifact }}_*.zip
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
release_name: '${{ github.ref_name }}: Jellyfin v10.9'
|
release_name: '${{ github.ref_name }}: Jellyfin v10.8'
|
||||||
file_glob: true
|
file_glob: true
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- name: Publish manifest
|
- name: Publish manifest
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageId>AnitomySharp.NET6</PackageId>
|
<PackageId>AnitomySharp.NET6</PackageId>
|
||||||
<PackageVersion>0.4.0</PackageVersion>
|
<PackageVersion>0.4.0</PackageVersion>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
|
|
@ -64,11 +64,7 @@ namespace Jellyfin.Plugin.MetaShark.Test
|
||||||
var imdbApi = new ImdbApi(loggerFactory);
|
var imdbApi = new ImdbApi(loggerFactory);
|
||||||
|
|
||||||
var provider = new SeasonProvider(httpClientFactory, loggerFactory, libraryManagerStub.Object, httpContextAccessorStub.Object, doubanApi, tmdbApi, omdbApi, imdbApi);
|
var provider = new SeasonProvider(httpClientFactory, loggerFactory, libraryManagerStub.Object, httpContextAccessorStub.Object, doubanApi, tmdbApi, omdbApi, imdbApi);
|
||||||
|
var result = provider.GuessSeasonNumberByDirectoryName("/data/downloads/jellyfin/tv/向往的生活/第2季");
|
||||||
var result = provider.GuessSeasonNumberByDirectoryName("/data/downloads/jellyfin/tv/冰与火之歌S01-S08.Game.of.Thrones.1080p.Blu-ray.x265.10bit.AC3/冰与火之歌S2.列王的纷争.2012.1080p.Blu-ray.x265.10bit.AC3");
|
|
||||||
Assert.AreEqual(result, 2);
|
|
||||||
|
|
||||||
result = provider.GuessSeasonNumberByDirectoryName("/data/downloads/jellyfin/tv/向往的生活/第2季");
|
|
||||||
Assert.AreEqual(result, 2);
|
Assert.AreEqual(result, 2);
|
||||||
|
|
||||||
result = provider.GuessSeasonNumberByDirectoryName("/data/downloads/jellyfin/tv/向往的生活 第2季");
|
result = provider.GuessSeasonNumberByDirectoryName("/data/downloads/jellyfin/tv/向往的生活 第2季");
|
||||||
|
|
|
@ -246,21 +246,15 @@ namespace Jellyfin.Plugin.MetaShark.Core
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsSpecialDirectory(string path, bool isDirectory = false)
|
public static bool IsSpecialDirectory(string path)
|
||||||
{
|
{
|
||||||
var folder = Path.GetFileName(Path.GetDirectoryName(path))?.ToUpper() ?? string.Empty;
|
var folder = Path.GetFileName(Path.GetDirectoryName(path))?.ToUpper() ?? string.Empty;
|
||||||
if (isDirectory) {
|
return folder == "SPS" || folder == "SPECIALS" || folder.Contains("特典");
|
||||||
folder = Path.GetFileName(path)?.ToUpper() ?? string.Empty;
|
|
||||||
}
|
|
||||||
return folder == "SP" || folder == "SPS" || folder == "SPECIALS" || folder.Contains("特典");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsExtraDirectory(string path, bool isDirectory = false)
|
public static bool IsExtraDirectory(string path)
|
||||||
{
|
{
|
||||||
var folder = Path.GetFileName(Path.GetDirectoryName(path))?.ToUpper() ?? string.Empty;
|
var folder = Path.GetFileName(Path.GetDirectoryName(path))?.ToUpper() ?? string.Empty;
|
||||||
if (isDirectory) {
|
|
||||||
folder = Path.GetFileName(path)?.ToUpper() ?? string.Empty;
|
|
||||||
}
|
|
||||||
return folder == "EXTRA"
|
return folder == "EXTRA"
|
||||||
|| folder == "MENU"
|
|| folder == "MENU"
|
||||||
|| folder == "MENUS"
|
|| folder == "MENUS"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RootNamespace>Jellyfin.Plugin.MetaShark</RootNamespace>
|
<RootNamespace>Jellyfin.Plugin.MetaShark</RootNamespace>
|
||||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
@ -21,12 +21,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AngleSharp" Version="1.0.1" />
|
<PackageReference Include="AngleSharp" Version="1.0.1" />
|
||||||
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.32">
|
<PackageReference Include="ILRepack.Lib.MSBuild.Minor" Version="2.1.19-alpha.2" />
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<PackageReference Include="Jellyfin.Controller" Version="10.8.0" />
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PackageReference Include="Jellyfin.Model" Version="10.8.0" />
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Jellyfin.Controller" Version="10.9.0" />
|
|
||||||
<PackageReference Include="Jellyfin.Model" Version="10.9.0" />
|
|
||||||
<PackageReference Include="RateLimiter" Version="2.2.0" />
|
<PackageReference Include="RateLimiter" Version="2.2.0" />
|
||||||
<PackageReference Include="TMDbLib" Version="2.2.0" />
|
<PackageReference Include="TMDbLib" Version="2.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -19,7 +19,6 @@ using TMDbLib.Objects.General;
|
||||||
using Jellyfin.Plugin.MetaShark.Configuration;
|
using Jellyfin.Plugin.MetaShark.Configuration;
|
||||||
using Jellyfin.Plugin.MetaShark.Core;
|
using Jellyfin.Plugin.MetaShark.Core;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.MetaShark.Providers
|
namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
|
@ -51,7 +50,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
|
|
||||||
protected Regex regMetaSourcePrefix = new Regex(@"^\[.+\]", RegexOptions.Compiled);
|
protected Regex regMetaSourcePrefix = new Regex(@"^\[.+\]", RegexOptions.Compiled);
|
||||||
protected Regex regSeasonNameSuffix = new Regex(@"\s第[0-9一二三四五六七八九十]+?季$|\sSeason\s\d+?$|(?<![0-9a-zA-Z])\d$", RegexOptions.Compiled);
|
protected Regex regSeasonNameSuffix = new Regex(@"\s第[0-9一二三四五六七八九十]+?季$|\sSeason\s\d+?$|(?<![0-9a-zA-Z])\d$", RegexOptions.Compiled);
|
||||||
protected Regex regDoubanIdAttribute = new Regex(@"\[(?:douban|doubanid)-(\d+?)\]", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
protected PluginConfiguration config
|
protected PluginConfiguration config
|
||||||
{
|
{
|
||||||
|
@ -109,17 +107,11 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
protected async Task<string?> GuessByDoubanAsync(ItemLookupInfo info, CancellationToken cancellationToken)
|
protected async Task<string?> GuessByDoubanAsync(ItemLookupInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var fileName = GetOriginalFileName(info);
|
var fileName = GetOriginalFileName(info);
|
||||||
// 从文件名属性格式获取,如[douban-12345]或[doubanid-12345]
|
|
||||||
var doubanId = this.regDoubanIdAttribute.FirstMatchGroup(fileName);
|
|
||||||
if (!string.IsNullOrWhiteSpace(doubanId))
|
|
||||||
{
|
|
||||||
this.Log($"Found douban [id] by attr: {doubanId}");
|
|
||||||
return doubanId;
|
|
||||||
}
|
|
||||||
var parseResult = NameParser.Parse(fileName);
|
var parseResult = NameParser.Parse(fileName);
|
||||||
var searchName = !string.IsNullOrEmpty(parseResult.ChineseName) ? parseResult.ChineseName : parseResult.Name;
|
var searchName = !string.IsNullOrEmpty(parseResult.ChineseName) ? parseResult.ChineseName : parseResult.Name;
|
||||||
info.Year = parseResult.Year; // 默认parser对anime年份会解析出错,以anitomy为准
|
info.Year = parseResult.Year; // 默认parser对anime年份会解析出错,以anitomy为准
|
||||||
|
|
||||||
|
|
||||||
this.Log($"GuessByDouban of [name]: {info.Name} [file_name]: {fileName} [year]: {info.Year} [search name]: {searchName}");
|
this.Log($"GuessByDouban of [name]: {info.Name} [file_name]: {fileName} [year]: {info.Year} [search name]: {searchName}");
|
||||||
List<DoubanSubject> result;
|
List<DoubanSubject> result;
|
||||||
DoubanSubject? item;
|
DoubanSubject? item;
|
||||||
|
@ -133,13 +125,13 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
item = result.Where(x => x.Year == info.Year && x.Name == searchName).FirstOrDefault();
|
item = result.Where(x => x.Year == info.Year && x.Name == searchName).FirstOrDefault();
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
this.Log($"Found douban [id]: {item.Name}({item.Sid}) (suggest)");
|
this.Log($"GuessByDouban found -> {item.Name}({item.Sid}) (suggest)");
|
||||||
return item.Sid;
|
return item.Sid;
|
||||||
}
|
}
|
||||||
item = result.Where(x => x.Year == info.Year).FirstOrDefault();
|
item = result.Where(x => x.Year == info.Year).FirstOrDefault();
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
this.Log($"Found douban [id]: {item.Name}({item.Sid}) (suggest)");
|
this.Log($"GuessByDouban found -> {item.Name}({item.Sid}) (suggest)");
|
||||||
return item.Sid;
|
return item.Sid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +169,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
item = result.Where(x => x.Category == cat).FirstOrDefault();
|
item = result.Where(x => x.Category == cat).FirstOrDefault();
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
this.Log($"Found douban [id] by first match: {item.Name}({item.Sid})");
|
this.Log($"GuessByDouban found -> {item.Name}({item.Sid})");
|
||||||
return item.Sid;
|
return item.Sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,8 +394,8 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
|
|
||||||
public int? GuessSeasonNumberByDirectoryName(string path)
|
public int? GuessSeasonNumberByDirectoryName(string path)
|
||||||
{
|
{
|
||||||
// TODO: 有时 series name 中会带有季信息
|
// TODO: 有时series name中会带有季信息
|
||||||
// 当没有 season 级目录时,或 season 文件夹特殊不规范命名时,会解析不到 seasonNumber,这时 path 为空,直接返回
|
// 当没有season级目录时,path为空,直接返回
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
this.Log($"Season path is empty!");
|
this.Log($"Season path is empty!");
|
||||||
|
@ -417,7 +409,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 中文季名
|
|
||||||
var regSeason = new Regex(@"第([0-9零一二三四五六七八九]+?)(季|部)", RegexOptions.Compiled);
|
var regSeason = new Regex(@"第([0-9零一二三四五六七八九]+?)(季|部)", RegexOptions.Compiled);
|
||||||
var match = regSeason.Match(fileName);
|
var match = regSeason.Match(fileName);
|
||||||
if (match.Success && match.Groups.Count > 1)
|
if (match.Success && match.Groups.Count > 1)
|
||||||
|
@ -434,26 +425,12 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SXX 季名
|
|
||||||
regSeason = new Regex(@"(?<![a-z])S(\d\d?)(?![0-9a-z])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
||||||
match = regSeason.Match(fileName);
|
|
||||||
if (match.Success && match.Groups.Count > 1)
|
|
||||||
{
|
|
||||||
var seasonNumber = match.Groups[1].Value.ToInt();
|
|
||||||
if (seasonNumber > 0)
|
|
||||||
{
|
|
||||||
this.Log($"Found season number of filename: {fileName} seasonNumber: {seasonNumber}");
|
|
||||||
return seasonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 动漫季特殊命名
|
|
||||||
var seasonNameMap = new Dictionary<string, int>() {
|
var seasonNameMap = new Dictionary<string, int>() {
|
||||||
{@"[ ._](I|1st)[ ._]", 1},
|
{@"[ ._](I|1st|S01|S1)[ ._]", 1},
|
||||||
{@"[ ._](II|2nd)[ ._]", 2},
|
{@"[ ._](II|2nd|S02|S2)[ ._]", 2},
|
||||||
{@"[ ._](III|3rd)[ ._]", 3},
|
{@"[ ._](III|3rd|S03|S3)[ ._]", 3},
|
||||||
{@"[ ._](IIII|4th)[ ._]", 3},
|
{@"[ ._](IIII|4th|S04|S4)[ ._]", 3},
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var entry in seasonNameMap)
|
foreach (var entry in seasonNameMap)
|
||||||
|
@ -623,47 +600,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string? GetOriginalSeasonPath(EpisodeInfo info)
|
protected string RemoveSeasonSubfix(string name)
|
||||||
{
|
|
||||||
if (info.Path == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var seasonPath = Path.GetDirectoryName(info.Path);
|
|
||||||
var item = this._libraryManager.FindByPath(seasonPath, true);
|
|
||||||
// 没有季文件夹
|
|
||||||
if (item is Series) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return seasonPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool IsVirtualSeason(EpisodeInfo info)
|
|
||||||
{
|
|
||||||
if (info.Path == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var seasonPath = Path.GetDirectoryName(info.Path);
|
|
||||||
var parent = this._libraryManager.FindByPath(seasonPath, true);
|
|
||||||
// 没有季文件夹
|
|
||||||
if (parent is Series) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var seriesPath = Path.GetDirectoryName(seasonPath);
|
|
||||||
var series = this._libraryManager.FindByPath(seriesPath, true);
|
|
||||||
// 季文件夹不规范,没法识别
|
|
||||||
if (series is Series && parent is not Season) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string RemoveSeasonSuffix(string name)
|
|
||||||
{
|
{
|
||||||
return regSeasonNameSuffix.Replace(name, "");
|
return regSeasonNameSuffix.Replace(name, "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
// 识别:info的Name、IndexNumber和ParentIndexNumber是从文件名解析出来的,provinceIds有指定选择项的ProvinceId
|
// 识别:info的Name、IndexNumber和ParentIndexNumber是从文件名解析出来的,provinceIds有指定选择项的ProvinceId
|
||||||
// 覆盖所有元数据:info的Name、IndexNumber和ParentIndexNumber是从文件名解析出来的,provinceIds保留所有旧值
|
// 覆盖所有元数据:info的Name、IndexNumber和ParentIndexNumber是从文件名解析出来的,provinceIds保留所有旧值
|
||||||
// 搜索缺少的元数据:info的Name、IndexNumber和ParentIndexNumber是从当前的元数据获取,provinceIds保留所有旧值
|
// 搜索缺少的元数据:info的Name、IndexNumber和ParentIndexNumber是从当前的元数据获取,provinceIds保留所有旧值
|
||||||
var fileName = Path.GetFileName(info.Path);
|
this.Log($"GetEpisodeMetadata of [name]: {info.Name} number: {info.IndexNumber} ParentIndexNumber: {info.ParentIndexNumber} EnableTmdb: {config.EnableTmdb}");
|
||||||
this.Log($"GetEpisodeMetadata of [name]: {info.Name} [fileName]: {fileName} number: {info.IndexNumber} ParentIndexNumber: {info.ParentIndexNumber} EnableTmdb: {config.EnableTmdb}");
|
|
||||||
var result = new MetadataResult<Episode>();
|
var result = new MetadataResult<Episode>();
|
||||||
|
|
||||||
// 动画特典和extras处理
|
// 动画特典和extras处理
|
||||||
|
@ -130,59 +129,69 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重新解析文件名
|
/// 重新解析文件名
|
||||||
/// 注意:这里修改替换 ParentIndexNumber 值后,会重新触发 SeasonProvier 的 GetMetadata 方法,并带上最新的季数 IndexNumber
|
/// 注意:这里修改替换ParentIndexNumber值后,会重新触发SeasonProvier的GetMetadata方法,并带上最新的季数IndexNumber
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EpisodeInfo FixParseInfo(EpisodeInfo info)
|
public EpisodeInfo FixParseInfo(EpisodeInfo info)
|
||||||
{
|
{
|
||||||
// 使用 AnitomySharp 进行重新解析,解决 anime 识别错误
|
// 使用AnitomySharp进行重新解析,解决anime识别错误
|
||||||
var fileName = Path.GetFileNameWithoutExtension(info.Path) ?? info.Name;
|
var fileName = Path.GetFileNameWithoutExtension(info.Path) ?? info.Name;
|
||||||
var parseResult = NameParser.ParseEpisode(fileName);
|
var parseResult = NameParser.ParseEpisode(fileName);
|
||||||
info.Year = parseResult.Year;
|
info.Year = parseResult.Year;
|
||||||
info.Name = parseResult.ChineseName ?? parseResult.Name;
|
info.Name = parseResult.ChineseName ?? parseResult.Name;
|
||||||
|
|
||||||
// 文件名带有季数数据时,从文件名解析出季数进行修正
|
// 修正文件名有特殊命名SXXEPXX时,默认解析到错误季数的问题,如神探狄仁杰 Detective.Dee.S01EP01.2006.2160p.WEB-DL.x264.AAC-HQC
|
||||||
// 修正文件名有特殊命名 SXXEPXX 时,默认解析到错误季数的问题,如神探狄仁杰 Detective.Dee.S01EP01.2006.2160p.WEB-DL.x264.AAC-HQC
|
|
||||||
// TODO: 会导致覆盖用户手动修改元数据的季数
|
// TODO: 会导致覆盖用户手动修改元数据的季数
|
||||||
if (parseResult.ParentIndexNumber.HasValue && parseResult.ParentIndexNumber > 0 && info.ParentIndexNumber != parseResult.ParentIndexNumber)
|
if (info.ParentIndexNumber.HasValue && parseResult.ParentIndexNumber.HasValue && parseResult.ParentIndexNumber > 0 && info.ParentIndexNumber != parseResult.ParentIndexNumber)
|
||||||
{
|
{
|
||||||
this.Log("FixSeasonNumber by anitomy. old: {0} new: {1}", info.ParentIndexNumber, parseResult.ParentIndexNumber);
|
this.Log("FixSeasonNumber by anitomy. old: {0} new: {1}", info.ParentIndexNumber, parseResult.ParentIndexNumber);
|
||||||
info.ParentIndexNumber = parseResult.ParentIndexNumber;
|
info.ParentIndexNumber = parseResult.ParentIndexNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 修正anime命名格式导致的seasonNumber错误(从season元数据读取)
|
// 没有season级目录(即虚拟季)ParentIndexNumber默认是1,季文件夹命名不规范时,ParentIndexNumber默认是null
|
||||||
// if (info.ParentIndexNumber is null)
|
if (info.ParentIndexNumber is null)
|
||||||
// {
|
|
||||||
// var episodeItem = this._libraryManager.FindByPath(info.Path, false);
|
|
||||||
// var season = episodeItem != null ? ((Episode)episodeItem).Season : null;
|
|
||||||
// if (season != null && season.IndexNumber.HasValue && info.ParentIndexNumber != season.IndexNumber)
|
|
||||||
// {
|
|
||||||
// info.ParentIndexNumber = season.IndexNumber;
|
|
||||||
// this.Log("FixSeasonNumber by season. old: {0} new: {1}", info.ParentIndexNumber, season.IndexNumber);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 从季文件夹名称猜出 season number
|
|
||||||
// 没有 season 级目录或部分特殊不规范命名,会变成虚拟季,ParentIndexNumber 默认设为 1
|
|
||||||
// https://github.com/jellyfin/jellyfin/blob/926470829d91d93b4c0b22c5b8b89a791abbb434/Emby.Server.Implementations/Library/LibraryManager.cs#L2626
|
|
||||||
var isVirtualSeason = this.IsVirtualSeason(info);
|
|
||||||
var seasonFolderPath = this.GetOriginalSeasonPath(info);
|
|
||||||
if (info.ParentIndexNumber is null or 1 && isVirtualSeason && seasonFolderPath != null)
|
|
||||||
{
|
{
|
||||||
var guestSeasonNumber = this.GuessSeasonNumberByDirectoryName(seasonFolderPath);
|
info.ParentIndexNumber = parseResult.ParentIndexNumber;
|
||||||
if (guestSeasonNumber.HasValue && guestSeasonNumber != info.ParentIndexNumber)
|
}
|
||||||
|
|
||||||
|
// 修正anime命名格式导致的seasonNumber错误(从season元数据读取)
|
||||||
|
if (info.ParentIndexNumber is null)
|
||||||
|
{
|
||||||
|
var episodeItem = _libraryManager.FindByPath(info.Path, false);
|
||||||
|
var season = episodeItem != null ? ((Episode)episodeItem).Season : null;
|
||||||
|
if (season != null && season.IndexNumber.HasValue && info.ParentIndexNumber != season.IndexNumber)
|
||||||
{
|
{
|
||||||
this.Log("FixSeasonNumber by season path. old: {0} new: {1}", info.ParentIndexNumber, guestSeasonNumber);
|
this.Log("FixSeasonNumber by season. old: {0} new: {1}", info.ParentIndexNumber, season.IndexNumber);
|
||||||
info.ParentIndexNumber = guestSeasonNumber;
|
info.ParentIndexNumber = season.IndexNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // 当没有season级目录时,默认为1,即当成只有一季(不需要处理,虚拟季jellyfin默认传的ParentIndexNumber=1)
|
||||||
|
// if (info.ParentIndexNumber is null && season != null && season.LocationType == LocationType.Virtual)
|
||||||
|
// {
|
||||||
|
// this.Log("FixSeasonNumber: season is virtual, set to default 1");
|
||||||
|
// info.ParentIndexNumber = 1;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从季文件夹名称猜出season number
|
||||||
|
var seasonFolderPath = Path.GetDirectoryName(info.Path);
|
||||||
|
if (info.ParentIndexNumber is null && seasonFolderPath != null)
|
||||||
|
{
|
||||||
|
info.ParentIndexNumber = this.GuessSeasonNumberByDirectoryName(seasonFolderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 识别特典
|
// 识别特典
|
||||||
if (info.ParentIndexNumber is null && NameParser.IsAnime(fileName) && (parseResult.IsSpecial || NameParser.IsSpecialDirectory(info.Path)))
|
if (info.ParentIndexNumber is null && NameParser.IsAnime(fileName) && (parseResult.IsSpecial || NameParser.IsSpecialDirectory(info.Path)))
|
||||||
{
|
{
|
||||||
this.Log("FixSeasonNumber to special. old: {0} new: 0", info.ParentIndexNumber);
|
|
||||||
info.ParentIndexNumber = 0;
|
info.ParentIndexNumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // 设为默认季数为1(问题:当同时存在S01和剧场版季文件夹时,剧场版的影片会因为默认第一季而在S01也显示出来)
|
||||||
|
// if (info.ParentIndexNumber is null)
|
||||||
|
// {
|
||||||
|
// this.Log("FixSeasonNumber: season number is null, set to default 1");
|
||||||
|
// info.ParentIndexNumber = 1;
|
||||||
|
// }
|
||||||
|
|
||||||
// 特典优先使用文件名(特典除了前面特别设置,还有 SXX/Season XX 等默认的)
|
// 特典优先使用文件名(特典除了前面特别设置,还有 SXX/Season XX 等默认的)
|
||||||
if (info.ParentIndexNumber.HasValue && info.ParentIndexNumber == 0)
|
if (info.ParentIndexNumber.HasValue && info.ParentIndexNumber == 0)
|
||||||
{
|
{
|
||||||
|
@ -196,6 +205,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
info.IndexNumber = parseResult.IndexNumber;
|
info.IndexNumber = parseResult.IndexNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.Log("FixParseInfo: fileName: {0} seasonNumber: {1} episodeNumber: {2} name: {3}", fileName, info.ParentIndexNumber, info.IndexNumber, info.Name);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +241,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//// 特典也有 tmdb 剧集信息,不在这里处理
|
//// 特典也有剧集信息,不在这里处理
|
||||||
// if (parseResult.IsSpecial || NameParser.IsSpecialDirectory(info.Path))
|
// if (parseResult.IsSpecial || NameParser.IsSpecialDirectory(info.Path))
|
||||||
// {
|
// {
|
||||||
// this.Log($"Found anime sp of [name]: {fileName}");
|
// this.Log($"Found anime sp of [name]: {fileName}");
|
||||||
|
|
|
@ -7,7 +7,6 @@ using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AngleSharp.Text;
|
using AngleSharp.Text;
|
||||||
using Jellyfin.Data.Enums;
|
|
||||||
using Jellyfin.Plugin.MetaShark.Api;
|
using Jellyfin.Plugin.MetaShark.Api;
|
||||||
using Jellyfin.Plugin.MetaShark.Core;
|
using Jellyfin.Plugin.MetaShark.Core;
|
||||||
using Jellyfin.Plugin.MetaShark.Model;
|
using Jellyfin.Plugin.MetaShark.Model;
|
||||||
|
@ -183,7 +182,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
subject.LimitDirectorCelebrities.Take(Configuration.PluginConfiguration.MAX_CAST_MEMBERS).ToList().ForEach(c => result.AddPerson(new PersonInfo
|
subject.LimitDirectorCelebrities.Take(Configuration.PluginConfiguration.MAX_CAST_MEMBERS).ToList().ForEach(c => result.AddPerson(new PersonInfo
|
||||||
{
|
{
|
||||||
Name = c.Name,
|
Name = c.Name,
|
||||||
Type = c.RoleType == PersonType.Director ? PersonKind.Director : PersonKind.Actor,
|
Type = c.RoleType,
|
||||||
Role = c.Role,
|
Role = c.Role,
|
||||||
ImageUrl = this.GetLocalProxyImageUrl(c.Img),
|
ImageUrl = this.GetLocalProxyImageUrl(c.Img),
|
||||||
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
|
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
|
||||||
|
@ -302,7 +301,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
Name = actor.Name.Trim(),
|
Name = actor.Name.Trim(),
|
||||||
Role = actor.Character,
|
Role = actor.Character,
|
||||||
Type = PersonKind.Actor,
|
Type = PersonType.Actor,
|
||||||
SortOrder = actor.Order,
|
SortOrder = actor.Order,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -345,7 +344,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
Name = person.Name.Trim(),
|
Name = person.Name.Trim(),
|
||||||
Role = person.Job,
|
Role = person.Job,
|
||||||
Type = type == PersonType.Director ? PersonKind.Director : (type == PersonType.Producer ? PersonKind.Producer : PersonKind.Actor),
|
Type = type
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(person.ProfilePath))
|
if (!string.IsNullOrWhiteSpace(person.ProfilePath))
|
||||||
|
|
|
@ -14,8 +14,6 @@ using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Jellyfin.Data.Enums;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.MetaShark.Providers
|
namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
|
@ -42,27 +40,25 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
var result = new MetadataResult<Season>();
|
var result = new MetadataResult<Season>();
|
||||||
|
|
||||||
// 使用刷新元数据时,之前识别的 seasonNumber 会保留,不会被覆盖
|
// 使用刷新元数据时,之前识别的seasonNumber会保留,不会被覆盖
|
||||||
info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out var seriesTmdbId);
|
info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out var seriesTmdbId);
|
||||||
info.SeriesProviderIds.TryGetMetaSource(Plugin.ProviderId, out var metaSource);
|
info.SeriesProviderIds.TryGetMetaSource(Plugin.ProviderId, out var metaSource);
|
||||||
info.SeriesProviderIds.TryGetValue(DoubanProviderId, out var sid);
|
info.SeriesProviderIds.TryGetValue(DoubanProviderId, out var sid);
|
||||||
var seasonNumber = info.IndexNumber; // S00/Season 00特典目录会为0
|
var seasonNumber = info.IndexNumber; // S00/Season 00特典目录会为0
|
||||||
var seasonSid = info.GetProviderId(DoubanProviderId);
|
var seasonSid = info.GetProviderId(DoubanProviderId);
|
||||||
var fileName = Path.GetFileName(info.Path);
|
var fileName = this.GetOriginalFileName(info);
|
||||||
this.Log($"GetSeasonMetaData of [name]: {info.Name} [fileName]: {fileName} number: {info.IndexNumber} seriesTmdbId: {seriesTmdbId} sid: {sid} metaSource: {metaSource} EnableTmdb: {config.EnableTmdb}");
|
this.Log($"GetSeasonMetaData of [name]: {info.Name} [fileName]: {fileName} number: {info.IndexNumber} seriesTmdbId: {seriesTmdbId} sid: {sid} metaSource: {metaSource} EnableTmdb: {config.EnableTmdb}");
|
||||||
|
|
||||||
if (metaSource != MetaSource.Tmdb && !string.IsNullOrEmpty(sid))
|
if (metaSource != MetaSource.Tmdb && !string.IsNullOrEmpty(sid))
|
||||||
{
|
{
|
||||||
// seasonNumber 为 null 有三种情况:
|
// 季文件夹名称不规范,没法拿到seasonNumber,尝试从文件夹名猜出
|
||||||
// 1. 没有季文件夹时,即虚拟季,info.Path 为空
|
// 注意:本办法没法处理没有季文件夹的/虚拟季,因为path会为空
|
||||||
// 2. 一般不规范文件夹命名,没法被 EpisodeResolver 解析的,info.Path 不为空,如:摇曳露营△
|
|
||||||
// 3. 特殊不规范文件夹命名,能被 EpisodeResolver 错误解析,这时被当成了视频文件,相当于没有季文件夹,info.Path 为空,如:冰与火之歌 S02.列王的纷争.2012.1080p.Blu-ray.x265.10bit.AC3
|
|
||||||
// 相关代码:https://github.com/jellyfin/jellyfin/blob/dc2eca9f2ca259b46c7b53f59251794903c730a4/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs#L70
|
|
||||||
if (seasonNumber is null)
|
if (seasonNumber is null)
|
||||||
{
|
{
|
||||||
seasonNumber = this.GuessSeasonNumberByDirectoryName(info.Path);
|
seasonNumber = this.GuessSeasonNumberByDirectoryName(info.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索豆瓣季 id
|
// 搜索豆瓣季id
|
||||||
if (string.IsNullOrEmpty(seasonSid))
|
if (string.IsNullOrEmpty(seasonSid))
|
||||||
{
|
{
|
||||||
seasonSid = await this.GuessDoubanSeasonId(sid, seriesTmdbId, seasonNumber, info, cancellationToken).ConfigureAwait(false);
|
seasonSid = await this.GuessDoubanSeasonId(sid, seriesTmdbId, seasonNumber, info, cancellationToken).ConfigureAwait(false);
|
||||||
|
@ -93,19 +89,19 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
subject.LimitDirectorCelebrities.Take(Configuration.PluginConfiguration.MAX_CAST_MEMBERS).ToList().ForEach(c => result.AddPerson(new PersonInfo
|
subject.LimitDirectorCelebrities.Take(Configuration.PluginConfiguration.MAX_CAST_MEMBERS).ToList().ForEach(c => result.AddPerson(new PersonInfo
|
||||||
{
|
{
|
||||||
Name = c.Name,
|
Name = c.Name,
|
||||||
Type = c.RoleType == PersonType.Director ? PersonKind.Director : PersonKind.Actor,
|
Type = c.RoleType,
|
||||||
Role = c.Role,
|
Role = c.Role,
|
||||||
ImageUrl = this.GetLocalProxyImageUrl(c.Img),
|
ImageUrl = this.GetLocalProxyImageUrl(c.Img),
|
||||||
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
|
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.Log($"Season [{info.Name}] found douban [sid]: {seasonSid}");
|
this.Log($"GetSeasonMetaData of douban [sid]: {seasonSid}");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.Log($"Season [{info.Name}] not found douban season id!");
|
this.Log($"GetSeasonMetaData of [name]: {info.Name} not found douban season id!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,19 +139,10 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没有季文件夹或季文件夹名不规范时(即虚拟季),info.Path 会为空,seasonNumber 为 null
|
// 没有季文件夹(即虚拟季),info.Path会为空,直接用series的sid
|
||||||
if (string.IsNullOrEmpty(info.Path) && !seasonNumber.HasValue)
|
if (string.IsNullOrEmpty(info.Path))
|
||||||
{
|
{
|
||||||
return null;
|
return sid;
|
||||||
}
|
|
||||||
|
|
||||||
// 从季文件夹名属性格式获取,如 [douban-12345] 或 [doubanid-12345]
|
|
||||||
var fileName = this.GetOriginalFileName(info);
|
|
||||||
var doubanId = this.regDoubanIdAttribute.FirstMatchGroup(fileName);
|
|
||||||
if (!string.IsNullOrWhiteSpace(doubanId))
|
|
||||||
{
|
|
||||||
this.Log($"Found season douban [id] by attr: {doubanId}");
|
|
||||||
return doubanId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从sereis获取正确名称,info.Name当是标准格式如S01等时,会变成第x季,非标准名称默认文件名
|
// 从sereis获取正确名称,info.Name当是标准格式如S01等时,会变成第x季,非标准名称默认文件名
|
||||||
|
@ -164,7 +151,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var seriesName = this.RemoveSeasonSuffix(series.Name);
|
var seriesName = RemoveSeasonSubfix(series.Name);
|
||||||
|
|
||||||
// 没有季id,但存在tmdbid,尝试从tmdb获取对应季的年份信息,用于从豆瓣搜索对应季数据
|
// 没有季id,但存在tmdbid,尝试从tmdb获取对应季的年份信息,用于从豆瓣搜索对应季数据
|
||||||
var seasonYear = 0;
|
var seasonYear = 0;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Plugin.MetaShark.Api;
|
||||||
using Jellyfin.Plugin.MetaShark.Api;
|
|
||||||
using Jellyfin.Plugin.MetaShark.Model;
|
using Jellyfin.Plugin.MetaShark.Model;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
@ -105,12 +104,12 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
}
|
}
|
||||||
subject.Celebrities = await this._doubanApi.GetCelebritiesBySidAsync(sid, cancellationToken).ConfigureAwait(false);
|
subject.Celebrities = await this._doubanApi.GetCelebritiesBySidAsync(sid, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var seriesName = RemoveSeasonSuffix(subject.Name);
|
var seriesName = RemoveSeasonSubfix(subject.Name);
|
||||||
var item = new Series
|
var item = new Series
|
||||||
{
|
{
|
||||||
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, subject.Sid }, { Plugin.ProviderId, $"{MetaSource.Douban}_{subject.Sid}" } },
|
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, subject.Sid }, { Plugin.ProviderId, $"{MetaSource.Douban}_{subject.Sid}" } },
|
||||||
Name = seriesName,
|
Name = seriesName,
|
||||||
OriginalTitle = RemoveSeasonSuffix(subject.OriginalName),
|
OriginalTitle = RemoveSeasonSubfix(subject.OriginalName),
|
||||||
CommunityRating = subject.Rating,
|
CommunityRating = subject.Rating,
|
||||||
Overview = subject.Intro,
|
Overview = subject.Intro,
|
||||||
ProductionYear = subject.Year,
|
ProductionYear = subject.Year,
|
||||||
|
@ -153,7 +152,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
subject.LimitDirectorCelebrities.Take(Configuration.PluginConfiguration.MAX_CAST_MEMBERS).ToList().ForEach(c => result.AddPerson(new PersonInfo
|
subject.LimitDirectorCelebrities.Take(Configuration.PluginConfiguration.MAX_CAST_MEMBERS).ToList().ForEach(c => result.AddPerson(new PersonInfo
|
||||||
{
|
{
|
||||||
Name = c.Name,
|
Name = c.Name,
|
||||||
Type = c.RoleType == PersonType.Director ? PersonKind.Director : PersonKind.Actor,
|
Type = c.RoleType,
|
||||||
Role = c.Role,
|
Role = c.Role,
|
||||||
ImageUrl = this.GetLocalProxyImageUrl(c.Img),
|
ImageUrl = this.GetLocalProxyImageUrl(c.Img),
|
||||||
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
|
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
|
||||||
|
@ -357,7 +356,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
Name = actor.Name.Trim(),
|
Name = actor.Name.Trim(),
|
||||||
Role = actor.Character,
|
Role = actor.Character,
|
||||||
Type = PersonKind.Actor,
|
Type = PersonType.Actor,
|
||||||
SortOrder = actor.Order,
|
SortOrder = actor.Order,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -401,7 +400,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
Name = person.Name.Trim(),
|
Name = person.Name.Trim(),
|
||||||
Role = person.Job,
|
Role = person.Job,
|
||||||
Type = type == PersonType.Director ? PersonKind.Director : (type == PersonType.Producer ? PersonKind.Producer : PersonKind.Actor),
|
Type = type
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(person.ProfilePath))
|
if (!string.IsNullOrWhiteSpace(person.ProfilePath))
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Plugin.MetaShark.Api;
|
using Jellyfin.Plugin.MetaShark.Api;
|
||||||
using MediaBrowser.Controller;
|
using Jellyfin.Plugin.MetaShark.Providers;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Common.Plugins;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.MetaShark
|
namespace Jellyfin.Plugin.MetaShark
|
||||||
{
|
{
|
||||||
|
@ -10,22 +20,21 @@ namespace Jellyfin.Plugin.MetaShark
|
||||||
public class ServiceRegistrator : IPluginServiceRegistrator
|
public class ServiceRegistrator : IPluginServiceRegistrator
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void RegisterServices(IServiceCollection serviceCollection, IServerApplicationHost applicationHost)
|
public void RegisterServices(IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
|
serviceCollection.AddSingleton<DoubanApi>((ctx) =>
|
||||||
serviceCollection.AddSingleton((ctx) =>
|
|
||||||
{
|
{
|
||||||
return new DoubanApi(ctx.GetRequiredService<ILoggerFactory>());
|
return new DoubanApi(ctx.GetRequiredService<ILoggerFactory>());
|
||||||
});
|
});
|
||||||
serviceCollection.AddSingleton((ctx) =>
|
serviceCollection.AddSingleton<TmdbApi>((ctx) =>
|
||||||
{
|
{
|
||||||
return new TmdbApi(ctx.GetRequiredService<ILoggerFactory>());
|
return new TmdbApi(ctx.GetRequiredService<ILoggerFactory>());
|
||||||
});
|
});
|
||||||
serviceCollection.AddSingleton((ctx) =>
|
serviceCollection.AddSingleton<OmdbApi>((ctx) =>
|
||||||
{
|
{
|
||||||
return new OmdbApi(ctx.GetRequiredService<ILoggerFactory>());
|
return new OmdbApi(ctx.GetRequiredService<ILoggerFactory>());
|
||||||
});
|
});
|
||||||
serviceCollection.AddSingleton((ctx) =>
|
serviceCollection.AddSingleton<ImdbApi>((ctx) =>
|
||||||
{
|
{
|
||||||
return new ImdbApi(ctx.GetRequiredService<ILoggerFactory>());
|
return new ImdbApi(ctx.GetRequiredService<ILoggerFactory>());
|
||||||
});
|
});
|
||||||
|
|
10
README.md
10
README.md
|
@ -1,7 +1,7 @@
|
||||||
# jellyfin-plugin-metashark
|
# jellyfin-plugin-metashark
|
||||||
|
|
||||||
[](https://github.com/cxfksword/jellyfin-plugin-metashark/releases)
|
[](https://github.com/cxfksword/jellyfin-plugin-metashark/releases)
|
||||||
[](https://github.com/cxfksword/jellyfin-plugin-metashark/releases)
|
[](https://github.com/cxfksword/jellyfin-plugin-metashark/releases)
|
||||||
[](https://github.com/cxfksword/jellyfin-plugin-metashark/main/LICENSE)
|
[](https://github.com/cxfksword/jellyfin-plugin-metashark/main/LICENSE)
|
||||||
|
|
||||||
jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TheMovieDb补全缺失的剧集数据。
|
jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TheMovieDb补全缺失的剧集数据。
|
||||||
|
@ -14,9 +14,11 @@ jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TheMov
|
||||||
|
|
||||||
## 安装插件
|
## 安装插件
|
||||||
|
|
||||||
|
只支持最新的`jellyfin 10.8.x`版本
|
||||||
|
|
||||||
添加插件存储库:
|
添加插件存储库:
|
||||||
|
|
||||||
国内加速:https://gitee.com/cwhzy/jellyfin-plugin-metashark/releases/download/manifest/manifest_cn.json
|
国内加速:https://mirror.ghproxy.com/https://github.com/cxfksword/jellyfin-plugin-metashark/releases/download/manifest/manifest_cn.json
|
||||||
|
|
||||||
国外访问:https://github.com/cxfksword/jellyfin-plugin-metashark/releases/download/manifest/manifest.json
|
国外访问:https://github.com/cxfksword/jellyfin-plugin-metashark/releases/download/manifest/manifest.json
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TheMov
|
||||||
|
|
||||||
1. Clone or download this repository
|
1. Clone or download this repository
|
||||||
|
|
||||||
2. Ensure you have .NET Core SDK 8.0 setup and installed
|
2. Ensure you have .NET Core SDK 6.0 setup and installed
|
||||||
|
|
||||||
3. Build plugin with following command.
|
3. Build plugin with following command.
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ dotnet publish --configuration=Release Jellyfin.Plugin.MetaShark/Jellyfin.Plugin
|
||||||
|
|
||||||
1. Build the plugin
|
1. Build the plugin
|
||||||
|
|
||||||
2. Create a folder, like `metashark` and copy `./Jellyfin.Plugin.MetaShark/bin/Release/net8.0/Jellyfin.Plugin.MetaShark.dll` into it
|
2. Create a folder, like `metashark` and copy `./Jellyfin.Plugin.MetaShark/bin/Release/net6.0/Jellyfin.Plugin.MetaShark.dll` into it
|
||||||
|
|
||||||
3. Move folder `metashark` to jellyfin `data/plugins` folder
|
3. Move folder `metashark` to jellyfin `data/plugins` folder
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ def generate_version(filepath, version, changelog):
|
||||||
return {
|
return {
|
||||||
'version': f"{version}.0",
|
'version': f"{version}.0",
|
||||||
'changelog': changelog,
|
'changelog': changelog,
|
||||||
'targetAbi': '10.9.0.0',
|
'targetAbi': '10.8.0.0',
|
||||||
'sourceUrl': f'https://github.com/cxfksword/jellyfin-plugin-metashark/releases/download/v{version}/metashark_{version}.0.zip',
|
'sourceUrl': f'https://github.com/cxfksword/jellyfin-plugin-metashark/releases/download/v{version}/metashark_{version}.0.zip',
|
||||||
'checksum': md5sum(filepath),
|
'checksum': md5sum(filepath),
|
||||||
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
|
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
Loading…
Reference in New Issue