erome.com video length

Duration of video on erome.com

  1. // ==UserScript==
  2. // @name erome.com video length
  3. // @namespace https://github.com/drdre1/
  4. // @icon https://www.erome.com/favicon.ico
  5. // @version 1.0
  6. // @description Duration of video on erome.com
  7. // @author drdre1
  8. // @match https://www.erome.com/*
  9. // @grant GM.xmlHttpRequest
  10. // ==/UserScript==
  11.  
  12. (function () {
  13.  
  14. const onLength = function (milliseconds, a, video) {
  15. let s = milliseconds / 1000;
  16. const h = Math.floor(s / 3600);
  17. s -= h * 3600;
  18. const m = Math.floor(s / 60);
  19. s = Math.floor(s - m * 60);
  20.  
  21. const span = document.createElement('span');
  22. span.appendChild(document.createTextNode(` ${h > 0 ? `${h}:` : ''}${h > 0 ? m.toString().padStart(2, '0') : m}:${s.toString().padStart(2, '0')}`));
  23. a.parentNode.insertBefore(span, a.nextElementSibling || a);
  24.  
  25. if (video && video.dataset) {
  26. s = parseInt(milliseconds / 1000);
  27. video.dataset.length = s;
  28. const slider = document.getElementById('slider_min_length');
  29. if (slider) {
  30. slider.max = Math.max(slider.max, s);
  31. }
  32. }
  33. };
  34.  
  35. const videoLength = function (url, a, video) {
  36. const storedTime = window.localStorage.getItem(`$vl#${url}`);
  37. if (storedTime && !isNaN(parseInt(storedTime))) {
  38. const t = parseInt(storedTime);
  39. if (t >= 0) {
  40. return onLength(t, a, video);
  41. }
  42. }
  43.  
  44. const xmlHttpRequest = GM.xmlHttpRequest({
  45. url,
  46. method: 'GET',
  47. headers: {
  48. Accept: 'video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5',
  49. Referer: 'https://www.erome.com/',
  50. Range: 'bytes=0-140',
  51. },
  52. responseType: 'blob',
  53. onprogress(response) {
  54. if (Math.max(response.loaded, response.total) > 150) {
  55. xmlHttpRequest.abort();
  56. }
  57. },
  58. onload(response) {
  59. const m = response.responseText.match(/\x03.*\xe8/);
  60. if (m) {
  61. const i = response.responseText.indexOf(m[0]) + m[0].length;
  62. const s = response.responseText.substring(i, i + 4);
  63. const ms = Array.from(s)
  64. .map((c) => c.charCodeAt(0))
  65. .map((value, index, values) => value * Math.pow(256, values.length - index - 1))
  66. .reduce((a, b) => a + b);
  67. window.localStorage.setItem(`$vl#${url}`, ms);
  68. return onLength(ms, a, video);
  69. }
  70. },
  71. });
  72. };
  73.  
  74. const showSlider = function () {
  75. const div = document.body.appendChild(document.createElement('div'));
  76. div.setAttribute('style', 'position:fixed; right:0px; top:50px');
  77. div.innerHTML = 'Minimal length:<br>';
  78. const output = div.appendChild(document.createElement('output'));
  79. output.setAttribute('id', 'slider_min_length_output');
  80. const slider = div.appendChild(document.createElement('input'));
  81. slider.setAttribute('id', 'slider_min_length');
  82. slider.setAttribute('type', 'range');
  83. slider.setAttribute('step', '1');
  84. slider.setAttribute('min', '1');
  85. slider.setAttribute('max', '5');
  86. slider.setAttribute('value', '1');
  87. slider.addEventListener('input', () => {
  88. const minS = parseInt(slider.value);
  89. if (minS > 1) {
  90. const m = parseInt(slider.value / 60);
  91. const s = minS - m * 60;
  92. output.textContent = `${m}:${s > 9 ? s : (`0${s}`)}`;
  93. document.querySelectorAll('.video')
  94. .forEach((vc) => {
  95. const video = vc.querySelector('.player video');
  96. if (video && 'length' in video.dataset && video.dataset.length < minS) {
  97. vc.style.display = 'none';
  98. } else {
  99. vc.style.display = '';
  100. }
  101. });
  102. } else {
  103. output.textContent = 'Off';
  104. document.querySelectorAll('.video')
  105. .forEach((vc) => {
  106. vc.style.display = '';
  107. });
  108. }
  109. });
  110. };
  111.  
  112. let minNumberOfVideos = 0;
  113. const showOnlyVideosThumbs = function () {
  114. document.querySelectorAll('.album')
  115. .forEach((album) => {
  116. const e = album.querySelector('.album-videos');
  117. if (e && e.textContent && parseInt(e.textContent) && parseInt(e.textContent) >= minNumberOfVideos) {
  118. return;
  119. }
  120. album.style.display = 'none';
  121. });
  122. };
  123.  
  124. const showOnlyVideos = function (ev) {
  125. if (ev) {
  126. ev.preventDefault();
  127. }
  128. minNumberOfVideos++;
  129. if (document.location.hash.match(/onlyvideos=(\d+)/)) {
  130. document.location.hash = document.location.hash.replace(/onlyvideos=\d+/, `onlyvideos=${minNumberOfVideos}`);
  131. } else {
  132. document.location.hash = `#onlyvideos=${minNumberOfVideos}`;
  133. }
  134. if (document.location.pathname.startsWith('/a/')) {
  135. showOnlyVideosAlbum();
  136. } else {
  137. showOnlyVideosThumbs();
  138. }
  139. document.querySelectorAll('a[href]')
  140. .forEach((a) => {
  141. a.hash = `#onlyvideos=${minNumberOfVideos}`;
  142. });
  143. };
  144.  
  145. const showOnlyVideosAlbum = function () {
  146. document.querySelectorAll('.media-group')
  147. .forEach((mediaGroup) => {
  148. if (!mediaGroup.querySelector('.video')) {
  149. mediaGroup.remove();
  150. }
  151. });
  152. };
  153.  
  154. const disableShowOnlyVideos = function (ev) {
  155. if (ev) {
  156. ev.preventDefault();
  157. }
  158. document.location.hash = '';
  159. document.location.reload();
  160. };
  161.  
  162. if (document.querySelectorAll('video')
  163. .length > 1) {
  164. showSlider();
  165. }
  166. window.requestAnimationFrame(() => {
  167. document.querySelectorAll('.player video source')
  168. .forEach((source) => {
  169. const url = source.src;
  170. const a = document.createElement('a');
  171. a.href = url;
  172. a.appendChild(document.createTextNode(url));
  173. a.target = '_blank';
  174. source.parentNode.parentNode.parentNode.insertBefore(a, source.parentNode.parentNode);
  175. videoLength(url, a, source.parentNode);
  176. });
  177. });
  178.  
  179. if (document.querySelector('#app-navbar-collapse ul.navbar-right')) {
  180. const a = document.querySelector('#app-navbar-collapse ul.navbar-right')
  181. .appendChild(document.createElement('li'))
  182. .appendChild(document.createElement('a'));
  183. a.href = `#onlyvideos=${minNumberOfVideos + 1}`;
  184. a.title = 'Right click to disable';
  185. a.addEventListener('click', showOnlyVideos);
  186. a.addEventListener('contextmenu', disableShowOnlyVideos);
  187. a.appendChild(document.createTextNode('only videos'));
  188. }
  189.  
  190. if (document.location.hash.match(/onlyvideos=(\d+)/)) {
  191. const n = parseInt(document.location.hash.match(/onlyvideos=(\d+)/)[1]);
  192. for (let i = 0; i < n; i++) {
  193. showOnlyVideos();
  194. }
  195. }
  196. }());