AniList - Activity Assistant

Script that speeds up Activity Making

安裝腳本?
作者推薦腳本

您可能也會喜歡 AniList - Activity Templates

安裝腳本
  1. // ==UserScript==
  2. // @name AniList - Activity Assistant
  3. // @namespace https://www.youtube.com/c/NurarihyonMaou/
  4. // @version 1.3.6
  5. // @description Script that speeds up Activity Making
  6. // @author NurarihyonMaou
  7. // @match https://anilist.co/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=anilist.co
  9. // @require https://code.jquery.com/jquery-3.6.0.js
  10. // @require https://code.jquery.com/ui/1.13.1/jquery-ui.js
  11. // @resource IMPORTED_CSS https://code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css
  12. // @grant GM_getResourceText
  13. // @grant GM_addStyle
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // ==/UserScript==
  17.  
  18. const $ = window.jQuery;
  19. const x_csrf_token = $("head script:contains('window.al_token')").text().split(/[“"”]+/g)[1];
  20.  
  21. const imported_CSS = GM_getResourceText("IMPORTED_CSS");
  22. const list_Style = 'ul.ui-autocomplete { background-color: rgb(21, 31, 46); color: RGB(159,173,189); }';
  23. const category_Style = '.ui-autocomplete-category { font-weight: bold; padding: .2em .4em; margin: .8em 0 .2em;line-height: 1.5;}';
  24.  
  25. GM_addStyle(list_Style);
  26. GM_addStyle(imported_CSS);
  27. GM_addStyle(category_Style);
  28.  
  29. let autoComplete = [];
  30. let textArea, prefix, wordsConnector, caretPos, CaretPos;
  31. let allWords, currentWord, lastSearched, words;
  32.  
  33. (function init() {
  34.  
  35. textArea = document.getElementsByClassName("el-textarea__inner");
  36.  
  37. if (textArea.length > 0) {
  38.  
  39. if (GM_getValue("wordsConnector") == undefined || GM_getValue("prefix") == undefined) {
  40. prefix = prompt("Type a Character that You want to use as a Prefix for using the AutoComplete. You can change it later by Typing - 'changePrefix'", ".");
  41. wordsConnector = prompt("Type a Character that You want to use as a Connector for Multiple-Word-Search. You can change it later by Typing - 'wordsConnector'", "_");
  42. GM_setValue("prefix", prefix);
  43. GM_setValue("wordsConnector", wordsConnector);
  44. } else { wordsConnector = GM_getValue("wordsConnector"); prefix = GM_getValue("prefix"); }
  45.  
  46. $(textArea).after('<input type="hidden" id="testArea">');
  47.  
  48. function searchQuery(word) {
  49. var query = `
  50. query($search:String,$isAdult:Boolean){anime:Page(perPage:8){pageInfo{total}results:media(type:ANIME,isAdult:$isAdult,search:$search){id title{romaji, english, native}coverImage{medium}type format bannerImage isLicensed startDate{year}}}manga:Page(perPage:8){pageInfo{total}results:media(type:MANGA,isAdult:$isAdult,search:$search){id title{romaji, english, native}coverImage{medium}type format bannerImage isLicensed startDate{year}}}characters:Page(perPage:8){pageInfo{total}results:characters(search:$search){id name{full, native, alternative}image{medium}}}staff:Page(perPage:8){pageInfo{total}results:staff(search:$search){id primaryOccupations name{full, native, alternative}image{medium}}}studios:Page(perPage:13){pageInfo{total}results:studios(search:$search){id name}}users:Page(perPage:8){results:users(search:$search){id name avatar{medium}}}}
  51. `;
  52.  
  53. var variables = {
  54. search: word
  55. };
  56.  
  57. var url = 'https://anilist.co/graphql',
  58. options = {
  59. method: 'POST',
  60. headers: {
  61. 'Content-Type': 'application/json',
  62. 'Accept': 'application/json',
  63. "x-csrf-token": x_csrf_token
  64. },
  65. body: JSON.stringify({
  66. query: query,
  67. variables: variables
  68. })
  69. };
  70.  
  71. fetch(url, options).then(handleResponse)
  72. .then(handleData)
  73. .catch(handleError);
  74.  
  75. function handleResponse(response) {
  76. return response.json().then(function (json) {
  77. return response.ok ? json : Promise.reject(json);
  78. });
  79. }
  80.  
  81. function handleData(data) {
  82.  
  83. autoComplete = [];
  84.  
  85. $.each(data.data.anime.results, function (index, element) {
  86. autoComplete.push({ 'value': 'https://anilist.co/anime/' + element.id, 'label': [element.title.romaji, element.title.english, element.title.native], 'category': 'Anime' });
  87. });
  88.  
  89. $.each(data.data.manga.results, function (index, element) {
  90. autoComplete.push({ 'value': 'https://anilist.co/manga/' + element.id, 'label': [element.title.romaji, element.title.english, element.title.native], 'category': 'Manga' });
  91. });
  92.  
  93. $.each(data.data.characters.results, function (index, element) {
  94. autoComplete.push({ 'value': '[' + element.name.full + '](https://anilist.co/character/' + element.id + ")", 'label': [element.name.full, element.name.native, element.name.alternative], 'category': 'Characters' });
  95. });
  96.  
  97. $.each(data.data.staff.results, function (index, element) {
  98. autoComplete.push({ 'value': '[' + element.name.full + '](https://anilist.co/staff/' + element.id + ")", 'label': [element.name.full, element.name.native, element.name.alternative], 'category': 'Staff' });
  99. });
  100.  
  101. $.each(data.data.users.results, function (index, element) {
  102. autoComplete.push({ 'value': '@' + element.name, 'label': element.name, 'category': 'Users' });
  103. });
  104.  
  105. $.each(data.data.studios.results, function (index, element) {
  106. autoComplete.push({ 'value': '[' + element.name + '](https://anilist.co/studio/' + element.id + ")", 'label': element.name, 'category': 'Studios' });
  107. });
  108.  
  109. }
  110.  
  111. function handleError(error) {
  112. alert('Error, check console');
  113. console.error(error);
  114. }
  115. }
  116.  
  117. $.widget("custom.catcomplete", $.ui.autocomplete, {
  118. _create: function () {
  119. this._super();
  120. this.widget().menu("option", "items", "> :not(.ui-autocomplete-category)");
  121. },
  122. _renderMenu: function (ul, items) {
  123. var that = this,
  124. currentCategory = "";
  125. $.each(items, function (index, item) {
  126. var li;
  127. if (item.category != currentCategory) {
  128. ul.append("<li class='ui-autocomplete-category'>" + item.category + "</li>");
  129. currentCategory = item.category;
  130. }
  131. li = that._renderItemData(ul, item);
  132. let useThisLabel = Array.isArray(item.label) ? item.label[0] : item.label;
  133. if (item.category) {
  134. li.attr("aria-label", item.category + " : " + useThisLabel);
  135. }
  136. li.children().text(useThisLabel);
  137. });
  138. }
  139. });
  140.  
  141. function ReturnWord(text, caretPos) {
  142. let preText = text.substring(0, caretPos);
  143. allWords = preText.split(/\s+/);
  144. return allWords[allWords.length - 1];
  145. }
  146.  
  147. function GetCaretPosition(ctrl) {
  148. if (document.selection) {
  149. ctrl.focus();
  150. let Sel = document.selection.createRange();
  151. Sel.moveStart('character', -ctrl.value.length);
  152. CaretPos = Sel.text.length;
  153. }
  154. else if (ctrl.selectionStart || ctrl.selectionStart == '0')
  155. CaretPos = ctrl.selectionStart;
  156. return (CaretPos);
  157. }
  158.  
  159. function setCaretPosition(caretPos) {
  160. if (textArea[0] != null) {
  161. if (textArea[0].createTextRange) {
  162. var range = textArea[0].createTextRange();
  163. range.move('character', caretPos);
  164. range.select();
  165. }
  166. else {
  167. if (textArea[0].selectionStart) {
  168. textArea[0].focus();
  169. textArea[0].setSelectionRange(caretPos, caretPos);
  170. }
  171. else
  172. textArea[0].focus();
  173. }
  174. }
  175. }
  176.  
  177. $(textArea).on('input', function () {
  178. caretPos = GetCaretPosition(textArea[0])
  179. currentWord = ReturnWord($(textArea).val(), caretPos).replaceAll(wordsConnector, " ");
  180.  
  181. if (currentWord == "wordsConnector") {
  182. $(textArea).val($(textArea).val().replace("wordsConnector", ""));
  183. wordsConnector = prompt("Type a Character that You want to use as a Connector for Multiple-Word-Search.", wordsConnector);
  184. GM_setValue("wordsConnector", wordsConnector);
  185. }
  186. else if (currentWord == "changePrefix") {
  187. $(textArea).val($(textArea).val().replace("changePrefix", ""));
  188. prefix = prompt("Type a Character that You want to use as a Prefix for using the AutoComplete.", prefix);
  189. GM_setValue("changePrefix", prefix);
  190. }
  191. else if (currentWord.length > 2 && lastSearched != currentWord && currentWord[0] == prefix) {
  192. currentWord = currentWord.substring(1);
  193. searchQuery(currentWord);
  194. lastSearched = currentWord;
  195. }
  196. });
  197.  
  198. $(textArea).catcomplete({
  199. delay: 500,
  200. minLength: 3,
  201. source: function (request, response) {
  202. response($.ui.autocomplete.filter(
  203. autoComplete, currentWord));
  204. },
  205. focus: function () {
  206. return false;
  207. },
  208. select: function (event, ui) {
  209. let insertAutoComplete = $(textArea).val().substring(0, caretPos - currentWord.length - 1) + ui.item.value + $(textArea).val().substr(caretPos);
  210. $(textArea).val(insertAutoComplete);
  211. setCaretPosition(caretPos + ((ui.item.value).length - currentWord.length));
  212. autoComplete = [];
  213. currentWord = "";
  214. return false;
  215. }
  216. });
  217.  
  218. } else {
  219. setTimeout(init, 0);
  220. }
  221. })();
  222.  
  223. let oldURL;
  224.  
  225. (function () {
  226. let pushState = history.pushState;
  227. let replaceState = history.replaceState;
  228.  
  229. history.pushState = function () {
  230. pushState.apply(history, arguments);
  231. window.dispatchEvent(new Event("pushstate"));
  232. window.dispatchEvent(new Event("locationchange"));
  233. };
  234.  
  235. history.replaceState = function () {
  236. replaceState.apply(history, arguments);
  237. window.dispatchEvent(new Event("replacestate"));
  238. window.dispatchEvent(new Event("locationchange"));
  239. };
  240.  
  241. window.addEventListener("popstate", function () {
  242. window.dispatchEvent(new Event("locationchange"));
  243. });
  244. })();
  245.  
  246. $(window).on("load", function () {
  247. GM_setValue("oldURL", $(location).attr("pathname").split("/")[1]);
  248. });
  249.  
  250. window.addEventListener("locationchange", function () {
  251. oldURL = GM_getValue("oldURL");
  252.  
  253. if (
  254. (oldURL != $(location).attr("pathname").split("/")[1]) &&
  255. ($(location).attr("pathname").split("/")[1] == "user" || $(location).attr("pathname").split("/")[1] == "home" || $(location).attr("pathname").split("/")[1] == "forum" || $(location).attr("pathname").split("/")[1] == "activity")
  256. ) {
  257. GM_setValue("oldURL", $(location).attr("pathname").split("/")[1]);
  258. location.reload();
  259. } else GM_setValue("oldURL", $(location).attr("pathname").split("/")[1]);
  260. });