Greasy Fork

Greasy Fork is available in English.

阿里云盘标清替换成最高画质

通过阿里云盘开放平台将原标清替换成最高画质(支持分享链接),打开视频自动播放,视频前进后退5秒,更多倍速播放以及记忆倍速,视频下载,自动跳过片头片尾,播放器工具栏置底并设置透明度,播放历史记录,字幕颜色设置,上传本地字幕(vtt,srt,ass),WebDav同步配置信息,键盘快捷键:home上一集,end下一集,enter全屏,鼠标快捷键:双击:暂停/播放,中键:全屏,滚轮:音量加减

当前为 2024-05-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         阿里云盘标清替换成最高画质
// @namespace    http://tampermonkey.net/
// @version      1.1.6
// @description  通过阿里云盘开放平台将原标清替换成最高画质(支持分享链接),打开视频自动播放,视频前进后退5秒,更多倍速播放以及记忆倍速,视频下载,自动跳过片头片尾,播放器工具栏置底并设置透明度,播放历史记录,字幕颜色设置,上传本地字幕(vtt,srt,ass),WebDav同步配置信息,键盘快捷键:home上一集,end下一集,enter全屏,鼠标快捷键:双击:暂停/播放,中键:全屏,滚轮:音量加减
// @author       bygavin
// @match        https://www.aliyundrive.com/*
// @match        https://www.alipan.com/*
// @icon         https://img.alicdn.com/imgextra/i1/O1CN01JDQCi21Dc8EfbRwvF_!!6000000000236-73-tps-64-64.ico
// @license      MIT
// @grant        unsafeWindow
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// ==/UserScript==

var openapiclient_id = GM_getValue('openapiclient_id') || '55091393987b4cc090b090ee17e85e0a'
var wdusername = GM_getValue('webdav_user')
var wdpassword = GM_getValue('webdav_pwd')
var wdurl = GM_getValue('webdav_url')
var authHeader = 'Basic ' + btoa(wdusername + ':' + wdpassword);
var newurl, sdlurl, isfullscreen, sinfo, openapicode_verifier, observer, storedBlob, savedevice_id, playinfo
var vtthearder = 'WEBVTT\n0:00:00.000 --> 0:00:01.500\n<b>脚本制作人:bygavin(星峰)</b>\n'
var oldxhr = unsafeWindow.XMLHttpRequest
var oldfetch = unsafeWindow.fetch
function newobj() { }
if (openapiclient_id) {
        (function (send) {
        unsafeWindow.XMLHttpRequest.prototype.send = function (sendParams) {
            const sendurl = this.__recordInfo__.url
            if (sendurl.indexOf("/file/list") > 0 || sendurl.indexOf("/file/search") > 0 || sendurl.indexOf("/file/list_by_share") > 0) {
                const oldargument = JSON.parse(sendParams)
                oldargument.limit = 200
                if (sendurl.indexOf("/file/list_by_share") <= 0)
                    savedevice_id = oldargument?.drive_id
                arguments[0] = JSON.stringify(oldargument);
            }
            send.apply(this, arguments);
        };
    })(unsafeWindow.XMLHttpRequest.prototype.send);
            unsafeWindow.XMLHttpRequest = function () {
        let tagetobk = new newobj();
        tagetobk.oldxhr = new oldxhr();
        let handle = {
            get: function (target, prop) {
                if (prop === 'oldxhr')
                    return Reflect.get(target, prop);
                if (typeof Reflect.get(target.oldxhr, prop) === 'function') {
                    if (Reflect.get(target.oldxhr, prop + 'proxy') === undefined) {
                        target.oldxhr[prop + 'proxy'] = new Proxy(Reflect.get(target.oldxhr, prop), {
                            apply: function (target, thisArg, argumentsList) {
                                return Reflect.apply(target, thisArg.oldxhr, argumentsList);
                            }
                        });
                    }
                    return Reflect.get(target.oldxhr, prop + 'proxy')
                }
                const responseURL = target.oldxhr.responseURL
                const lpfn = localStorage.getItem('last_play_file_name')?.split('›').pop()
                if (responseURL.indexOf("/file/get_video_preview_play_info") > 0 && prop.indexOf('response') !== -1) {
                    const isshare = responseURL.indexOf("/file/get_video_preview_play_info_by_share") > 0
                    const response = target.oldxhr?.response || target.oldxhr?.responseText
                    var res = JSON.parse(response);
                    const tasklist = res?.video_preview_play_info?.live_transcoding_task_list
                    if (!lpfn) {
                        const share_token = target.oldxhr.__reqCtx__.headers["x-share-token"]
                        sinfo = { share_token: share_token, file_id: res.file_id }
                        sdlurl = ''
                        newurl = getsetnewurl(res.file_id)
                        if (newurl) {
                            newurl.length > 1 && (sdlurl = newurl[1])
                            newurl = newurl[0]
                        }
                        else {
                            if (isshare) {
                                const saveinfo = savefile(res.file_id, share_token).responses[0].body
                                newurl = getVideoPreviewPlayInfo(saveinfo.drive_id, saveinfo.file_id)
                                deletefile(saveinfo.file_id)
                            }
                            else
                                newurl = getVideoPreviewPlayInfo(res.drive_id, res.file_id)
                            newurl && getsetnewurl(res.file_id, [newurl])
                        }
                        newurl && (tasklist[isshare ? 1 : 0].url = newurl)
                        createVttBlob(res)
                        res = JSON.stringify(res);
                        if (newurl)
                            return res;
                    }
                    else {
                        sdlurl = ''
                        newurl = tasklist[isshare ? 1 : 0].url
                        return response;
                    }
                }
                else if (responseURL.indexOf("/file/get_video_preview_play_info") > 0 && prop === "statusText")
                    morerate()
                else if ((responseURL.indexOf("/file/list") > 0 || responseURL.indexOf("/file/list_by_share") > 0) && prop === "statusText" && lpfn && observer === undefined) {
                    observer = new MutationObserver(function () {
                        const target = document.querySelector('.text-primary--JzAb9')
                        if (target) {
                            observer.disconnect();
                            const lastvideo = document.querySelector('.text-primary--JzAb9[title="' + lpfn + '"]');
                            if (lastvideo) {
                                lastvideo.click()
                                localStorage.removeItem('last_play_file_name')
                            }
                            else {
                                const anyvideo = document.querySelector('img[alt="video"]')
                                if (anyvideo)
                                    anyvideo.click()
                                else
                                    localStorage.removeItem('last_play_file_name')
                            }
                        }
                    });
                    observer.observe(document, { childList: true, subtree: true });
                }
                return Reflect.get(target.oldxhr, prop);
            },
            set(target, prop, value) {
                return Reflect.set(target.oldxhr, prop, value);
            },
            has(target, key) {
                return Reflect.has(target.oldxhr, key);
            }
        }
        return new Proxy(tagetobk, handle);
    }
            unsafeWindow.fetch = function (...bianliang) {
        return new Promise(function (resolve) {
            oldfetch(...bianliang).then(function (response) {
                let handler = {
                    get: function (target, prop) {
                        if (typeof Reflect.get(target, prop) === 'function') {
                            if (Reflect.get(target, prop + 'proxy') === undefined) {
                                target[prop + 'proxy'] = (...funcargs) => {
                                    let result = target[prop].call(target, ...funcargs)
                                    if (bianliang.length > 0 && prop === 'blob' && bianliang[0].startsWith('blob')) {
                                        return new Promise(function (resolve) {
                                            result.then(
                                                function (data) {
                                                    if (bianliang[0].endsWith('#bygavin') && storedBlob) {
                                                        const blob = new Blob([storedBlob], { type: 'application/octet-stream;charset=utf-8;' });
                                                        resolve(blob);
                                                    }
                                                    else
                                                        resolve(data)
                                                }
                                            )
                                        });
                                    }
                                    return result
                                }
                            }
                            return Reflect.get(target, prop + 'proxy')
                        }
                        return Reflect.get(target, prop);
                    },
                    set(target, prop, value) {
                        return Reflect.set(target, prop, value);
                    },
                };
                resolve(new Proxy(response, handler))
            })
        });
    }
    }


