|
|
@ -1,6 +1,5 @@
|
|
|
|
using System.IO.Compression;
|
|
|
|
using System.IO.Compression;
|
|
|
|
using System.Text;
|
|
|
|
using System.Text;
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
|
|
|
|
|
|
|
|
namespace STranslateDLL;
|
|
|
|
namespace STranslateDLL;
|
|
|
@ -15,64 +14,23 @@ public static class Program
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Utilities.Initial();
|
|
|
|
Utilities.Initial();
|
|
|
|
|
|
|
|
|
|
|
|
var getToken = token ?? CancellationToken.None;
|
|
|
|
var getToken = token ?? CancellationToken.None;
|
|
|
|
var splitResult = await SplitTextAsync(content, getToken);
|
|
|
|
var splitResult = await SplitTextAsync(content, getToken);
|
|
|
|
|
|
|
|
|
|
|
|
var splitData = JsonNode.Parse(splitResult);
|
|
|
|
var splitData = JsonNode.Parse(splitResult);
|
|
|
|
var splitError = splitData?["error"]?["message"]?.ToString();
|
|
|
|
var splitError = splitData?["error"]?["message"]?.ToString();
|
|
|
|
if (splitError != null)
|
|
|
|
if (splitError != null)
|
|
|
|
{
|
|
|
|
|
|
|
|
return Utilities.Serialize(new Response
|
|
|
|
return Utilities.Serialize(new Response
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Code = 500,
|
|
|
|
Code = 500,
|
|
|
|
Data = splitError
|
|
|
|
Data = splitError
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sourceLang.Equals("auto", StringComparison.CurrentCultureIgnoreCase) || sourceLang.Equals(""))
|
|
|
|
|
|
|
|
sourceLang = splitData?["result"]?["lang"]?["detected"]?.ToString()?.ToUpper() ?? "auto";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var jobs = new List<Job>();
|
|
|
|
sourceLang = GetSourceLang(sourceLang, splitData);
|
|
|
|
var chunks = splitData?["result"]?["texts"]?[0]?["chunks"];
|
|
|
|
|
|
|
|
if (chunks is JsonArray chunkArray)
|
|
|
|
|
|
|
|
for (var i = 0; i < chunkArray.Count; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var sentence = chunkArray[i]?["sentences"]?[0];
|
|
|
|
|
|
|
|
var contextBefore = Array.Empty<string>();
|
|
|
|
|
|
|
|
var contextAfter = Array.Empty<string>();
|
|
|
|
|
|
|
|
if (i > 0) contextBefore = [chunkArray[i - 1]?["sentences"]?[0]?["text"]?.ToString() ?? ""];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i < chunkArray.Count - 1)
|
|
|
|
|
|
|
|
contextAfter = [chunkArray[i + 1]?["sentences"]?[0]?["text"]?.ToString() ?? ""];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var job = new Job
|
|
|
|
var jobs = CreateJobs(splitData);
|
|
|
|
{
|
|
|
|
|
|
|
|
Kind = "default",
|
|
|
|
|
|
|
|
PreferredNumBeams = 4,
|
|
|
|
|
|
|
|
RawEnContextBefore = contextBefore,
|
|
|
|
|
|
|
|
RawEnContextAfter = contextAfter,
|
|
|
|
|
|
|
|
Sentences =
|
|
|
|
|
|
|
|
[
|
|
|
|
|
|
|
|
new Sentence
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Prefix = sentence?["prefix"]?.ToString() ?? "",
|
|
|
|
|
|
|
|
Text = sentence?["text"]?.ToString() ?? "",
|
|
|
|
|
|
|
|
Id = i + 1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
jobs.Add(job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var hasRegionalVariant = false;
|
|
|
|
var targetLangCode = GetTargetLangCode(targetLang, out var hasRegionalVariant);
|
|
|
|
var targetLangCode = targetLang;
|
|
|
|
|
|
|
|
var targetLangParts = targetLang.Split("-");
|
|
|
|
|
|
|
|
if (targetLangParts.Length > 1)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
targetLangCode = targetLangParts[0];
|
|
|
|
|
|
|
|
hasRegionalVariant = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var id = Utilities.CreateId();
|
|
|
|
var id = Utilities.CreateId();
|
|
|
|
var reqData = new DeepLRequest
|
|
|
|
var reqData = new DeepLRequest
|
|
|
@ -89,7 +47,6 @@ public static class Program
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Lang = new ReqParamsLang
|
|
|
|
Lang = new ReqParamsLang
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// SourceLangUserSelected = sourceLang,
|
|
|
|
|
|
|
|
SourceLangComputed = sourceLang.ToUpper(),
|
|
|
|
SourceLangComputed = sourceLang.ToUpper(),
|
|
|
|
TargetLang = targetLangCode.ToUpper()
|
|
|
|
TargetLang = targetLangCode.ToUpper()
|
|
|
|
},
|
|
|
|
},
|
|
|
@ -102,19 +59,95 @@ public static class Program
|
|
|
|
var json = Utilities.Serialize(reqData);
|
|
|
|
var json = Utilities.Serialize(reqData);
|
|
|
|
json = Utilities.AdjustJsonContent(json, id);
|
|
|
|
json = Utilities.AdjustJsonContent(json, id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var responseBody = await SendRequestAsync(json, getToken, "LMT_handle_jobs");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var jNode = JsonNode.Parse(responseBody);
|
|
|
|
|
|
|
|
var data = jNode?["result"]?["translations"]?[0]?["beams"]?[0]?["sentences"]?[0]?["text"]?.ToString();
|
|
|
|
|
|
|
|
var errorMsg = jNode?["error"]?["message"]?.ToString();
|
|
|
|
|
|
|
|
var detailsMsg = jNode?["error"]?["data"]?["what"]?.ToString();
|
|
|
|
|
|
|
|
var error = $"Error: {errorMsg}\nDetails: {detailsMsg}";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Utilities.Serialize(new Response
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Code = data != null ? 200 : 500,
|
|
|
|
|
|
|
|
Data = data ?? error
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static string GetSourceLang(string sourceLang, JsonNode? splitData)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (sourceLang.Equals("auto", StringComparison.CurrentCultureIgnoreCase) || sourceLang.Equals(""))
|
|
|
|
|
|
|
|
sourceLang = splitData?["result"]?["lang"]?["detected"]?.ToString().ToUpper() ?? "auto";
|
|
|
|
|
|
|
|
return sourceLang;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static List<Job> CreateJobs(JsonNode? splitData)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var jobs = new List<Job>();
|
|
|
|
|
|
|
|
var chunks = splitData?["result"]?["texts"]?[0]?["chunks"];
|
|
|
|
|
|
|
|
if (chunks is JsonArray chunkArray)
|
|
|
|
|
|
|
|
for (var i = 0; i < chunkArray.Count; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var sentence = chunkArray[i]?["sentences"]?[0];
|
|
|
|
|
|
|
|
var contextBefore = i > 0
|
|
|
|
|
|
|
|
? new[] { chunkArray[i - 1]?["sentences"]?[0]?["text"]?.ToString() ?? "" }
|
|
|
|
|
|
|
|
: Array.Empty<string>();
|
|
|
|
|
|
|
|
var contextAfter = i < chunkArray.Count - 1
|
|
|
|
|
|
|
|
? new[] { chunkArray[i + 1]?["sentences"]?[0]?["text"]?.ToString() ?? "" }
|
|
|
|
|
|
|
|
: Array.Empty<string>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var job = new Job
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Kind = "default",
|
|
|
|
|
|
|
|
PreferredNumBeams = 4,
|
|
|
|
|
|
|
|
RawEnContextBefore = contextBefore,
|
|
|
|
|
|
|
|
RawEnContextAfter = contextAfter,
|
|
|
|
|
|
|
|
Sentences = new[]
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
new Sentence
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Prefix = sentence?["prefix"]?.ToString() ?? "",
|
|
|
|
|
|
|
|
Text = sentence?["text"]?.ToString() ?? "",
|
|
|
|
|
|
|
|
Id = i + 1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
jobs.Add(job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return jobs;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static string GetTargetLangCode(string targetLang, out bool hasRegionalVariant)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var targetLangCode = targetLang;
|
|
|
|
|
|
|
|
var targetLangParts = targetLang.Split("-");
|
|
|
|
|
|
|
|
hasRegionalVariant = targetLangParts.Length > 1;
|
|
|
|
|
|
|
|
if (hasRegionalVariant) targetLangCode = targetLangParts[0];
|
|
|
|
|
|
|
|
return targetLangCode;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static async Task<string> SendRequestAsync(string json, CancellationToken token, string method)
|
|
|
|
|
|
|
|
{
|
|
|
|
using var client = new HttpClient();
|
|
|
|
using var client = new HttpClient();
|
|
|
|
var request = new HttpRequestMessage(HttpMethod.Post,
|
|
|
|
var uri = $"{Utilities.Url}?client=chrome-extension,1.28.0&method={method}";
|
|
|
|
"https://www2.deepl.com/jsonrpc?client=chrome-extension,1.28.0&method=LMT_handle_jobs")
|
|
|
|
var request = new HttpRequestMessage(HttpMethod.Post, uri)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
|
|
|
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AddRequestHeaders(request);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var resp = await client.SendAsync(request, token);
|
|
|
|
|
|
|
|
return await GetResponseBodyAsync(resp, token);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static void AddRequestHeaders(HttpRequestMessage request)
|
|
|
|
|
|
|
|
{
|
|
|
|
request.Headers.Add("Accept", "*/*");
|
|
|
|
request.Headers.Add("Accept", "*/*");
|
|
|
|
request.Headers.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh-HK;q=0.6,zh;q=0.5");
|
|
|
|
request.Headers.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh-HK;q=0.6,zh;q=0.5");
|
|
|
|
request.Headers.Add("Authorization", "None");
|
|
|
|
request.Headers.Add("Authorization", "None");
|
|
|
|
request.Headers.Add("Cache-Control", "no-cache");
|
|
|
|
request.Headers.Add("Cache-Control", "no-cache");
|
|
|
|
// request.Headers.Add("Content-Type", "application/json");
|
|
|
|
|
|
|
|
request.Headers.Add("DNT", "1");
|
|
|
|
request.Headers.Add("DNT", "1");
|
|
|
|
request.Headers.Add("Origin", "chrome-extension://cofdbpoegempjloogbagkncekinflcnj");
|
|
|
|
request.Headers.Add("Origin", "chrome-extension://cofdbpoegempjloogbagkncekinflcnj");
|
|
|
|
request.Headers.Add("Pragma", "no-cache");
|
|
|
|
request.Headers.Add("Pragma", "no-cache");
|
|
|
@ -126,52 +159,26 @@ public static class Program
|
|
|
|
request.Headers.Add("Sec-GPC", "1");
|
|
|
|
request.Headers.Add("Sec-GPC", "1");
|
|
|
|
request.Headers.Add("User-Agent",
|
|
|
|
request.Headers.Add("User-Agent",
|
|
|
|
"DeepLBrowserExtension/1.28.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
|
|
|
|
"DeepLBrowserExtension/1.28.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var resp = await client.SendAsync(request, getToken);
|
|
|
|
private static async Task<string> GetResponseBodyAsync(HttpResponseMessage resp, CancellationToken token)
|
|
|
|
//resp.EnsureSuccessStatusCode();
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!resp.Content.Headers.ContentEncoding.Contains("br"))
|
|
|
|
string responseBody;
|
|
|
|
return await resp.Content.ReadAsStringAsync(token);
|
|
|
|
|
|
|
|
|
|
|
|
if (resp.Content.Headers.ContentEncoding.Contains("br"))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
await using var responseStream = await resp.Content.ReadAsStreamAsync(getToken);
|
|
|
|
|
|
|
|
await using var decompressionStream = new BrotliStream(
|
|
|
|
|
|
|
|
responseStream,
|
|
|
|
|
|
|
|
CompressionMode.Decompress
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
using var streamReader = new StreamReader(decompressionStream);
|
|
|
|
|
|
|
|
responseBody = await streamReader.ReadToEndAsync(getToken);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
responseBody = await resp.Content.ReadAsStringAsync(getToken);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var jNode = JsonNode.Parse(responseBody);
|
|
|
|
|
|
|
|
var data = jNode?["result"]?["translations"]?[0]?["beams"]?[0]?["sentences"]?[0]?["text"]?.ToString();
|
|
|
|
|
|
|
|
// data = UnicodeToString(data);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var errorMsg = jNode?["error"]?["message"]?.ToString();
|
|
|
|
|
|
|
|
var detailsMsg = jNode?["error"]?["data"]?["what"]?.ToString();
|
|
|
|
|
|
|
|
var error = $"Error: {errorMsg}\nDetails: {detailsMsg}";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var response = new Response
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Code = resp.StatusCode.GetHashCode(),
|
|
|
|
|
|
|
|
Data = data ?? error
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Utilities.Serialize(response);
|
|
|
|
await using var responseStream = await resp.Content.ReadAsStreamAsync(token);
|
|
|
|
|
|
|
|
await using var decompressionStream = new BrotliStream(responseStream, CompressionMode.Decompress);
|
|
|
|
|
|
|
|
using var streamReader = new StreamReader(decompressionStream);
|
|
|
|
|
|
|
|
return await streamReader.ReadToEndAsync(token);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static async Task<string> SplitTextAsync(string text, CancellationToken? token)
|
|
|
|
private static async Task<string> SplitTextAsync(string text, CancellationToken token)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var id = Utilities.CreateId();
|
|
|
|
var id = Utilities.CreateId();
|
|
|
|
var getToken = token ?? CancellationToken.None;
|
|
|
|
|
|
|
|
var requestData = new DeepLRequest
|
|
|
|
var requestData = new DeepLRequest
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Jsonrpc = "2.0",
|
|
|
|
Jsonrpc = "2.0",
|
|
|
|
Method = "LMT_split_text2",
|
|
|
|
Method = "LMT_split_text",
|
|
|
|
Id = id,
|
|
|
|
Id = id,
|
|
|
|
Params = new ReqParams
|
|
|
|
Params = new ReqParams
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -183,55 +190,13 @@ public static class Program
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SourceLangUserSelected = "auto"
|
|
|
|
SourceLangUserSelected = "auto"
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Texts = [text],
|
|
|
|
Texts = new[] { text },
|
|
|
|
TextType = Utilities.TextTypeDic[ /*tagHandling*/false || Utilities.IsRichText(text)]
|
|
|
|
TextType = Utilities.TextTypeDic[Utilities.IsRichText(text)]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var json = Utilities.Serialize(requestData);
|
|
|
|
var json = Utilities.Serialize(requestData);
|
|
|
|
json = Utilities.AdjustJsonContent(json, id);
|
|
|
|
json = Utilities.AdjustJsonContent(json, id);
|
|
|
|
using var client = new HttpClient();
|
|
|
|
return await SendRequestAsync(json, token, "LMT_split_text");
|
|
|
|
var request = new HttpRequestMessage(HttpMethod.Post,
|
|
|
|
|
|
|
|
"https://www2.deepl.com/jsonrpc?client=chrome-extension,1.28.0&method=LMT_split_text")
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// Add headers to the request
|
|
|
|
|
|
|
|
request.Headers.Add("Accept", "*/*");
|
|
|
|
|
|
|
|
request.Headers.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh-HK;q=0.6,zh;q=0.5");
|
|
|
|
|
|
|
|
request.Headers.Add("Authorization", "None");
|
|
|
|
|
|
|
|
request.Headers.Add("Cache-Control", "no-cache");
|
|
|
|
|
|
|
|
// request.Headers.Add("Content-Type", "application/json");
|
|
|
|
|
|
|
|
request.Headers.Add("DNT", "1");
|
|
|
|
|
|
|
|
request.Headers.Add("Origin", "chrome-extension://cofdbpoegempjloogbagkncekinflcnj");
|
|
|
|
|
|
|
|
request.Headers.Add("Pragma", "no-cache");
|
|
|
|
|
|
|
|
request.Headers.Add("Priority", "u=1, i");
|
|
|
|
|
|
|
|
request.Headers.Add("Referer", "https://www.deepl.com/");
|
|
|
|
|
|
|
|
request.Headers.Add("Sec-Fetch-Dest", "empty");
|
|
|
|
|
|
|
|
request.Headers.Add("Sec-Fetch-Mode", "cors");
|
|
|
|
|
|
|
|
request.Headers.Add("Sec-Fetch-Site", "none");
|
|
|
|
|
|
|
|
request.Headers.Add("Sec-GPC", "1");
|
|
|
|
|
|
|
|
request.Headers.Add("User-Agent",
|
|
|
|
|
|
|
|
"DeepLBrowserExtension/1.28.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var resp = await client.SendAsync(request, getToken);
|
|
|
|
|
|
|
|
string responseBody;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (resp.Content.Headers.ContentEncoding.Contains("br"))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
await using var responseStream = await resp.Content.ReadAsStreamAsync(getToken);
|
|
|
|
|
|
|
|
await using var decompressionStream = new BrotliStream(
|
|
|
|
|
|
|
|
responseStream,
|
|
|
|
|
|
|
|
CompressionMode.Decompress
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
using var streamReader = new StreamReader(decompressionStream);
|
|
|
|
|
|
|
|
responseBody = await streamReader.ReadToEndAsync(getToken);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
responseBody = await resp.Content.ReadAsStringAsync(getToken);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return responseBody;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|