PotPlayer云盘-专供版

此脚本为《PotPlayer播放云盘视频》姊妹篇,需配合MediaPlayParse - PanVideo.as脚本使用。在potplayer中选择画质、字幕,迅雷云盘增加原画,阿里云盘增加时长。

  1. // ==UserScript==
  2. // @name PotPlayer云盘-专供版
  3. // @namespace https://github.com/Bleu404/PotplayerPanVideoSV
  4. // @version 1.1.0
  5. // @description 此脚本为《PotPlayer播放云盘视频》姊妹篇,需配合MediaPlayParse - PanVideo.as脚本使用。在potplayer中选择画质、字幕,迅雷云盘增加原画,阿里云盘增加时长。
  6. // @author bleu
  7. // @compatible edge Tampermonkey
  8. // @compatible chrome Tampermonkey
  9. // @compatible firefox Tampermonkey
  10. // @license MIT
  11. // @match https://pan.xunlei.com/*
  12. // @match https://www.aliyundrive.com/*
  13. // @icon https://fastly.jsdelivr.net/gh/Bleu404/PRPO@latest/png/ppvsv.png
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_registerMenuCommand
  18. // @grant unsafeWindow
  19. // @connect *
  20. // @connect xunlei.com
  21. // @connect aliyundrive.com
  22. // @connect jianguoyun.com
  23. // @connect teracloud.jp
  24. // @require https://fastly.jsdelivr.net/npm/sweetalert2@11.1.0/dist/sweetalert2.all.min.js
  25. // @require https://fastly.jsdelivr.net/npm/bleutools@1.0.2/bleutools.min.js
  26. // ==/UserScript==
  27.  
  28. (function () {
  29. 'use strict';
  30. const ORGXHRSRH = XMLHttpRequest.prototype.setRequestHeader;
  31. let bleuc,contextMenu, itemsInfo, arryIndex, Option, observer,cloud;
  32. const flieTypeStr = ".wmv,.rmvb,.avi,.mp4,.mkv,.flv,.swf.mpeg4,.mpeg2,.3gp,.mpga,.qt,.rm,.wmz,.wmd,.wvx,.wmx,.wm,.mpg,.mpeg,mov,.asf,.m4v,";
  33. const tools = {
  34. getCloudName() {
  35. switch (document.domain) {
  36. case 'xunlei.com':
  37. cloud = xunlei;
  38. break;
  39. case 'pan.xunlei.com':
  40. cloud = xunlei;
  41. break;
  42. case 'www.aliyundrive.com':
  43. cloud = aliyun;
  44. this.hookXHRHeader();
  45. break;
  46. }
  47. },
  48. checkFileType(name) {
  49. let type = name.toLowerCase().substring(name.lastIndexOf('.')) || "bleu"
  50. return flieTypeStr.indexOf(`${type},`) >= 0 ? true : false
  51. },
  52. async putFileInWebdav(name, info) {
  53. let header = {
  54. "authorization": `Basic ${btoa(`${bleuc.cun}:${bleuc.cpw}`)}`
  55. }
  56. let url = `https://${bleuc.cip}/PanPlaylist`;
  57. let method = bleuc.cip.indexOf('teracloud')>0?'GET':'PROPFIND';
  58. await bleu.XHR(method, url, undefined, header, undefined).then( () => {}
  59. ,async()=>{await bleu.XHR('MKCOL', url, undefined, header, undefined)})
  60. url = `https://${bleuc.cip}/PanPlaylist/${name}`;
  61. await bleu.XHR('PUT',url , info, header, 'xml').then(() => {
  62. bleu.swalInfo(`✅${name}`, 3000, 'center');
  63. }, () => bleu.swalInfo(`❌${name}`, 3000, 'center'))
  64. },
  65. checkConfig() {
  66. bleuc = JSON.parse(GM_getValue('bleuc') || null) || {cip: '',cun: '',cpw: ''};
  67. if (!(bleuc.cip != '' && bleuc.cun != '' && bleuc.cpw != '')) {
  68. bleu.swalInfo(`❗请先设置WEBDAV`, '', 'center')
  69. return false
  70. }
  71. return true
  72. },
  73. saveConfig() {
  74. let temp = document.querySelector('#cip').value.trim()
  75. temp = temp.charAt(temp.length - 1) === '/' ? temp.substring(0, temp.length - 1) : temp
  76. temp = temp.indexOf('https://') < 0 ? temp : temp.replace('https://', '')
  77. GM_setValue("bleuc", JSON.stringify({
  78. 'cip': temp,
  79. 'cun': document.querySelector('#cun').value.trim(),
  80. 'cpw': document.querySelector('#cpw').value.trim(),
  81. }));
  82. },
  83. configHtml() {
  84. bleuc = JSON.parse(GM_getValue('bleuc') || null) || {cip: '',cun: '',cpw: ''};
  85. let html = `
  86. <div class="bleuc_config_item"><p>
  87. <div><label>主机:</label><input type="text" class="bleuc_inp" id="cip" value="${bleuc.cip}"/></div>
  88. <div><label>用户:</label><input type="text" class="bleuc_inp" id="cun" value="${bleuc.cun}"/></div>
  89. <div><label>密码:</label><input type="text" class="bleuc_inp" id="cpw" value="${bleuc.cpw}"/></div></p></div>
  90. `;
  91. return html;
  92. },
  93. hookXHRHeader() {
  94. XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
  95. if(header == "x-signature"){
  96. aliyun._signature=value;
  97. }
  98. return ORGXHRSRH.apply(this, arguments);
  99. }
  100. },
  101. cssStyle: `
  102. .bleuc_config_item{border-radius: 10px;font-size: 20px;margin: 12px 50px;color: #fff;background: linear-gradient(45deg,#12c2e9, #c471ed, #f64f59);box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);}
  103. .bleuc_config_item label{font-size: 15px}
  104. .bleuc_config_item input.bleuc_inp{margin: 0px 10px;font-size: 15px;background: linear-gradient(45deg,#12c2e9, #c471ed, #f64f59);border-style:none;color:black;width:200px}
  105. .bleuc_config_item p{text-align: left;margin: 0px 20px;}`,
  106.  
  107. }
  108. const xunlei = {
  109. addTag() {
  110. if (contextMenu.innerText.match(/PotPlayer/)) return
  111. let ul = document.createElement('ul');
  112. ul.innerHTML = `<a id="bleuReSave" class="pan-dropdown-menu-item">PotPlayer打开</a>`;
  113. contextMenu.firstChild.prepend(ul.firstChild);
  114. main.addClickEvent();
  115. },
  116. getselectFilesInfo() {
  117. let temp = document.querySelectorAll('li.SourceListItem__item--XxpOC.SourceListItem__active--4U0f4');
  118. temp.forEach((item) => {
  119. this._pushItem(item.__vue__.info);
  120. })
  121. },
  122. async updateFile(item) {
  123. Option["list"].push({
  124. "title": item.name,
  125. "url": `https://api-pan.xunlei.com/drive/v1/files/${item.id}`
  126. });
  127. },
  128. async openNextDir(item) {
  129. let url = `https://api-pan.xunlei.com/drive/v1/files?limit=100&parent_id=${item.id}&filters={"phase":{"eq":"PHASE_TYPE_COMPLETE"},"trashed":{"eq":false}}&with_audit=true`;
  130. await bleu.XHR('GET', url, undefined, Option.header).then((res) => {
  131. arryIndex++;
  132. res.files.forEach((item) => {
  133. xunlei._pushItem(item);
  134. })
  135. },()=>{
  136. bleu.swalInfo("❗进出目录之后重新转存", '', 'center');
  137. throw "PPVSV:迅雷-超时,重新转存";
  138. })
  139. },
  140. findContext(node) {
  141. if (node.className === 'pan-content') {
  142. node = node.querySelector('div.pan-dropdown-menu.context-menu');
  143. if (!node) return;
  144. contextMenu = node;
  145. xunlei.addTag();
  146. }
  147. },
  148. closeMenu() {},
  149. _pushItem(temp) {
  150. if (!itemsInfo[arryIndex]) itemsInfo[arryIndex] = [];
  151. if (temp.kind === 'drive#file' && !tools.checkFileType(temp.name)) return
  152. let itemInfo = {
  153. 'id': temp.id,
  154. 'isdir': temp.kind === 'drive#file' ? false : true,
  155. 'name': temp.name,
  156. };
  157. itemsInfo[arryIndex].push(itemInfo);
  158. },
  159. getHeaderInfo() {
  160. Option.header = {};
  161. Option.header.withCredentials = false;
  162. Option.header['content-type'] = 'application/json';
  163. for (let key in localStorage) {
  164. let temp = localStorage.getItem(key)
  165. if (key.indexOf('credentials') === 0) {
  166. Option.header["Authorization"] = JSON.parse(temp).token_type + ' ' + JSON.parse(temp).access_token;
  167. Option.header["token_type"] = JSON.parse(temp).token_type;
  168. Option.header["access_token"] = JSON.parse(temp).access_token;
  169. Option.header["refresh_token"] = JSON.parse(temp).refresh_token;
  170. Option["clientid"] = key.substring(key.indexOf('_') + 1);
  171. }
  172. if (key.indexOf('captcha') === 0)
  173. Option.header['x-captcha-token'] = JSON.parse(temp).token
  174. if (key === 'deviceid')
  175. Option.header['x-device-id'] = temp.substring(temp.indexOf('.') + 1, 32 + temp.indexOf('.') + 1)
  176. }
  177. },
  178. async finallyFunc() {
  179. Option.header["clientid"] = Option["clientid"];
  180. await tools.putFileInWebdav('panvideo.txt', JSON.stringify(Option));
  181. unsafeWindow.location.href = `potplayer://panvideo##xunlei##https://${bleuc.cip}/PanPlaylist/panvideo.txt##${bleuc.cun}##${bleuc.cpw}`;
  182. }
  183. }
  184. const aliyun = {
  185. addTag() {
  186. if (contextMenu.innerText.match(/PotPlayer|新建/)) return
  187. let ul = document.createElement('ul');
  188. ul.innerHTML = `<li id="bleuReSave" class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child" role="menuitem"><div class="outer-menu--ihDUR"><div data-confirm="false" class="menu-wrapper--1ZYh_" data-spm-anchor-id="aliyundrive.drive.0.i11.40516c75ahPUGN"><div class="menu-name--1F5vk" data-spm-anchor-id="aliyundrive.drive.0.i12.40516c75ahPUGN">PotPlayer打开</div></div></div></li>`;
  189. contextMenu.prepend(ul.firstChild);
  190. main.addClickEvent();
  191. },
  192. getselectFilesInfo() {
  193. let temp = document.querySelectorAll('div[data-index]')
  194. let attrName;
  195. for(let attr in temp[0]){
  196. if(attr.indexOf('__reactFiber')==0){
  197. attrName = attr;
  198. break;
  199. }
  200. }
  201. temp.forEach((item)=>{
  202. if(item.querySelector('input')&&item.querySelector('input').checked){
  203. let value = item[attrName].return.pendingProps;
  204. aliyun._pushItem(value.data[value.index]||value.data[value.rowIndex][value.columnIndex]);
  205. }
  206. })
  207. },
  208. async updateFile(item) {
  209. Option["list"].push({
  210. "title": item.name,
  211. "url": "https://"+item.id
  212. });
  213. },
  214. async openNextDir(item) {
  215. let url = `https://api.aliyundrive.com/adrive/v3/file/list?jsonmask=next_marker%2Citems(name%2Cfile_id%2Cdrive_id%2Ctype%2Csize%2Ccreated_at%2Cupdated_at%2Ccategory%2Cfile_extension%2Cparent_file_id%2Cmime_type%2Cstarred%2Cthumbnail%2Curl%2Cstreams_info%2Ccontent_hash%2Cuser_tags%2Ctrashed%2Cvideo_media_metadata%2Cvideo_preview_metadata)`,
  216. token = JSON.parse(localStorage.getItem('token')),
  217. data = {
  218. 'drive_id': token.default_drive_id,
  219. 'parent_file_id': item.id,
  220. 'limit': 100,
  221. },
  222. header = {
  223. 'x-canary': 'client=web,app=adrive,version=v2.4.0',
  224. 'x-device-id': document.cookie.match(/cna=([^;]*)/)[1],
  225. authorization: `${token.token_type} ${token.access_token}`,
  226. 'x-signature':this._signature
  227. };
  228. await bleu.XHR('POST', url, JSON.stringify(data),header).then((res) => {
  229. arryIndex++;
  230. res.items.forEach((item)=>{
  231. aliyun._pushItem(item);
  232. },()=>{
  233. bleu.swalInfo("🔴💬刷新页面,重新获取", '', 'center');
  234. throw "PPVSV:阿里-超时,重新转存";
  235. })
  236. })
  237. },
  238. _signature:'',
  239. findContext(node) {
  240. node = document.querySelector('ul.ant-dropdown-menu');
  241. if (!node) return;
  242. //observer.disconnect();
  243. contextMenu = node;
  244. aliyun.addTag();
  245. },
  246. closeMenu(){
  247. contextMenu.parentNode.className='ant-dropdown dropdown-menu--1KRbu ant-dropdown-placement-bottomLeft ant-dropdown-hidden';
  248. contextMenu.parentNode.style.left='-578px';
  249. contextMenu.parentNode.style.top='-646px';
  250. },
  251. _pushItem(temp) {
  252. if(!itemsInfo[arryIndex]) itemsInfo[arryIndex]= [];
  253. if (temp.type==='file'&&temp.category!="video") return
  254. let itemInfo = {
  255. 'id': temp.fileId||temp.file_id,
  256. 'isdir': temp.type === 'file' ? false : true,
  257. 'name': temp.name,
  258. };
  259. itemsInfo[arryIndex].push(itemInfo);
  260. },
  261. getHeaderInfo() {
  262. Option.header ={};
  263. let token = JSON.parse(localStorage.getItem('token'));
  264. Option.header["authorization"] =`${token.token_type} ${token.access_token}`;
  265. Option.header["drive_id"] =token.default_drive_id;
  266. Option.header["x-signature"]=this._signature;
  267. Option.header["x-device-id"]=document.cookie.match(/cna=([^;]*)/)[1];//decodeURIComponent(localStorage.getItem('APLUS_CNA').substring(9))
  268. },
  269. async finallyFunc(){
  270. await tools.putFileInWebdav('panvideo.txt', JSON.stringify(Option));
  271. unsafeWindow.location.href = `potplayer://panvideo##aliyun##https://${bleuc.cip}/PanPlaylist/panvideo.txt##${bleuc.cun}##${bleuc.cpw}`;
  272. }
  273. }
  274. const main = {
  275. init() {
  276. observer = new MutationObserver(function (mutations) {
  277. for (let mutation of mutations) {
  278. if (mutation.type === 'childList') {
  279. cloud.findContext(mutation.target);
  280. }
  281. }
  282. });
  283. observer.observe(document, {
  284. 'childList': true,
  285. 'subtree': true
  286. });
  287. },
  288. addClickEvent() {
  289. let bleuButton = document.getElementById('bleuReSave');
  290. bleuButton.addEventListener('click', async function () {
  291. itemsInfo = [];
  292. arryIndex = 0;
  293. Option = {}, Option["list"] = [];
  294. if(!tools.checkConfig())return;
  295. cloud.closeMenu();
  296. cloud.getselectFilesInfo();
  297. cloud.getHeaderInfo();
  298. if (!itemsInfo[arryIndex]||itemsInfo[arryIndex].length === 0) {
  299. bleu.swalInfo(`❌未选择文件转存!`, 3000, 'center')
  300. return;
  301. }
  302. try {
  303. await main.updateAllFiles(itemsInfo[arryIndex]);
  304. } catch (e) {
  305. console.log(e);
  306. return;
  307. }
  308. Option["list"].length!=0&&cloud.finallyFunc();
  309. })
  310. },
  311. async updateAllFiles(loopArry) {
  312. for (let index = 0; index < loopArry.length; index++) {
  313. if (!loopArry[index].isdir) {
  314. await cloud.updateFile(loopArry[index]);
  315. } else {
  316. await cloud.openNextDir(loopArry[index]);
  317. await main.updateAllFiles(itemsInfo[arryIndex]);
  318. }
  319. bleu.sleep(800);
  320. }
  321. },
  322. };
  323. tools.getCloudName();
  324. //tools.checkConfig();
  325. bleu.addCssStyle(tools.cssStyle);
  326. GM_registerMenuCommand('配置WEBDAV', () => {
  327. bleu.swalUI('WEBDAV', tools.configHtml(), '400px').then(tools.saveConfig)
  328. }, 'w')
  329. main.init();
  330. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址