HiAnime QoL

UI changes, removes unnecessary stuff, toggle to hide cursor movements in player.

  1. // ==UserScript==
  2. // @name HiAnime QoL
  3. // @namespace https://greasyfork.org/en/users/1262395-grinnch
  4. // @version 1.4
  5. // @description UI changes, removes unnecessary stuff, toggle to hide cursor movements in player.
  6. // @author grinnch
  7. // @license MIT
  8. // @match https://hianimez.to/*
  9. // @match https://hianimez.tv/*
  10. // @match https://hianime.nz/*
  11. // @match https://hianime.pe/*
  12. // @match https://hianime.sx/*
  13. // @icon https://cdn-b.saashub.com/images/app/service_logos/274/o0hsec74es20/large.png
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @grant GM_registerMenuCommand
  17. // @grant GM_unregisterMenuCommand
  18. // ==/UserScript==
  19.  
  20. (async () => {
  21. 'use strict';
  22.  
  23. let expandElementClicked = false;
  24. let expandDescElementClicked = false;
  25.  
  26. const debounce = (func, delay) => {
  27. let timeoutId;
  28. return (...args) => {
  29. clearTimeout(timeoutId);
  30. timeoutId = setTimeout(() => {
  31. func.apply(this, args);
  32. }, delay);
  33. };
  34. };
  35.  
  36. function modifyStyle() {
  37. // Auto expands player
  38. if (!expandElementClicked) {
  39. var expandElement = document.querySelector('#media-resize');
  40. if (expandElement) {
  41. expandElement.click();
  42. expandElementClicked = true;
  43. }
  44. }
  45.  
  46. // Auto expands description
  47. if (!expandDescElementClicked) {
  48. var expandDescElement = document.querySelector('#ani_detail > div > div > div.anis-watch-wrap.extend > div.anis-watch-detail > div > div.anisc-detail > div.film-description.m-hide > div > span');
  49. if (expandDescElement) {
  50. expandDescElement.click();
  51. expandDescElementClicked = true;
  52. }
  53. }
  54.  
  55. // Prevents header from moving when scrolling
  56. let headerElement = document.querySelector('#header');
  57. if (headerElement) {
  58. headerElement.style.position = 'relative';
  59. }
  60.  
  61. // Removes padding from header
  62. let wrapperElement = document.querySelector('#wrapper');
  63. if (wrapperElement) {
  64. wrapperElement.style.paddingTop = '0';
  65. }
  66.  
  67. // Removes padding from left-side of player to make it centered
  68. let playerLeftPaddingElement = document.querySelector('#ani_detail > div > div > div.anis-watch-wrap.extend > div.anis-watch.anis-watch-tv');
  69. if (playerLeftPaddingElement) {
  70. playerLeftPaddingElement.style.paddingLeft = '0';
  71. }
  72.  
  73. // Removes padding from right-side of player to make it centered when toggling "Light"
  74. let playerRightPaddingElement = document.querySelector('#ani_detail > div > div > div.anis-watch-wrap.extend.active > div.anis-watch.anis-watch-tv');
  75. if (playerRightPaddingElement) {
  76. playerRightPaddingElement.style.paddingRight = '0';
  77. }
  78.  
  79. // Reduces padding on bottom of player to reduce player size
  80. let frameElement = document.querySelector('#ani_detail > div > div > div.anis-watch-wrap.extend > div.anis-watch.anis-watch-tv > div.watch-player > div.player-frame');
  81. if (frameElement) {
  82. frameElement.style.paddingBottom = '53.75%'; // 51.9%
  83. }
  84.  
  85. // Places episode panel underneath player
  86. let episodesElement = document.querySelector('#episodes-content');
  87. if (episodesElement) {
  88. episodesElement.style.position = 'relative';
  89. episodesElement.style.paddingTop = '18%';
  90. episodesElement.style.width = 'unset';
  91. //episodesElement.style.marginTop = '1px'; // optional seperator between episode panel and player
  92. }
  93.  
  94. // Reduces padding under episode panel
  95. let wrapperPaddingElement = document.querySelector('#ani_detail > div > div > div.anis-watch-wrap.extend');
  96. if (wrapperPaddingElement) {
  97. wrapperPaddingElement.style.paddingBottom = '0';
  98. }
  99.  
  100. // Moves description under episode panel
  101. let contentElement = document.querySelector('#ani_detail > div > div > div.anis-watch-wrap.extend > div.anis-watch-detail');
  102. if (contentElement) {
  103. contentElement.style.display = 'unset';
  104. contentElement.style.position = 'static';
  105. }
  106.  
  107. // Reduces size of background image
  108. let backgroundImgElement = document.querySelector('#ani_detail > div > div > div.anis-cover-wrap > div');
  109. if (backgroundImgElement) {
  110. backgroundImgElement.style.height = '62.25%';
  111. }
  112.  
  113. // Removes share bar
  114. let shareBarElement = document.querySelector('.share-buttons.share-buttons-detail');
  115. if (shareBarElement) {
  116. shareBarElement.remove();
  117. }
  118.  
  119. // Removes description ad
  120. let descAdElement = document.querySelector('.film-text.m-hide.mb-3');
  121. if (descAdElement) {
  122. descAdElement.remove();
  123. }
  124.  
  125. // Removes comments shortcut
  126. let commentButtonElement = document.querySelector('.dt-comment');
  127. if (commentButtonElement) {
  128. commentButtonElement.remove();
  129. }
  130. }
  131.  
  132. modifyStyle();
  133.  
  134. // Mutation observer for dynamic updates
  135. let observer = new MutationObserver(debounce(modifyStyle, 100));
  136. let target = document.querySelector('#ani_detail');
  137. if (target) {
  138. observer.observe(target, { attributes: true, childList: true, subtree: true });
  139. }
  140.  
  141. // Creates toggleable overlay to hide player controls during mouse movement
  142. let overlayEnabled = GM_getValue('overlayEnabled', false);
  143. let overlay, iframe;
  144. let enableMenuCommandId, disableMenuCommandId;
  145. let isControlsVisible = false;
  146.  
  147. function createOverlay() {
  148. overlay = document.createElement('div');
  149. overlay.style.cssText = `
  150. position: absolute;
  151. top: 0;
  152. left: 0;
  153. width: 100%;
  154. height: 100%;
  155. background-color: transparent;
  156. z-index: 1000;
  157. cursor: none;
  158. display: ${overlayEnabled ? 'block' : 'none'};
  159. `;
  160. iframe.parentNode.insertBefore(overlay, iframe.nextSibling);
  161. }
  162.  
  163. function enableOverlay() {
  164. overlayEnabled = true;
  165. GM_setValue('overlayEnabled', true);
  166. if (overlay) {
  167. overlay.style.display = 'block';
  168. }
  169. updateControlsVisibility();
  170. updateMenuCommands();
  171. }
  172.  
  173. function disableOverlay() {
  174. overlayEnabled = false;
  175. GM_setValue('overlayEnabled', false);
  176. if (overlay) {
  177. overlay.style.display = 'none';
  178. }
  179. updateControlsVisibility();
  180. updateMenuCommands();
  181. }
  182.  
  183. function updateControlsVisibility() {
  184. if (overlayEnabled) {
  185. hideControls();
  186. } else {
  187. showControls();
  188. }
  189. }
  190.  
  191. function showControls() {
  192. iframe.style.cursor = 'default';
  193. overlay.style.pointerEvents = 'none';
  194. isControlsVisible = true;
  195. }
  196.  
  197. function hideControls() {
  198. iframe.style.cursor = 'none';
  199. overlay.style.pointerEvents = 'auto';
  200. isControlsVisible = false;
  201. }
  202.  
  203. function handleMouseMove(e) {
  204. if (!overlayEnabled) return;
  205.  
  206. const iframeRect = iframe.getBoundingClientRect();
  207. const isNearBottom = e.clientY >= iframeRect.bottom - 150;
  208.  
  209. if (isNearBottom) {
  210. showControls();
  211. } else {
  212. hideControls();
  213. }
  214.  
  215. clearTimeout(overlay.timeoutId);
  216. overlay.timeoutId = setTimeout(hideControls, 2000); // Change this to adjust hide cursor speed
  217. }
  218.  
  219. function handleClick(e) {
  220. if (!overlayEnabled) return;
  221.  
  222. const iframeRect = iframe.getBoundingClientRect();
  223. const isNearBottom = e.clientY >= iframeRect.bottom - 150;
  224.  
  225. if (isControlsVisible || isNearBottom) {
  226. // Pass the click to the iframe
  227. const iframeClickEvent = new MouseEvent('click', {
  228. clientX: e.clientX - iframeRect.left,
  229. clientY: e.clientY - iframeRect.top,
  230. bubbles: true,
  231. cancelable: true,
  232. view: window
  233. });
  234. iframe.contentDocument.elementFromPoint(e.clientX - iframeRect.left, e.clientY - iframeRect.top).dispatchEvent(iframeClickEvent);
  235. } else {
  236. // Show controls when clicking anywhere on the video
  237. showControls();
  238. clearTimeout(overlay.timeoutId);
  239. overlay.timeoutId = setTimeout(hideControls, 2000);
  240. }
  241. }
  242.  
  243. function updateMenuCommands() {
  244. if (enableMenuCommandId) GM_unregisterMenuCommand(enableMenuCommandId);
  245. if (disableMenuCommandId) GM_unregisterMenuCommand(disableMenuCommandId);
  246.  
  247. if (!overlayEnabled) {
  248. enableMenuCommandId = GM_registerMenuCommand("Enable Overlay", enableOverlay);
  249. } else {
  250. disableMenuCommandId = GM_registerMenuCommand("Disable Overlay", disableOverlay);
  251. }
  252. }
  253.  
  254. function init() {
  255. iframe = document.querySelector("#iframe-embed");
  256. if (!iframe) return;
  257.  
  258. createOverlay();
  259. updateControlsVisibility();
  260. updateMenuCommands();
  261.  
  262. overlay.addEventListener('mousemove', handleMouseMove);
  263. overlay.addEventListener('click', handleClick);
  264. }
  265.  
  266. window.onload = function() {
  267. // Creates overlay
  268. init();
  269. };
  270. })();