Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Youdao Translate Error: 50 #65

Closed

Conversation

rea1shane
Copy link

最近在调用翻译的时候会收到报错 Youdao Translate Error: 50,虽然可以正常得到结果,但是有报错看起来还是不太舒服。

image

搜索了下貌似是个反扒相关的报错,根据 https://fishc.com.cn/forum.php?mod=redirect&goto=findpost&ptid=106575&pid=3248429 给出的方案修复。我也不清楚这是否是最佳的解决方案。如果有更好的解决方案的话还请指出。

注意!因为不熟悉 Raycast 插件开发所以 没有验证过该 PR 是否可用,有劳大佬验证一下是否解决了问题。

感谢大佬及这个插件。

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello rea1shane, Thank you for your first PR contribution 🎉 rea1shane

@rea1shane
Copy link
Author

搜索了下貌似是个反扒相关的报错,根据 https://fishc.com.cn/forum.php?mod=redirect&goto=findpost&ptid=106575&pid=3248429 给出的方案修复。我也不清楚这是否是最佳的解决方案。如果有更好的解决方案的话还请指出。

这个错误是最近才出现的,但是解决方案是几年前的,我觉得可能是有道近期更新了什么请求策略导致的该错误,和之前的情况可能不太一样,所以我怀疑链接中的方案可能不是该问题的最佳解决方案。

@tisfeng
Copy link
Owner

tisfeng commented Jan 4, 2025

ok,感谢 PR,稍后我看一下。

@tisfeng
Copy link
Owner

tisfeng commented Jan 4, 2025

试了一下新的接口,不行,这个接口恐怕已经废弃了,毕竟过了好几年了。

最终可能还是要用有道翻译的最新 web 端接口 webtranslate,这个我已经用 Swift 写过一遍了,目前没什么问题。

@rea1shane 如果你会写 TS,可以帮忙用 TS 实现这里的 有道翻译接口 吗?

@rea1shane
Copy link
Author

我不会 TS,用两种 AI 翻译了下代码,你看看可用么?

翻译的是 L46L717-L794

Claude 3.5 Sonnet:

import CryptoJS from 'crypto-js';

// Type definitions
interface RequestOptions {
    method: string;
    url: string;
    data?: string;
    headers?: Record<string, string>;
    anonymous?: boolean;
}

interface TranslateParams {
    keyid: string;
    client: string;
    product: string;
    appVersion: string;
    vendor: string;
    pointParam: string;
    mysticTime: string;
    keyfrom: string;
    sign: string;
    i?: string;
    from?: string;
    to?: string;
    dictResult?: string;
}

interface TranslateResponse {
    translateResult: Array<Array<{ tgt: string }>>;
}

// Declare external functions/variables that aren't defined in the code
declare function Request(options: RequestOptions): Promise<any>;
declare function BaseTranslate(
    service: string,
    raw: string,
    options: RequestOptions,
    responseHandler: (response: any) => string
): Promise<string>;

const sessionStorage = window.sessionStorage;

async function translate_youdao_startup(): Promise<void> {
    if (sessionStorage.getItem('youdao_key')) return;
    
    const ts: string = String(new Date().getTime());
    const params: TranslateParams = {
        keyid: "webfanyi-key-getter",
        client: "fanyideskweb",
        product: "webfanyi",
        appVersion: "1.0.0",
        vendor: "web",
        pointParam: "client,mysticTime,product",
        mysticTime: ts,
        keyfrom: "fanyi.web",
        sign: CryptoJS.MD5(`client=fanyideskweb&mysticTime=${ts}&product=webfanyi&key=asdjnjfenknafdfsdfsd`).toString()
    };

    const options: RequestOptions = {
        method: "GET",
        url: `https://dict.youdao.com/webtranslate/key?${Object.entries(params).map(item => item.join('=')).join('&')}`,
        headers: {
            "Origin": "https://fanyi.youdao.com"
        }
    };

    const res = await Request(options);
    const responseData: { data: { secretKey: string } } = JSON.parse(res.responseText);
    sessionStorage.setItem('youdao_key', responseData.data.secretKey);
}

