fix: 加固射手网 API 稳定性并进行全量代码格式化

- 修复:针对射手网 API 年久失修、无结果时返回乱码或非法内容的问题,增加了 JSON 合法性校验逻辑,确保插件在异常返回下能静默退出而不崩溃。
- 优化:执行了全量代码格式化 (dotnet format),确保缩进、换行及代码风格符合 .NET 官方规范。
- 维护:清理了所有项目中不再使用的提示性条目逻辑,保持代码简洁。
This commit is contained in:
Meiam
2025-12-22 18:06:54 +08:00
parent 8f79853e00
commit 35ea11883f
6 changed files with 125 additions and 64 deletions

View File

@@ -20,7 +20,7 @@ namespace Emby.Subtitle.DevTool
Console.OutputEncoding = Encoding.UTF8;
Console.WriteLine("================ MeiamSubtitles 调试工具 ================");
// 待测试的影音文件路径
var testFilePath = @"D:\Source\MeiamSubtitles\TestServer\Movie\2009\三傻大闹宝莱坞\三傻大闹宝莱坞 (2009) - 1080p.mkv";
@@ -69,7 +69,15 @@ namespace Emby.Subtitle.DevTool
var response = await _httpClient.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine($" > STATUS: {response.StatusCode}");
Console.WriteLine($" > RETURN: {result}");
if (!result.Trim().StartsWith("["))
{
Console.WriteLine($" > [警告] API 返回了非法内容 (可能已失效或乱码): {result}");
}
else
{
Console.WriteLine($" > RETURN: {result}");
}
}
catch (Exception ex)
{
@@ -84,7 +92,7 @@ namespace Emby.Subtitle.DevTool
// 迅雷搜索接口通常基于文件名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");

View File

@@ -45,7 +45,7 @@ namespace Emby.MeiamSub.Shooter
#endregion
#region
public ShooterProvider(ILogManager logManager, IJsonSerializer jsonSerializer,IHttpClient httpClient)
public ShooterProvider(ILogManager logManager, IJsonSerializer jsonSerializer, IHttpClient httpClient)
{
_logger = logManager.GetLogger(GetType().Name);
_jsonSerializer = jsonSerializer;
@@ -65,7 +65,7 @@ namespace Emby.MeiamSub.Shooter
/// <returns>远程字幕信息列表</returns>
public async Task<IEnumerable<RemoteSubtitleInfo>> Search(SubtitleSearchRequest request, CancellationToken cancellationToken)
{
_logger.Info("{0} Search | SubtitleSearchRequest -> {1}", new object[2] { Name , _jsonSerializer.SerializeToString(request) });
_logger.Info("{0} Search | SubtitleSearchRequest -> {1}", new object[2] { Name, _jsonSerializer.SerializeToString(request) });
var subtitles = await SearchSubtitlesAsync(request);
@@ -127,7 +127,25 @@ namespace Emby.MeiamSub.Shooter
if (response.StatusCode == HttpStatusCode.OK && response.ContentType.Contains("application/json"))
{
var subtitleResponse = _jsonSerializer.DeserializeFromStream<List<SubtitleResponseRoot>>(response.Content);
// 修改人: Meiam
// 修改时间: 2025-12-22
// 备注: 增加对射手网 API 返回非法内容(如乱码)的校验
string responseBody;
using (var reader = new StreamReader(response.Content, Encoding.UTF8))
{
responseBody = await reader.ReadToEndAsync();
}
_logger.Info("{0} Search | ResponseBody -> {1}", new object[2] { Name, responseBody });
if (string.IsNullOrEmpty(responseBody) || !responseBody.Trim().StartsWith("["))
{
_logger.Info("{0} Search | Summary -> API returned invalid content (likely no subtitles found or API error).", Name);
return Array.Empty<RemoteSubtitleInfo>();
}
var subtitleResponse = _jsonSerializer.DeserializeFromString<List<SubtitleResponseRoot>>(responseBody);
if (subtitleResponse != null)
{
@@ -141,21 +159,22 @@ namespace Emby.MeiamSub.Shooter
{
remoteSubtitles.Add(new RemoteSubtitleInfo()
{
Id = Base64Encode(_jsonSerializer.SerializeToString(new DownloadSubInfo
{
Url = subFile.Link,
Format = subFile.Ext,
Id = Base64Encode(_jsonSerializer.SerializeToString(new DownloadSubInfo
{
Url = subFile.Link,
Format = subFile.Ext,
Language = request.Language,
IsForced = request.IsForced
})),
Name = $"[MEIAMSUB] {Path.GetFileName(request.MediaPath)} | {request.Language} | 射手",
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
}); }
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 });
@@ -286,7 +305,7 @@ namespace Emby.MeiamSub.Shooter
if (text.Contains(ASS)) return ASS;
if (text.Contains(SSA)) return SSA;
if (text.Contains(SRT)) return SRT;
return null;
}

View File

@@ -20,7 +20,7 @@ namespace Emby.MeiamSub.Thunder.Model
public int Duration { get; set; }
public string[] Languages { get; set; }
public string Langs=> Languages != null ? string.Join(",", Languages) : string.Empty;
public string Langs => Languages != null ? string.Join(",", Languages) : string.Empty;
public int Source { get; set; }
public int Score { get; set; }

View File

@@ -132,21 +132,22 @@ namespace Emby.MeiamSub.Thunder
{
remoteSubtitles.Add(new RemoteSubtitleInfo()
{
Id = Base64Encode(_jsonSerializer.SerializeToString(new DownloadSubInfo
{
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,
}); }
Id = Base64Encode(_jsonSerializer.SerializeToString(new DownloadSubInfo
{
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,
});
}
}
_logger.Info("{0} Search | Summary -> Get {1} Subtitles", new object[2] { Name, remoteSubtitles.Count });
@@ -177,7 +178,7 @@ namespace Emby.MeiamSub.Thunder
/// <returns>包含字幕流的响应对象</returns>
public async Task<SubtitleResponse> GetSubtitles(string id, CancellationToken cancellationToken)
{
_logger.Info("{0} DownloadSub | Request -> {1}", new object[2] { Name, id });
_logger.Info("{0} DownloadSub | Request -> {1}", new object[2] { Name, id });
return await DownloadSubAsync(id);
}
@@ -324,7 +325,7 @@ namespace Emby.MeiamSub.Thunder
{
// 使用 BinaryReader 配合 BaseStream 需要小心,因为 BinaryReader 本身不支持异步 Read
// 这里我们直接操作 stream 进行异步读取,不再使用 BinaryReader因为只是读取字节数组
var fileSize = new FileInfo(filePath).Length;
using (var sha1 = SHA1.Create())
{

View File

@@ -71,7 +71,7 @@ namespace Jellyfin.MeiamSub.Shooter
/// <returns>远程字幕信息列表</returns>
public async Task<IEnumerable<RemoteSubtitleInfo>> Search(SubtitleSearchRequest request, CancellationToken cancellationToken)
{
_logger.LogInformation($"{Name} Search | SubtitleSearchRequest -> { JsonSerializer.Serialize(request) }");
_logger.LogInformation($"{Name} Search | SubtitleSearchRequest -> {JsonSerializer.Serialize(request)}");
var subtitles = await SearchSubtitlesAsync(request);
@@ -130,12 +130,43 @@ namespace Jellyfin.MeiamSub.Shooter
_logger.LogInformation($"{Name} Search | Response -> {JsonSerializer.Serialize(response)}");
// 处理响应
if (response.IsSuccessStatusCode && response.Content.Headers.Any(m => m.Value.Contains("application/json; charset=utf-8")))
{
var responseBody = await response.Content.ReadAsStringAsync();
_logger.LogInformation($"{Name} Search | ResponseBody -> {responseBody} ");
if (string.IsNullOrEmpty(responseBody) || !responseBody.Trim().StartsWith("["))
{
_logger.LogInformation($"{Name} Search | Summary -> API returned invalid content (likely no subtitles found or API error).");
return Array.Empty<RemoteSubtitleInfo>();
}
var subtitles = JsonSerializer.Deserialize<List<SubtitleResponseRoot>>(responseBody);
_logger.LogInformation($"{Name} Search | Response -> {JsonSerializer.Serialize(subtitles)}");
@@ -151,20 +182,21 @@ namespace Jellyfin.MeiamSub.Shooter
{
remoteSubtitles.Add(new RemoteSubtitleInfo()
{
Id = Base64Encode(JsonSerializer.Serialize(new DownloadSubInfo
{
Url = subFile.Link,
Id = Base64Encode(JsonSerializer.Serialize(new DownloadSubInfo
{
Url = subFile.Link,
Format = subFile.Ext,
Language = request.Language,
TwoLetterISOLanguageName = request.TwoLetterISOLanguageName,
})),
Name = $"[MEIAMSUB] {Path.GetFileName(request.MediaPath)} | {request.TwoLetterISOLanguageName} | 射手",
Author = "Meiam ",
ProviderName = $"{Name}",
Format = subFile.Ext,
Language = request.Language,
TwoLetterISOLanguageName = request.TwoLetterISOLanguageName,
})),
Name = $"[MEIAMSUB] {Path.GetFileName(request.MediaPath)} | {request.TwoLetterISOLanguageName} | 射手",
Author = "Meiam ",
ProviderName = $"{Name}",
Format = subFile.Ext,
Comment = $"Format : {ExtractFormat(subFile.Ext)}",
IsHashMatch = true
}); }
Comment = $"Format : {ExtractFormat(subFile.Ext)}",
IsHashMatch = true
});
}
}
_logger.LogInformation($"{Name} Search | Summary -> Get {remoteSubtitles.Count} Subtitles");

View File

@@ -68,7 +68,7 @@ namespace Jellyfin.MeiamSub.Thunder
/// <returns>远程字幕信息列表</returns>
public async Task<IEnumerable<RemoteSubtitleInfo>> Search(SubtitleSearchRequest request, CancellationToken cancellationToken)
{
_logger.LogInformation($"{Name} Search | SubtitleSearchRequest -> { JsonSerializer.Serialize(request) }");
_logger.LogInformation($"{Name} Search | SubtitleSearchRequest -> {JsonSerializer.Serialize(request)}");
var subtitles = await SearchSubtitlesAsync(request);
@@ -138,16 +138,17 @@ namespace Jellyfin.MeiamSub.Thunder
{
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,
}); }
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");