阿里云盘播放器(mux.js)
// ==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: '<img src="https://artplayer.org/assets/img/ploading.gif">',
state: '<img width="150" heigth="150" src="https://artplayer.org/assets/img/state.svg">',
indicator: '<img width="16" heigth="16" src="https://artplayer.org/assets/img/indicator.svg">',
},
});
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...
})();