mirror of
https://github.com/OwO-Network/DeepLX.git
synced 2025-04-19 14:13:24 +00:00
fix: unable to translate (switch to DeepL iOS)
This commit is contained in:
parent
26a9003b13
commit
2400139a8d
@ -2,7 +2,7 @@
|
|||||||
* @Author: Vincent Young
|
* @Author: Vincent Young
|
||||||
* @Date: 2024-09-16 11:59:24
|
* @Date: 2024-09-16 11:59:24
|
||||||
* @LastEditors: Vincent Yang
|
* @LastEditors: Vincent Yang
|
||||||
* @LastEditTime: 2025-01-20 17:09:59
|
* @LastEditTime: 2025-03-01 04:23:49
|
||||||
* @FilePath: /DeepLX/translate/translate.go
|
* @FilePath: /DeepLX/translate/translate.go
|
||||||
* @Telegram: https://t.me/missuo
|
* @Telegram: https://t.me/missuo
|
||||||
* @GitHub: https://github.com/missuo
|
* @GitHub: https://github.com/missuo
|
||||||
@ -14,6 +14,8 @@ package translate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"compress/flate"
|
||||||
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -27,13 +29,9 @@ import (
|
|||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
const baseURL = "https://www2.deepl.com/jsonrpc"
|
|
||||||
|
|
||||||
// makeRequest makes an HTTP request to DeepL API
|
// makeRequest makes an HTTP request to DeepL API
|
||||||
|
func makeRequest(postData *PostData, proxyURL string, dlSession string) (gjson.Result, error) {
|
||||||
func makeRequest(postData *PostData, urlMethod string, proxyURL string, dlSession string) (gjson.Result, error) {
|
urlFull := "https://www2.deepl.com/jsonrpc"
|
||||||
urlFull := fmt.Sprintf("%s?client=chrome-extension,1.28.0&method=%s", baseURL, urlMethod)
|
|
||||||
|
|
||||||
postStr := formatPostString(postData)
|
postStr := formatPostString(postData)
|
||||||
|
|
||||||
// Create a new req client
|
// Create a new req client
|
||||||
@ -41,21 +39,18 @@ func makeRequest(postData *PostData, urlMethod string, proxyURL string, dlSessio
|
|||||||
|
|
||||||
// Set headers
|
// Set headers
|
||||||
headers := http.Header{
|
headers := http.Header{
|
||||||
"Accept": []string{"*/*"},
|
|
||||||
"Accept-Language": []string{"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"},
|
|
||||||
"Authorization": []string{"None"},
|
|
||||||
"Cache-Control": []string{"no-cache"},
|
|
||||||
"Content-Type": []string{"application/json"},
|
"Content-Type": []string{"application/json"},
|
||||||
"DNT": []string{"1"},
|
"User-Agent": []string{"DeepL/1627620 CFNetwork/3826.500.62.2.1 Darwin/24.4.0"},
|
||||||
"Origin": []string{"chrome-extension://cofdbpoegempjloogbagkncekinflcnj"},
|
"Accept": []string{"*/*"},
|
||||||
"Pragma": []string{"no-cache"},
|
"X-App-Os-Name": []string{"iOS"},
|
||||||
"Priority": []string{"u=1, i"},
|
"X-App-Os-Version": []string{"18.4.0"},
|
||||||
|
"Accept-Language": []string{"en-US,en;q=0.9"},
|
||||||
|
"Accept-Encoding": []string{"gzip, deflate, br"}, // Keep this!
|
||||||
|
"X-App-Device": []string{"iPhone16,2"},
|
||||||
"Referer": []string{"https://www.deepl.com/"},
|
"Referer": []string{"https://www.deepl.com/"},
|
||||||
"Sec-Fetch-Dest": []string{"empty"},
|
"X-Product": []string{"translator"},
|
||||||
"Sec-Fetch-Mode": []string{"cors"},
|
"X-App-Build": []string{"1627620"},
|
||||||
"Sec-Fetch-Site": []string{"none"},
|
"X-App-Version": []string{"25.1"},
|
||||||
"Sec-GPC": []string{"1"},
|
|
||||||
"User-Agent": []string{"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"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dlSession != "" {
|
if dlSession != "" {
|
||||||
@ -83,40 +78,28 @@ func makeRequest(postData *PostData, urlMethod string, proxyURL string, dlSessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
var bodyReader io.Reader
|
var bodyReader io.Reader
|
||||||
if resp.Header.Get("Content-Encoding") == "br" {
|
contentEncoding := resp.Header.Get("Content-Encoding")
|
||||||
|
switch contentEncoding {
|
||||||
|
case "br":
|
||||||
bodyReader = brotli.NewReader(resp.Body)
|
bodyReader = brotli.NewReader(resp.Body)
|
||||||
} else {
|
case "gzip":
|
||||||
|
bodyReader, err = gzip.NewReader(resp.Body) // Use gzip.NewReader
|
||||||
|
if err != nil {
|
||||||
|
return gjson.Result{}, fmt.Errorf("failed to create gzip reader: %w", err)
|
||||||
|
}
|
||||||
|
case "deflate": // Less common, but good to handle
|
||||||
|
bodyReader = flate.NewReader(resp.Body)
|
||||||
|
default:
|
||||||
bodyReader = resp.Body
|
bodyReader = resp.Body
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := io.ReadAll(bodyReader)
|
body, err := io.ReadAll(bodyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gjson.Result{}, err
|
return gjson.Result{}, fmt.Errorf("failed to read response body: %w", err)
|
||||||
}
|
}
|
||||||
return gjson.ParseBytes(body), nil
|
return gjson.ParseBytes(body), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitText splits the input text for translation
|
|
||||||
func splitText(text string, tagHandling bool, proxyURL string, dlSession string) (gjson.Result, error) {
|
|
||||||
postData := &PostData{
|
|
||||||
Jsonrpc: "2.0",
|
|
||||||
Method: "LMT_split_text",
|
|
||||||
ID: getRandomNumber(),
|
|
||||||
Params: Params{
|
|
||||||
CommonJobParams: CommonJobParams{
|
|
||||||
Mode: "translate",
|
|
||||||
},
|
|
||||||
Lang: Lang{
|
|
||||||
LangUserSelected: "auto",
|
|
||||||
},
|
|
||||||
Texts: []string{text},
|
|
||||||
TextType: map[bool]string{true: "richtext", false: "plaintext"}[tagHandling || isRichText(text)],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return makeRequest(postData, "LMT_split_text", proxyURL, dlSession)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TranslateByDeepLX performs translation using DeepL API
|
// TranslateByDeepLX performs translation using DeepL API
|
||||||
func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string, proxyURL string, dlSession string) (DeepLXTranslationResult, error) {
|
func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string, proxyURL string, dlSession string) (DeepLXTranslationResult, error) {
|
||||||
if text == "" {
|
if text == "" {
|
||||||
@ -126,6 +109,10 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tagHandling == "" {
|
||||||
|
tagHandling = "plaintext"
|
||||||
|
}
|
||||||
|
|
||||||
// Split text by newlines and store them for later reconstruction
|
// Split text by newlines and store them for later reconstruction
|
||||||
textParts := strings.Split(text, "\n")
|
textParts := strings.Split(text, "\n")
|
||||||
var translatedParts []string
|
var translatedParts []string
|
||||||
@ -138,15 +125,6 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split text first
|
|
||||||
splitResult, err := splitText(part, tagHandling == "html" || tagHandling == "xml", proxyURL, dlSession)
|
|
||||||
if err != nil {
|
|
||||||
return DeepLXTranslationResult{
|
|
||||||
Code: http.StatusServiceUnavailable,
|
|
||||||
Message: err.Error(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get detected language if source language is auto
|
// Get detected language if source language is auto
|
||||||
if sourceLang == "auto" || sourceLang == "" {
|
if sourceLang == "auto" || sourceLang == "" {
|
||||||
sourceLang = strings.ToUpper(whatlanggo.DetectLang(part).Iso6391())
|
sourceLang = strings.ToUpper(whatlanggo.DetectLang(part).Iso6391())
|
||||||
@ -154,32 +132,18 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
|
|||||||
|
|
||||||
// Prepare jobs from split result
|
// Prepare jobs from split result
|
||||||
var jobs []Job
|
var jobs []Job
|
||||||
chunks := splitResult.Get("result.texts.0.chunks").Array()
|
|
||||||
for idx, chunk := range chunks {
|
|
||||||
sentence := chunk.Get("sentences.0")
|
|
||||||
|
|
||||||
// Handle context
|
|
||||||
contextBefore := []string{}
|
|
||||||
contextAfter := []string{}
|
|
||||||
if idx > 0 {
|
|
||||||
contextBefore = []string{chunks[idx-1].Get("sentences.0.text").String()}
|
|
||||||
}
|
|
||||||
if idx < len(chunks)-1 {
|
|
||||||
contextAfter = []string{chunks[idx+1].Get("sentences.0.text").String()}
|
|
||||||
}
|
|
||||||
|
|
||||||
jobs = append(jobs, Job{
|
jobs = append(jobs, Job{
|
||||||
Kind: "default",
|
Kind: "default",
|
||||||
PreferredNumBeams: 4,
|
PreferredNumBeams: 4,
|
||||||
RawEnContextBefore: contextBefore,
|
RawEnContextBefore: []string{},
|
||||||
RawEnContextAfter: contextAfter,
|
RawEnContextAfter: []string{},
|
||||||
Sentences: []Sentence{{
|
Sentences: []Sentence{{
|
||||||
Prefix: sentence.Get("prefix").String(),
|
Prefix: "",
|
||||||
Text: sentence.Get("text").String(),
|
Text: text,
|
||||||
ID: idx + 1,
|
ID: 0,
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
hasRegionalVariant := false
|
hasRegionalVariant := false
|
||||||
targetLangCode := targetLang
|
targetLangCode := targetLang
|
||||||
@ -199,13 +163,18 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
|
|||||||
Params: Params{
|
Params: Params{
|
||||||
CommonJobParams: CommonJobParams{
|
CommonJobParams: CommonJobParams{
|
||||||
Mode: "translate",
|
Mode: "translate",
|
||||||
|
Formality: "undefined",
|
||||||
|
TranscribeAs: "romanize",
|
||||||
|
AdvancedMode: false,
|
||||||
|
TextType: tagHandling,
|
||||||
|
WasSpoken: false,
|
||||||
},
|
},
|
||||||
Lang: Lang{
|
Lang: Lang{
|
||||||
SourceLangComputed: strings.ToUpper(sourceLang),
|
SourceLangUserSelected: "auto",
|
||||||
TargetLang: strings.ToUpper(targetLangCode),
|
TargetLang: strings.ToUpper(targetLangCode),
|
||||||
|
SourceLangComputed: strings.ToUpper(sourceLang),
|
||||||
},
|
},
|
||||||
Jobs: jobs,
|
Jobs: jobs,
|
||||||
Priority: 1,
|
|
||||||
Timestamp: getTimeStamp(getICount(part)),
|
Timestamp: getTimeStamp(getICount(part)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -218,21 +187,26 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
|
|||||||
Params: Params{
|
Params: Params{
|
||||||
CommonJobParams: CommonJobParams{
|
CommonJobParams: CommonJobParams{
|
||||||
Mode: "translate",
|
Mode: "translate",
|
||||||
RegionalVariant: map[bool]string{true: targetLang, false: ""}[hasRegionalVariant],
|
Formality: "undefined",
|
||||||
|
TranscribeAs: "romanize",
|
||||||
|
AdvancedMode: false,
|
||||||
|
TextType: tagHandling,
|
||||||
|
WasSpoken: false,
|
||||||
|
RegionalVariant: targetLang,
|
||||||
},
|
},
|
||||||
Lang: Lang{
|
Lang: Lang{
|
||||||
SourceLangComputed: strings.ToUpper(sourceLang),
|
SourceLangUserSelected: "auto",
|
||||||
TargetLang: strings.ToUpper(targetLangCode),
|
TargetLang: strings.ToUpper(targetLangCode),
|
||||||
|
SourceLangComputed: strings.ToUpper(sourceLang),
|
||||||
},
|
},
|
||||||
Jobs: jobs,
|
Jobs: jobs,
|
||||||
Priority: 1,
|
|
||||||
Timestamp: getTimeStamp(getICount(part)),
|
Timestamp: getTimeStamp(getICount(part)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make translation request
|
// Make translation request
|
||||||
result, err := makeRequest(postData, "LMT_handle_jobs", proxyURL, dlSession)
|
result, err := makeRequest(postData, proxyURL, dlSession)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DeepLXTranslationResult{
|
return DeepLXTranslationResult{
|
||||||
Code: http.StatusServiceUnavailable,
|
Code: http.StatusServiceUnavailable,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* @Author: Vincent Young
|
* @Author: Vincent Young
|
||||||
* @Date: 2024-09-16 11:59:24
|
* @Date: 2024-09-16 11:59:24
|
||||||
* @LastEditors: Vincent Yang
|
* @LastEditors: Vincent Yang
|
||||||
* @LastEditTime: 2024-11-01 23:18:56
|
* @LastEditTime: 2025-03-01 04:16:07
|
||||||
* @FilePath: /DeepLX/translate/types.go
|
* @FilePath: /DeepLX/translate/types.go
|
||||||
* @Telegram: https://t.me/missuo
|
* @Telegram: https://t.me/missuo
|
||||||
* @GitHub: https://github.com/missuo
|
* @GitHub: https://github.com/missuo
|
||||||
@ -14,14 +14,19 @@ package translate
|
|||||||
|
|
||||||
// Lang represents the language settings for translation
|
// Lang represents the language settings for translation
|
||||||
type Lang struct {
|
type Lang struct {
|
||||||
SourceLangComputed string `json:"source_lang_computed,omitempty"`
|
SourceLangUserSelected string `json:"source_lang_user_selected"` // Can be "auto"
|
||||||
TargetLang string `json:"target_lang"`
|
TargetLang string `json:"target_lang"`
|
||||||
LangUserSelected string `json:"lang_user_selected,omitempty"`
|
SourceLangComputed string `json:"source_lang_computed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommonJobParams represents common parameters for translation jobs
|
// CommonJobParams represents common parameters for translation jobs
|
||||||
type CommonJobParams struct {
|
type CommonJobParams struct {
|
||||||
|
Formality string `json:"formality"` // Can be "undefined"
|
||||||
|
TranscribeAs string `json:"transcribe_as"`
|
||||||
Mode string `json:"mode"`
|
Mode string `json:"mode"`
|
||||||
|
WasSpoken bool `json:"wasSpoken"`
|
||||||
|
AdvancedMode bool `json:"advancedMode"`
|
||||||
|
TextType string `json:"textType"`
|
||||||
RegionalVariant string `json:"regionalVariant,omitempty"`
|
RegionalVariant string `json:"regionalVariant,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,10 +50,7 @@ type Job struct {
|
|||||||
type Params struct {
|
type Params struct {
|
||||||
CommonJobParams CommonJobParams `json:"commonJobParams"`
|
CommonJobParams CommonJobParams `json:"commonJobParams"`
|
||||||
Lang Lang `json:"lang"`
|
Lang Lang `json:"lang"`
|
||||||
Texts []string `json:"texts,omitempty"`
|
Jobs []Job `json:"jobs"`
|
||||||
TextType string `json:"textType,omitempty"`
|
|
||||||
Jobs []Job `json:"jobs,omitempty"`
|
|
||||||
Priority int `json:"priority,omitempty"`
|
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,25 +62,6 @@ type PostData struct {
|
|||||||
Params Params `json:"params"`
|
Params Params `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitTextResponse represents the response from text splitting
|
|
||||||
type SplitTextResponse struct {
|
|
||||||
Jsonrpc string `json:"jsonrpc"`
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
Result struct {
|
|
||||||
Lang struct {
|
|
||||||
Detected string `json:"detected"`
|
|
||||||
} `json:"lang"`
|
|
||||||
Texts []struct {
|
|
||||||
Chunks []struct {
|
|
||||||
Sentences []struct {
|
|
||||||
Prefix string `json:"prefix"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
} `json:"sentences"`
|
|
||||||
} `json:"chunks"`
|
|
||||||
} `json:"texts"`
|
|
||||||
} `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TranslationResponse represents the response from translation
|
// TranslationResponse represents the response from translation
|
||||||
type TranslationResponse struct {
|
type TranslationResponse struct {
|
||||||
Jsonrpc string `json:"jsonrpc"`
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
@ -86,23 +69,34 @@ type TranslationResponse struct {
|
|||||||
Result struct {
|
Result struct {
|
||||||
Translations []struct {
|
Translations []struct {
|
||||||
Beams []struct {
|
Beams []struct {
|
||||||
Sentences []struct {
|
Sentences []SentenceResponse `json:"sentences"`
|
||||||
Text string `json:"text"`
|
NumSymbols int `json:"num_symbols"`
|
||||||
} `json:"sentences"`
|
RephraseVariant struct { // Added rephrase_variant
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"rephrase_variant"`
|
||||||
} `json:"beams"`
|
} `json:"beams"`
|
||||||
|
Quality string `json:"quality"` // Added quality
|
||||||
} `json:"translations"`
|
} `json:"translations"`
|
||||||
SourceLang string `json:"source_lang"`
|
|
||||||
TargetLang string `json:"target_lang"`
|
TargetLang string `json:"target_lang"`
|
||||||
|
SourceLang string `json:"source_lang"`
|
||||||
|
SourceLangIsConfident bool `json:"source_lang_is_confident"`
|
||||||
|
DetectedLanguages map[string]interface{} `json:"detectedLanguages"` // Use interface{} for now
|
||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SentenceResponse is a helper struct for the response sentences
|
||||||
|
type SentenceResponse struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
IDS []int `json:"ids"` // Added IDS
|
||||||
|
}
|
||||||
|
|
||||||
// DeepLXTranslationResult represents the final translation result
|
// DeepLXTranslationResult represents the final translation result
|
||||||
type DeepLXTranslationResult struct {
|
type DeepLXTranslationResult struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"` // The primary translated text
|
||||||
Alternatives []string `json:"alternatives"`
|
Alternatives []string `json:"alternatives"` // Other possible translations
|
||||||
SourceLang string `json:"source_lang"`
|
SourceLang string `json:"source_lang"`
|
||||||
TargetLang string `json:"target_lang"`
|
TargetLang string `json:"target_lang"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
|
Loading…
Reference in New Issue
Block a user