video play util

Universal video control, Control of the first video element of the page, advance and retract and multiply speed.

Versione datata 18/03/2025. Vedi la nuova versione l'ultima versione.

  1. // ==UserScript==
  2. // @name video play util
  3. // @namespace https://gist.github.com/zqcccc/32eb827d35b8134f32f9dd3f70d9fb26
  4. // @version 0.0.5
  5. // @description Universal video control, Control of the first video element of the page, advance and retract and multiply speed.
  6. // @author zqcccc
  7. // @match https://www.disneyplus.com/*
  8. // @match https://www.bilibili.com/video/*
  9. // @match https://jable.tv/videos/*
  10. // @match https://dsxys.live/player/*
  11. // @match https://web.telegram.org/k/*
  12. // @match https://www.youtube.com/watch*
  13. // @match https://kaiwu.lagou.com/*
  14. // @match https://ddys.pro/*
  15. // @include /^https:\/\/ddys.+$/
  16. // @match https://www.iole.tv/vodplay/*
  17. // @match https://sxyprn.com/post/*
  18. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  19. // @grant none
  20. // @license MIT
  21. // ==/UserScript==
  22.  
  23. ;(function () {
  24. 'use strict'
  25.  
  26. function getFirstVideo() {
  27. document.documentElement.background = '#fff'
  28. return document.querySelectorAll('video')[0] || window.$0 // chrome 自己指定
  29. }
  30.  
  31. function attachKeydownEvent() {
  32. function addEvent() {
  33. document.documentElement.addEventListener('keydown', keydownHandle)
  34. }
  35. function removeEvent() {
  36. document.documentElement.removeEventListener('keydown', keydownHandle)
  37. }
  38.  
  39. const keydownHandle = (e) => {
  40. const videoElement = getFirstVideo()
  41. if (!videoElement) removeEvent()
  42. switch (e.code) {
  43. case 'Period':
  44. videoElement.currentTime += 1
  45. break
  46. case 'Comma':
  47. videoElement.currentTime -= 2
  48. break
  49. case 'Equal':
  50. videoElement.playbackRate += 0.1
  51. break
  52. case 'Minus':
  53. videoElement.playbackRate -= 0.1
  54. break
  55. default:
  56. break
  57. }
  58. }
  59.  
  60. let hasAddEvent = false
  61. function check() {
  62. const videoElement = getFirstVideo()
  63. if (videoElement) {
  64. hasAddEvent = true
  65. emptyHandles()
  66. addEvent()
  67. }
  68. }
  69.  
  70. let intervalTimes = 0
  71. const timer = setInterval(() => {
  72. if (hasAddEvent || intervalTimes >= 120) {
  73. clearInterval(timer)
  74. } else {
  75. check()
  76. }
  77. intervalTimes++
  78. }, 1000)
  79. return removeEvent
  80. }
  81.  
  82. function observeVideo() {
  83. const v = getFirstVideo()
  84. if (v) {
  85. const ob = new MutationObserver((mutations, observer) => {
  86. mutations.forEach((mut) => {
  87. console.log(
  88. '%c mut: ',
  89. 'font-size:12px;background-color: #553E2E;color:#fff;',
  90. mut
  91. )
  92. if (mut.type === 'attributes' && mut.attributeName === 'src') {
  93. console.log('src changed')
  94. setTimeout(() => {
  95. emptyHandles()
  96. addRemove(attachKeydownEvent())
  97. }, 3000)
  98. }
  99. })
  100. })
  101. ob.observe(v, { attributes: true, attributeOldValue: true })
  102. return () => {
  103. ob.disconnect()
  104. }
  105. } else {
  106. console.log('no video element')
  107. }
  108. }
  109.  
  110. var waitRemoveHandles = []
  111. function emptyHandles() {
  112. for (let i = waitRemoveHandles.length - 1; i >= 0; i--) {
  113. waitRemoveHandles.pop()?.()
  114. }
  115. }
  116.  
  117. function insertPanel() {
  118. document.querySelector('#panel-control')?.remove()
  119.  
  120. const panel = document.createElement('div')
  121.  
  122. panel.style.cssText = `
  123. display: flex;
  124. flex-direction: column;
  125. align-items: center;
  126. justify-content: center;
  127. position: fixed;
  128. z-index: 100;
  129. width: 200px;
  130. height: 200px;
  131. background: rgba(0,0,0,0.4);
  132. color: #fff;
  133. `
  134. panel.style.left = '0'
  135. panel.style.top = '50vh'
  136. panel.draggable = 'true'
  137. panel.setAttribute('id', 'panel-control')
  138.  
  139. panel.innerHTML = `<style>
  140. #panel-control {
  141. opacity: 0.2
  142. }
  143. #panel-control:hover {
  144. opacity: 1
  145. }
  146. #panel-control button {
  147. background: rgba(0,0,0,0.5);
  148. border: none;
  149. color: #fff;
  150. }
  151. #refresh-panel {
  152. user-select: none;
  153. cursor: pointer;
  154. position: absolute;
  155. right: 10px;
  156. top: 10px;
  157. }
  158. </style>
  159. <div class="info"></div>
  160. <button class="get-info">info</button>
  161. <button class="add-speed">speed+0.1</button>
  162. <button class="minus-speed">speed-0.1</button>
  163. <button class="forward">+1s</button>
  164. <button class="backward">-2s</button>
  165. <button id="refresh-panel">↻</button>
  166. `
  167.  
  168. panel.querySelector('.get-info')?.addEventListener('click', () => {
  169. const video = getFirstVideo()
  170. if (video) {
  171. const infoDiv = panel.querySelector('.info')
  172. infoDiv.innerHTML = `rate:${Math.floor(video.playbackRate * 100) / 100}`
  173. }
  174. })
  175. panel.querySelector('.add-speed')?.addEventListener('click', () => {
  176. const video = getFirstVideo()
  177. video && (video.playbackRate += 0.1)
  178. })
  179. panel.querySelector('.minus-speed')?.addEventListener('click', () => {
  180. const video = getFirstVideo()
  181. video && (video.playbackRate -= 0.1)
  182. })
  183. panel.querySelector('.forward')?.addEventListener('click', () => {
  184. const video = getFirstVideo()
  185. video && (video.currentTime += 1)
  186. })
  187. panel.querySelector('.backward')?.addEventListener('click', () => {
  188. const video = getFirstVideo()
  189. video && (video.currentTime -= 2)
  190. })
  191. panel.querySelector('#refresh-panel')?.addEventListener('click', () => {
  192. init()
  193. })
  194.  
  195. let canDrag = false,
  196. lastX,
  197. lastY,
  198. panelLeft,
  199. panelTop
  200.  
  201. panel.addEventListener('dragstart', (e) => {
  202. canDrag = true
  203. lastX = e.pageX
  204. lastY = e.pageY
  205. const rect = panel.getBoundingClientRect()
  206. panelLeft = rect.left
  207. panelTop = rect.top
  208. })
  209. panel.addEventListener('drag', (e) => {
  210. if (canDrag) {
  211. const disX = e.pageX - lastX
  212. panel.style.left = panelLeft + disX + 'px'
  213. const disY = e.pageY - lastY
  214. panel.style.top = panelTop + disY + 'px'
  215. }
  216. })
  217. panel.addEventListener('dragend', () => (canDrag = false))
  218. panel.addEventListener('dragover', function (e) {
  219. e.preventDefault()
  220. })
  221.  
  222. document.documentElement.appendChild(panel)
  223. }
  224.  
  225. function addRemove(fn) {
  226. waitRemoveHandles.push(fn)
  227. }
  228.  
  229. function init() {
  230. emptyHandles()
  231. const cancel = observeVideo()
  232. addRemove(cancel)
  233. insertPanel()
  234. addRemove(attachKeydownEvent())
  235. }
  236.  
  237. init()
  238. })()