// ==UserScript== // @name 阿里云盘标清替换成最高画质 // @namespace http://tampermonkey.net/ // @version 1.1.4 // @description 通过阿里云盘开放平台将原标清替换成最高画质(支持分享链接),打开视频自动播放,视频前进后退5秒,更多倍速播放以及记忆倍速,视频下载,播放器工具栏置底并设置透明度,播放历史记录,字幕颜色设置,上传本地字幕(vtt,srt,ass),快捷键: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 // @downloadURL none // ==/UserScript== var openapiclient_id = GM_getValue('openapiclient_id') || '55091393987b4cc090b090ee17e85e0a' var newurl, sdlurl, isfullscreen, sinfo, openapicode_verifier, observer, storedBlob, savedevice_id var vtthearder = 'WEBVTT\n0:00:00.000 --> 0:00:01.500\n脚本制作人:bygavin(星峰)\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) GM_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 GM_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 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') { var direction = e.key === 'Home' ? -1 : 1; changevideo(direction) } 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("确定设置此目录为临时转存目录")) GM_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) { GM_setValue('openapiclient_id', userInput) openapiclient_id = userInput; GM_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 } }) const colorsgv = '#637dff' const settingsvg = '' const potplayerdiv = '' 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 = ` .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{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; GM_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 { GM_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 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() }); const selector = ul.parentElement ul.remove() selector.innerHTML += `