using System.Net; using System.Xml; using FluentScheduler; using FreeSql; using FreeSql.DataAnnotations; using Interface.Jobs; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; namespace Service.Jobs; public class ChineseNfoRegistry : Registry, IChineseNfoRegistry { private readonly HttpClient _apiClient; private readonly HttpClient _imageClient; private readonly IConfiguration _configuration; private readonly ILogger _logger; private readonly IFreeSql _freeSql; public ChineseNfoRegistry(IConfiguration configuration, ILogger logger) { _configuration = configuration; _logger = logger; var httpClientHandler = new HttpClientHandler(); var proxyAddress = _configuration["ChineseNfo:HttpProxy"]; if (string.IsNullOrEmpty(proxyAddress) == false) { httpClientHandler.Proxy = string.IsNullOrEmpty(proxyAddress) ? null : new WebProxy(proxyAddress, false); httpClientHandler.UseProxy = !string.IsNullOrEmpty(proxyAddress); } _apiClient = new HttpClient(httpClientHandler); _apiClient.BaseAddress = new Uri("http://api.themoviedb.org"); _imageClient = new HttpClient(httpClientHandler); _imageClient.BaseAddress = new Uri("http://image.tmdb.org"); _freeSql = new FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.Sqlite, _configuration["ChineseNfo:ConnectionString"]) .UseAutoSyncStructure(true) .Build(); Schedule(() => Job(true, true)).ToRunEvery(1).Days(); } public async void Job(bool ignoreLocked, bool ignoreCompleted) { try { await JobExecute(ignoreLocked, ignoreCompleted); } catch (Exception e) { _logger.LogError(e, "ChineseNfoRegistry.Job() error"); } } private async Task JobExecute( bool ignoreLocked, bool ignoreCompleted, string[]? includeFields = null) { var tvFolder = _configuration["ChineseNfo:TvFolder"]; if (string.IsNullOrEmpty(tvFolder)) { _logger.LogError("ChineseNfoRegistry.Job() tvFolder is null or empty"); return; } /* * 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) { _logger.LogError("ChineseNfoRegistry.Job() tvNfo is null or empty"); return; } foreach (var tv in tvNfos) { await HandleTv(tv); } async Task HandleTv(string tvNfo) { var nfoContent = File.ReadAllText(tvNfo); var tvXml = new XmlDocument(); tvXml.LoadXml(nfoContent); var uniqueIdNode = tvXml.SelectSingleNode("//uniqueid[@type='tmdb']"); if (uniqueIdNode == null) { _logger.LogError("ChineseNfoRegistry.Job() uniqueIdNode is null"); return null; } if (!int.TryParse(uniqueIdNode.InnerText, out var tmdbId)) { _logger.LogError("ChineseNfoRegistry.Job() tmdbId is null"); return null; } var a = await GetTmdbTv(tvNfo, tmdbId); _logger.LogInformation("ChineseNfoRegistry.Job() tmdbId: {tmdbId}, name: {name}", tmdbId,a?["name"]?.ToString()); return []; } } private async Task GetTmdbTv( string path, int tmdbId, TheMovieDbLanguage language = TheMovieDbLanguage.ZhCn) { var record = await _freeSql.Select() .Where(x => x.UniqueId == tmdbId.ToString()) .FirstAsync(); if (record != null) { return JObject.Parse(record.Json); } record = new TheMovieDbRecord { Type = TheMovieDbType.Tv, UniqueId = tmdbId.ToString(), Language = language }; string tvUrl = "/3/tv/{0}?api_key=e28e1bc408db7adefc8bacce225c5085&language="; if(language == TheMovieDbLanguage.ZhCn) { tvUrl += "zh-CN"; } else { tvUrl += "zh-TW"; } var requestUrl = string.Format(tvUrl, 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); 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; _freeSql.Insert(record); _logger.LogInformation("ChineseNfoRegistry.GetTmdbTv() 接口调用, 休眠 5S"); await Task.Delay(5000); return json; } catch (Exception e) { Console.WriteLine($"{requestUrl} & {path} \r {e}"); return null; } } } public class TheMovieDbRecord { public long Id { get; set; } public TheMovieDbType Type { get; set; } public string UniqueId { get; set; } = string.Empty; public TheMovieDbLanguage Language { get; set; } [Column(DbType = "text")] public string Json { get; set; } = string.Empty; } public enum TheMovieDbType { Tv = 1, Season = 2, Episode = 3, } public enum TheMovieDbLanguage { ZhCn = 1, ZhTw = 2 }