async function translate_youdao(raw: string): Promise<string> {
    const ts: string = String(new Date().getTime());
    const params: TranslateParams = {
        i: encodeURIComponent(raw),
        from: 'auto',
        to: '',
        dictResult: 'true',
        keyid: "webfanyi",
        client: "fanyideskweb",
        product: "webfanyi",
        appVersion: "1.0.0",
        vendor: "web",
        pointParam: "client,mysticTime,product",
        mysticTime: ts,
        keyfrom: "fanyi.web",
        sign: CryptoJS.MD5(`client=fanyideskweb&mysticTime=${ts}&product=webfanyi&key=${sessionStorage.getItem('youdao_key')}`).toString()
    };

    const options: RequestOptions = {
        method: "POST",
        url: 'https://dict.youdao.com/webtranslate',
        data: Object.entries(params).map(item => item.join('=')).join('&'),
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
            "Referer": "https://fanyi.youdao.com/",
            "Origin": "https://fanyi.youdao.com",
            "Host": "dict.youdao.com",
            "Cookie": "[email protected]"
        },
        anonymous: true,
    };

    const res = await Request(options);
    const decrypted = A(res);
    console.log(decrypted);

    return await BaseTranslate(
        '有道翻译',
        raw,
        options,
        (res) => JSON.parse(A(res)).translateResult.map((e: Array<{ tgt: string }>) => 
            e.map(t => t.tgt).join('')
        ).join('\n')
    );
}

function m(e: string): string {
    return CryptoJS.MD5(e).toString(CryptoJS.enc.Hex);
}

function A(t: string, o?: string, n?: string): string | null {
    o = "ydsecret://query/key/BRGygVywfNBwpmBaZgWT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl";
    n = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4";
    
    if (!t) return null;
    
    const a = CryptoJS.enc.Hex.parse(m(o));
    const r = CryptoJS.enc.Hex.parse(m(n));
    const i = CryptoJS.AES.decrypt(t, a, {
        iv: r
    });
    
    return i.toString(CryptoJS.enc.Utf8);
}

export {
    translate_youdao_startup,
    translate_youdao,
    m,
    A
};

GPT 4o:

// 引入 CryptoJS,如果使用 npm 安装了 crypto-js
import CryptoJS from "crypto-js";

// 类型定义
interface RequestOptions {
    method: string;
    url: string;
    headers: Record<string, string>;
    data?: string;
    anonymous?: boolean;
}

// 提供 Request 和 BaseTranslate 函数的声明
declare function BaseTranslate(
    service: string,
    raw: string,
    options: RequestOptions,
    callback: (res: any) => string
): Promise<string>;

declare function Request(options: RequestOptions): Promise<{ responseText: string }>;

const sessionStorage = window.sessionStorage;

async function translateYoudaoStartup(): Promise<void> {
    if (sessionStorage.getItem('youdao_key')) return;
    const ts = "" + new Date().getTime();
    const params = {
        keyid: "webfanyi-key-getter",
        client: "fanyideskweb",
        product: "webfanyi",
        appVersion: "1.0.0",
        vendor: "web",
        pointParam: "client,mysticTime,product",
        mysticTime: ts,
        keyfrom: "fanyi.web",
        sign: CryptoJS.MD5(`client=fanyideskweb&mysticTime=${ts}&product=webfanyi&key=asdjnjfenknafdfsdfsd`).toString(),
    };
    const options = {
        method: "GET",
        url: `https://dict.youdao.com/webtranslate/key?${Object.entries(params).map(item => item.join('=')).join('&')}`,
        headers: {
            "Origin": "https://fanyi.youdao.com",
        },
    };
    const res = await Request(options);
    sessionStorage.setItem('youdao_key', JSON.parse(res.responseText).data.secretKey);
}

async function translateYoudao(raw: string): Promise<string> {
    const ts = "" + new Date().getTime();
    const youdaoKey = sessionStorage.getItem('youdao_key') || '';
    const params = {
        i: encodeURIComponent(raw),
        from: 'auto',
        to: '',
        dictResult: 'true',
        keyid: "webfanyi",
        client: "fanyideskweb",
        product: "webfanyi",
        appVersion: "1.0.0",
        vendor: "web",
        pointParam: "client,mysticTime,product",
        mysticTime: ts,
        keyfrom: "fanyi.web",
        sign: CryptoJS.MD5(`client=fanyideskweb&mysticTime=${ts}&product=webfanyi&key=${youdaoKey}`).toString(),
    };
    const options = {
        method: "POST",
        url: 'https://dict.youdao.com/webtranslate',
        data: Object.entries(params).map(item => item.join('=')).join('&'),
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
            "Referer": "https://fanyi.youdao.com/",
            "Origin": "https://fanyi.youdao.com",
            "Host": "dict.youdao.com",
            "Cookie": "[email protected]",
        },
        anonymous: true,
    };
    const res = await Request(options);
    const decrypted = A(res);
    console.log(decrypted);
    return await BaseTranslate('有道翻译', raw, options, res => 
        JSON.parse(A(res)).translateResult.map((e: any) => e.map((t: any) => t.tgt).join('')).join('\n')
    );
}

function m(e: string): string {
    return CryptoJS.MD5(e).toString(CryptoJS.enc.Hex);
}

function A(t: string, o?: string, n?: string): string | null {
    o = "ydsecret://query/key/BRGygVywfNBwpmBaZgWT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl";
    n = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4";
    if (!t) return null;
    const a = CryptoJS.enc.Hex.parse(m(o)),
        r = CryptoJS.enc.Hex.parse(m(n)),
        i = CryptoJS.AES.decrypt(t, a, { iv: r });
    return i.toString(CryptoJS.enc.Utf8);
}

@tisfeng
Copy link
Owner

tisfeng commented Jan 5, 2025

行,稍后我试一下这个代码,用 AI 辅助编程确实省力不少,我也在用 😌

@tisfeng tisfeng mentioned this pull request Jan 12, 2025
@tisfeng
Copy link
Owner

tisfeng commented Jan 12, 2025

我已经实现了新的有道翻译接口 #66 ,这个 PR 就关闭了。

@rea1shane
Copy link
Author

发现了一个这次更新带来的新的问题:

截屏2025-01-15 15 22 28

貌似还有一个问题,是提示 object object 之类的错误信息(大概吧,没看清),不知道如何复现。

上班还有任务不方便查问题,有空我会查看一下的,也麻烦大佬关注下。

@rea1shane
Copy link
Author

貌似还有一个问题,是提示 object object 之类的错误信息(大概吧,没看清),不知道如何复现。

截屏2025-01-15 16 00 58

问题捕捉到了,但是不太能稳定复现。

2025-01-15.16.05.50.mov

@tisfeng
Copy link
Owner

tisfeng commented Jan 19, 2025

ok,稍后我看看。

@tisfeng
Copy link
Owner

tisfeng commented Jan 22, 2025

我尝试了一下,似乎不能复现这个错误,不知道是不是有道接口波动问题。

你再尝试看看,看是否能稳定复现问题。

@rea1shane
Copy link
Author

我尝试了一下,似乎不能复现这个错误,不知道是不是有道接口波动问题。

你再尝试看看,看是否能稳定复现问题。

问题一是稳定复现的,翻译 ConfigurationSnippet 即可。

问题二我这台电脑不能复现,明天换发现问题的电脑再试试。

@rea1shane
Copy link
Author

问题二我这台电脑不能复现,明天换发现问题的电脑再试试。

问题二在我发现该问题的电脑上可以较为稳定地复现(就像视频中表现的一样),在另一台电脑上无法复现。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants