video play util

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

目前為 2022-11-01 提交的版本,檢視 最新版本

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