// ==UserScript== // @name Replace ddys Origin Player // @namespace https://github.com/s0urcelab/replace-ddys-origin-player // @version 1.3 // @description 替换ddys播放器,移除Adblock屏蔽,修复滚轮和全屏快捷键失效bug,优化选集和线路功能,自动记忆选集 // @author s0urce // @match https://ddys.art/* // @icon https://www.google.com/s2/favicons?sz=64&domain=ddys.art // @grant GM_addStyle // @grant GM_xmlhttpRequest // @require https://fastly.jsdelivr.net/npm/xgplayer@2.31.2/browser/index.min.js // @run-at document-end // @downloadURL none // ==/UserScript== const QS = (q) => document.querySelector(q) const QSA = (q) => document.querySelectorAll(q) const domain = window.location.hostname const src4domain = `v.ddys.pro` const globalStyle = ` .wp-playlist-tracks { display: none!important; } .wp-video-playlist { display: flex; padding: 0!important; border: none!important; background: none!important; } .entry > p { display: none; } .player-sider { width: 220px; display: flex; flex-direction: column; background-color: #2e2e2e; border-radius: 8px; margin-left: 10px; padding: 4px; } .tab-item { cursor: pointer; margin-bottom: 6px; padding: 8px; color: white; background-color: #5a5a5a; border-radius: 5px; } .tab-item.playing { font-weight: bold; color: #3a8fb7; background-color: #232323; } .tab-item:not(.playing):hover { background-color: #232323; } .tab-item > .indicator { height: 14px; width: 14px; font-size: 14px; margin-right: 5px; } .switch-root { cursor: pointer; user-select: none; position: relative; background: #e0e0e0; border-radius: 26px; width: 174px; padding: 2px; } .sw-group { position: absolute; top: 0; left: 0; padding: 2px; width: 170px; display: flex; justify-content: space-between; } .sw-item { line-height: 30px; padding: 0 10px; color: #666; } .sw-item.active { font-weight: bold; color: #333; } .switch-root > .indicator { transition: all 0.2s ease; margin-left: 0; width: 86px; height: 30px; background: #fff; border-radius: 26px; box-shadow: 0px 0px 6px -2px #111; } .switch-root > .indicator.overseas { margin-left: 84px; } .ep-tip { margin: 10px 0; color: white; } ` function parseResUrl(region, d) { // type 4 if (d.srctype === '4') return { ...d, url: `https://${src4domain}${d.src3}` } // 海外线路 if (region == 'overseas') return { ...d, url: `https://w.ddys.art${d.src0}?ddrkey=${d.src2}` } return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', responseType: 'json', headers: { 'referer': `https://${domain}/` }, url: `https://${domain}/getvddr2/video?id=${d.src1}&type=json`, onload: res => { resolve({ ...d, url: res.response.url }) }, onerror: function (error) { reject(error) }, }) }) } class Tabs { constructor(init) { this.root = init.root this.data = init.data this.onSelect = init.onSelect this.selectedKey = init.data[0].key } render(key = this.selectedKey) { // update selectedKey this.selectedKey = key // render dom this.root.innerHTML = this.data.reduce((acc, curr) => { const isTarget = key === curr.key return `${acc}
` }, '') // bind click const self = this for (const tabElment of this.root.children) { tabElment.onclick = function() { const tabKey = tabElment.dataset.tabKey const record = self.data.find(v => v.key === tabKey) self.render(tabKey) self.onSelect(tabKey, record) } } } } class Switch { constructor(init) { this.root = init.root this.data = init.data this.onSelect = init.onSwitch this.selectedKey = init.data[0].key } render(key = this.selectedKey) { // update selectedKey this.selectedKey = key // render dom const group = this.data.reduce((acc, curr) => { const isTarget = key === curr.key return `${acc}选集: