UltividsWorld

Add Ultivids note taking to Ultiworld videos

当前为 2025-03-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name UltividsWorld
  3. // @namespace https://ultivids.com
  4. // @version 0.1.2
  5. // @description Add Ultivids note taking to Ultiworld videos
  6. // @author Rui Da Costa
  7. // @match https://ultiworld.com/video/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=ultivids.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. let ultividsFrame;
  16.  
  17. window.ultividsQuickNote = (data) => {
  18. muxReady().then(muxVideo => {
  19. if(ultividsFrame){
  20. const args = {
  21. name: 'newNote',
  22. value: muxVideo.currentTime
  23. }
  24. ultividsFrame.contentWindow.postMessage(args, 'https://ultivids.com');
  25. }
  26. });
  27. }
  28.  
  29. window.ultividsStartNote = (data) => {
  30. muxReady().then(muxVideo => {
  31. if(ultividsFrame){
  32. const args = {
  33. name: 'startNote',
  34. value: muxVideo.currentTime
  35. }
  36. ultividsFrame.contentWindow.postMessage(args, 'https://ultivids.com');
  37. }
  38. });
  39. }
  40. window.ultividsEndNote = (data) => {
  41. muxReady().then(muxVideo => {
  42. if(ultividsFrame){
  43. const args = {
  44. name: 'endNote',
  45. value: muxVideo.currentTime
  46. }
  47. ultividsFrame.contentWindow.postMessage(args, 'https://ultivids.com');
  48. }
  49. });
  50. }
  51.  
  52. window.ultividsGoTo = (data) => {
  53. muxReady().then(muxVideo => {
  54. if(data.time) muxVideo.currentTime = data.time;
  55. if(muxVideo.paused) muxVideo.play();
  56. })
  57. }
  58.  
  59. window.ultividsForward = (data) => {
  60. muxReady().then(muxVideo => {
  61. muxVideo.currentTime = muxVideo.currentTime + (data.time ? data.time : 10);
  62. })
  63. }
  64. window.ultividsReverse = (data) => {
  65. muxReady().then(muxVideo => {
  66. muxVideo.currentTime = muxVideo.currentTime - (data.time ? data.time : 10);
  67. })
  68. }
  69.  
  70. window.ultividsClose = (data) => {
  71. muxReady().then(muxVideo => {
  72. if (document.fullscreenElement) {
  73. document.exitFullscreen().then(() => {
  74. closeUltivids();
  75. });
  76. }
  77. });
  78. }
  79.  
  80. const onTimeUpdate = (event) => {
  81. const muxVideo = document.getElementsByTagName('mux-player')[0];
  82.  
  83. const args = {
  84. name: 'timeupdate',
  85. value: muxVideo.currentTime
  86. }
  87. ultividsFrame.contentWindow.postMessage(args, 'https://ultivids.com');
  88. }
  89.  
  90. const muxReady = () => {
  91. return new Promise(res => {
  92. if(document.getElementsByTagName('mux-player').length > 0){
  93. res(document.getElementsByTagName('mux-player')[0]);
  94. }
  95. else {
  96. setTimeout(() => {
  97. muxReady().then((player) => { res(player); })
  98. }, 500)
  99. }
  100. })
  101.  
  102. }
  103.  
  104. const setStyles = (elem, styles) => {
  105. Object.keys(styles).forEach(key => {
  106. elem.style[key] = styles[key];
  107. });
  108. }
  109.  
  110. const exitFullscreen = (event) => {
  111. if (!document.fullscreenElement) {
  112. closeUltivids();
  113. }
  114. }
  115.  
  116. const closeUltivids = () => {
  117. const muxVideo = document.getElementsByTagName('mux-player')[0];
  118. ultividsFrame.remove();
  119. const shareDiv = document.getElementsByClassName('video-share')[0];
  120. const section = document.getElementsByClassName('reference-section')[0];
  121. setStyles(shareDiv, { display: 'block' });
  122. setStyles(muxVideo, { width: 'auto'});
  123. setStyles(section, { display: 'block' });
  124. muxVideo.removeEventListener('timeupdate', onTimeUpdate, false);
  125. }
  126.  
  127. muxReady().then((muxVideo) => {
  128. const onMessage = (event) => {
  129. // Check sender origin to be trusted
  130. if (event.origin !== "https://ultivids.com") return;
  131.  
  132. var data = event.data;
  133.  
  134. if (typeof(window[data.func]) == "function") {
  135. window[data.func].call(null, data);
  136. }
  137. }
  138.  
  139. if (window.addEventListener) {
  140. window.addEventListener("message", onMessage, false);
  141. }
  142. else if (window.attachEvent) {
  143. window.attachEvent("onmessage", onMessage, false);
  144. }
  145. muxVideo.addEventListener('timeupdate', onTimeUpdate, false);
  146.  
  147. const shareDiv = document.getElementsByClassName('video-share')[0];
  148. const ultividsButton = document.createElement('button');
  149. ultividsButton.innerText = 'Open Ultivids';
  150. setStyles(ultividsButton, {
  151. margin: '5px 10px',
  152. border: '0',
  153. backgroundColor: '#000',
  154. color: '#fff',
  155. borderRadius: '5px',
  156. height: '36px',
  157. padding: '0 15px',
  158. fontSize: '14px',
  159. top: '.5px',
  160. position: 'relative'
  161. });
  162. document.addEventListener("fullscreenchange", exitFullscreen, false);
  163. shareDiv.prepend(ultividsButton);
  164. ultividsButton.addEventListener("click", (event) => {
  165. let uwUser = -1;
  166. const section = document.getElementsByClassName('reference-section')[0];
  167. ultividsFrame = document.createElement('iframe');
  168. const splits = window.location.href.split('/');
  169. const videoId = splits[splits.findIndex(item => item == 'video') + 1];
  170. ultividsFrame.src = `https://ultivids.com/ultiworld/${uwUser}/${videoId}`;
  171. setStyles(section, {
  172. display: 'flex',
  173. 'flex-direction': 'row'
  174. });
  175. section.append(ultividsFrame);
  176. const width = '18rem';
  177. setStyles(ultividsFrame, {
  178. width: width,
  179. border: 0
  180. })
  181. setStyles(shareDiv, { display: 'none' });
  182. setStyles(muxVideo, { width: `calc(100% - ${width})`});
  183. section.requestFullscreen();
  184. });
  185. });
  186. })();