您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Universal video control, Control of the first video element of the page, advance and retract and multiply speed.
当前为
// ==UserScript== // @name video play util // @namespace https://gist.github.com/zqcccc/32eb827d35b8134f32f9dd3f70d9fb26 // @version 0.0.6 // @description Universal video control, Control of the first video element of the page, advance and retract and multiply speed. // @author zqcccc // @match https://www.disneyplus.com/* // @match https://www.bilibili.com/video/* // @match https://jable.tv/videos/* // @match https://dsxys.live/player/* // @match https://web.telegram.org/k/* // @match https://www.youtube.com/watch* // @match https://kaiwu.lagou.com/* // @match https://ddys.art/* // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com // @grant none // @license MIT // ==/UserScript== ; (function () { 'use strict' Element.prototype._attachShadow = Element.prototype.attachShadow Element.prototype.attachShadow = function (option) { return this._attachShadow(Object.assign(option, { mode: 'open' })) } function traverseElements(element, cb) { if (cb(element)) return true // 遍历当前元素的子节点 var children = element.children; for (var i = 0; i < children.length; i++) { const res = traverseElements(children[i], cb); if (res) break } } let videoElement function getFirstVideo() { if (videoElement) return videoElement document.documentElement.background = '#fff' const currentElement = document.querySelectorAll('video')[0] || window.$0 // chrome 自己指定 if (currentElement) { videoElement = currentElement } else { traverseElements(document.documentElement, (element) => { if (element.shadowRoot) { const shadowRoot = element.shadowRoot const shadowVideo = shadowRoot.querySelector('video') if (shadowVideo) { videoElement = shadowVideo return true } } }) } return videoElement } function attachKeydownEvent() { function addEvent() { document.documentElement.addEventListener('keydown', keydownHandle) } function removeEvent() { document.documentElement.removeEventListener('keydown', keydownHandle) } const keydownHandle = (e) => { const videoElement = getFirstVideo() if (!videoElement) removeEvent() switch (e.code) { case 'Period': videoElement.currentTime += 1 break case 'Comma': videoElement.currentTime -= 2 break case 'Equal': videoElement.playbackRate += 0.1 break case 'Minus': videoElement.playbackRate -= 0.1 break default: console.log(e.code) break } } let hasAddEvent = false function check() { const videoElement = getFirstVideo() if (videoElement) { hasAddEvent = true emptyHandles() addEvent() } } let intervalTimes = 0 const timer = setInterval(() => { if (hasAddEvent || intervalTimes >= 120) { clearInterval(timer) } else { check() } intervalTimes++ }, 1000) return removeEvent } function observeVideo() { const v = getFirstVideo() if (v) { const ob = new MutationObserver((mutations, observer) => { mutations.forEach((mut) => { console.log( '%c mut: ', 'font-size:12px;background-color: #553E2E;color:#fff;', mut ) if (mut.type === 'attributes' && mut.attributeName === 'src') { console.log('src changed') setTimeout(() => { emptyHandles() addRemove(attachKeydownEvent()) }, 3000) } }) }) ob.observe(v, { attributes: true, attributeOldValue: true }) return () => { ob.disconnect() } } else { console.log('no video element') } } var waitRemoveHandles = [] function emptyHandles() { for (let i = waitRemoveHandles.length - 1; i >= 0; i--) { waitRemoveHandles.pop()?.() } } function insertPanel() { document.querySelector('#panel-control')?.remove() const panel = document.createElement('div') panel.style.cssText = ` display: flex; flex-direction: column; align-items: center; justify-content: center; position: fixed; z-index: 100; width: 200px; height: 200px; background: rgba(0,0,0,0.4); color: #fff; ` panel.style.left = '0' panel.style.top = '50vh' panel.draggable = 'true' panel.setAttribute('id', 'panel-control') panel.innerHTML = `<style> #panel-control { opacity: 0.2 } #panel-control:hover { opacity: 1 } #panel-control button { background: rgba(0,0,0,0.5); border: none; color: #fff; } #refresh-panel { user-select: none; cursor: pointer; position: absolute; right: 10px; top: 10px; } </style> <div class="info"></div> <button class="get-info">info</button> <button class="add-speed">speed+0.1</button> <button class="minus-speed">speed-0.1</button> <button class="forward">+1s</button> <button class="backward">-2s</button> <button id="refresh-panel">↻</button> ` panel.querySelector('.get-info')?.addEventListener('click', () => { const video = getFirstVideo() if (video) { const infoDiv = panel.querySelector('.info') infoDiv.innerHTML = `rate:${Math.floor(video.playbackRate * 100) / 100}` } }) panel.querySelector('.add-speed')?.addEventListener('click', () => { const video = getFirstVideo() video && (video.playbackRate += 0.1) }) panel.querySelector('.minus-speed')?.addEventListener('click', () => { const video = getFirstVideo() video && (video.playbackRate -= 0.1) }) panel.querySelector('.forward')?.addEventListener('click', () => { const video = getFirstVideo() video && (video.currentTime += 1) }) panel.querySelector('.backward')?.addEventListener('click', () => { const video = getFirstVideo() video && (video.currentTime -= 2) }) panel.querySelector('#refresh-panel')?.addEventListener('click', () => { videoElement = null init() }) let canDrag = false, lastX, lastY, panelLeft, panelTop panel.addEventListener('dragstart', (e) => { canDrag = true lastX = e.pageX lastY = e.pageY const rect = panel.getBoundingClientRect() panelLeft = rect.left panelTop = rect.top }) panel.addEventListener('drag', (e) => { if (canDrag) { const disX = e.pageX - lastX panel.style.left = panelLeft + disX + 'px' const disY = e.pageY - lastY panel.style.top = panelTop + disY + 'px' } }) panel.addEventListener('dragend', () => (canDrag = false)) panel.addEventListener('dragover', function (e) { e.preventDefault() }) document.documentElement.appendChild(panel) } function addRemove(fn) { waitRemoveHandles.push(fn) } function init() { emptyHandles() const cancel = observeVideo() addRemove(cancel) insertPanel() addRemove(attachKeydownEvent()) } init() })()