V LIVE Video Rotation

Adds buttons and keyboard shortcuts to rotate and flip the video.

当前为 2020-06-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name V LIVE Video Rotation
  3. // @description Adds buttons and keyboard shortcuts to rotate and flip the video.
  4. // @version 1.3
  5. // @author aqmx
  6. // @namespace aqmx
  7. // @license MIT
  8. // @match *://www.vlive.tv/video/*
  9. // @grant GM_addStyle
  10. // ==/UserScript==
  11.  
  12.  
  13. GM_addStyle(`
  14. .vlive_info {
  15. display: inline-block;
  16. box-sizing: border-box;
  17. width: 100%;
  18. }
  19. .vlive_info .tit {
  20. display: block;
  21. margin-bottom: 9px;
  22. }
  23. .vlive_info .status_area {
  24. display: inline-flex;
  25. align-items: center;
  26. }
  27. .vlive_info .ico_blue {
  28. margin-right: unset;
  29. }
  30. .vlive_info .txt, .vlive_info .like, .vlive_info .date {
  31. margin-top: 0;
  32. }
  33. .vlive_info .icon_play, .vlive_info .icon_like {
  34. margin-top: 1px;
  35. }
  36.  
  37. #video-rotation-controls {
  38. position: relative;
  39. display: inline-block;
  40. margin-left: 15px;
  41. z-index: 1;
  42. }
  43. #video-rotation-controls button {
  44. font-size: 20px;
  45. background: #f5f5f5;
  46. border: 1px solid #d9d9d9;
  47. color: #414141;
  48. margin-top: -4px;
  49. line-height: 22px;
  50. height: 24px;
  51. width: 24px;
  52. outline: 0;
  53. }
  54. #video-rotation-controls button:not(:last-child) {
  55. margin-right: 3px;
  56. }
  57. `);
  58.  
  59.  
  60. let directions = {
  61. left: 'r270',
  62. up: 'r0',
  63. right: 'r90',
  64. down: 'r180',
  65. flipH: 'flipH',
  66. flipV: 'flipV',
  67. }
  68. let rotations = {
  69. r90: 'rotate(90deg)',
  70. r180: 'rotate(180deg)',
  71. r270: 'rotate(270deg)',
  72. };
  73. let scaling = {
  74. flipH: 'scaleX(-1)',
  75. flipV: 'scaleY(-1)',
  76. portrait: 'scale(1.759)',
  77. landscape: 'scale(0.559)',
  78. };
  79.  
  80. /*let brightnessPercent = 100;
  81. let brightness = {
  82. up: 5,
  83. down: -5,
  84. reset: 0,
  85. }*/
  86.  
  87. let shortcutsEnabled = true;
  88. let shortcuts = {
  89. 'Numpad8': directions.up,
  90. 'Numpad2': directions.down,
  91. 'Numpad4': directions.left,
  92. 'Numpad6': directions.right,
  93. 'Numpad9': directions.flipH,
  94. 'Numpad3': directions.flipV,
  95. }
  96. let stylesheet = null;
  97.  
  98.  
  99. (() => {
  100. stylesheet = document.createElement('style');
  101. document.head.appendChild(stylesheet);
  102.  
  103. let getAllSubsets = arr => arr.reduce((subsets, value) => subsets.concat(subsets.map(set => [...set, value])), [[]]).slice(1);
  104. let scalings = getAllSubsets(Object.keys(scaling));
  105.  
  106. for (let rule in rotations) {
  107. stylesheet.sheet.insertRule(`video.${rule} { transform: ${rotations[rule]}; }`, stylesheet.sheet.cssRules.length);
  108. for (let scalingSet of scalings) {
  109. stylesheet.sheet.insertRule(`video.${rule}.${scalingSet.reduce((s, v) => s+'.'+v)} { transform: ${rotations[rule] + scalingSet.reduce((s, v) => s+' '+scaling[v], '')}; }`, stylesheet.sheet.cssRules.length);
  110. }
  111. }
  112.  
  113. let flips = getAllSubsets([directions.flipH, directions.flipV]);
  114. for (let flipSet of flips) {
  115. stylesheet.sheet.insertRule(`video.${flipSet.reduce((s, v) => s+'.'+v)} { transform:${flipSet.reduce((s, v) => s+' '+scaling[v], '')}; }`, stylesheet.sheet.cssRules.length);
  116. }
  117. })();
  118.  
  119. function addButton() {
  120. let btnArea = document.querySelector('#content .vlive_section .vlive_info .btn_area');
  121. if (!btnArea) {
  122. setTimeout(addButton, 500);
  123. return;
  124. }
  125.  
  126. let btnDirections = [
  127. [directions.left, '🠘'],
  128. [directions.up, '🠙'],
  129. [directions.right, '🠚'],
  130. [directions.down, '🠛'],
  131. [directions.flipV, '🡙'],
  132. [directions.flipH, '🡘'],
  133. ];
  134. /*let btnBrightness = [
  135. ['up', '+'],
  136. ['down', '−'],
  137. ['reset', '⟳'],
  138. ];*/
  139.  
  140. let div = document.createElement('div');
  141. div.id = 'video-rotation-controls';
  142. for (let entry of btnDirections) {
  143. let btn = document.createElement('button');
  144. btn.dataset.direction = entry[0];
  145. btn.textContent = entry[1];
  146. div.appendChild(btn);
  147. }
  148. /*for (let entry of btnBrightness) {
  149. let btn = document.createElement('button');
  150. btn.dataset.brightness = entry[0];
  151. btn.textContent = entry[1];
  152. div.appendChild(btn);
  153. }*/
  154.  
  155. btnArea.parentNode.insertBefore(div, btnArea);
  156.  
  157. div.addEventListener('click', function(e) {
  158. if (e.target.tagName.toLowerCase() != 'button') {
  159. return;
  160. }
  161. else if (e.target.dataset.direction) {
  162. rotateVideo(e.target.dataset.direction);
  163. }
  164. /*else if (e.target.dataset.brightness) {
  165. changeBrightness(e.target.dataset.brightness);
  166. }*/
  167. });
  168. }
  169.  
  170. function rotateVideo(direction) {
  171. let video = document.querySelector('.u_rmcplayer_video video') || document.querySelector('.vwplayer_vlivelive .videoBox video');
  172. if (!video) return;
  173. let flip = [directions.flipH, directions.flipV].includes(direction);
  174.  
  175. if (flip) {
  176. video.classList.toggle(direction);
  177. }
  178. else {
  179. video.classList.remove(directions.left, directions.right, directions.down, 'portrait', 'landscape');
  180. if (direction != directions.up) {
  181. video.classList.add(direction);
  182. if ([directions.left, directions.right].includes(direction)) {
  183. video.classList.add(video.videoHeight > video.videoWidth ? 'portrait' : 'landscape');
  184. }
  185. }
  186. }
  187. }
  188.  
  189. /*function changeBrightness(value) {
  190. let video = document.querySelector('.u_rmcplayer_video video') || document.querySelector('.vwplayer_vlivelive .videoBox video');
  191. if (!video) return;
  192.  
  193. if (brightness[value]) {
  194. brightnessPercent += brightness[value];
  195. video.style.filter = 'brightness('+brightnessPercent+'%)';
  196. }
  197. else {
  198. brightnessPercent = 100;
  199. video.style.filter = null;
  200. }
  201. }*/
  202.  
  203. addButton();
  204.  
  205.  
  206. // Shortcuts
  207. window.addEventListener('keydown', function(e) {
  208. if (shortcuts[e.code] && shortcutsEnabled) {
  209. rotateVideo(shortcuts[e.code]);
  210. }
  211. else if (e.code == 'Pause') {
  212. shortcutsEnabled = !shortcutsEnabled;
  213. }
  214. });