Enhance ChineseNfoRegistry job method to support optional parameters for TMDB ID, season, and episode; update configuration for HTTP proxy and connection string
This commit is contained in:
35
.vscode/launch.json
vendored
Normal file
35
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// 使用 IntelliSense 找出 C# 调试存在哪些属性
|
||||
// 将悬停用于现有属性的说明
|
||||
// 有关详细信息,请访问 https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md。
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// 如果已更改目标框架,请确保更新程序路径。
|
||||
"program": "${workspaceFolder}/src/WebApi/bin/Debug/net8.0/WebApi.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/src/WebApi",
|
||||
"stopAtEntry": false,
|
||||
// 启用在启动 ASP.NET Core 时启动 Web 浏览器。有关详细信息: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/NasRobot.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/NasRobot.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/NasRobot.sln"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,5 +2,11 @@ namespace Interface.Jobs;
|
||||
|
||||
public interface IChineseNfoRegistry
|
||||
{
|
||||
void Job(bool ignoreLocked, bool ignoreCompleted);
|
||||
void Job(
|
||||
string? tmdbId = null,
|
||||
string? seasonNumber = null,
|
||||
string? episodeNumber = null,
|
||||
bool ignoreLocked = false,
|
||||
bool ignoreCompleted = false
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using FluentScheduler;
|
||||
using FreeSql;
|
||||
@@ -44,10 +45,16 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
.UseAutoSyncStructure(true)
|
||||
.Build();
|
||||
|
||||
Schedule(() => Job(true, true)).ToRunEvery(1).Days();
|
||||
Schedule(() => Job(ignoreLocked: true, ignoreCompleted: true)).ToRunEvery(1).Days();
|
||||
}
|
||||
|
||||
public async void Job(bool ignoreLocked, bool ignoreCompleted)
|
||||
public async void Job(
|
||||
string? tmdbId = null,
|
||||
string? seasonNumber = null,
|
||||
string? episodeNumber = null,
|
||||
bool ignoreLocked = false,
|
||||
bool ignoreCompleted = false
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -61,8 +68,7 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
|
||||
private async Task JobExecute(
|
||||
bool ignoreLocked,
|
||||
bool ignoreCompleted,
|
||||
string[]? includeFields = null)
|
||||
bool ignoreCompleted)
|
||||
{
|
||||
var tvFolder = _configuration["ChineseNfo:TvFolder"];
|
||||
|
||||
@@ -73,29 +79,11 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. 支持指定字段
|
||||
* 2. 接口数据保留
|
||||
* 3. 支持语言降级到繁体
|
||||
* 4. 支持演员名称翻译
|
||||
*/
|
||||
|
||||
var fields =
|
||||
includeFields ??
|
||||
[
|
||||
"tv.title",
|
||||
"tv.plot",
|
||||
"tv.outline",
|
||||
"tv.poster",
|
||||
"tv.genre",
|
||||
"tv.actor.name",
|
||||
"tv.actor.role",
|
||||
"season.title",
|
||||
"season.plot",
|
||||
"episode.title",
|
||||
"episode.plot",
|
||||
"episode.actor.name",
|
||||
];
|
||||
|
||||
var tvNfos = Directory.GetFiles(tvFolder, "tvshow.nfo", SearchOption.AllDirectories);
|
||||
|
||||
if (tvNfos.Length == 0)
|
||||
@@ -107,42 +95,472 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
foreach (var tv in tvNfos)
|
||||
{
|
||||
await HandleTv(tv);
|
||||
|
||||
var seasonNfos = Directory.GetFiles(Path.GetDirectoryName(tv) ?? string.Empty, "season.nfo", SearchOption.AllDirectories);
|
||||
|
||||
foreach (var season in seasonNfos)
|
||||
{
|
||||
await HandleSeason(tv, season);
|
||||
|
||||
var episodeNfos = Directory
|
||||
.GetFiles(Path.GetDirectoryName(season) ?? string.Empty, "*.nfo", SearchOption.AllDirectories)
|
||||
.Where(x => !x.EndsWith("season.nfo"))
|
||||
.ToList();
|
||||
|
||||
foreach (var episode in episodeNfos)
|
||||
{
|
||||
await HandleEpisode(tv, season, episode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async Task<string[]?> HandleTv(string tvNfo)
|
||||
async Task HandleTv(string tvNfo)
|
||||
{
|
||||
var nfoContent = File.ReadAllText(tvNfo);
|
||||
|
||||
var tvXml = new XmlDocument();
|
||||
tvXml.LoadXml(nfoContent);
|
||||
|
||||
var isLockedNode = tvXml.SelectSingleNode("//locked");
|
||||
|
||||
if (isLockedNode != null && isLockedNode.InnerText == "true" && ignoreLocked)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvNfo is locked");
|
||||
return;
|
||||
}
|
||||
|
||||
var isCompletedNode = tvXml.SelectSingleNode("//completed");
|
||||
|
||||
if (isCompletedNode != null && isCompletedNode.InnerText == "true" && ignoreCompleted)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvNfo is completed");
|
||||
return;
|
||||
}
|
||||
|
||||
var uniqueIdNode = tvXml.SelectSingleNode("//uniqueid[@type='tmdb']");
|
||||
|
||||
if (uniqueIdNode == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() uniqueIdNode is null");
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(uniqueIdNode.InnerText, out var tmdbId))
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tmdbId is null");
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
var a = await GetTmdbTv(tvNfo, tmdbId);
|
||||
var tvInfo = await GetTmdbTv(tvNfo, tmdbId);
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.Job() tmdbId: {tmdbId}, name: {name}", tmdbId,a?["name"]?.ToString());
|
||||
return [];
|
||||
if (tvInfo == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvInfo is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tvInfo["name"] != null)
|
||||
{
|
||||
var titleNode = tvXml.SelectSingleNode("//title");
|
||||
if (titleNode != null)
|
||||
{
|
||||
titleNode.InnerXml = $"<![CDATA[{tvInfo["name"]}]]>";
|
||||
}
|
||||
|
||||
var sorttitleNode = tvXml.SelectSingleNode("//sorttitle");
|
||||
if (sorttitleNode != null)
|
||||
{
|
||||
sorttitleNode.InnerXml = $"<![CDATA[{tvInfo["name"]}]]>";
|
||||
}
|
||||
}
|
||||
|
||||
if (tvInfo["overview"] != null)
|
||||
{
|
||||
var plotNode = tvXml.SelectSingleNode("//plot");
|
||||
if (plotNode != null)
|
||||
{
|
||||
plotNode.InnerXml = $"<![CDATA[{tvInfo["overview"]}]]>";
|
||||
}
|
||||
|
||||
var outlineNode = tvXml.SelectSingleNode("//outline");
|
||||
if (outlineNode != null)
|
||||
{
|
||||
outlineNode.InnerXml = $"<![CDATA[{tvInfo["overview"]}]]>";
|
||||
}
|
||||
}
|
||||
|
||||
if (tvInfo["poster_path"] != null)
|
||||
{
|
||||
var posterPath = tvInfo["poster_path"]!.ToString();
|
||||
var image = await GetTmdbImage(tvNfo, posterPath);
|
||||
if (image != null)
|
||||
{
|
||||
var imagePath = Path.Combine(Path.GetDirectoryName(tvNfo) ?? string.Empty, "poster" + Path.GetExtension(posterPath));
|
||||
await File.WriteAllBytesAsync(imagePath, image);
|
||||
}
|
||||
}
|
||||
|
||||
var actors = tvXml.SelectNodes("//actor");
|
||||
if (actors != null)
|
||||
{
|
||||
foreach (XmlNode actor in actors)
|
||||
{
|
||||
await HandleActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.Job() tmdbId: {tmdbId}, name: {name}", tmdbId, tvInfo["name"]?.ToString());
|
||||
|
||||
if (isLockedNode != null)
|
||||
{
|
||||
isLockedNode.InnerText = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvXml.CreateElement("locked");
|
||||
isLockedNode = tvXml.SelectSingleNode("//locked");
|
||||
isLockedNode!.InnerText = "true";
|
||||
}
|
||||
|
||||
if (isCompletedNode != null)
|
||||
{
|
||||
isCompletedNode.InnerText = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvXml.CreateElement("completed");
|
||||
isCompletedNode = tvXml.SelectSingleNode("//completed");
|
||||
isCompletedNode!.InnerText = "true";
|
||||
}
|
||||
|
||||
// 保存
|
||||
tvXml.Save(tvNfo);
|
||||
}
|
||||
|
||||
async Task HandleSeason(string tvNfo, string seasonNfo)
|
||||
{
|
||||
var tvNfoContent = File.ReadAllText(tvNfo);
|
||||
|
||||
var tvXml = new XmlDocument();
|
||||
tvXml.LoadXml(tvNfoContent);
|
||||
|
||||
var uniqueIdNode = tvXml.SelectSingleNode("//uniqueid[@type='tmdb']");
|
||||
|
||||
if (uniqueIdNode == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() uniqueIdNode is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(uniqueIdNode.InnerText, out var tmdbId))
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tmdbId is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var nfoContent = File.ReadAllText(seasonNfo);
|
||||
|
||||
var seasonXml = new XmlDocument();
|
||||
seasonXml.LoadXml(nfoContent);
|
||||
|
||||
var isLockedNode = seasonXml.SelectSingleNode("//locked");
|
||||
|
||||
if (isLockedNode != null && isLockedNode.InnerText == "true" && ignoreLocked)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvNfo is locked");
|
||||
return;
|
||||
}
|
||||
|
||||
var isCompletedNode = seasonXml.SelectSingleNode("//completed");
|
||||
|
||||
if (isCompletedNode != null && isCompletedNode.InnerText == "true" && ignoreCompleted)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvNfo is completed");
|
||||
return;
|
||||
}
|
||||
|
||||
var seasonNumberNode = seasonXml.SelectSingleNode("//seasonnumber");
|
||||
|
||||
if (seasonNumberNode == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() seasonNumberNode is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(seasonNumberNode.InnerText, out var seasonNumber))
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() seasonNumber is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var seasonInfo = await GetTmdbSeason(seasonNfo, tmdbId, seasonNumber);
|
||||
|
||||
if (seasonInfo == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() seasonInfo is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var titleNode = seasonXml.SelectSingleNode("//sorttitle");
|
||||
if (titleNode != null && seasonInfo["name"] != null)
|
||||
{
|
||||
titleNode.InnerXml = $"<![CDATA[{seasonInfo["name"]}]]>";
|
||||
}
|
||||
|
||||
var plotNode = seasonXml.SelectSingleNode("//plot");
|
||||
if (plotNode != null && seasonInfo["overview"] != null)
|
||||
{
|
||||
plotNode.InnerXml = $"<![CDATA[{seasonInfo["overview"]}]]>";
|
||||
}
|
||||
|
||||
var outlineNode = seasonXml.SelectSingleNode("//outline");
|
||||
if (outlineNode != null && seasonInfo["overview"] != null)
|
||||
{
|
||||
outlineNode.InnerXml = $"<![CDATA[{seasonInfo["overview"]}]]>";
|
||||
}
|
||||
|
||||
var poster_path = seasonInfo["poster_path"]?.ToString();
|
||||
if (poster_path != null)
|
||||
{
|
||||
var image = await GetTmdbImage(seasonNfo, poster_path);
|
||||
if (image != null)
|
||||
{
|
||||
// season01-poster.jpg
|
||||
var imagePath = Path.Combine(Path.GetDirectoryName(tvNfo) ?? string.Empty, "season" + seasonNumber.ToString("D2") + "-poster" + Path.GetExtension(poster_path));
|
||||
await File.WriteAllBytesAsync(imagePath, image);
|
||||
}
|
||||
}
|
||||
|
||||
if (isLockedNode != null)
|
||||
{
|
||||
isLockedNode.InnerText = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvXml.CreateElement("locked");
|
||||
isLockedNode = tvXml.SelectSingleNode("//locked");
|
||||
isLockedNode!.InnerText = "true";
|
||||
}
|
||||
|
||||
if (isCompletedNode != null)
|
||||
{
|
||||
isCompletedNode.InnerText = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvXml.CreateElement("completed");
|
||||
isCompletedNode = tvXml.SelectSingleNode("//completed");
|
||||
isCompletedNode!.InnerText = "true";
|
||||
}
|
||||
|
||||
seasonXml.Save(seasonNfo);
|
||||
}
|
||||
|
||||
async Task HandleEpisode(string tvNfo, string seasonNfo, string episodeNfo)
|
||||
{
|
||||
var tvNfoContent = File.ReadAllText(tvNfo);
|
||||
|
||||
var tvXml = new XmlDocument();
|
||||
tvXml.LoadXml(tvNfoContent);
|
||||
|
||||
var uniqueIdNode = tvXml.SelectSingleNode("//uniqueid[@type='tmdb']");
|
||||
|
||||
if (uniqueIdNode == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() uniqueIdNode is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(uniqueIdNode.InnerText, out var tmdbId))
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tmdbId is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var seasonNfoContent = File.ReadAllText(seasonNfo);
|
||||
|
||||
var seasonXml = new XmlDocument();
|
||||
seasonXml.LoadXml(seasonNfoContent);
|
||||
|
||||
var seasonNumberNode = seasonXml.SelectSingleNode("//seasonnumber");
|
||||
|
||||
if (seasonNumberNode == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() seasonNumberNode is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(seasonNumberNode.InnerText, out var seasonNumber))
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() seasonNumber is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var nfoContent = File.ReadAllText(episodeNfo);
|
||||
|
||||
var episodeXml = new XmlDocument();
|
||||
episodeXml.LoadXml(nfoContent);
|
||||
|
||||
var isLockedNode = episodeXml.SelectSingleNode("//locked");
|
||||
|
||||
if (isLockedNode != null && isLockedNode.InnerText == "true" && ignoreLocked)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvNfo is locked");
|
||||
return;
|
||||
}
|
||||
|
||||
var isCompletedNode = episodeXml.SelectSingleNode("//completed");
|
||||
|
||||
if (isCompletedNode != null && isCompletedNode.InnerText == "true" && ignoreCompleted)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() tvNfo is completed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var episodeNumberNode = episodeXml.SelectSingleNode("//episode");
|
||||
|
||||
if (episodeNumberNode == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() episodeNumberNode is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(episodeNumberNode.InnerText, out var episodeNumber))
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() episodeNumber is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var episodeInfo = await GetTmdbEpisode(episodeNfo, tmdbId, seasonNumber, episodeNumber);
|
||||
|
||||
if (episodeInfo == null)
|
||||
{
|
||||
_logger.LogError("ChineseNfoRegistry.Job() episodeInfo is null");
|
||||
return;
|
||||
}
|
||||
|
||||
var titleNode = episodeXml.SelectSingleNode("//title");
|
||||
if (titleNode != null && episodeInfo["name"] != null)
|
||||
{
|
||||
// 特殊符号保留
|
||||
titleNode.InnerXml = $"<![CDATA[{episodeInfo["name"]}]]>";
|
||||
}
|
||||
|
||||
var plotNode = episodeXml.SelectSingleNode("//plot");
|
||||
if (plotNode != null && episodeInfo["overview"] != null)
|
||||
{
|
||||
plotNode.InnerXml = $"<![CDATA[{episodeInfo["overview"]}]]>";
|
||||
}
|
||||
|
||||
var outlineNode = episodeXml.SelectSingleNode("//outline");
|
||||
if (outlineNode != null && episodeInfo["overview"] != null)
|
||||
{
|
||||
outlineNode.InnerXml = $"<![CDATA[{episodeInfo["overview"]}]]>";
|
||||
}
|
||||
|
||||
var actors = episodeXml.SelectNodes("//actor");
|
||||
if (actors != null)
|
||||
{
|
||||
foreach (XmlNode actor in actors)
|
||||
{
|
||||
await HandleActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.Job() tmdbId: {tmdbId}, name: {name}", tmdbId, episodeInfo["name"]?.ToString());
|
||||
|
||||
if (isLockedNode != null)
|
||||
{
|
||||
isLockedNode.InnerText = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvXml.CreateElement("locked");
|
||||
isLockedNode = tvXml.SelectSingleNode("//locked");
|
||||
isLockedNode!.InnerText = "true";
|
||||
}
|
||||
|
||||
if (isCompletedNode != null)
|
||||
{
|
||||
isCompletedNode.InnerText = "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvXml.CreateElement("completed");
|
||||
isCompletedNode = tvXml.SelectSingleNode("//completed");
|
||||
isCompletedNode!.InnerText = "true";
|
||||
}
|
||||
|
||||
// 保存
|
||||
episodeXml.Save(episodeNfo);
|
||||
}
|
||||
|
||||
async Task<string?> GetTmdbPersonName(
|
||||
string path,
|
||||
int? tmdbId = null,
|
||||
string? name = null
|
||||
)
|
||||
{
|
||||
if (tmdbId != null)
|
||||
{
|
||||
var person = await GetTmdbPerson(path, tmdbId.Value);
|
||||
return person?["name"]?.ToString() ?? name;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
{
|
||||
// 如果名称是中文直接返回
|
||||
if (Regex.IsMatch(name, "^[\u4e00-\u9fa5]+$"))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
var person = await GetTmdbPersonSearch(path, name);
|
||||
return person?["name"]?.ToString() ?? name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async Task HandleActor(XmlNode actor)
|
||||
{
|
||||
var nameNode = actor.SelectSingleNode("name");
|
||||
var tmdbIdNode = actor.SelectSingleNode("tmdbid");
|
||||
if (nameNode != null || tmdbIdNode != null)
|
||||
{
|
||||
var name = await GetTmdbPersonName(
|
||||
tvFolder,
|
||||
int.TryParse(tmdbIdNode?.InnerText, out var actorTmdbId) ? actorTmdbId : null,
|
||||
nameNode?.InnerText
|
||||
);
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameNode != null)
|
||||
{
|
||||
nameNode.InnerXml = $"<![CDATA[{name}]]>";
|
||||
}
|
||||
else
|
||||
{
|
||||
actor.AppendChild(new XmlDocument().CreateElement("name"));
|
||||
nameNode = actor.SelectSingleNode("name");
|
||||
nameNode!.InnerXml = $"<![CDATA[{name}]]>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<JObject?> GetTmdbTv(
|
||||
string path,
|
||||
int tmdbId,
|
||||
TheMovieDbLanguage language = TheMovieDbLanguage.ZhCn)
|
||||
int tmdbId)
|
||||
{
|
||||
var record = await _freeSql.Select<TheMovieDbRecord>()
|
||||
.Where(x => x.Type == TheMovieDbType.Tv)
|
||||
.Where(x => x.UniqueId == tmdbId.ToString())
|
||||
.FirstAsync();
|
||||
|
||||
@@ -154,21 +572,10 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
record = new TheMovieDbRecord
|
||||
{
|
||||
Type = TheMovieDbType.Tv,
|
||||
UniqueId = tmdbId.ToString(),
|
||||
Language = language
|
||||
UniqueId = tmdbId.ToString()
|
||||
};
|
||||
|
||||
string tvUrl = "/3/tv/{0}?api_key=e28e1bc408db7adefc8bacce225c5085&language=";
|
||||
|
||||
if(language == TheMovieDbLanguage.ZhCn)
|
||||
{
|
||||
tvUrl += "zh-CN";
|
||||
}
|
||||
else
|
||||
{
|
||||
tvUrl += "zh-TW";
|
||||
}
|
||||
|
||||
string tvUrl = "/3/tv/{0}?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN";
|
||||
var requestUrl = string.Format(tvUrl, tmdbId);
|
||||
|
||||
try
|
||||
@@ -184,16 +591,6 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
var str = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var json = JObject.Parse(str);
|
||||
var name = json["name"];
|
||||
// 判断是否包含中文字符
|
||||
var isChinese = name != null && name.ToString().Any(c => c >= 0x4E00 && c <= 0x9FA5);
|
||||
if (language == TheMovieDbLanguage.ZhCn && !isChinese)
|
||||
{
|
||||
_logger.LogWarning("ChineseNfoRegistry.GetTmdbTv() name: {name}, 无中文文字, 降级到繁体字", name);
|
||||
// 降级到繁体
|
||||
return await GetTmdbTv(path, tmdbId, TheMovieDbLanguage.ZhTw);
|
||||
}
|
||||
|
||||
record.Json = str;
|
||||
await _freeSql.Insert(record).ExecuteIdentityAsync();
|
||||
|
||||
@@ -208,6 +605,249 @@ public class ChineseNfoRegistry : Registry, IChineseNfoRegistry
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<JObject?> GetTmdbPerson(
|
||||
string path,
|
||||
int tmdbId)
|
||||
{
|
||||
var record = await _freeSql.Select<TheMovieDbRecord>()
|
||||
.Where(x => x.Type == TheMovieDbType.Person)
|
||||
.Where(x => x.UniqueId == tmdbId.ToString())
|
||||
.FirstAsync();
|
||||
|
||||
if (record != null)
|
||||
{
|
||||
return JObject.Parse(record.Json);
|
||||
}
|
||||
|
||||
record = new TheMovieDbRecord
|
||||
{
|
||||
Type = TheMovieDbType.Person,
|
||||
UniqueId = tmdbId.ToString(),
|
||||
Language = TheMovieDbLanguage.ZhCn
|
||||
};
|
||||
|
||||
var requestUrl = string.Format("/3/person/{0}?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN", tmdbId);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _apiClient.GetAsync(requestUrl);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var str = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var json = JObject.Parse(str);
|
||||
|
||||
record.Json = str;
|
||||
await _freeSql.Insert(record).ExecuteIdentityAsync();
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.GetTmdbPerson() 接口调用, 休眠 5S");
|
||||
await Task.Delay(5000);
|
||||
|
||||
return json;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} \r {e}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<JObject?> GetTmdbPersonSearch(
|
||||
string path,
|
||||
string name)
|
||||
{
|
||||
var record = await _freeSql.Select<TheMovieDbRecord>()
|
||||
.Where(x => x.Type == TheMovieDbType.Person)
|
||||
.Where(x => x.UniqueId == name)
|
||||
.FirstAsync();
|
||||
|
||||
if (record != null)
|
||||
{
|
||||
return JObject.Parse(record.Json);
|
||||
}
|
||||
|
||||
record = new TheMovieDbRecord
|
||||
{
|
||||
Type = TheMovieDbType.Person,
|
||||
UniqueId = name
|
||||
};
|
||||
|
||||
var requestUrl = string.Format("/3/search/person?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN&query={0}", name);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _apiClient.GetAsync(requestUrl);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var str = await response.Content.ReadAsStringAsync();
|
||||
|
||||
var json = JObject.Parse(str);
|
||||
|
||||
var results = json["results"];
|
||||
|
||||
if (results != null)
|
||||
{
|
||||
foreach (var result in results.Cast<JObject>())
|
||||
{
|
||||
record.Json = result.ToString();
|
||||
await _freeSql.Insert(record).ExecuteIdentityAsync();
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.GetTmdbPersonSearch() 接口调用, 休眠 5S");
|
||||
await Task.Delay(5000);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} \r {e}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<byte[]?> GetTmdbImage(
|
||||
string path,
|
||||
string posterPath)
|
||||
{
|
||||
var requestUrl = string.Format("/t/p/w1280/{0}", posterPath);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _imageClient.GetAsync(requestUrl);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return await response.Content.ReadAsByteArrayAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} \r {e}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<JObject?> GetTmdbSeason(
|
||||
string path,
|
||||
int tmdbId,
|
||||
int seasonNumber)
|
||||
{
|
||||
var uniqueId = $"{tmdbId}-{seasonNumber}";
|
||||
|
||||
var record = await _freeSql.Select<TheMovieDbRecord>()
|
||||
.Where(x => x.Type == TheMovieDbType.Season)
|
||||
.Where(x => x.UniqueId == uniqueId)
|
||||
.FirstAsync();
|
||||
|
||||
if (record != null)
|
||||
{
|
||||
return JObject.Parse(record.Json);
|
||||
}
|
||||
|
||||
record = new TheMovieDbRecord
|
||||
{
|
||||
Type = TheMovieDbType.Season,
|
||||
UniqueId = uniqueId
|
||||
};
|
||||
|
||||
var requestUrl = string.Format("/3/tv/{0}/season/{1}?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN", tmdbId, seasonNumber);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _apiClient.GetAsync(requestUrl);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var str = await response.Content.ReadAsStringAsync();
|
||||
|
||||
record.Json = str;
|
||||
await _freeSql.Insert(record).ExecuteIdentityAsync();
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.GetTmdbSeason() 接口调用, 休眠 5S");
|
||||
await Task.Delay(5000);
|
||||
|
||||
return JObject.Parse(str);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} \r {e}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<JObject?> GetTmdbEpisode(
|
||||
string path,
|
||||
int tmdbId,
|
||||
int seasonNumber,
|
||||
int episodeNumber)
|
||||
{
|
||||
var uniqueId = $"{tmdbId}-{seasonNumber}-{episodeNumber}";
|
||||
|
||||
var record = await _freeSql.Select<TheMovieDbRecord>()
|
||||
.Where(x => x.Type == TheMovieDbType.Episode)
|
||||
.Where(x => x.UniqueId == uniqueId)
|
||||
.FirstAsync();
|
||||
|
||||
if (record != null)
|
||||
{
|
||||
return JObject.Parse(record.Json);
|
||||
}
|
||||
|
||||
record = new TheMovieDbRecord
|
||||
{
|
||||
Type = TheMovieDbType.Episode,
|
||||
UniqueId = uniqueId
|
||||
};
|
||||
|
||||
var requestUrl = string.Format("/3/tv/{0}/season/{1}/episode/{2}?api_key=e28e1bc408db7adefc8bacce225c5085&language=zh-CN", tmdbId, seasonNumber, episodeNumber);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _apiClient.GetAsync(requestUrl);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} & {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var str = await response.Content.ReadAsStringAsync();
|
||||
|
||||
record.Json = str;
|
||||
await _freeSql.Insert(record).ExecuteIdentityAsync();
|
||||
|
||||
_logger.LogInformation("ChineseNfoRegistry.GetTmdbEpisode() 接口调用, 休眠 5S");
|
||||
await Task.Delay(5000);
|
||||
|
||||
return JObject.Parse(str);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"{requestUrl} & {path} \r {e}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TheMovieDbRecord
|
||||
@@ -221,8 +861,7 @@ public class TheMovieDbRecord
|
||||
|
||||
public TheMovieDbLanguage Language { get; set; }
|
||||
|
||||
[Column(DbType = "text")]
|
||||
public string Json { get; set; } = string.Empty;
|
||||
[Column(DbType = "text")] public string Json { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public enum TheMovieDbType
|
||||
@@ -230,6 +869,7 @@ public enum TheMovieDbType
|
||||
Tv = 1,
|
||||
Season = 2,
|
||||
Episode = 3,
|
||||
Person = 4
|
||||
}
|
||||
|
||||
public enum TheMovieDbLanguage
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Interface.Jobs;
|
||||
using System.Text.Json.Nodes;
|
||||
using Interface.Jobs;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace WebApi.Controllers;
|
||||
@@ -95,9 +96,30 @@ public class JobTriggerController : BaseController
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public string ConvertChineseNfo(bool ignoreLocked = false, bool ignoreCompleted = false)
|
||||
public string ConvertChineseNfo(
|
||||
bool ignoreLocked = false,
|
||||
bool ignoreCompleted = false)
|
||||
{
|
||||
_chineseNfoRegistry.Job(ignoreLocked, ignoreCompleted);
|
||||
_chineseNfoRegistry.Job(ignoreLocked: ignoreLocked, ignoreCompleted: ignoreCompleted);
|
||||
|
||||
return "OK";
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<string> SonarrChangedConvertChineseNfo()
|
||||
{
|
||||
var body = Request.Body;
|
||||
|
||||
using var reader = new StreamReader(body);
|
||||
var text = await reader.ReadToEndAsync();
|
||||
|
||||
var json = JsonNode.Parse(text);
|
||||
|
||||
var tmdbId = json?["series"]?["tmdbId"]?.ToString();
|
||||
var seasonNumber = json?["episodes"]?[0]?["seasonNumber"]?.ToString();
|
||||
var episodeNumber = json?["episodes"]?[0]?["episodeNumber"]?.ToString();
|
||||
|
||||
_chineseNfoRegistry.Job(tmdbId: tmdbId, seasonNumber: seasonNumber, episodeNumber: episodeNumber);
|
||||
|
||||
return "OK";
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
],
|
||||
"ChineseNfo": {
|
||||
"TvFolder": "D:\\codes\\others\\ConvertChineseNfo",
|
||||
"HttpProxy": "http://suncheng.online:47890"
|
||||
"HttpProxy": "",
|
||||
"ConnectionString": "Data Source=D:\\codes\\others\\ConvertChineseNfo\\chinesenfo.db;"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user