Greasy Fork is available in English.
替换ddys播放器,移除Adblock屏蔽,修复滚轮和全屏快捷键失效bug,优化选集和线路功能,自动记忆选集
- // ==UserScript==// @name 替换ddys(低端影视)播放器// @namespace https://github.com/s0urcelab/userscripts// @version 1.5// @description 替换ddys播放器,移除Adblock屏蔽,修复滚轮和全屏快捷键失效bug,优化选集和线路功能,自动记忆选集// @author s0urce// @match https://ddys.art/*// @match https://ddys.pro/*// @icon https://ddys.pro/favicon-16x16.png// @grant GM_addStyle// @grant GM_xmlhttpRequest// @require https://fastly.jsdelivr.net/npm/xgplayer@2.31.2/browser/index.min.js// @run-at document-end// ==/UserScript==const QS = (q) => document.querySelector(q)const QSA = (q) => document.querySelectorAll(q)const domain = window.location.hostnameconst 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;}`function parseR###rl(d) {return { ...d, url: `https://${src4domain}${d[`src${d.srctype - 1}`]}` }}class Tabs {constructor(init) {this.root = init.rootthis.data = init.datathis.onSelect = init.onSelectthis.selectedKey = init.data[0].key}render(key = this.selectedKey) {// update selectedKeythis.selectedKey = key// render domthis.root.innerHTML = this.data.reduce((acc, curr) => {const isTarget = key === curr.keyreturn `${acc}<div class="tab-item ${isTarget ? 'playing' : ''}" data-tab-key="${curr.key}">${isTarget ? '<img class="indicator" src="//s1.hdslb.com/bfs/static/jinkela/video/asserts/playing.gif"></img>' : ''}${curr.label}</div>`}, '')// bind clickconst self = thisfor (const tabElment of this.root.children) {tabElment.onclick = function() {const tabKey = tabElment.dataset.tabKeyconst record = self.data.find(v => v.key === tabKey)self.render(tabKey)self.onSelect(tabKey, record)}}}}; (async function () {'use strict';const originContainer = QS('.wp-video-playlist')// cannot found Player, quitif (!originContainer) return;// inject global styleGM_addStyle(globalStyle)// hide origin containerfor (const item of originContainer.children) {item.style.display = 'none'}// append container for xgplayeroriginContainer.innerHTML += `<div id="xgplayer"></div><div class="player-sider"><div class="tabs-root"></div></div>`// get video resource from page dataconst res = JSON.parse(QS('.wp-playlist-script').textContent)const resPromise = res.tracks.map((track, idx) => ({ ...track, key: `${idx + 1}`, label: track.caption })).map(parseR###rl)const resGroups = await Promise.all(resPromise)// init xgplayerconst initVolume = window.localStorage['volume'] ? parseFloat(window.localStorage['volume']) : 1const isWatched = window.localStorage[location.pathname]const initEp = isWatched ? JSON.parse(isWatched).ep : '1'const initPlayUrl = resGroups.find(v => v.key === initEp).urlconsole.warn(`当前播放资源url:${initPlayUrl}`)const player = new window.Player({id: 'xgplayer',url: initPlayUrl,volume: initVolume,fluid: true,videoInit: true,lastPlayTimeHideDelay: 3,...isWatched && {lastPlayTime: JSON.parse(isWatched).seek},})// init tabsconst tabs = new Tabs({root: QS('.tabs-root'),data: resGroups,onSelect: (key, record) => {console.warn(`切换选集:【${key}】${record.label}`)player.src = record.urlconsole.warn(`当前播放资源url:${record.url}`)player.play()}})// render tabstabs.render(initEp)// update video progressplayer.on('timeupdate', function({ currentTime }) {window.localStorage[location.pathname] = JSON.stringify({seek: currentTime,ep: tabs.selectedKey,})})// update volumeplayer.on('volumechange', function({ volume }) {window.localStorage['volume'] = volume})})()