阿里云原画播放

在画质选项中加入原画播放选项,使用potplayer播放阿里云盘原画视频(需要安装potplayer插件)https://github.com/gene9831/AliyunDrivePotPlayer。【提示】抓的接口限制增加,账号可能被风控限速,请酌情使用

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name              阿里云原画播放
// @version           1.1.3
// @author            Author Moe
// @date              2023-03-04
// @description       在画质选项中加入原画播放选项,使用potplayer播放阿里云盘原画视频(需要安装potplayer插件)https://github.com/gene9831/AliyunDrivePotPlayer。【提示】抓的接口限制增加,账号可能被风控限速,请酌情使用
// @license           AGPL-3.0-or-later
// @match             *://www.aliyundrive.com/s/*
// @match             *://www.aliyundrive.com/drive*
// @require           https://unpkg.com/jquery@3.6.0/dist/jquery.min.js
// @require           https://unpkg.com/bn.js@4.11.8/lib/bn.js
// @require           https://unpkg.com/@lionello/secp256k1-js@1.1.0/src/secp256k1.js
// @connect           aliyundrive.com
// @connect           localhost
// @connect           *
// @run-at            document-idle
// @grant             unsafeWindow
// @grant             GM_xmlhttpRequest
// @grant             GM_setClipboard
// @grant             GM_setValue
// @grant             GM_getValue
// @grant             GM_openInTab
// @grant             GM_info
// @grant             GM_registerMenuCommand
// @grant             GM_cookie
// @icon              https://gw.alicdn.com/imgextra/i3/O1CN01aj9rdD1GS0E8io11t_!!6000000000620-73-tps-16-16.ico
// @namespace https://greasyfork.org/users/1026976
// ==/UserScript==

(function () {
    'use strict';
    let g_drive_id = "", g_file_id = "", g_file_name = "", g_share_id = "";
    let privateKey = "", publicKey = "";
    let app_id = "", device_id = "",user_id = "";
    let signature = "";
    let headers={};
    let api_url = {
            "0": "https://api.aliyundrive.com/v2/file/get_share_link_download_url",
            "1": "https://api.aliyundrive.com/v2/file/get_download_url"
        };


    let main = {

        isType(obj) {
            return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
        },

        post(url, data, headers, type) {
            if (this.isType(data) === 'object') {
                data = JSON.stringify(data);
            }
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "POST", url, headers, data,
                    responseType: type || 'json',
                    onload: (res) => {
                        type === 'blob' ? resolve(res) : resolve(res.response || res.responseText);
                    },
                    onerror: (err) => {
                        reject(err);
                    },
                });
            });
        },

        getStorage(key) {
            try {
                return JSON.parse(localStorage.getItem(key));
            } catch (e) {
                return localStorage.getItem(key);
            }
        },

        async getRealLink(d, f) {
            let res = await this.post(api_url[1], {
                drive_id: d,
                file_id: f
            }, headers);
            //console.log("getRealLink", d,f,res);
            if (res.url) {
                return res.url;
            }
            return '';
        },

        async getPCSLink(f, s){
            try {
                let authorization = `${this.getStorage('token').token_type} ${this.getStorage('token').access_token}`;
                let xShareToken = this.getStorage('shareToken').share_token;
                let res = await this.post(api_url[0], {
                    expire_sec: 600,
                    file_id: g_file_id,
                    share_id: g_share_id
                }, {
                    authorization,
                    "content-type": "application/json;charset=utf-8",
                    "x-share-token": xShareToken
                });
                if (res.download_url) {
                    return res.download_url;
                }
            } catch (e) {
                //console.log('提示:请先登录网盘!');
            }
        },


        initDefaultConfig() {
            let value = [{
                name: 'url-scheme',
                value: 'potplayer://'
            },];

            value.forEach((v) => {
                GM_getValue(v.name) === undefined && GM_setValue(v.name, v.value);
            });
        },

        async initECDSAKey() {
            let privateKeyBuf = window.crypto.getRandomValues(new Uint8Array(32));
            privateKey = Secp256k1.uint256(privateKeyBuf, 16);
            publicKey = Secp256k1.generatePublicKeyFromPrivateKeyData(privateKey);
            publicKey = "04" + publicKey.x + publicKey.y;
            app_id = "5dde4e1bdf9e4966b387ba58f4b3fdc3";
            device_id = this.getStorage('token').device_id;
            user_id = this.getStorage('token').user_id;
            console.log("initECDSAKey",privateKeyBuf);
            let nonce = 0;
            //sign
            let text = `${app_id}:${device_id}:${user_id}:${nonce}`;
            let encoder = new TextEncoder();
            let data = encoder.encode(text);
            let hashBuffer = await crypto.subtle.digest('SHA-256', data);
            //hashBuffer to uint8 array
            hashBuffer = new Uint8Array(hashBuffer);
            console.log("hashBuffer",hashBuffer);
            let sig = Secp256k1.ecsign(privateKey, Secp256k1.uint256(hashBuffer, 16));
            signature = sig.r + sig.s + "01";
            headers = {
                "content-type": "application/json;charset=utf-8",
                "authorization": `${this.getStorage('token').token_type} ${this.getStorage('token').access_token}`,
                "origin": "https://www.aliyundrive.com",
                "referer": "https://www.aliyundrive.com/",
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.41",
                "x-canary": "client=web,app=adrive,version=v3.17.0",
                "x-device-id": device_id,
                "x-signature": signature,
            }
            //create session
            const req = await fetch('https://api.aliyundrive.com/users/v1/users/device/create_session', {
                method: 'POST',
                body: JSON.stringify({ "deviceName": "Edge浏览器", "modelName": "Windows网页版", "pubKey": publicKey }),
                headers: headers
            });
            const res = await req.json();
            console.log("create session",res);
        },

        init() {
            main.initDefaultConfig();
            main.initECDSAKey();
            //识别页面类型
            let sharepage=window.location.href.indexOf("s/")>0;
            //劫持XMLHttpRequest
            var send = XMLHttpRequest.prototype.send;
            XMLHttpRequest.prototype.send = function (data) {
                let url = this.openParams ? this.openParams[1] : this.responseURL;
                //console.log("aopsend",data)
                if (url.indexOf("/file/get_video_preview_play_info") > 0) {
                    //console.log("inject",data)
                    g_drive_id = JSON.parse(data).drive_id;
                    g_file_id = JSON.parse(data).file_id;
                    g_share_id = JSON.parse(data).share_id;
                    if (sharepage) {
                        g_file_name = document.getElementsByClassName("header-file-name--CN_fq")[0].textContent;
                    }
                    else {
                        g_file_name = document.getElementsByClassName("text--2KGvI")[0].textContent;
                    }
                    //console.log("got:", url, g_drive_id, g_file_id, g_file_name);

                    //循环检测dom创建,添加按钮
                    let ins = setInterval(() => {
                        let quality = document.getElementsByClassName("drawer-list--JYzyI");
                        if (quality.length > 0) {
                            if (sharepage) {
                                quality[0].innerHTML += `<li class="drawer-item--2cNtQ original-video-play" data-is-current="false">
                                            <div class="text--AMJbu">原画下载</div>
                                        </li>`;
                                let play_button = document.getElementsByClassName("original-video-play")[0];
                                play_button.addEventListener("click", async function () {
                                    let url = await main.getPCSLink(g_file_id, g_share_id);
                                    let d = document.createElement("a");
                                    d.download = g_file_name;
                                    d.rel = "noopener";
                                    d.href = url;
                                    d.dispatchEvent(new MouseEvent("click"));
                                });
                            }
                            else {
                                quality[2].innerHTML += `<li class="drawer-item--2cNtQ original-video-play" data-is-current="false">
                                            <div class="text--AMJbu">原画播放</div>
                                        </li>`;
                                let play_button = document.getElementsByClassName("original-video-play")[0];
                                play_button.addEventListener("click", async function () {
                                    let url = await main.getRealLink(g_drive_id, g_file_id);
                                    let scheme = GM_getValue('url-scheme');
                                    url = scheme + url;
                                    let d = document.createElement("a");
                                    d.download = g_file_name;
                                    d.rel = "noopener";
                                    d.href = url;
                                    d.dispatchEvent(new MouseEvent("click"));
                                });
                            }
                            clearInterval(ins);
                        }
                    }, 50);

                }

                send.apply(this, arguments);
            };
        }
    };
    main.init();
})();