function getVideoPreviewPlayInfo(drive_id, file_id) {
    const access_token = getopenapitoken();
    var xhr = new oldxhr();
    xhr.open("POST", "https://openapi.aliyundrive.com/adrive/v1.0/openFile/getVideoPreviewPlayInfo", false);
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.setRequestHeader("Authorization", access_token);
    xhr.send(JSON.stringify({ "drive_id": drive_id, "file_id": file_id, "category": "live_transcoding", "url_expire_sec": 14400 }));
    return xhr.status === 200 ? JSON.parse(xhr.responseText).video_preview_play_info?.live_transcoding_task_list.pop().url : xhr.statusText;
}
function getDownloadUrl(drive_id, file_id) {
    const access_token = getopenapitoken();
    var xhr = new oldxhr();
    xhr.open("POST", "https://openapi.aliyundrive.com/adrive/v1.0/openFile/getDownloadUrl", false);
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.setRequestHeader("Authorization", access_token);
    xhr.send(JSON.stringify({ "drive_id": drive_id, "file_id": file_id, "expire_sec": 14400 }));
    return xhr.status === 200 ? JSON.parse(xhr.responseText).url : xhr.statusText;
}
function savefile(sharefileid, share_token) {
    const token = JSON.parse(localStorage.getItem('token'))
    const getsaveinfo = GM_getValue('saveinfo');
    let saveinfo = getsaveinfo || {}
    if (getsaveinfo && typeof getsaveinfo === "string") {
        saveinfo = JSON.parse(getsaveinfo)
        NewGM_setValue('saveinfo', saveinfo)
    }
    const shareid = location.pathname.split('/')[2]
    const savedata = { "requests": [{ "body": { "file_id": sharefileid, "share_id": shareid, "auto_rename": true, "to_parent_file_id": saveinfo?.savefile_id || 'root', "to_drive_id": saveinfo?.savedevice_id || token.default_drive_id }, "headers": { "Content-Type": "application/json" }, "id": "0", "method": "POST", "url": "/file/copy" }], "resource": "file" }
    var xhr = new oldxhr();
    xhr.open("POST", "https://api.aliyundrive.com/adrive/v3/batch", false);
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.setRequestHeader("Authorization", token.access_token);
    xhr.setRequestHeader("X-Share-Token", share_token);
    xhr.send(JSON.stringify(savedata));
    return xhr.status === 200 ? JSON.parse(xhr.responseText) : xhr.statusText;
}
function deletefile(file_id) {
    const token = JSON.parse(localStorage.getItem('token'))
    const saveinfo = GM_getValue('saveinfo') || {}
    const deleteinfo = { "requests": [{ "body": { "drive_id": saveinfo?.savedevice_id || token.default_drive_id, "file_id": file_id }, "headers": { "Content-Type": "application/json" }, "id": file_id, "method": "POST", "url": "/file/delete" }], "resource": "file" }
    var xhr = new oldxhr();
    xhr.open("POST", "https://api.aliyundrive.com/adrive/v3/batch", false);
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.setRequestHeader("Authorization", token.access_token);
    xhr.send(JSON.stringify(deleteinfo));
    return xhr.status === 200 ? JSON.parse(xhr.responseText) : xhr.statusText;
}
function getopenapicode() {
    openapicode_verifier = new Date().getTime();
    const accesstk = JSON.parse(localStorage.getItem('token')).access_token
    var xhr = new oldxhr();
    var url = 'https://open.aliyundrive.com/oauth/users/authorize';
    var data = { scope: 'user:base,file:all:read,file:all:write', authorize: 1, drives: ['backup', 'resource'] };
    var params = '?client_id=' + openapiclient_id + '&redirect_uri=oob&scope=user:base,file:all:read,file:all:write&code_challenge=' + openapicode_verifier + '&code_challenge_method=plain';
    xhr.open('POST', url + params, false);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.setRequestHeader('authorization', 'Bearer ' + accesstk);
    xhr.send(JSON.stringify(data));
    return xhr.status === 200 ? JSON.parse(xhr.responseText).redirectUri.split('=')[1] : xhr.statusText;
}
function getopenapitoken() {
    const nowtime = new Date().getTime();
    const openapitoken = GM_getValue('openapitoken') || {}
    if (openapitoken?.access_token) {
        if (openapitoken.createdate + openapitoken.expires_in > nowtime) {
            return openapitoken.access_token
        }
    }
    const openapicode = getopenapicode()
    var xhr = new oldxhr();
    var url = 'https://openapi.aliyundrive.com/oauth/access_token';
    var data = { client_id: openapiclient_id, grant_type: 'authorization_code', code: openapicode, code_verifier: openapicode_verifier }
    xhr.open('POST', url, false);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.send(JSON.stringify(data));
    if (xhr.status === 200) {
        const tokejson = JSON.parse(xhr.responseText)
        tokejson.createdate = nowtime
        NewGM_setValue('openapitoken', tokejson)
        return tokejson.access_token;
    } else
        return (xhr.statusText);
}
function createVttBlob(json) {
    const blob = new Blob([vtthearder], { type: 'application/octet-stream;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    let sublist = json.video_preview_play_info?.live_transcoding_subtitle_task_list || []
    if (sublist.length > 0) {
        const newsublist = []
        var xhr = new oldxhr();
        sublist.forEach(function (item) {
            xhr.open('GET', item.url, false);
            xhr.send();
            if (xhr.status === 200) {
                const subvalue = xhr.responseText
                if (subvalue.length > 1000) {
                    const newblob = new Blob([subvalue.replace('WEBVTT', vtthearder)], { type: 'application/octet-stream;charset=utf-8;' });
                    item.url = URL.createObjectURL(newblob) + "#byweb";
                    newsublist.push(item)
                }
            }
        })
        sublist = newsublist
    }
    sublist.push({ "status": "finished", url: url + "#bygavin" })
    json.video_preview_play_info.live_transcoding_subtitle_task_list = sublist
}
function NewGM_setValue(key, value) {
    GM_setValue('timestamp', new Date().getTime())
    GM_setValue(key, value)
}
unsafeWindow.addEventListener('beforeunload', updateConfigIfNecessary)
function addkeyboardevent(e) {
    const videoElement = document.querySelector('video')
    var isvideo = true
    let volume = parseInt(videoElement.volume * 100)
    const volumeflag = volume < 6 ? 1 : volume < 33 ? 5 : 10
    if (e && e.key === 'ArrowLeft')
        videoElement.currentTime -= 5;
    else if (e && e.key === 'ArrowRight')
        videoElement.currentTime += 5;
    else if (e && e.key === 'ArrowUp')
        volume += volumeflag;
    else if (e && e.key === 'ArrowDown')
        volume -= volumeflag;
    else
        isvideo = false
    videoElement.volume = (volume > 100 ? 100 : volume < 0 ? 0 : volume) / 100
    return isvideo
}
document.addEventListener('keydown', function (e) {
    const videoElement = document.querySelector('video')
    if (videoElement) {
        if (e.key === 'Home' || e.key === 'End')
            changevideo(e.key === 'Home' ? -1 : 1)
        else if (e.key === 'Enter')
            document.querySelector('.action--HeWYA:not([data-active])').click()
        addkeyboardevent(e)
    }
    if (e.altKey && e.code == 'KeyS') {
        if (savedevice_id) {
            const savefile_id = this.location.pathname.split('/')[4] || 'root'
            if (confirm("确定设置此目录为临时转存目录"))
                NewGM_setValue("saveinfo", { savedevice_id: savedevice_id, savefile_id: savefile_id })
        }
    }
    else if (e.altKey && e.code == 'KeyD') {
        var userInput = prompt("输入阿里云盘开放平台的client_id");
        if (userInput !== null) {
            NewGM_setValue('openapiclient_id', userInput)
            openapiclient_id = userInput;
            NewGM_setValue('openapitoken', null)
        }
    }
});
document.addEventListener('wheel', function (event) {
    const videoElement = document.querySelector('video')
    if (event.target === videoElement) {
        let volume = parseInt(videoElement.volume * 100)
        const volumeflag = volume < 6 ? 1 : volume < 33 ? 5 : 10
        volume += volumeflag * (event.deltaY > 0 ? -1 : 1);
        videoElement.volume = (volume > 100 ? 100 : volume < 0 ? 0 : volume) / 100
    }
    else if (event.target.tagName === "INPUT" && event.target.type === "time") {
        const times = event.target.value.split(':')
        const maxtimes = event.target.max.split(':')
        const changeindex = event.offsetX > 30 ? 2 : 1
        let newvalue = parseInt(times[changeindex]) + (event.deltaY > 0 ? -1 : 1)
        let maxvalue = parseInt(maxtimes[changeindex])
        newvalue > maxvalue && (newvalue = 0)
        newvalue < 0 && (newvalue = maxvalue)
        times[changeindex] = ("0" + (newvalue)).slice(-2);
        event.target.value = times.join(':')
    }
})
function morerate() {
    storedBlob = null
    let playbackRate = GM_getValue("playbackRate") || 1
    let video = document.querySelector("video");
    if (video) {
        video.onplay = function () {
            video.playbackRate = playbackRate
            video.volume = GM_getValue('volume') || 1
            if (video.volume < 1) {
                video.volume += .01
                video.volume -= .01
            }
            setTimeout(() => {
                const allsubel = document.querySelectorAll('.meta--iPZhB')
                const subInput = allsubel[allsubel.length - 1]
                subInput.querySelector('.text--G8ymN').textContent = '本地外挂字幕'
                subInput.querySelector('.text--G8ymN').title = '本地外挂字幕'
            }, 0)
            playing();
        };
    }
    const ul = document.querySelector('div[class^="drawer-list-grid"]')
    if (!ul || !video)
        return
    else if (document.querySelector('.btndownload'))
        return
    addsubcolor();
    adddownloadbut();
    setfullscreen();
    video.addEventListener('dblclick', function () {
        document.querySelector('.video-player--k1J-M .btn--UrTVT').click()
    });
    video.addEventListener('mousedown', function (event) {
        event.button === 1 && document.querySelector('.action--HeWYA:not([data-active])').click()
    });
    video.addEventListener('volumechange', function () {
        NewGM_setValue('volume', video.volume)
        const volume = video.volume * 100
        let volumelevel = parseInt((volume - 2) / 33) + 1
        volumelevel = volume == 0 ? 0 : volumelevel
        Array.from(document.querySelectorAll('.current--Dbz2w.current--0tS5B')).pop().style.width = volume + '%'
        Array.from(document.querySelectorAll('.indicator--oPSic.indicator--qlLq-')).pop().style = `left: ${volume}%; transform: translate(-${volume}%, -50%);`
        Array.from(document.querySelectorAll('.icon--EkKaB.icon--D3kMk use')).pop().setAttribute('xlink:href', '#PDSvolume' + volumelevel)
    })
    video.parentElement.parentElement.removeEventListener('keydown', null);
    video.parentElement.parentElement.addEventListener('keydown', function (e) {
        if (document.querySelector('.drawers--t3zFN').contains(e.target))
            e.stopPropagation()
        else
            addkeyboardevent(e) && e.stopPropagation()
    })
    document.querySelector('.header-left--Kobd9').removeEventListener('click', updateConfigIfNecessary)
    document.querySelector('.header-left--Kobd9').addEventListener('click', updateConfigIfNecessary)
    const selector = ul.parentElement
    ul.remove()
    selector.innerHTML += `<ul class="drawer-list--qzUDz"><li class="drawer-item--22XTO playbackRate" data-is-current="true"><div class="text--dp1BR"  style="margin:auto">${playbackRate} 倍速</div><span data-role="icon" style="position: absolute;right: 10px;" data-render-as="svg" data-icon-type="PDSCheckmark"class="icon--TBY0u icon--D3kMk "><svg viewBox="0 0 1024 1024"><use xlink:href="#PDSCheckmark"></use></svg></span></li></ul>`
    const ratelist = [0.1, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5, 6, 8, 10, 12, 14, 16]
    let moreratehtml = `<ul class="drawer-list--qzUDz ratemenulist" style="position:absolute;width:100%;top:15px;overflow:hidden;height:111px;padding-top:0px;padding-bottom:0px;display:none"><div style="width:91%;position:absolute;">${[ratelist[ratelist.length - 1], ...ratelist, ratelist[0]].map(ratenub => { return `<li class="drawer-item--22XTO" data-is-current="false"><div class="text--dp1BR" style="margin:auto">${ratenub} 倍速</div></li>` }).join('')}</div></ul><div class="drawer-label--FWKBs" ><span>跳过片头时长</span><div class="media-label-action--PwF31" style="margin:auto;" settype="default" >设置默认</div><span>跳过片尾时长</span><div></div></div><div class="drawer-label--FWKBs setautojump"><div class="media-label-action--PwF31" settype="start" >设置</div><input class="ant-input ant-input-borderless input--TWZaN" type="time" value="${playinfo?.startTime || "00:00:00"}" min="00:00:00" max="00:09:59" step="1" ></input><div class="media-label-action--PwF31" style="margin:auto;" settype="now" >设置播放进度</div><input class="ant-input ant-input-borderless input--TWZaN" type="time" value="${playinfo?.endTime || "00:00:00"}" min="00:00:00" max="00:09:59" step="1"></input><div class="media-label-action--PwF31" settype="end" >设置</div></div>`
    selector.innerHTML += moreratehtml
    const playbr = document.querySelector('.playbackRate')
    const ratemenulist = document.querySelector('.ratemenulist')
    const nowratediv = playbr.querySelector('div')
    playbr.addEventListener('click', (e) => {
        let nowrate = parseFloat(nowratediv.textContent.replace(' 倍速', ''))
        nowratediv.textContent = ' '
        ratemenulist.style.display = 'block'
        const nowrateindex = ratelist.indexOf(nowrate)
        ratemenulist.firstChild.style.top = (nowrateindex * -37) + 'px';
        e.stopPropagation();
    })
    ratemenulist.addEventListener('click', (event) => {
        let newSpeedStr = ''
        if (event.target.tagName === 'LI')
            newSpeedStr = event.target.firstChild.textContent
        else if (event.target.tagName === 'DIV')
            newSpeedStr = event.target.textContent
        playbackRate = parseFloat(newSpeedStr.replace(' 倍速', ''));
        video.playbackRate = playbackRate
        NewGM_setValue("playbackRate", playbackRate)
        nowratediv.textContent = newSpeedStr;
        ratemenulist.style.display = 'none';

    })
    ratemenulist.addEventListener('wheel', function (event) {
        event.preventDefault();
        const flag = (event.deltaY > 0 ? -1 : 1);
        let newtop = parseInt(ratemenulist.firstChild.style.top.replace('px', '')) + flag * 37
        let mintop = -37 * (ratelist.length - 1)
        if (newtop > 0)
            newtop = mintop
        if (newtop < mintop)
            newtop = 0
        ratemenulist.firstChild.style.top = newtop + 'px';
    });
    selector.addEventListener("click", (event) => {
        const target = event.target
        const classList = target.classList
        if (!target.classList.contains('playbackRate')) {
            ratemenulist.style.display = 'none';
            nowratediv.textContent = playbackRate + ' 倍速';
        }
        if (classList.contains('media-label-action--PwF31')) {
            let buttype = target.getAttribute('settype')
            const timetxts = document.querySelectorAll('input[type="time"]')
            let t = ''
            const playhistory = GM_getValue('playhistory') || []
            const file_path = location.pathname
            const index = playhistory.findIndex(item => item.file_path === file_path)
            playinfo = index === -1 ? { file_path: file_path } : playhistory[index]
            if (buttype === 'default') {
                const defaulttime = '00:02:00'
                playinfo.startTime = defaulttime
                playinfo.endTime = defaulttime
                timetxts[0].value = defaulttime
                timetxts[1].value = defaulttime
            }
            else {
                if (buttype === 'now') {
                    t = parseInt(video.currentTime);
                    buttype = t < video.duration / 2 ? 'start' : 'end';
                    t = buttype === 'start' ? t : parseInt(video.duration - t)
                    t = Math.min(t, 599)
                    let date = new Date(t * 1000);
                    t = ("0" + (date.getHours() - 8)).slice(-2) + ':' + ("0" + date.getMinutes()).slice(-2) + ':' + ("0" + date.getSeconds()).slice(-2)
                    if (buttype === 'start')
                        timetxts[0].value = t
                    else if (buttype === 'end')
                        timetxts[1].value = t
                }
                else {
                    if (buttype === 'start')
                        t = timetxts[0].value
                    else if (buttype === 'end')
                        t = timetxts[1].value
                }
                if (buttype === 'start')
                    playinfo.startTime = t
                else
                    playinfo.endTime = t
            }
            if (index === -1)
                playhistory.unshift(playinfo)
            NewGM_setValue('playhistory', playhistory)
        }
    })
}
function playing() {
    const lpfn = localStorage.getItem('last_play_file_name')?.split('›').pop()
    if (lpfn) {
        document.querySelector('.title--RYadk[title="' + lpfn + '"]')?.click()
        localStorage.removeItem('last_play_file_name')
    }
    else {
        const video = document.querySelector('video')
        let file_id = new URLSearchParams(newurl).get('f')
        const playhistory = GM_getValue('playhistory') || []
        let file_path = location.pathname
        const index = playhistory.findIndex(item => item.file_path === file_path)
        playinfo = index === -1 ? { file_path: file_path } : playhistory[index]
        const nameel = document.querySelectorAll('.breadcrumb--gnRPG[data-calc="true"] .breadcrumb-item--j8J5H')
        let file_name = ''
        for (let i = 1; i < nameel.length; i++)
            file_name += nameel[i].textContent
        var listItems = Array.from(document.querySelectorAll('.list--5o17x li'));
        if (listItems.length) {
            var currentIndex = listItems.findIndex(li => li.getAttribute('data-is-current') === 'true');
            file_name += listItems[currentIndex].querySelector('.title--RYadk').textContent
            const currentTime = JSON.parse(localStorage.getItem('currentTime') || '{}')
            if (currentTime?.currentTime) {
                const currentTimeindex = playhistory.findIndex(item => item.file_path === currentTime.file_path)
                if (currentTimeindex !== -1) {
                    playhistory[currentTimeindex].currentTime = currentTime.currentTime
                    if (index === currentTimeindex)
                        playinfo.currentTime = currentTime.currentTime
                }
            }
            if (playinfo.currentTime && playinfo.file_id === file_id) {
                video.currentTime = playinfo.currentTime
            }
            else if (playinfo.startTime) {
                video.currentTime = playinfo.startTime.split(':').reduce((acc, v) => 60 * acc + +v);
            }
            playinfo.file_id = file_id
            playinfo.file_name = file_name
            index !== -1 && playhistory.splice(index, 1)
            playhistory.unshift(playinfo)
        }
        NewGM_setValue('playhistory', playhistory.slice(0, 10))
        video.removeEventListener('timeupdate', null)
        video.addEventListener('timeupdate', function () {
            video.currentTime && localStorage.setItem('currentTime', JSON.stringify({ file_path: file_path, currentTime: video.currentTime }))
            if (playinfo.endTime)
                video.currentTime > video.duration - playinfo.endTime.split(':').reduce((acc, v) => 60 * acc + +v) && changevideo(1)
        })
    }
}
const colorsgv = '#637dff'
const settingsvg = '<svg fill="' + colorsgv + '" style="margin-right: 15px; stroke-width="0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" class="hope-icon hope-c-XNyZK hope-c-PJLV hope-c-PJLV-ifkxHPo-css" tips="local_settings" height="1.5em" width="2em" style="overflow: visible;"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg>'
const potplayerdiv = '<svg style="margin-left: 10px;margin-right: 10px;cursor: pointer;" fill="' + colorsgv + '" stroke-width="0" class="hope-icon hope-c-XNyZK hope-c-PJLV hope-c-PJLV-ifkxHPo-css history" tips="history" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2770" width="2.5em" height="2.5em"><path d="M981.184 160.096c-143.616-20.64-302.336-32.096-469.184-32.096s-325.568 11.456-469.184 32.096c-27.52 107.712-42.816 226.752-42.816 351.904s15.264 244.16 42.816 351.904c143.648 20.64 302.336 32.096 469.184 32.096s325.568-11.456 469.184-32.096c27.52-107.712 42.816-226.752 42.816-351.904s-15.264-244.16-42.816-351.904zM384 704l0-384 320 192-320 192z" p-id="2771"></path></svg>'
function setStyle() {
    const fontcss = GM_getValue('fontColor') || ''
    const newsetstyle = document.querySelector('#newsetstyle')
    newsetstyle && newsetstyle.remove();
    var style = document.createElement('style');
    const butnum = 3
    const rightpx = 41 + butnum * 62
    style.id = 'newsetstyle'
    style.innerHTML = `
    #webdav-panel .ant-input{box-shadow: 0 0 0 1px var(--theme_primary);}
    .setautojump .media-label-action--PwF31{margin-left:2px;margin-right:2px;}
    input[type="time"]{color:white !important;text-indent:-11px;width:61px;height:27px;top:-3px;}
    input[type="time"]::-webkit-inner-spin-button,input[type="time"]::-webkit-calendar-picker-indicator {display: none;-webkit-appearance: none;}
    .action--H2mi0:first-of-type,.drawers--t3zFN .drawer-container--tMDPx:first-of-type .title--6eEg9{text-indent:-9999px;display:flex;}
    .action--H2mi0:first-of-type::after,.drawers--t3zFN .drawer-container--tMDPx:first-of-type .title--6eEg9::after {content: "设置";text-indent:0px;}
    .breadcrumb--gnRPG.play-button:hover{color: rebeccapurple;}
    .breadcrumb--gnRPG.play-button:hover svg{display:block}
    .breadcrumb--gnRPG.play-button svg{height:20px;width:20px;position:absolute;top:-16px;display:none;}
    .btnsetting{position: absolute;right: 10px;}
    .btnsetting:hover>.mymemu:not(:empty) {display: flex;}
    .mymemu {position: relative;display: none;right: -${rightpx}px;top: -20px;background-color: white;border-radius:10px}
    .mymemu button{ padding: 5px 10px; border: none; color: #fff; border-radius: 4px; cursor: pointer;margin-top: 15px;margin-bottom: 15px;margin-right: 10px;}
    .list--5o17x,.scroll-container--MsQem{scrollbar-width: none; -ms-overflow-style: none; }
    #playhistory-panel .breadcrumb-item-link--9zcQY,#webdav-panel .breadcrumb-item-link--9zcQY{color: var(--theme_hover);}
    :fullscreen .video-player--k1J-M {bottom: 0px;opacity:0!important;}
    .video-player--k1J-M {bottom: -80px;opacity:0.8!important;}
    .text-primary--3DHOJ{overflow:visible;font-weight:bold}
    .loader--3P7-4,.loader--zXBWG{opacity:0.8!important}
    .outer-wrapper--3ViSy{opacity:0!important}
    .outer-wrapper--3ViSy:hover,.video-player--k1J-M:hover{opacity:0.8!important}
    .button--1pH7M,.container--CIvrv,.ant-tooltip-inner,.loading--zyXaT{display:none}
    .ended-container--Tz5lR,.content-wrapper--A93tB,.feature-blocker--vh7jp,.sign-bar--1XrSl,.ai-summary-btn--fQnJ{display:none!important}
    `;
    fontcss && (style.innerHTML += '.cue--rlq6T.cue-medium--be9UK,#colorPreview{color:' + fontcss + ';cursor: pointer;}')
    document.head.appendChild(style);
}
setStyle();
function getsetnewurl(file_id, setnewurl) {
    const today = new Date().toLocaleDateString()
    const newurls = GM_getValue('newurls') || {}
    if (!newurls.date)
        newurls.date = today
    if (setnewurl) {
        newurls[file_id] = setnewurl;
        NewGM_setValue('newurls', newurls)
    }
    else {
        if (today === newurls.date) {
            let geturl = newurls[file_id]
            if (geturl) {
                if (typeof geturl === "string")
                    geturl = [geturl]
                const newsearch = new URLSearchParams(geturl[0])
                if (parseInt(newsearch.get('x-oss-expires') + '000') < new Date().getTime())
                    geturl = undefined
            }
            return geturl
        }
        else {
            NewGM_setValue('newurls', null)
            return undefined;
        }
    }
}
function setfullscreen() {
    function videoEndHandler() {
        changevideo(1)
    }
    if (isfullscreen && document.fullscreenElement === null)
        document.querySelector('.action--HeWYA:not([data-active])').click()
    document.querySelector('.video-player--k1J-M .btn--UrTVT').click()
    var elements = document.querySelectorAll('.list--5o17x li, .next--k9RTS');
    elements.forEach(function (element) {
        element.addEventListener('click', function () {
            isfullscreen = document.fullscreenElement !== null
        });
    });
    const video = document.querySelector("video");
    video.removeEventListener('ended', videoEndHandler, false);
    video.addEventListener('ended', videoEndHandler, false);
}
function addsubcolor() {
    const fontcss = GM_getValue('fontColor') || ''
    document.querySelectorAll('.scroll-wrapper--aByOe .drawer-label--FWKBs')[1].insertAdjacentHTML('beforeend', '<input ' + (fontcss ? '' : 'value="' + fontcss + '"') + ' style="margin-right: 130px;top:-50px;position:relative;" type="color" id="colorInput"><span id="colorPreview">字幕颜色</span>')
    var colorInput = document.querySelector('#colorInput');
    var colorPreview = document.querySelector('#colorPreview');
    colorPreview.addEventListener('click', () => { colorInput.click(); });
    colorInput.addEventListener('change', function () {
        colorPreview.style.color = colorInput.value;
        NewGM_setValue('fontColor', colorInput.value)
        setStyle();
    });
    const loadsubbtn = document.querySelector('.meta--iPZhB').parentElement.parentElement
    loadsubbtn.insertAdjacentHTML('beforeend', loadsubbtn.innerHTML.replace('手动添加外挂字幕', '添加本地外挂字幕').replace('data-is-current', 'style="margin-left: auto;" data-is-current'))
    loadsubbtn.style.display = 'flex'
    loadsubbtn.querySelectorAll('li .meta--iPZhB')[1].parentElement.addEventListener('click', function () {
        var input = document.createElement('input');
        input.type = 'file';
        input.style.display = 'none';
        document.body.appendChild(input);
        input.addEventListener('change', function (e) {
            var file = e.target.files[0];
            var reader = new FileReader();
            reader.onload = function (event) {
                storedBlob = event.target.result;
                if (file.name.toLowerCase().endsWith('.ass'))
                    storedBlob = convertAssToVtt(storedBlob)
                else if (file.name.toLowerCase().endsWith('.srt'))
                    storedBlob = convertSrtToVtt(storedBlob)
                document.body.removeChild(input);
                document.querySelector('.action--H2mi0[data-active="true"]')?.click()
                const subInput = Array.from(document.querySelectorAll('.meta--iPZhB')).pop()
                subInput.querySelector('.text--G8ymN').textContent = file.name
                subInput.querySelector('.text--G8ymN').title = file.name
                if (subInput.parentElement.getAttribute('data-is-current') === 'true')
                    subInput.click()
                subInput.click()
            };
            reader.readAsText(file);
        });
        input.click()
    })
}
function convertAssToVtt(assSubtitles) {
    const assLines = assSubtitles.split('\n');
    let vttOutput = vtthearder;
    assLines.forEach((line) => {
        if (!line.trim() || line.trim().startsWith(';') || !line.trim().startsWith('Dialogue:')) return;
        const lines = line.split(',');
        const startTime = lines[1];
        const endTime = lines[2];
        const text = lines.slice(9).join(',');
        const startTimeVtt = convertAssTimeToVttTime(startTime);
        const endTimeVtt = convertAssTimeToVttTime(endTime);
        vttOutput += `\n${startTimeVtt} --> ${endTimeVtt}\n${text}\n`
    });
    return vttOutput;
}
function convertAssTimeToVttTime(assTime) {
    const parts = assTime.split('.').map(part => part.padStart(2, '0'));
    const hours = parts[0].split(':')[0];
    const minutes = parts[0].split(':')[1];
    const seconds = parts[0].split(':')[2];
    const milliseconds = '000' + parts[1];
    return `${hours}:${minutes}:${seconds}.${milliseconds.substring(milliseconds.length - 3)}`;
}
function convertSrtToVtt(srtSubtitles) {
    const assLines = srtSubtitles.split('\n');
    let vttOutput = vtthearder;
    assLines.forEach((line) => {
        const regex = /^\d+$/;
        if (regex.test(line.trim())) return;
        if (line.indexOf('-->') !== -1)
            line = line.replaceAll(',', '.')
        vttOutput += line + '\n';
    });
    return vttOutput;
}
function adddownloadbut() {
    const selffile = location.pathname.startsWith('/drive/file')
    const div = document.querySelector('.actions--YfXrK')
    div.insertAdjacentHTML('beforeend', '<div class="action--H2mi0 btndownload" data-active="false" data-disabled="false">下载</div>');
    document.querySelector('.btndownload').addEventListener("click", () => {
        const dl = document.createElement('a');
        if (!sdlurl) {
            const sss = new URLSearchParams(newurl)
            const sfile_id = sss.get('f')
            const newurls = GM_getValue('newurls') || {}
            if (selffile) {
                sdlurl = getDownloadUrl(sss.get('dr'), sfile_id)
                newurls[sfile_id] = [newurl, sdlurl]
            }
            else {
                const saveinfo = savefile(sinfo.file_id, sinfo.share_token).responses[0].body
                sdlurl = getDownloadUrl(saveinfo.drive_id, saveinfo.file_id)
                deletefile(saveinfo.file_id)
                newurls[sinfo.file_id] = [newurl, sdlurl]
            }
            NewGM_setValue('newurls', newurls)
        }
        dl.href = sdlurl
        dl.download = ''
        dl.click();
    })
    setTimeout(() => {
        const allmenubtn = document.querySelectorAll('.action--H2mi0:not(.btndownload)')
        let showtime = []
        allmenubtn.forEach(function (element, index) {
            showtime.push(false)
            const allshowdiv = document.querySelectorAll('.drawer-container--tMDPx')
            const menudiv = allshowdiv[index + allshowdiv.length - allmenubtn.length];
            [element, menudiv].forEach((el) => {
                el.addEventListener('mouseenter', function () {
                    if (!document.querySelector('.action--H2mi0:not(.btndownload)[data-active="true"]')) {
                        showtime[index] && clearTimeout(showtime[index])
                        showtime[index] = setTimeout(() => {
                            menudiv.setAttribute('data-open', 'true')
                            menudiv.style.height = '384px'
                        }, 111);
                    }
                });
                el.addEventListener('mouseleave', function () {
                    if (!document.querySelector('.action--H2mi0:not(.btndownload)[data-active="true"]')) {
                        showtime[index] && clearTimeout(showtime[index])
                        showtime[index] = setTimeout(() => {
                            menudiv.setAttribute('data-open', 'false')
                            menudiv.style.height = '68px'
                        }, 111);
                    }
                });
            })
        });
    }, 0)
}
function changevideo(direction) {
    var listItems = Array.from(document.querySelectorAll('.list--5o17x li'));
    var currentIndex = listItems.findIndex(li => li.getAttribute('data-is-current') === 'true');
    if ((direction === -1 && currentIndex > 0) || (direction === 1 && currentIndex < listItems.length - 1)) {
        isfullscreen = document.fullscreenElement !== null
        listItems[currentIndex + direction]?.click();
    }
}
function abnormalplay() {
    new MutationObserver(function () {
        if (document.querySelector('.error--3ZTlN'))
            document.querySelector('.video-player--k1J-M .btn--UrTVT').click()
    }).observe(document.body, { childList: true, subtree: true });
}
unsafeWindow.onload = function () {
    updateConfigIfNecessary();
    abnormalplay();
    addplayhistory();
};
function addplayhistory() {
    var settingsButton = document.createElement('div');
    settingsButton.innerHTML = `<div style="position: fixed; right: 40px; bottom:115px; z-index:112;border:none;width:auto;" class='membership-wrapper--6egJF'>${potplayerdiv}</div>`;
    document.body.appendChild(settingsButton);
    document.querySelector('.history').addEventListener('click', showManagementPanel);
}
function showManagementPanel() {
    var previousPanel = document.getElementById('playhistory-panel');
    previousPanel && previousPanel.parentNode.removeChild(previousPanel);
    var playlist = GM_getValue('playhistory') || [];
    var panel = document.createElement('div');
    panel.id = 'playhistory-panel';
    panel.style = `position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 99;`
    panel.innerHTML =
        `<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); width: 800px;"><div style="display: flex; "><h2 style="margin-top: 0; margin-bottom: 10px; font-size: 24px;">历史播放记录</h2><div style="display: flex; justify-content: flex-end;top:30px" class="btnsetting"><div class="mymemu" style="right:0px"><button class="reset-button" playinfo-index="-1" style="background-color: #ffa31a;">重置所有设置</button><button class="clear-button" playinfo-index="-1" style="background-color: #ff4d4f;">清空播放记录</button><button class="webdav-button" playinfo-index="-1" style="background-color: #00c270;margin-right: 0px;">WebDav设置</button></div>${settingsvg}</div></div><hr style="margin-bottom: 20px;"><div style="overflow-y: auto; max-height: 600px;">${playlist.map(function (playinfo, index) {
            let filenamelist = playinfo.file_name.split('›').filter(item => { return item !== "" }); const filename = filenamelist.pop(); let anotherNamehtml = ''; playinfo.anotherName && (filenamelist = [playinfo.anotherName]); filenamelist.map((fn) => { anotherNamehtml += `<div class="breadcrumb-item--j8J5H" data-hide="false" data-more="false"><div class="breadcrumb-item-link--9zcQY">${fn}</div><div class="breadcrumb-item-separator--MnbFV">›</div></div>` }); return `<div class="history-item" style="display: flex; margin-bottom: 10px;"><div playinfo-index="${index}" style="display: ruby;margin-top: auto;margin-bottom: auto;flex: 1;padding-right: 36px;cursor: pointer;" class="breadcrumb--gnRPG play-button" data-calc="true">${anotherNamehtml + filename}<div style="position: relative;">${potplayerdiv}</div></div><div style="display: flex; justify-content: flex-end;" class="btnsetting"><div class="mymemu" style="right:0px"><button class="rename-button" playinfo-index="${index}" style="background-color: #ffa31a;">别名</button><button class="delete-button" playinfo-index="${index}" style="background-color: #ff4d4f;margin-right: 0px;">删除</button></div>${settingsvg}</div></div>`;
        }).join('')}</div></div>`;
    document.body.appendChild(panel);
    panel.addEventListener('click', function (e) {
        var playhistory = GM_getValue('playhistory') || [];
        let target = e.target
        if (target == panel)
            panel.parentNode.removeChild(panel);
        else if (target.classList.contains('webdav-button')) {
            panel.parentNode.removeChild(panel);
            var panelwebdav = document.getElementById('webdav-panel');
            panelwebdav && panelwebdav.parentNode.removeChild(panelwebdav);
            panelwebdav = document.createElement('div');
            panelwebdav.id = 'webdav-panel';
            panelwebdav.style = `position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 99;`
            panelwebdav.innerHTML =
                `<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); width: 800px;"><div style="display: flex; "><h2 style="margin-top: 0; margin-bottom: 10px; font-size: 24px;">WebDav设置</h2><div style="display: flex; justify-content: flex-end;top:30px" class="btnsetting"><div class="mymemu" style="right:10px;display:block"><button class="save-button" playinfo-index="-1" style="background-color: #00c270;margin-right: 0px;">保存</button></div></div></div><hr style="margin-bottom: 20px;"><div class="history-item" style="display: flex; margin-bottom: 10px;"><div data-more="false" data-hide="false" class="breadcrumb-item--j8J5H" style="flex: 1;"><div class="breadcrumb-item-link--9zcQY">配置文件完整地址</div></div><input value=${wdurl} style="margin-left: 13px;height: 100%;flex: 4;" class="ant-input ant-input-borderless input--TWZaN" type="text"></div><div class="history-item" style="display: flex; margin-bottom: 10px;"><div data-more="false" data-hide="false" class="breadcrumb-item--j8J5H" style="flex: 1;"><div class="breadcrumb-item-link--9zcQY">账号</div></div><input value=${wdusername} style="margin-left: 13px;height: 100%;flex: 4;" class="ant-input ant-input-borderless input--TWZaN" type="text"></div><div class="history-item" style="display: flex; margin-bottom: 10px;"><div data-more="false" data-hide="false" class="breadcrumb-item--j8J5H" style="flex: 1;"><div class="breadcrumb-item-link--9zcQY">密码</div></div><input value=${wdpassword} style="margin-left: 13px;height: 100%;flex: 4;" class="ant-input ant-input-borderless input--TWZaN" type="text"></div>
                </div>`
            document.body.appendChild(panelwebdav);
            panelwebdav.addEventListener('click', function (event) {
                if (event.target == panelwebdav)
                    panelwebdav.parentNode.removeChild(panelwebdav);
                else if (event.target.tagName === "BUTTON") {
                    const inputs = panelwebdav.querySelectorAll('input')
                    GM_setValue('webdav_url', inputs[0].value)
                    GM_setValue('webdav_user', inputs[1].value)
                    GM_setValue('webdav_pwd', inputs[2].value)
                    location.reload()
                }
            })
        }
        else {
            if (target.parentElement.getAttribute('playinfo-index'))
                target = target.parentElement
            if (target.parentElement.parentElement.getAttribute('playinfo-index'))
                target = target.parentElement.parentElement
            let index = target.getAttribute('playinfo-index')
            if (target.classList.contains('play-button')) {
                localStorage.setItem('last_play_file_name', playhistory[index].file_name)
                location.href = playhistory[index].file_path
            }
            else if (target.classList.contains('delete-button')) {
                playhistory.splice(index, 1)
                NewGM_setValue('playhistory', playhistory)
            }
            else if (target.classList.contains('rename-button')) {
                var userInput = prompt("设置别名为:");
                if (userInput) {
                    playhistory[index].anotherName = userInput
                    NewGM_setValue('playhistory', playhistory)
                }
            }
            else if (target.classList.contains('reset-button'))
                confirm("确定要重置所有设置吗?") && clearsetValue(['openapiclient_id', 'openapitoken', 'saveinfo', 'playbackRate', 'volume', 'fontColor', 'newurls', 'playhistory'])
            else if (target.classList.contains('clear-button'))
                confirm("确定要清空播放记录吗?") && clearsetValue(['newurls', 'playhistory'])
            showManagementPanel()
        }
        function clearsetValue(keys) {
            keys.map(key => NewGM_setValue(key, null))
        }
    });
}
function getAllGMdata() {
    const GMkey = ['openapiclient_id', 'saveinfo', 'playbackRate', 'volume', 'fontColor', 'playhistory', 'timestamp']
    const allGMdata = {}
    GMkey.map(key => {
        const GMvalue = GM_getValue(key)
        GMvalue && (allGMdata[key] = GMvalue)
    })
    return allGMdata
}
function updateGMdata(jsobject) {
    Object.keys(jsobject).map((key) => {
        GM_setValue(key, jsobject[key])
    })
}
function updateConfigIfNecessary() {
    const currentTime = JSON.parse(localStorage.getItem('currentTime') || '{}')
    if (currentTime?.currentTime) {
        const playhistory = GM_getValue('playhistory') || []
        const index = playhistory.findIndex(item => item.file_path === currentTime.file_path)
        if (index !== -1) {
            localStorage.removeItem('currentTime')
            playhistory[index].currentTime = currentTime.currentTime
            NewGM_setValue('playhistory', playhistory)
        }
    }
    if (wdpassword !== '' && wdurl !== '' && wdusername !== '') {
        const configPath = wdurl + '#' + new Date().getTime()
        GM_xmlhttpRequest({
            method: 'GET',
            url: configPath,
            headers: {
                'Authorization': authHeader
            },
            onload: function (response) {
                const localConfigData = getAllGMdata()
                if (response.status === 200) {
                    const serverConfigObject = JSON.parse(response.responseText);
                    if ((localConfigData?.timestamp || 0) > serverConfigObject.timestamp)
                        updateWebDAVConfig(localConfigData);
                    else {
                        updateGMdata(serverConfigObject)
                    }
                }
                else {
                    updateWebDAVConfig(localConfigData);
                }
            }
        });
    }
}
function updateWebDAVConfig(newConfigData) {
    const configPath = wdurl + '#' + new Date().getTime()
    newConfigData.timestamp = new Date().getTime()
    GM_xmlhttpRequest({
        method: 'PUT',
        url: configPath,
        data: JSON.stringify(newConfigData),
        headers: {
            'Authorization': authHeader,
            'Content-Type': 'application/json;charset=UTF-8'
        }
    });
}
//#endregion