🏠 Home 

9anime Hide Title Spoilers

Automatically hide titles for current & future episodes (shows past episode titles)


Install this script?
  1. // ==UserScript==
  2. // @name 9anime Hide Title Spoilers
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.1
  5. // @description Automatically hide titles for current & future episodes (shows past episode titles)
  6. // @author Discord: @nvllptr
  7. // @match https://9anime.to/*
  8. // @match https://9anime.pl/*
  9. // @match https://9anime.gs/*
  10. // @match https://9anime.id/*
  11. // @match https://9anime.ph/*
  12. // @match https://aniwave.to/*
  13. // @icon https://www.google.com/s2/favicons?sz=64&domain=aniwave.to
  14. // @grant none
  15. // @license MIT
  16. // ==/UserScript==
  17. (async () => {
  18. 'use strict';
  19. function observeUntilCondition(conditionCallback) {
  20. return new Promise(resolve => {
  21. const observer = new MutationObserver(async mutations => {
  22. if (!(await conditionCallback(mutations))) {
  23. return;
  24. }
  25. resolve();
  26. observer.disconnect();
  27. });
  28. observer.observe(document.body, {
  29. childList: true,
  30. subtree: true
  31. });
  32. });
  33. }
  34. function waitForElement(selector) {
  35. return new Promise(async resolve => {
  36. if (document.querySelector(selector)) {
  37. return resolve(document.querySelector(selector));
  38. }
  39. await observeUntilCondition(() => document.querySelector(selector));
  40. resolve(document.querySelector(selector));
  41. });
  42. }
  43. const listElementToMeta = item => item.firstElementChild;
  44. const metaToEpisodeNumber = meta => Number(meta.dataset.num);
  45. async function updateTitles() {
  46. const episodeListSelector = '.ep-range';
  47. const episodeList = await waitForElement(episodeListSelector);
  48. const listElements = episodeList.children;
  49. //const currentEpisodeNumber = metaToEpisodeNumber(Array.from(listElements, listElementToMeta)
  50. // .find(item => item.classList.contains('active')));
  51. const titleEpisodeMatches = window.location.href.match(/(?<=.*ep-)\d+/);
  52. if (titleEpisodeMatches === null || titleEpisodeMatches.length === 0) {
  53. console.error('[Userscript 9anime Hide title spoilers] could not find current episode number');
  54. return;
  55. }
  56. const currentEpisodeNumber = Number(titleEpisodeMatches[0]);
  57. for (const listElement of listElements) {
  58. const episodeMetaElement = listElementToMeta(listElement);
  59. const titleElement = listElement.querySelector('.d-title');
  60. if (!episodeMetaElement || !titleElement)
  61. continue;
  62. const episodeNumber = metaToEpisodeNumber(episodeMetaElement);
  63. const shouldHideTitle = (episodeNumber >= currentEpisodeNumber);
  64. if (!episodeMetaElement.dataset.title) {
  65. episodeMetaElement.dataset.title = titleElement.innerHTML;
  66. }
  67. const realTitle = episodeMetaElement.dataset.title;
  68. const fakeTitle = `Episode ${episodeNumber}`;
  69. const desiredTitle = shouldHideTitle ? fakeTitle : realTitle;
  70. const undesiredTitle = shouldHideTitle ? realTitle : fakeTitle;
  71. titleElement.innerHTML = desiredTitle;
  72. listElement.title = listElement.title.replace(undesiredTitle, desiredTitle);
  73. }
  74. }
  75. // Wait for the episode list to populate
  76. await waitForElement('.ep-range > li > a > .d-title');
  77. // Update the titles on load
  78. await updateTitles();
  79. // Update the tiles every time the href changes (new episode)
  80. let oldHref = window.location.href;
  81. await observeUntilCondition(async () => {
  82. if (window.location.href === oldHref) {
  83. return false;
  84. }
  85. oldHref = window.location.href;
  86. await updateTitles();
  87. return false;
  88. });
  89. })();