diff --git a/Emby.MeiamSub.DevTool/Program.cs b/Emby.MeiamSub.DevTool/Program.cs index ce4b235..ffc9a4f 100644 --- a/Emby.MeiamSub.DevTool/Program.cs +++ b/Emby.MeiamSub.DevTool/Program.cs @@ -1,96 +1,211 @@ -using System; +using System; +using System.Collections.Generic; +using System.Diagnostics; using System.IO; -using System.Runtime.Intrinsics.Arm; +using System.Net.Http; using System.Security.Cryptography; using System.Text; +using System.Threading.Tasks; +using System.Web; namespace Emby.Subtitle.DevTool { class Program { - static void Main(string[] args) + private static readonly HttpClient _httpClient = new HttpClient(); + + static async Task Main(string[] args) { - //Console.WriteLine(ComputeFileHash($"X:\\Favorites\\Movie\\八佰 (2020)\\八佰 (2020) 1080p TrueHD.mkv")); - Console.WriteLine(ComputeFileHash($"D:\\Documents\\Downloads\\testidx.avi")); + // 设置控制台编码为 UTF8 防止中文乱码 + Console.OutputEncoding = Encoding.UTF8; + + Console.WriteLine("================ MeiamSubtitles 调试工具 ================"); + + // 待测试的影音文件路径 + var testFilePath = @"D:\Source\MeiamSubtitles\TestServer\Movie\2009\三傻大闹宝莱坞\三傻大闹宝莱坞 (2009) - 1080p.mkv"; + + if (!File.Exists(testFilePath)) + { + Console.WriteLine($"[错误] 文件不存在: {testFilePath}"); + return; + } + + Console.WriteLine($"[文件] {testFilePath}"); + Console.WriteLine("-------------------------------------------------------"); + + // 1. 射手网 (Shooter) + Console.WriteLine("\n[1/2] 正在请求:射手网 (Shooter)..."); + var shooterHash = ComputeShooterHash(testFilePath); + Console.WriteLine($" > HASH: {shooterHash}"); + await TestShooterApi(testFilePath, shooterHash); + + // 2. 迅雷影音 (Thunder) + Console.WriteLine("\n[2/2] 正在请求:迅雷影音 (Thunder)..."); + var thunderCid = await GetThunderCidAsync(testFilePath); + Console.WriteLine($" > CID: {thunderCid}"); + await TestThunderApi(testFilePath, thunderCid); + + Console.WriteLine("\n-------------------------------------------------------"); + Console.WriteLine("调试结束,按任意键退出..."); Console.ReadKey(); } - private static string GetCid(string filePath) - { - var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); - var reader = new BinaryReader(stream); - var fileSize = new FileInfo(filePath).Length; - var sha1 = SHA1.Create(); - var buffer = new byte[0xf000]; - if (fileSize < 0xf000) - { - reader.Read(buffer, 0, (int)fileSize); - buffer = sha1.ComputeHash(buffer, 0, (int)fileSize); - } - else - { - reader.Read(buffer, 0, 0x5000); - stream.Seek(fileSize / 3, SeekOrigin.Begin); - reader.Read(buffer, 0x5000, 0x5000); - stream.Seek(fileSize - 0x5000, SeekOrigin.Begin); - reader.Read(buffer, 0xa000, 0x5000); + #region API 测试方法 - buffer = sha1.ComputeHash(buffer, 0, 0xf000); - } - var result = ""; - foreach (var i in buffer) + private static async Task TestShooterApi(string filePath, string hash) + { + try { - result += string.Format("{0:X2}", i); + var url = "https://www.shooter.cn/api/subapi.php"; + var formData = new Dictionary + { + { "filehash", hash}, + { "pathinfo", Path.GetFileName(filePath)}, + { "format", "json"}, + { "lang", "chn"} + }; + + var content = new FormUrlEncodedContent(formData); + var response = await _httpClient.PostAsync(url, content); + var result = await response.Content.ReadAsStringAsync(); + Console.WriteLine($" > STATUS: {response.StatusCode}"); + Console.WriteLine($" > RETURN: {result}"); + } + catch (Exception ex) + { + Console.WriteLine($" > ERROR: {ex.Message}"); } - return result; } - public static string ComputeFileHash(string filePath) + private static async Task TestThunderApi(string filePath, string cid) + { + try + { + // 迅雷搜索接口通常基于文件名,CID 用于后续匹配校验 + var fileName = Path.GetFileName(filePath); + var url = $"https://api-shoulei-ssl.xunlei.com/oracle/subtitle?name={HttpUtility.UrlEncode(fileName)}"; + + var request = new HttpRequestMessage(HttpMethod.Get, url); + request.Headers.Add("User-Agent", "MeiamSub.Thunder"); + + var response = await _httpClient.SendAsync(request); + var result = await response.Content.ReadAsStringAsync(); + Console.WriteLine($" > STATUS: {response.StatusCode}"); + Console.WriteLine($" > RETURN: {result}"); + } + catch (Exception ex) + { + Console.WriteLine($" > ERROR: {ex.Message}"); + } + } + + #endregion + + #region HASH 算法实现 + + /// + /// 射手网 HASH 算法 + /// + public static string ComputeShooterHash(string filePath) { FileInfo fileInfo = new FileInfo(filePath); + if (!fileInfo.Exists || fileInfo.Length < 8 * 1024) return ""; - string ret = ""; - - if (!fileInfo.Exists || fileInfo.Length < 8 * 1024) + using (FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read)) { + long[] offset = new long[4]; + offset[3] = fileInfo.Length - 8 * 1024; + offset[2] = fileInfo.Length / 3; + offset[1] = fileInfo.Length / 3 * 2; + offset[0] = 4 * 1024; + + string ret = ""; + byte[] bBuf = new byte[4096]; + + using (MD5 md5 = MD5.Create()) + { + for (int i = 0; i < 4; ++i) + { + fs.Seek(offset[i], SeekOrigin.Begin); + fs.Read(bBuf, 0, 4096); + byte[] data = md5.ComputeHash(bBuf); + StringBuilder sBuilder = new StringBuilder(); + for (int j = 0; j < data.Length; j++) sBuilder.Append(data[j].ToString("x2")); + if (!string.IsNullOrEmpty(ret)) ret += ";"; + ret += sBuilder.ToString(); + } + } return ret; } - - FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read); - - long[] offset = new long[4]; - offset[3] = fileInfo.Length - 8 * 1024; - offset[2] = fileInfo.Length / 3; - offset[1] = fileInfo.Length / 3 * 2; - offset[0] = 4 * 1024; - - byte[] bBuf = new byte[1024 * 4]; - - for (int i = 0; i < 4; ++i) - { - fs.Seek(offset[i], 0); - fs.Read(bBuf, 0, 4 * 1024); - - MD5 md5Hash = MD5.Create(); - byte[] data = md5Hash.ComputeHash(bBuf); - StringBuilder sBuilder = new StringBuilder(); - - for (int j = 0; j < data.Length; j++) - { - sBuilder.Append(data[j].ToString("x2")); - } - - if (!string.IsNullOrEmpty(ret)) - { - ret += ";"; - } - - ret += sBuilder.ToString(); - } - - fs.Close(); - - return ret; } + + /// + /// 迅雷 CID 算法 (基于 SHA1) + /// + public static async Task GetThunderCidAsync(string filePath) + { + using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous)) + { + var fileSize = new FileInfo(filePath).Length; + using (var sha1 = SHA1.Create()) + { + var buffer = new byte[0xf000]; + if (fileSize < 0xf000) + { + await stream.ReadAsync(buffer, 0, (int)fileSize); + buffer = sha1.ComputeHash(buffer, 0, (int)fileSize); + } + else + { + await stream.ReadAsync(buffer, 0, 0x5000); + stream.Seek(fileSize / 3, SeekOrigin.Begin); + await stream.ReadAsync(buffer, 0x5000, 0x5000); + stream.Seek(fileSize - 0x5000, SeekOrigin.Begin); + await stream.ReadAsync(buffer, 0xa000, 0x5000); + buffer = sha1.ComputeHash(buffer, 0, 0xf000); + } + var result = ""; + foreach (var i in buffer) result += string.Format("{0:X2}", i); + return result; + } + } + } + + /// + /// QQ 播放器 VUID 算法 + /// + public static async Task ComputeQQVuidAsync(string filePath) + { + FileInfo fileInfo = new FileInfo(filePath); + if (!fileInfo.Exists || fileInfo.Length < 8 * 1024) return ""; + + using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous)) + { + long[] offsets = new long[3]; + offsets[0] = 0; + offsets[1] = fileInfo.Length / 3; + offsets[2] = fileInfo.Length - 8 * 1024; + + StringBuilder combinedMd5 = new StringBuilder(); + byte[] buffer = new byte[4096]; + + using (var md5 = MD5.Create()) + { + foreach (var offset in offsets) + { + fs.Seek(offset, SeekOrigin.Begin); + await fs.ReadAsync(buffer, 0, 4096); + byte[] hashBytes = md5.ComputeHash(buffer); + foreach (byte b in hashBytes) combinedMd5.Append(b.ToString("x2")); + } + byte[] finalHash = md5.ComputeHash(Encoding.ASCII.GetBytes(combinedMd5.ToString())); + StringBuilder result = new StringBuilder(); + foreach (byte b in finalHash) result.Append(b.ToString("x2")); + return result.ToString(); + } + } + } + + #endregion } } diff --git a/Emby.MeiamSub.Shooter/ShooterProvider.cs b/Emby.MeiamSub.Shooter/ShooterProvider.cs index 7a2d52b..d65a217 100644 --- a/Emby.MeiamSub.Shooter/ShooterProvider.cs +++ b/Emby.MeiamSub.Shooter/ShooterProvider.cs @@ -35,7 +35,7 @@ namespace Emby.MeiamSub.Shooter private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; - public int Order => 1; + public int Order => 100; public string Name => "MeiamSub.Shooter"; /// @@ -145,17 +145,17 @@ namespace Emby.MeiamSub.Shooter { Url = subFile.Link, Format = subFile.Ext, - Language = request.Language, - IsForced = request.IsForced - })), - Name = $"[MEIAMSUB] {Path.GetFileName(request.MediaPath)} | {language} | 射手", - Language = request.Language, - Author = "Meiam ", - ProviderName = $"{Name}", - Format = subFile.Ext, - Comment = $"Format : {ExtractFormat(subFile.Ext)}", - IsHashMatch = true - }); } + Language = request.Language, + IsForced = request.IsForced + })), + Name = $"[MEIAMSUB] {Path.GetFileName(request.MediaPath)} | {request.Language} | 射手", + Language = request.Language, + Author = "Meiam ", + ProviderName = $"{Name}", + Format = subFile.Ext, + Comment = $"Format : {ExtractFormat(subFile.Ext)}", + IsHashMatch = true + }); } } _logger.Info("{0} Search | Summary -> Get {1} Subtitles", new object[2] { Name, remoteSubtitles.Count }); diff --git a/Emby.MeiamSub.Thunder/ThunderProvider.cs b/Emby.MeiamSub.Thunder/ThunderProvider.cs index 6c33406..2dc4e59 100644 --- a/Emby.MeiamSub.Thunder/ThunderProvider.cs +++ b/Emby.MeiamSub.Thunder/ThunderProvider.cs @@ -35,7 +35,7 @@ namespace Emby.MeiamSub.Thunder private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; - public int Order => 1; + public int Order => 100; public string Name => "MeiamSub.Thunder"; @@ -136,17 +136,17 @@ namespace Emby.MeiamSub.Thunder { Url = item.Url, Format = item.Ext, - Language = request.Language, - IsForced = request.IsForced - })), - Name = $"[MEIAMSUB] {item.Name} | {(item.Langs == string.Empty ? "未知" : item.Langs)} | 迅雷", - Language = request.Language, - Author = "Meiam ", - ProviderName = $"{Name}", - Format = item.Ext, - Comment = $"Format : {item.Ext}", - IsHashMatch = cid == item.Cid, - }); } + Language = request.Language, + IsForced = request.IsForced + })), + Name = $"[MEIAMSUB] {item.Name} | {(item.Langs == string.Empty ? "未知" : item.Langs)} | 迅雷", + Language = request.Language, + Author = "Meiam ", + ProviderName = $"{Name}", + Format = item.Ext, + Comment = $"Format : {item.Ext}", + IsHashMatch = cid == item.Cid, + }); } } _logger.Info("{0} Search | Summary -> Get {1} Subtitles", new object[2] { Name, remoteSubtitles.Count }); diff --git a/Jellyfin.MeiamSub.Shooter/ShooterProvider.cs b/Jellyfin.MeiamSub.Shooter/ShooterProvider.cs index 7ee7a7d..f67db0c 100644 --- a/Jellyfin.MeiamSub.Shooter/ShooterProvider.cs +++ b/Jellyfin.MeiamSub.Shooter/ShooterProvider.cs @@ -41,7 +41,7 @@ namespace Jellyfin.MeiamSub.Shooter private const string ApiUrl = "https://www.shooter.cn/api/subapi.php"; - public int Order => 1; + public int Order => 100; public string Name => "MeiamSub.Shooter"; diff --git a/Jellyfin.MeiamSub.Thunder/ThunderProvider.cs b/Jellyfin.MeiamSub.Thunder/ThunderProvider.cs index 7380035..b7e1d9d 100644 --- a/Jellyfin.MeiamSub.Thunder/ThunderProvider.cs +++ b/Jellyfin.MeiamSub.Thunder/ThunderProvider.cs @@ -1,170 +1,170 @@ -using Jellyfin.MeiamSub.Thunder.Model; +using Jellyfin.MeiamSub.Thunder.Model; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Subtitles; -using MediaBrowser.Model.Providers; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Cryptography; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -namespace Jellyfin.MeiamSub.Thunder -{ - /// - /// 迅雷看看字幕提供程序 - /// 负责与迅雷 API 进行交互,通过 CID (Content ID) 匹配并下载字幕。 - /// 修改人: Meiam - /// 修改时间: 2025-12-22 - /// - public class ThunderProvider : ISubtitleProvider, IHasOrder - { - #region 变量声明 - public const string ASS = "ass"; - public const string SSA = "ssa"; - public const string SRT = "srt"; - - private readonly ILogger _logger; - private readonly IHttpClientFactory _httpClientFactory; - private static readonly JsonSerializerOptions _deserializeOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower - }; - - public int Order => 1; - public string Name => "MeiamSub.Thunder"; - - /// - /// 支持电影、剧集 - /// - public IEnumerable SupportedMediaTypes => new[] { VideoContentType.Movie, VideoContentType.Episode }; - #endregion - - #region 构造函数 - public ThunderProvider(ILogger logger, IHttpClientFactory httpClientFactory) - { - _logger = logger; - _httpClientFactory = httpClientFactory; - _logger.LogInformation($"{Name} Init"); - } - #endregion - - #region 查询字幕 - - /// - /// 搜索字幕 (ISubtitleProvider 接口实现) - /// 根据媒体信息请求字幕列表。 - /// - /// 包含媒体路径、语言等信息的搜索请求对象 - /// 取消令牌 - /// 远程字幕信息列表 - public async Task> Search(SubtitleSearchRequest request, CancellationToken cancellationToken) - { - _logger.LogInformation($"{Name} Search | SubtitleSearchRequest -> { JsonSerializer.Serialize(request) }"); - - var subtitles = await SearchSubtitlesAsync(request); - - return subtitles; - } - - /// - /// 查询字幕 - /// - /// - /// - private async Task> SearchSubtitlesAsync(SubtitleSearchRequest request) - { - // 修改人: Meiam - // 修改时间: 2025-12-22 - // 备注: 增加异常处理 - - try - { - var language = NormalizeLanguage(request.Language); - - _logger.LogInformation("{Provider} Search | Target -> {File} | Language -> {Lang}", Name, Path.GetFileName(request.MediaPath), language); - - if (language != "chi") - { - _logger.LogInformation("{Provider} Search | Summary -> Language not supported, skip search.", Name); - return Array.Empty(); - } - - var stopWatch = Stopwatch.StartNew(); - var cid = await GetCidByFileAsync(request.MediaPath); - stopWatch.Stop(); - - _logger.LogInformation("{Provider} Search | FileHash -> {Hash} (Took {Elapsed}ms)", Name, cid, stopWatch.ElapsedMilliseconds); - - using var options = new HttpRequestMessage - { - Method = HttpMethod.Get, - RequestUri = new Uri($"https://api-shoulei-ssl.xunlei.com/oracle/subtitle?name={Path.GetFileName(request.MediaPath)}") - }; - - using var httpClient = _httpClientFactory.CreateClient(Name); - - var response = await httpClient.SendAsync(options); - - _logger.LogInformation($"{Name} Search | Response -> {JsonSerializer.Serialize(response)}"); - - if (response.StatusCode == HttpStatusCode.OK) - { - var subtitleResponse = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync(), _deserializeOptions); - - if (subtitleResponse != null) - { - _logger.LogInformation($"{Name} Search | Response -> {JsonSerializer.Serialize(subtitleResponse)}"); - - var subtitles = subtitleResponse.Data.Where(m => !string.IsNullOrEmpty(m.Name)); - - var remoteSubtitles = new List(); - - if (subtitles.Count() > 0) - { - foreach (var item in subtitles) - { - remoteSubtitles.Add(new RemoteSubtitleInfo() - { - Id = Base64Encode(JsonSerializer.Serialize(new DownloadSubInfo - { - Url = item.Url, - Format = item.Ext, - Language = request.Language, - TwoLetterISOLanguageName = request.TwoLetterISOLanguageName, - })), - Name = $"[MEIAMSUB] {item.Name} | {(item.Langs == string.Empty ? "未知" : item.Langs)} | 迅雷", - Author = "Meiam ", - ProviderName = $"{Name}", - Format = item.Ext, - Comment = $"Format : {item.Ext}", - IsHashMatch = cid == item.Cid, - }); } - } - - _logger.LogInformation($"{Name} Search | Summary -> Get {subtitles.Count()} Subtitles"); - - return remoteSubtitles; - } - } - } - catch (Exception ex) - { - _logger.LogError(ex, "{Provider} Search | Exception -> [{Type}] {Message}", Name, ex.GetType().Name, ex.Message); - } - - _logger.LogInformation($"{Name} Search | Summary -> Get 0 Subtitles"); - - return Array.Empty(); - } +using MediaBrowser.Controller.Subtitles; +using MediaBrowser.Model.Providers; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace Jellyfin.MeiamSub.Thunder +{ + /// + /// 迅雷看看字幕提供程序 + /// 负责与迅雷 API 进行交互,通过 CID (Content ID) 匹配并下载字幕。 + /// 修改人: Meiam + /// 修改时间: 2025-12-22 + /// + public class ThunderProvider : ISubtitleProvider, IHasOrder + { + #region 变量声明 + public const string ASS = "ass"; + public const string SSA = "ssa"; + public const string SRT = "srt"; + + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + private static readonly JsonSerializerOptions _deserializeOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower + }; + + public int Order => 100; + public string Name => "MeiamSub.Thunder"; + + /// + /// 支持电影、剧集 + /// + public IEnumerable SupportedMediaTypes => new[] { VideoContentType.Movie, VideoContentType.Episode }; + #endregion + + #region 构造函数 + public ThunderProvider(ILogger logger, IHttpClientFactory httpClientFactory) + { + _logger = logger; + _httpClientFactory = httpClientFactory; + _logger.LogInformation($"{Name} Init"); + } + #endregion + + #region 查询字幕 + + /// + /// 搜索字幕 (ISubtitleProvider 接口实现) + /// 根据媒体信息请求字幕列表。 + /// + /// 包含媒体路径、语言等信息的搜索请求对象 + /// 取消令牌 + /// 远程字幕信息列表 + public async Task> Search(SubtitleSearchRequest request, CancellationToken cancellationToken) + { + _logger.LogInformation($"{Name} Search | SubtitleSearchRequest -> { JsonSerializer.Serialize(request) }"); + + var subtitles = await SearchSubtitlesAsync(request); + + return subtitles; + } + + /// + /// 查询字幕 + /// + /// + /// + private async Task> SearchSubtitlesAsync(SubtitleSearchRequest request) + { + // 修改人: Meiam + // 修改时间: 2025-12-22 + // 备注: 增加异常处理 + + try + { + var language = NormalizeLanguage(request.Language); + + _logger.LogInformation("{Provider} Search | Target -> {File} | Language -> {Lang}", Name, Path.GetFileName(request.MediaPath), language); + + if (language != "chi") + { + _logger.LogInformation("{Provider} Search | Summary -> Language not supported, skip search.", Name); + return Array.Empty(); + } + + var stopWatch = Stopwatch.StartNew(); + var cid = await GetCidByFileAsync(request.MediaPath); + stopWatch.Stop(); + + _logger.LogInformation("{Provider} Search | FileHash -> {Hash} (Took {Elapsed}ms)", Name, cid, stopWatch.ElapsedMilliseconds); + + using var options = new HttpRequestMessage + { + Method = HttpMethod.Get, + RequestUri = new Uri($"https://api-shoulei-ssl.xunlei.com/oracle/subtitle?name={Path.GetFileName(request.MediaPath)}") + }; + + using var httpClient = _httpClientFactory.CreateClient(Name); + + var response = await httpClient.SendAsync(options); + + _logger.LogInformation($"{Name} Search | Response -> {JsonSerializer.Serialize(response)}"); + + if (response.StatusCode == HttpStatusCode.OK) + { + var subtitleResponse = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync(), _deserializeOptions); + + if (subtitleResponse != null) + { + _logger.LogInformation($"{Name} Search | Response -> {JsonSerializer.Serialize(subtitleResponse)}"); + + var subtitles = subtitleResponse.Data.Where(m => !string.IsNullOrEmpty(m.Name)); + + var remoteSubtitles = new List(); + + if (subtitles.Count() > 0) + { + foreach (var item in subtitles) + { + remoteSubtitles.Add(new RemoteSubtitleInfo() + { + Id = Base64Encode(JsonSerializer.Serialize(new DownloadSubInfo + { + Url = item.Url, + Format = item.Ext, + Language = request.Language, + TwoLetterISOLanguageName = request.TwoLetterISOLanguageName, + })), + Name = $"[MEIAMSUB] {item.Name} | {(item.Langs == string.Empty ? "未知" : item.Langs)} | 迅雷", + Author = "Meiam ", + ProviderName = $"{Name}", + Format = item.Ext, + Comment = $"Format : {item.Ext}", + IsHashMatch = cid == item.Cid, + }); } + } + + _logger.LogInformation($"{Name} Search | Summary -> Get {subtitles.Count()} Subtitles"); + + return remoteSubtitles; + } + } + } + catch (Exception ex) + { + _logger.LogError(ex, "{Provider} Search | Exception -> [{Type}] {Message}", Name, ex.GetType().Name, ex.Message); + } + + _logger.LogInformation($"{Name} Search | Summary -> Get 0 Subtitles"); + + return Array.Empty(); + } #endregion #region 下载字幕 @@ -204,16 +204,17 @@ using MediaBrowser.Controller.Providers; _logger.LogInformation($"{Name} DownloadSub | Url -> {downloadSub.Url} | Format -> {downloadSub.Format} | Language -> {downloadSub.Language} "); - using var options = new HttpRequestMessage - { - Method = HttpMethod.Get, - RequestUri = new Uri(downloadSub.Url) - }; - - using var httpClient = _httpClientFactory.CreateClient(Name); - - var response = await httpClient.SendAsync(options); - _logger.LogInformation($"{Name} DownloadSub | Response -> {response.StatusCode}"); + using var options = new HttpRequestMessage + { + Method = HttpMethod.Get, + RequestUri = new Uri(downloadSub.Url) + }; + + using var httpClient = _httpClientFactory.CreateClient(Name); + + var response = await httpClient.SendAsync(options); + + _logger.LogInformation($"{Name} DownloadSub | Response -> {response.StatusCode}"); if (response.StatusCode == HttpStatusCode.OK) { @@ -230,7 +231,7 @@ using MediaBrowser.Controller.Providers; } catch (Exception ex) { - _logger.LogError(ex, "{0} DownloadSub | Error -> {1}", Name, ex.Message); + _logger.LogError(ex, "{Provider} DownloadSub | Exception -> [{Type}] {Message}", Name, ex.GetType().Name, ex.Message); } return new SubtitleResponse(); @@ -353,4 +354,4 @@ using MediaBrowser.Controller.Providers; } #endregion } -} +} \ No newline at end of file