// ==UserScript== // @name 阿里云盘一键秒传到115云盘播放 // @namespace http://tampermonkey.net/ // @version 1.0.2 // @description 先通过alist将阿里云盘资源秒传到115网盘,然后再通过cd2播放,alist转存有缓存时间,cd2是实时,所以用它来播放,需要alist添加阿里云盘和115的存储,挂载路径为阿里云盘和115且需要设置缓存时间设置为1分钟,不然转存后可能要等很久才能够秒传,cd2需添加115网盘,名称为115,阿里云盘需设置默认转存目录进入目标目录后按ALT+S保存,设置的临时目录需和alist挂载设备一致,不可一个在资源库,一个在备份盘 // @author bygavin // @match https://www.aliyundrive.com/drive* // @match https://www.alipan.com/drive* // @match https://www.aliyundrive.com/s/* // @match https://www.alipan.com/s/* // @icon https://img.alicdn.com/imgextra/i1/O1CN01JDQCi21Dc8EfbRwvF_!!6000000000236-73-tps-64-64.ico // @license MIT // @grant GM_setValue // @grant GM_getValue // @grant unsafeWindow // @grant GM_xmlhttpRequest // @downloadURL https://update.greasyfork.icu/scripts/501986/%E9%98%BF%E9%87%8C%E4%BA%91%E7%9B%98%E4%B8%80%E9%94%AE%E7%A7%92%E4%BC%A0%E5%88%B0115%E4%BA%91%E7%9B%98%E6%92%AD%E6%94%BE.user.js // @updateURL https://update.greasyfork.icu/scripts/501986/%E9%98%BF%E9%87%8C%E4%BA%91%E7%9B%98%E4%B8%80%E9%94%AE%E7%A7%92%E4%BC%A0%E5%88%B0115%E4%BA%91%E7%9B%98%E6%92%AD%E6%94%BE.meta.js // ==/UserScript== //#region 变量定义 var savedevice_id, alistaliyun, getundone, getalist, oneclicksave, startbatch, morethen5G, videonamelist var obj = {}, pathinfo = {} const alist115yun = "/115/阿里云转存" var cd2url = GM_getValue("cd2url") || '' var alisturl = GM_getValue("alisturl") || '' var alisttoken = GM_getValue("alisttoken") || '' var oldxhr = unsafeWindow.XMLHttpRequest var savemode = GM_getValue("savemode") || 'save115' const saveinfo = GM_getValue('saveinfo') || {} const default_drive_id = JSON.parse(localStorage.getItem('token'))?.default_drive_id function newobj() { } //#endregion //#region 劫持send (function (send) { unsafeWindow.XMLHttpRequest.prototype.send = function (sendParams) { const sendurl = new URL(this.__recordInfo__.url).pathname if (sendurl.endsWith("/file/list") || sendurl.endsWith("/file/list_by_share")) {//修改获取列表数量为200 const oldargument = JSON.parse(sendParams) oldargument.limit && (oldargument.limit = 200) arguments[0] = JSON.stringify(oldargument); } else if (sendurl.endsWith('/batch')) {//强制修改转存路径 const oldargument = JSON.parse(sendParams) oldargument.requests.map(item => { if (item.body.to_parent_file_id) { item.body.to_parent_file_id = saveinfo.savefile_id item.body.to_drive_id = saveinfo.savedevice_id } }) arguments[0] = JSON.stringify(oldargument); } send.apply(this, arguments); }; })(unsafeWindow.XMLHttpRequest.prototype.send); //#endregion //#region 劫持xhr 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 = new URL(target.oldxhr.responseURL).pathname if (responseURL.endsWith('/batch') && prop.indexOf('response') !== -1 && saveinfo.savedevice_id) { const res = JSON.parse(target.oldxhr?.response || target.oldxhr?.responseText); const resstatus = res.responses.pop()?.status if ((resstatus === 200 || resstatus === 201)) { alito115play(saveinfo.alistaliyun, true) } } else if (responseURL.endsWith('file/get_path') && prop.indexOf('response') !== -1) { const res = JSON.parse(target.oldxhr?.response || target.oldxhr?.responseText); savedevice_id = res.items[0].drive_id let dirlist = res.items.map(item => item.name).reverse() if (savedevice_id === default_drive_id) dirlist = ["备份文件", ...dirlist] alistaliyun = ["阿里云盘", ...dirlist].join('/') pathinfo.alistaliyun = alistaliyun pathinfo.pathname = location.pathname } else if ((responseURL.endsWith("file/list") || responseURL.endsWith("file/list_by_share")) && prop.indexOf('response') !== -1) { const res = JSON.parse(target.oldxhr?.response || target.oldxhr?.responseText); if (res.items?.length) { morethen5G = res.items.filter((item) => { return item.size > 5368709120 }).map(item => item.name).join(',') videonamelist = res.items.map(item => item.name) } } 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); } //#region 功能主体 function alito115play(videopath, isshare) { startbatch && clearTimeout(startbatch) startbatch = setTimeout(() => { if (videopath) obj.showNotify("开始转存:" + videopath); else { obj.showNotify("无效的资源路径", "fail"); return } const resfun = function (response) { if (response.status === 200) { const alistlistinfo = JSON.parse(response.responseText).data.content if (!alistlistinfo) { getalist && clearTimeout(getalist) getalist = setTimeout(() => { obj.showNotify("缓存未刷新,请等待"); alistfun("api/fs/list", JSON.stringify({ "path": videopath, "password": "", "page": 1, "per_page": 0, "refresh": false }), resfun) }, 1000) } else { const savedir = alistlistinfo.length == 1 && alistlistinfo[0].is_dir ? ('/' + alistlist[0]) : '' const pandir = isshare ? '' : ('/' + videopath.split('/').pop()) const alistlist = alistlistinfo.map(item => item.name); const potplayerrun = function () { const cd2 = new URL(cd2url) const potplayerurl = `potplayer://${cd2url}static/${cd2.protocol.slice(0, -1) + '/' + cd2.host}/True/${encodeURIComponent(alist115yun + savedir + pandir)}.clfsplaylist.m3u` const dl = document.createElement('a'); dl.href = potplayerurl dl.click(); } if (!isshare) { if (new Set([...videonamelist, ...alistlist]).size === alistlist.length) { obj.showNotify("资源已存在115网盘中,无需转存,启动potplayer播放115网盘资源"); potplayerrun() return } } const copyjson = { "src_dir": videopath, "dst_dir": alist115yun + pandir, "names": alistlist } const removejson = { "dir": videopath, "names": alistlist } obj.showNotify("开始秒传到115"); alistfun("api/fs/copy", JSON.stringify(copyjson), function (res1) { if (res1.status === 200) { const removealiyun = function () { alistfun("api/admin/task/copy/undone", null, function (res2) { if (res1.status === 200) { const undonelist = JSON.parse(res2.responseText).data.length if (undonelist) { obj.showNotify("秒传进行中,请等待"); getundone && clearTimeout(getundone) getundone = setTimeout(removealiyun, 1000) } else { const play115 = function () { obj.showNotify("启动potplayer播放115网盘资源"); potplayerrun() } if (isshare) { obj.showNotify("开始删除阿里云转存"); alistfun("api/fs/remove", JSON.stringify(removejson), play115) } else { setTimeout(play115, 0) } } } }, 'GET') } getundone && clearTimeout(getundone) getundone = setTimeout(removealiyun, 1000) } }) } } } if (savemode === 'save115') alistfun("api/fs/list", JSON.stringify({ "path": videopath, "password": "", "page": 1, "per_page": 0, "refresh": false }), resfun) else { const alist115yuns = alist115yun.split('/') const dirname = alist115yuns.pop() const removejson = { "dir": alist115yuns.join('/'), "names": [dirname] } alistfun("api/fs/remove", JSON.stringify(removejson), function () { alistfun("api/fs/list", JSON.stringify({ "path": videopath, "password": "", "page": 1, "per_page": 0, "refresh": false }), resfun) }) } }, 333) } //#endregion //#region alist请求 function alistfun(url, data, fun, method) { GM_xmlhttpRequest({ method: (method || 'POST'), url: alisturl + url, data: data, headers: { "authorization": alisttoken, "content-type": "application/json;charset=UTF-8", }, onload: fun }); } //#endregion //#endregion //#region 键盘快捷键 document.addEventListener('keydown', function (e) { if (e.altKey && e.code == 'KeyS') { if (savedevice_id && alistaliyun) { saveinfo.savedevice_id = savedevice_id saveinfo.savefile_id = (this.location.pathname.split('/')[4] || 'root') saveinfo.alistaliyun = alistaliyun obj.confirm('确定设置此目录为临时转存目录?', () => GM_setValue("saveinfo", saveinfo)) } } }); //#endregion //#region svg图标 const aliyunto115 = '' //#endregion //#region 自定义样式 function setStyle() { document.querySelector('#newsetstyle1')?.remove(); var style = document.createElement('style'); style.id = 'newsetstyle1' style.innerHTML = ` #setting-panel .breadcrumb-item-link--9zcQY,#confirm-panel .breadcrumb-item-link--9zcQY{color:var(--theme_hover)} .history-item{display:flex;margin-bottom:10px}.history-item .breadcrumb-item--j8J5H{max-width:50%}.history-item .breadcrumb-item-link--9zcQY{overflow: hidden;text-overflow: ellipsis;}.history-item input::placeholder{color: #3b8f4c;} .right-bottom-container--6JaaW{right:-47px !important;transition:right 0.3s;}.right-bottom-container--6JaaW:hover{right:0px !important;} .aliyunto115{position:relative;right:-47px;transition:right 0.3s}.aliyunto115:hover{fill:var(--theme_hover);right:0px;} #setting-panel,#confirm-panel{position:fixed;top:0px;left:0px;width:100%;height:100%;background-color:rgba(0,0,0,0.5);z-index:99} #setting-panel>div,#confirm-panel>div{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} #confirm-panel .ant-input{box-shadow:0 0 0 1px var(--theme_primary)} .btnsetting{position:absolute;right:10px} .btnsetting:hover>.mymemu:not(:empty){display:flex} .mymemu{position:relative;display:none;top:-20px} .mymemu button{padding:5px 10px;border:none;color:#fff;border-radius:4px;cursor:pointer;margin-top:15px;margin-right:10px} .breadcrumb--gnRPG.play-button:hover{color:rebeccapurple} .oneclicksave{margin-left:16px;background-color: #00c270 !important;} `; const Notifycss = [ ".notify{display:none;position:absolute;top:0;left:25%;width:50%;text-align:center;overflow:hidden;z-index:1010}", ".alert-success,.alert-loading{background:#36be63 !important;}", ".alert-fail{background:#ff794a !important;}", ".alert.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}", ".alert.fade.in{opacity:1}" ] style.innerHTML += Notifycss.join(' ') document.head.appendChild(style); } setStyle(); //#endregion //#region 显示管理面板 function showManagementPanel() { document.querySelector('#confirm-panel,#setting-panel')?.remove() var panelsetting = document.createElement('div'); panelsetting.id = 'setting-panel'; panelsetting.style = `z-index: 100;` panelsetting.innerHTML = `