BetterAnimeWorld

Migliora AnimeWorld

目前为 2022-07-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name BetterAnimeWorld
  3. // @namespace https://pizidavi.altervista.org/
  4. // @icon https://static.animeworld.tv/assets/images/favicon/android-icon-192x192.png
  5. // @description Migliora AnimeWorld
  6. // @author pizidavi
  7. // @version 1.7.7
  8. // @copyright 2021, PIZIDAVI
  9. // @license MIT
  10. // @require https://cdn.jsdelivr.net/gh/soufianesakhi/node-creation-observer-js@edabdee1caaee6af701333a527a0afd95240aa3b/release/node-creation-observer-latest.min.js
  11. // @match https://www.animeworld.tv/*
  12. // @run-at document-body
  13. // @grant GM_addStyle
  14. // @grant GM_xmlhttpRequest
  15. // @grant window.onurlchange
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20.  
  21. const PAGE_TITLE = document.title;
  22. const PAGE_ANIME_TITLE = '{{title}} Ep. {{episode}} - AnimeWorld'
  23. const PAGE_ANIME_TITLE_NO_EP = '{{title}} - AnimeWorld'
  24.  
  25. NodeCreationObserver.onCreation('#sign > div.signed ul', function (element) {
  26. addStyle('#header .head #sign .signed, #header .head #sign .signin { width: unset !important; }');
  27.  
  28. element.querySelector('li:nth-child(3) > a').href += '?folder=1&sort=2';
  29. element.querySelector('li:nth-child(4) > a').textContent = 'Notifiche';
  30. element.querySelector('li:nth-child(4) > a').href = '/notifications';
  31. });
  32.  
  33. NodeCreationObserver.onCreation('#notification', function (element) {
  34. setNotify();
  35. setInterval(function() {
  36. getNotify();
  37. }, 2*60*1000); // 2 minuti
  38.  
  39. if (location.pathname.includes('/play/'))
  40. window.addEventListener('urlchange', (info) => {
  41. setNotify();
  42. });
  43. });
  44.  
  45. NodeCreationObserver.onCreation('div.menu-profile', function (element) {
  46. element.querySelector('a.pulsante-profilo-tabs:nth-child(2)').href += '?folder=1&sort=2';
  47. if(location.pathname.includes('/watchlist'))
  48. document.querySelector('.cover-profilo-aw').style.display = 'none';
  49. });
  50.  
  51. if(location.pathname.includes('/play/')) {
  52. NodeCreationObserver.onCreation('#player .cover, div.server ul a, #controls > div.prevnext', function (element) {
  53. element.addEventListener('click', function() {
  54. window.scrollTo(0, 133);
  55. const r = document.querySelector('#controls .resize');
  56. if(r.textContent.includes('Espandi'))
  57. r.click();
  58.  
  59. setTimeout(function() {
  60. document.querySelector('#controls .light').click();
  61. document.cookie = 'expandedPlayer=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
  62. }, 700);
  63. });
  64. });
  65. NodeCreationObserver.onCreation('#player iframe', function (element) {
  66. const button = document.createElement('button');
  67. button.id = 'skip-intro';
  68. button.textContent = 'Salta Intro';
  69. button.title = 'Click destro per nascondere';
  70. button.style = 'position: absolute; bottom: 6em; right: 2em; padding: 0.5em 1em 0.4em; font-size: 14px; border: 1px solid #bdc3c7; border-radius: 2px; color: #bdc3c7; background-color: rgba(0,0,0,0.7); opacity: 0.25; z-index:2147483648;';
  71.  
  72. element.addEventListener('load', function(e) {
  73. if (!this.contentDocument) return;
  74. const video = this.contentDocument?.querySelector('video');
  75. if (!video) return;
  76.  
  77. video.oncanplay = function(e) {
  78. this.play();
  79. this.focus();
  80. };
  81. video.ontimeupdate = function(e) {
  82. if (this.currentTime > this.duration / 3)
  83. button.remove();
  84. };
  85. button.onclick = function(e) {
  86. e.preventDefault(); e.stopPropagation();
  87. video.currentTime += 87;
  88. video.focus();
  89. this.remove();
  90. };
  91. button.oncontextmenu = function(e) {
  92. e.preventDefault(); e.stopPropagation();
  93. video.focus();
  94. this.remove();
  95. };
  96. video.parentNode.append(button);
  97. });
  98. });
  99. }
  100. else if(location.pathname.includes('/notifications')) {
  101. NodeCreationObserver.onCreation('#delete-all', function (element) {
  102. const parentDiv = element.parentElement;
  103. const button = element.cloneNode();
  104. button.id = 'delete-read-all';
  105. button.innerHTML = '<i class="fas fa-trash"></i> Cancella tutte le notifiche "lette"';
  106. button.onclick = function() {
  107. Swal.fire({
  108. title: 'Vuoi davvero cancellare tutte le notifiche lette?',
  109. icon: 'question',
  110. showCancelButton: true,
  111. confirmButtonColor: 'rgb(165, 220, 134)',
  112. cancelButtonColor: 'rgb(221, 51, 51)',
  113. confirmButtonText: 'Si',
  114. cancelButtonText: 'No',
  115. }).then((result) => {
  116. if (result.value) {
  117. document.querySelectorAll('.profile-page .row .widget:nth-child(2) li.is-notification-read').forEach(function(e, i) {
  118. e.querySelector('.actions i.delete-clickable-icon').click();
  119. });
  120. }
  121. });
  122. };
  123. parentDiv.appendChild(button);
  124. element.remove();
  125. });
  126. }
  127.  
  128.  
  129. // ------- Function -------
  130. function getNotify() {
  131. request({
  132. url: '/request-serie',
  133. success: function(data) {
  134. const html = document.createElement('html'); html.innerHTML = data;
  135. document.querySelector('#notification > ul').innerHTML = html.querySelector('#notification > ul').innerHTML;
  136. setNotify();
  137.  
  138. document.querySelectorAll('#notification > ul > li[data-id]').forEach(function(li, index) {
  139. const span = li.querySelector('.header-notification-read');
  140. span.addEventListener('click', function(e) {
  141. e.preventDefault(); e.stopPropagation();
  142. request({
  143. url: '/api/notifications/open/'+li.getAttribute('data-id'),
  144. success: function(data) {
  145. li.remove();
  146. setNotify();
  147. }
  148. });
  149. });
  150. });
  151. }
  152. });
  153. }
  154.  
  155. function setNotify() {
  156. const number = document.querySelectorAll('ul.notification > li[data-id]').length || '0';
  157. document.querySelectorAll('.notifications-number').forEach((value, index) => {
  158. value.textContent = number;
  159. });
  160.  
  161. if(location.pathname.includes('/play/')) {
  162. const title = document.querySelector('#anime-title').textContent;
  163. const episode = document.querySelector('div.server ul a.active')?.getAttribute('data-base');
  164. if (episode)
  165. document.title = (parseInt(number) ? number + ' - ' : '') + PAGE_ANIME_TITLE.replace('{{title}}', title).replace('{{episode}}', episode);
  166. else
  167. document.title = (parseInt(number) ? number + ' - ' : '') + PAGE_ANIME_TITLE_NO_EP.replace('{{title}}', title);
  168. }
  169. else
  170. document.title = (parseInt(number) ? number + ' - ' : '') + PAGE_TITLE;
  171. }
  172.  
  173. function request(options) {
  174. const onreadystatechange = function() {
  175. if (this.readyState === 4 && (this.status == 200 || this.status == 201)) {
  176. options.success(this.responseText);
  177. } else if (this.readyState === 4) {
  178. console.warn('%cBetterAnimeWorld%c - Errore nella richiesta', 'color:red;font-size:14px;', '');
  179. }
  180. };
  181. if (typeof GM_xmlhttpRequest != 'undefined') {
  182. options.onload = onreadystatechange;
  183. GM_xmlhttpRequest(options);
  184. } else {
  185. const xhttp = new XMLHttpRequest();
  186. xhttp.open(options.method || 'GET', options.url);
  187. xhttp.onreadystatechange = onreadystatechange;
  188. xhttp.send();
  189. }
  190. }
  191.  
  192. function addStyle(CSS) {
  193. if (typeof GM_addStyle != 'undefined') {
  194. GM_addStyle(CSS);
  195. } else {
  196. const style = document.createElement('style');
  197. style.innerText = CSS;
  198. document.head.appendChild(style);
  199. }
  200. }
  201.  
  202. })();