// ==UserScript== // @name 阿里云盘播放器(mux.js) // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author You // @match https://www.aliyundrive.com/s/* // @match https://www.aliyundrive.com/drive* // @require https://cdn.jsdelivr.net/npm/mux.js/dist/mux.min.js // @require https://cdn.staticfile.org/jquery/3.6.0/jquery.min.js // @require https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js // @require https://cdn.jsdelivr.net/npm/m3u8-parser/dist/m3u8-parser.min.js // @icon https://gw.alicdn.com/imgextra/i3/O1CN01aj9rdD1GS0E8io11t_!!6000000000620-73-tps-16-16.ico // @grant unsafeWindow // ==/UserScript== (function() { 'use strict'; var $ = $ || window.$; var obj = { file_page: { headers: {}, parent_file_id: "root", file_info: {}, items: [] }, video_page: { file_info: {}, play_info: {}, sub_info: { index: 0 }, elevideo: "", player: null } }; (function(send) { XMLHttpRequest.prototype.send = function (sendParams) { this.addEventListener("load", function(event) { if (this.readyState == 4 && this.status == 200) { var response = this.response, responseURL = this.responseURL; if (responseURL.endsWith("/users/device/create_session") || responseURL.endsWith("/users/device/renew_session")) { obj.file_page.headers = this._header_; } else if (responseURL.indexOf("/file/get_share_link_video_preview_play_info") > 0) { try { response = JSON.parse(response) } catch (error) { }; if (response instanceof Object) { obj.video_page.play_info = response; obj.initArtplayer(); } } else if (responseURL.indexOf("/file/get_video_preview_play_info") > 0) { try { response = JSON.parse(response) } catch (error) { }; if (response instanceof Object) { obj.video_page.play_info = response; if (obj.isSharePage()) { obj.get_share_link_video_preview_play_info().then((response) => { obj.video_page.play_info = response; obj.initArtplayer(); }); return; } obj.initArtplayer(); } } } }, false); send.apply(this, arguments); }; })(XMLHttpRequest.prototype.send); obj.initArtplayer = function () { var container, videoNode = document.querySelector("video"); if (videoNode) { container = document.getElementById("artplayer"); if (!container) { container = document.createElement("div"); container.setAttribute("id", "artplayer"); container.setAttribute("style", "width: 100%; height: 100%;"); var videoParentNode = videoNode.parentNode.parentNode; obj.video_page.elevideo = videoParentNode.parentNode.replaceChild(container, videoParentNode); } else { return; } } var quality = obj.getQuality(); if (!quality.length) { return console.log("获取播放信息失败:请刷新网页重试"); } var subtitles = obj.getSubtitle(), subtitle = subtitles.find((element, index) => element.default) || subtitles.slice(-1)[0] || {}; var art = unsafeWindow.art = new window.Artplayer({ container: container, url: quality.find((element, index) => element.default).url || quality.slice(-1).url, quality: quality, type: 'transmuxer', customType: { transmuxer: function (video, url, art) { // https://github.com/videojs/mux.js // 最大的问题 报错 SourceBuffer已满 console.log("video, url, art", video, url, art); var vidUrl = url.replace(/media.m3u8.+/, ""); var outputType = 'combined'; // 音视频:'combined', 视频:'video', 音频:'audio' var maxBufferLength = Math.min(30 * 2, 30 * 2 * 10); // 1080P 连续进度(end - currentTime > 350)引发错误:SourceBuffer已满 var duration = 0, currIndex = 0, lastIndex = 0; var parser, transmuxer = new window.muxjs.mp4.Transmuxer({ remux: outputType === 'combined' }); var sourceBuffer, mediaSource = new (window.MediaSource || window.WebKitMediaSource)(); const _video = video; art.off('destroy').on('destroy', () => { mediaSource.endOfStream(); sourceBuffer.removeEventListener('updateend', playNextSegment); console.info('destroy'); }); art.on('seek', () => { console.log("art.currentTime", art.currentTime); _video.ontimeupdate = null; getCurrIndex(); playNextSegment(); }); var remuxedSegments = []; var remuxedBytesLength = 0; var remuxedInitSegment = null; // 监听data事件,开始转换流 transmuxer.on('data', function(event) { if (event.type === outputType) { remuxedSegments.push(event); remuxedBytesLength += event.data.byteLength; remuxedInitSegment = event.initSegment; } }); // 监听转换完成事件,拼接最后结果并传入MediaSource transmuxer.on('done', function (event) { var offset = 0; var bytes = new Uint8Array(remuxedInitSegment.byteLength + remuxedBytesLength) bytes.set(remuxedInitSegment, offset); offset += remuxedInitSegment.byteLength; for (var j = 0, i = offset; j < remuxedSegments.length; j++) { bytes.set(remuxedSegments[j].data, i); i += remuxedSegments[j].byteLength; } remuxedSegments = []; remuxedBytesLength = 0; try { sourceBuffer.appendBuffer(bytes); const segments = parser.manifest.segments; segments[lastIndex].done = true; console.log("appendBuffer", lastIndex); } catch (error) { console.error(error); removeSourceBuffer(); } }); init(); function init () { return fetchM3u8(url).then((data) => { playManifest(data); const currIndex = getCurrIndex(); if (currIndex === 0) { playFirstSegment(); } }); } function playManifest (data) { parser = new window.m3u8Parser.Parser(); parser.push(data); parser.end(); duration = 0; const segments = parser.manifest.segments; segments.forEach(function (item, index) { item.uri = vidUrl + item.uri; item.start = duration; item.end = duration + item.duration; duration += item.duration; }); } function getCurrIndex () { const segments = parser.manifest.segments; const currentTime = art.currentTime || 0; currIndex = segments.findIndex(({ start, end }) => currentTime >= start && currentTime <= end); return currIndex; } function playFirstSegment () { video.src = URL.createObjectURL(mediaSource); mediaSource.addEventListener('sourceopen', appendFirstSegment, { once: true }); } function appendFirstSegment () { URL.revokeObjectURL(video.src); mediaSource.duration = duration; //设置视频总时长 // 转换后mp4的音频格式 视频格式 var codecsArray = ["avc1.64001f", "mp4a.40.5"]; if (outputType === 'combined') { // 转换为带音频、视频的mp4 sourceBuffer = mediaSource.addSourceBuffer('video/mp4;codecs="avc1.64001f,mp4a.40.5"'); } else if (outputType === 'video') { // 转换为只含视频的mp4 sourceBuffer = mediaSource.addSourceBuffer('video/mp4;codecs="' + codecsArray[0] + '"'); } else if (outputType === 'audio') { // 转换为只含音频的mp4 sourceBuffer = mediaSource.addSourceBuffer('audio/mp4;codecs="' + (codecsArray[1] || codecsArray[0]) + '"'); } sourceBuffer.addEventListener('updateend', playNextSegment); // 不间断的把视频剩余数据加载进来 pushBuffer(0); } function playNextSegment () { const segments = parser.manifest.segments; if (currIndex == segments.length - 1 && segments[currIndex].done) { console.log("playNextSegment 停止", currIndex); //mediaSource.endOfStream(); return; } if (sourceBuffer.updating) { return setTimeout(playNextSegment, 3e3); } const currentTime = art.currentTime; while (segments[currIndex].done && currIndex < segments.length && currIndex * 10 - currentTime < maxBufferLength) { currIndex += 1; } console.log("currIndex", currIndex); if (segments[currIndex].done) { waitNextSegment().then(playNextSegment); } else { appendNextSegment(currIndex); } } function waitNextSegment () { return new Promise(function (resolve, reject) { var lastTime = art.currentTime; var lastIdx = currIndex; _video.ontimeupdate = () => { const currentTime = art.currentTime; if (Math.abs(currentTime - lastTime) > 3) { lastTime = currentTime; const index = getCurrIndex(); if (index !== lastIdx) { //art.off('video:timeupdate'); // 影响播放器跳进度时间 _video.ontimeupdate = null; resolve(); } } }; }); } function appendNextSegment (index) { pushBuffer(index); } function pushBuffer (index) { const segment = parser.manifest.segments[index]; if (segment && segment.uri) { fetchTs(segment.uri).then((response) => { transmuxer.push(new Uint8Array(response)); transmuxer.flush(); }).catch((erroe) => { againPlayInfo(index).then((response) => { transmuxer.push(new Uint8Array(response)); transmuxer.flush(); }) }); } lastIndex = index; } function fetchM3u8 (m3u8url) { return fetch(m3u8url).then((response) => { return response.ok ? response.text() : Promise.reject(); }).then((data) => { return data ? data : Promise.reject(); }); } function fetchTs (tsurl) { return fetch(tsurl).then((response) => { return response.ok ? response.arrayBuffer() : Promise.reject(); }); } function againPlayInfo (index) { return obj.getPlayInfo().then((response) => { console.log("getPlayInfo", response); var quality = obj.getQuality(response); if (quality.length) { art.option.quality = quality; url = art.option.url = quality.find((element, index) => element.default)?.url || quality.slice(-1)?.url; return fetchM3u8(url).then((data) => { playManifest(data); const uri = parser.manifest.segments[index].uri; return fetchTs(uri); }); } else { return Promise.reject(); } }); } function getCurrBuffered () { const { currentTime, duration, buffered } = video; for (let i = 0; i < buffered.length; i++) { const start = buffered.start(i); const end = buffered.end(i); if (parseInt(start) <= currentTime && end >= currentTime) { return { start, end, currentTime }; } } return {}; } function removeSourceBuffer () { const { buffered } = sourceBuffer; if (buffered.length > 1) { for (let i = 0; i < buffered.length; i++) { const start = buffered.start(i); const end = buffered.end(i); const currentTime = art.currentTime; console.log("start, end", start, end, currentTime, currentTime >= start && currentTime <= end); // 清除当前所属缓冲区之外的所有缓冲区 if (!(currentTime >= start && currentTime <= end)) { sourceBuffer.remove(start, end); } } } } function isUrlExpires (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 6e3 , n = e.match(/&x-oss-expires=(\d+)&/); return !n || n && n[1] && +"".concat(n[1], "000") - t < Date.now(); } // 问题:进度条返回0位卡住不再播放 // 问题:遇到段之间间隙,应轻推进度 function tryNudgeBuffer() { const { config, hls, media, nudgeRetry } = this; if (media === null) { return; } const currentTime = media.currentTime; this.nudgeRetry++; if (nudgeRetry < config.nudgeMaxRetry) { const targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset; // playback stalled in buffered area ... let's nudge currentTime to try to overcome this const error = new Error( `Nudging 'currentTime' from ${currentTime} to ${targetTime}`, ); console.warn(error.message); media.currentTime = targetTime; } else { const error = new Error( `Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`, ); console.error(error.message); } } }, }, subtitle: subtitle, autoplay: true, pip: true, autoSize: true, autoMini: true, screenshot: true, setting: true, flip: true, playbackRate: true, aspectRatio: true, fullscreen: true, fullscreenWeb: true, subtitleOffset: true, miniProgressBar: true, backdrop: true, playsInline: true, autoPlayback: true, airplay: true, theme: '#23ade5', moreVideoAttr: { crossOrigin: 'anonymous', }, settings: [], controls: [], icons: { loading: '', state: '', indicator: '', }, }); art.on('ready', () => { }); $("#root > div.modal--nw7G9 > div > div.content--9N3Eh > div.header--u7XR- > div.header-left--Kobd9").one("click", function () { console.log("VideoPreviewer exit"); art.destroy(); }); console.log("=== art 初始化成功 ===", art); } obj.getQuality = function (play_info) { var task_list = (play_info || obj.video_page.play_info)?.video_preview_play_info?.live_transcoding_task_list || []; if (Array.isArray(task_list)) { task_list = task_list.filter(item => item.url); var templates = { UHD: "4K 超清", QHD: "2K 超清", FHD: "1080 全高清", HD: "720 高清", SD: "540 标清", LD: "360 流畅" }; task_list.forEach(function (item, index) { Object.assign(item, { default: ++index === task_list.length, html: templates[item.template_id] }); }); } return task_list; }; obj.getSubtitle = function (play_info) { var task_list = (play_info || obj.video_page.play_info)?.video_preview_play_info?.live_transcoding_subtitle_task_list || []; if (Array.isArray(task_list)) { task_list = task_list.filter(item => item.status === "finished"); var templates = { jpn: "日文字幕", chi: "中文字幕", eng: "英文字幕" }; task_list.forEach(function (item, index) { Object.assign(item, { type: "vtt", escape: true, encoding: 'utf-8', style: { color: '#fe9200', fontSize: '30px', bottom: '10%', fontWeight: 500 }, html: templates[item.language] || "未知语言", default: item.language === "chi" }); }); } return task_list; }; obj.getPlayInfo = function () { return obj.refresh_token().then (() => { return obj.isHomePage() ? obj.get_video_preview_play_info() : obj.get_share_link_video_preview_play_info(); }); }; obj.get_video_preview_play_info = function () { const { file_id } = obj.video_page.play_info; const { default_drive_id, token_type, access_token } = obj.getItem("token"); const { "x-device-id": deviceid, "x-signature": signature} = obj.file_page.headers; return fetch("https://api.aliyundrive.com/v2/file/get_video_preview_play_info", { body: JSON.stringify({ drive_id: default_drive_id, file_id: file_id, category: "live_transcoding", template_id: "", get_subtitle_info: !0 }), headers: { "authorization": "".concat(token_type || "", " ").concat(access_token || ""), "content-type": "application/json;charset=UTF-8", "x-device-id": deviceid || obj.getItem("cna"), "x-signature": signature }, method: "POST" }).then((response) => { return response.ok ? response.json() : Promise.reject(response.json()); }).then((response) => { obj.video_page.play_info = response; return response; }); }; obj.get_share_link_video_preview_play_info = function () { const { file_id, share_id } = obj.video_page.play_info; const { token_type, access_token } = obj.getItem("token"); const { share_token } = obj.getItem("shareToken"); const { "x-device-id": deviceid, "x-signature": signature } = obj.file_page.headers; return fetch("https://api.aliyundrive.com/v2/file/get_share_link_video_preview_play_info", { body: JSON.stringify({ category: "live_transcoding", file_id: file_id, get_preview_url: true, share_id: share_id || obj.getShareId(), template_id: "", //template_id: "OD|QHD|FHD|HD|SD|LD", get_subtitle_info: !0 }), headers: { "authorization": "".concat(token_type || "", " ").concat(access_token || ""), "content-type": "application/json;charset=UTF-8", "x-share-token": share_token, "x-device-id": deviceid || obj.getItem("cna"), "x-signature": signature }, method: "POST" }).then((response) => { return response.ok ? response.json() : Promise.reject(response.json()); }).then((response) => { obj.video_page.play_info = response; return response; }); }; obj.refresh_token = function () { var token = obj.getItem("token"); if (!(token && token.refresh_token)) { return Promise.reject(); } if (obj.isExpires(token)) { return Promise.resolve(); } return fetch("https://api.aliyundrive.com/token/refresh", { body: JSON.stringify({ refresh_token: token.refresh_token }), method: "POST" }).then((response) => { return response.ok ? response.json() : Promise.reject(); }).then((response) => { obj.setItem("token", response); return response; }); }; obj.create_session = function (callback) { obj.secp256k1Support(function (secp256k1) { const { device_id, user_id, token_type, access_token } = obj.getItem("token"); const { crypto, Secp256k1, Global: { app_id } } = unsafeWindow; // app_id : "5dde4e1bdf9e4966b387ba58f4b3fdc3"; const privateKeyBuf = crypto.getRandomValues(new Uint8Array(32)); const privateKey = Secp256k1.uint256(privateKeyBuf, 16); const publicKey = Secp256k1.generatePublicKeyFromPrivateKeyData(privateKey); const pubKey = "04" + publicKey.x + publicKey.y; const nonce = 0; const encoder = new TextEncoder(); const data = encoder.encode(`${app_id}:${device_id}:${user_id}:${nonce}`); crypto.subtle.digest("SHA-256", data).then(function (hashBuffer) { const hashUint8 = new Uint8Array(hashBuffer); const digest = Secp256k1.uint256(hashUint8, 16); const sig = Secp256k1.ecsign(privateKey, digest); const signature = sig.r + sig.s + "00"; $.ajax({ type: "post", url: "https://api.aliyundrive.com/users/v1/users/device/create_session", data: JSON.stringify({ deviceName: obj.getBrowser().browser.name + "浏览器", modelName: obj.getBrowser().os.name + "网页版", pubKey: pubKey }), headers: { "authorization": "".concat(token_type || "", " ").concat(access_token || ""), "content-type": "application/json;charset=utf-8", "x-device-id": obj.getItem("cna"), "x-signature": signature }, success: function (response) { console.log("=== 阿里云盘 create_session ===", response); callback && callback(response.result); }, error: function (error) { console.error("=== 阿里云盘 create_session ===", error); callback && callback(""); } }); }); }); }; obj.secp256k1Support = function (callback) { /* 参考 https://github.com/Souls-R/AliyunPlayScript */ /* https://cdn.jsdelivr.net/npm/secp256k1@5.0.0/elliptic.min.js https://unpkg.com/@noble/secp256k1 https://cdn.jsdelivr.net/npm/bn.js/lib/bn.min.js https://cdn.jsdelivr.net/npm/@lionello/secp256k1-js/src/secp256k1.min.js https://r.cnpmjs.org/bn.js https://mirrors.cloud.tencent.com/npm/bn.js */ obj.loadJs("https://unpkg.com/bn.js/lib/bn.js").then(function() { obj.loadJs("https://unpkg.com/@lionello/secp256k1-js/src/secp256k1.js").then(function() { callback && callback(unsafeWindow.Secp256k1); }, function() { callback && callback(""); }); }, function() { callback && callback(""); }); }; obj.getBrowser = function () { return obj.browser || function(i, o) { var n = i.navigator && i.navigator.userAgent ? i.navigator.userAgent : "" , l = "object" , a = "function" , c = "string" , p = "version" , d = "name" , F = "Facebook" , k = "BlackBerry" , U = { ME: "4.90", "NT 3.11": "NT3.51", "NT 4.0": "NT4.0", 2e3: "NT 5.0", XP: ["NT 5.1", "NT 5.2"], Vista: "NT 6.0", 7: "NT 6.1", 8: "NT 6.2", 8.1: "NT 6.3", 10: ["NT 6.4", "NT 10.0"], RT: "ARM" } , z = function (e, t) { for (var n in t) { if (typeof t[n] === l && t[n].length > 0) { for (var r = 0; r < t[n].length; r++) { if (R(t[n][r], e)) { return "?" === n ? o : n; } } } else if (R(t[n], e)) { return "?" === n ? o : n; } } return e; } , R = function (e, t) { return typeof e === c && -1 !== L(t).indexOf(L(e)); } , L = function (e) { return e.toLowerCase(); } , Z = function (e, t) { for (var n, r, i, s, c, u, d = 0; d < t.length && !c; ) { var f = t[d], h = t[d + 1]; for (n = r = 0; n < f.length && !c; ) { if (c = f[n++].exec(e)) { for (i = 0; i < h.length; i++) { u = c[++r]; typeof (s = h[i]) === l && s.length > 0 ? 2 === s.length ? typeof s[1] == a ? this[s[0]] = s[1].call(this, u) : this[s[0]] = s[1] : 3 === s.length ? typeof s[1] !== a || s[1].exec && s[1].test ? this[s[0]] = u ? u.replace(s[1], s[2]) : o : this[s[0]] = u ? s[1].call(this, u, s[2]) : o : 4 === s.length && (this[s[0]] = u ? s[3].call(this, u.replace(s[1], s[2])) : o) : this[s] = u || o; } } } d += 2; } } , r = { browser: [ [/\b(?:crmo|crios)\/([\w\.]+)/i], [p, [d, "Chrome"]], [/edg(?:e|ios|a)?\/([\w\.]+)/i], [p, [d, "Edge"]], [/(opera mini)\/([-\w\.]+)/i, /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i], [d, p], [/opios[\/ ]+([\w\.]+)/i], [p, [d, "Opera Mini"]], [/\bopr\/([\w\.]+)/i], [p, [d, "Opera"]], [/(kindle)\/([\w\.]+)/i, /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, /(ba?idubrowser)[\/ ]?([\w\.]+)/i, /(?:ms|\()(ie) ([\w\.]+)/i, /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq)\/([-\w\.]+)/i, /(weibo)__([\d\.]+)/i], [d, p], [/(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i], [p, [d, "UCBrowser"]], [/\bqbcore\/([\w\.]+)/i], [p, [d, "WeChat(Win) Desktop"]], [/micromessenger\/([\w\.]+)/i], [p, [d, "WeChat"]], [/konqueror\/([\w\.]+)/i], [p, [d, "Konqueror"]], [/trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i], [p, [d, "IE"]], [/yabrowser\/([\w\.]+)/i], [p, [d, "Yandex"]], [/(avast|avg)\/([\w\.]+)/i], [[d, /(.+)/, "$1 Secure Browser"], p], [/\bfocus\/([\w\.]+)/i], [p, [d, "Firefox Focus"]], [/\bopt\/([\w\.]+)/i], [p, [d, "Opera Touch"]], [/coc_coc\w+\/([\w\.]+)/i], [p, [d, "Coc Coc"]], [/dolfin\/([\w\.]+)/i], [p, [d, "Dolphin"]], [/coast\/([\w\.]+)/i], [p, [d, "Opera Coast"]], [/miuibrowser\/([\w\.]+)/i], [p, [d, "MIUI Browser"]], [/fxios\/([-\w\.]+)/i], [p, [d, "Firefox"]], [/\bqihu|(qi?ho?o?|360)browser/i], [[d, "360 Browser"]], [/(oculus|samsung|sailfish)browser\/([\w\.]+)/i], [[d, /(.+)/, "$1 Browser"], p], [/(comodo_dragon)\/([\w\.]+)/i], [[d, /_/g, " "], p], [/(electron)\/([\w\.]+) safari/i, /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i], [d, p], [/(metasr)[\/ ]?([\w\.]+)/i, /(lbbrowser)/i], [d], [/((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i], [[d, F], p], [/safari (line)\/([\w\.]+)/i, /\b(line)\/([\w\.]+)\/iab/i, /(chromium|instagram)[\/ ]([-\w\.]+)/i], [d, p], [/\bgsa\/([\w\.]+) .*safari\//i], [p, [d, "GSA"]], [/headlesschrome(?:\/([\w\.]+)| )/i], [p, [d, "Chrome Headless"]], [/ wv\).+(chrome)\/([\w\.]+)/i], [[d, "Chrome WebView"], p], [/droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i], [p, [d, "Android Browser"]], [/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i], [d, p], [/version\/([\w\.]+) .*mobile\/\w+ (safari)/i], [p, [d, "Mobile Safari"]], [/version\/([\w\.]+) .*(mobile ?safari|safari)/i], [p, d], [/webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i], [d, [p, z, { "1.0": "/8", 1.2: "/1", 1.3: "/3", "2.0": "/412", "2.0.2": "/416", "2.0.3": "/417", "2.0.4": "/419", "?": "/" }]], [/(webkit|khtml)\/([\w\.]+)/i], [d, p], [/(navigator|netscape\d?)\/([-\w\.]+)/i], [[d, "Netscape"], p], [/mobile vr; rv:([\w\.]+)\).+firefox/i], [p, [d, "Firefox Reality"]], [/ekiohf.+(flow)\/([\w\.]+)/i, /(swiftfox)/i, /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, /(firefox)\/([\w\.]+)/i, /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, /(links) \(([\w\.]+)/i], [d, p] ], os: [ [/microsoft (windows) (vista|xp)/i], [d, p], [/(windows) nt 6\.2; (arm)/i, /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i], [d, [p, z, U]], [/(win(?=3|9|n)|win 9x )([nt\d\.]+)/i], [[d, "Windows"], [p, z, U]], [/ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, /cfnetwork\/.+darwin/i], [[p, /_/g, "."], [d, "iOS"]], [/(mac os x) ?([\w\. ]*)/i, /(macintosh|mac_powerpc\b)(?!.+haiku)/i], [[d, "Mac OS"], [p, /_/g, "."]], [/droid ([\w\.]+)\b.+(android[- ]x86)/i], [p, d], [/(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i, /(blackberry)\w*\/([\w\.]*)/i, /(tizen|kaios)[\/ ]([\w\.]+)/i, /\((series40);/i], [d, p], [/\(bb(10);/i], [p, [d, k]], [/(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i], [p, [d, "Symbian"]], [/mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i], [p, [d, "Firefox OS"]], [/web0s;.+rt(tv)/i, /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i], [p, [d, "webOS"]], [/crkey\/([\d\.]+)/i], [p, [d, "Chromecast"]], [/(cros) [\w]+ ([\w\.]+\w)/i], [[d, "Chromium OS"], p], [/(nintendo|playstation) ([wids345portablevuch]+)/i, /(xbox); +xbox ([^\);]+)/i, /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, /(mint)[\/\(\) ]?(\w*)/i, /(mageia|vectorlinux)[; ]/i, /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, /(hurd|linux) ?([\w\.]*)/i, /(gnu) ?([\w\.]*)/i, /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, /(haiku) (\w+)/i], [d, p], [/(sunos) ?([\w\.\d]*)/i], [[d, "Solaris"], p], [/((?:open)?solaris)[-\/ ]?([\w\.]*)/i, /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, /(unix) ?([\w\.]*)/i], [d, p] ] } , getBrowser = function () { var e, t = {}; t.name = o; t.version = o; Z.call(t, n, r.browser); t.major = typeof (e = t.version) === c ? e.replace(/[^\d\.]/g, "").split(".")[0] : o; return t; } , getOS = function () { var e = {}; e.name = o; e.version = o; Z.call(e, n, r.os); return e; } , getUA = function () { return n; }; obj.browser = { ua: getUA(), browser: getBrowser(), os: getOS() }; return obj.browser; }("object" == typeof window ? window : unsafeWindow); }; obj.soundEnhancer = function (player) { const { user, storage, video, joySound } = player; if ((user && user.get("joysound")) || (storage && storage.get("joysound"))) { if (joySound) { joySound.setEnabled(!0); } else { obj.initJoysound(function (Joysound) { if (unsafeWindow.Joysound && unsafeWindow.Joysound.isSupport()) { let joySound = player.joySound = new unsafeWindow.Joysound(!0); joySound.hasSource() || joySound.init(video); joySound.setEnabled(!0); } }); } } else { joySound && joySound.hasSource() && joySound.setEnabled(!1); } }; obj.volumeEnhancer = function (player) { const { user, storage, video, joySound } = player; let gain = (user && user.get("gain")) || (storage && storage.get("gain")) || 0; if (joySound) { joySound.setVolume(gain); } else { obj.initJoysound(function (Joysound) { if (unsafeWindow.Joysound && unsafeWindow.Joysound.isSupport()) { var joySound = player.joySound = new unsafeWindow.Joysound(!0); joySound.hasSource() || joySound.init(video); joySound.setVolume(gain); } }); } /* const audioContext = window.audioContext || function () { const AudioContext = window.AudioContext || window.webkitAudioContext; return (window.audioContext = new AudioContext()); }(); const audioSource = video.audioSource || function () { return (video.audioSource = audioContext.createMediaElementSource(video)); }(); if (!video.gainNode) { video.gainNode = audioContext.createGain(); video.audioSource.connect(video.gainNode).connect(audioContext.destination); } video.gainNode.gain.value = 1 + percentage * 10; */ }; obj.initJoysound = function (callback) { if (unsafeWindow.Joysound) { callback && callback(unsafeWindow.Joysound); } else { (function laodcdn (urlArr, index) { var url = urlArr[index]; if (url) { obj.loadJs(url).then(function() { setTimeout(function () { callback && callback(unsafeWindow.Joysound); }); }).catch(function (error) { laodcdn(urlArr, ++index); }); } else { callback && callback(unsafeWindow.Joysound); } })([ "https://gitee.com/caogaolei/Self-use/raw/main/Joysound.js", "https://scriptcat.org/lib/950/^1.0.1/Joysound.js", "https://github.com/tampermonkeyStorage/Self-use/raw/main/Joysound.js" ], 0); } }; obj.isHomePage = function () { return location.href.indexOf(".aliyundrive.com/drive") > 0; }; obj.isSharePage = function () { return location.href.indexOf(".aliyundrive.com/s/") > 0; }; obj.isExpires = function (file) { var t = file.expire_time, i = Number(file.expires_in), e = Date.parse(t) - Date.now(); if (0 < e && e < 1e3 * i) return !0; return !1; }; obj.clamp = function (num, a, b) { return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b)); }; obj.loadJs = function (src) { if (!window.instances) { window.instances = {}; } if (!window.instances[src]) { window.instances[src] = new Promise((resolve, reject) => { const script = document.createElement("script") script.src = src; script.type = "text/javascript"; script.onload = resolve; script.onerror = reject; //document.head.appendChild(script); //document.head.append(script); Node.prototype.appendChild.call(document.head, script); }); } return window.instances[src]; }; obj.loadCss = function (href) { if (!window.instances) { window.instances = {}; } if (!window.instances[href]) { window.instances[href] = new Promise((resolve, reject) => { const style = document.createElement("link"); style.type = "text/css"; style.rel = "stylesheet"; style.href = href; style.onload = resolve; style.onerror = reject; // document.head.appendChild(style); //document.head.append(style); Node.prototype.appendChild.call(document.head, style); }); } return window.instances[href]; }; obj.getShareId = function () { var match = location.href.match(/aliyundrive\.com\/s\/([a-zA-Z\d]+)/); return match ? match[1] : null; }; obj.getItem = function (n) { n = localStorage.getItem(n) || sessionStorage.getItem(n); if (!n) { return null; } try { return JSON.parse(n); } catch (e) { return n; } }; obj.setItem = function (n, t) { n && t && localStorage.setItem(n, t instanceof Object ? JSON.stringify(t) : t); }; if (obj.isSharePage()) { obj.refresh_token().then (() => { obj.create_session(); setInterval(() => { obj.refresh_token().then (() => { obj.create_session(); }); }, 1000 * 60 * 5); }); } // Your code here... })();