AniList - Activity Assistant

Script that speeds up Activity Making

当前为 2022-05-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name AniList - Activity Assistant
  3. // @namespace https://www.youtube.com/c/NurarihyonMaou/
  4. // @version 1.2.7
  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{userPreferred}coverImage{medium}type format bannerImage isLicensed startDate{year}}}manga:Page(perPage:8){pageInfo{total}results:media(type:MANGA,isAdult:$isAdult,search:$search){id title{userPreferred}coverImage{medium}type format bannerImage isLicensed startDate{year}}}characters:Page(perPage:8){pageInfo{total}results:characters(search:$search){id name{userPreferred}image{medium}}}staff:Page(perPage:8){pageInfo{total}results:staff(search:$search){id primaryOccupations name{userPreferred}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.userPreferred, '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.userPreferred, 'category': 'Manga' });
  91. });
  92.  
  93. $.each(data.data.characters.results, function (index, element) {
  94. autoComplete.push({ 'value': '[' + element.name.userPreferred + '](https://anilist.co/character/' + element.id + ")", 'label': element.name.userPreferred, 'category': 'Characters' });
  95. });
  96.  
  97. $.each(data.data.staff.results, function (index, element) {
  98. autoComplete.push({ 'value': '[' + element.name.userPreferred + '](https://anilist.co/staff/' + element.id + ")", 'label': element.name.userPreferred, '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. if (item.category) {
  133. li.attr("aria-label", item.category + " : " + item.label);
  134. }
  135. });
  136. }
  137. });
  138.  
  139. function ReturnWord(text, caretPos) {
  140. let preText = text.substring(0, caretPos);
  141. allWords = preText.split(/\s+/);
  142. return allWords[allWords.length - 1];
  143. }
  144.  
  145. function GetCaretPosition(ctrl) {
  146. if (document.selection) {
  147. ctrl.focus();
  148. let Sel = document.selection.createRange();
  149. Sel.moveStart('character', -ctrl.value.length);
  150. CaretPos = Sel.text.length;
  151. }
  152. else if (ctrl.selectionStart || ctrl.selectionStart == '0')
  153. CaretPos = ctrl.selectionStart;
  154. return (CaretPos);
  155. }
  156.  
  157. function setCaretPosition(caretPos) {
  158. if (textArea[0] != null) {
  159. if (textArea[0].createTextRange) {
  160. var range = textArea[0].createTextRange();
  161. range.move('character', caretPos);
  162. range.select();
  163. }
  164. else {
  165. if (textArea[0].selectionStart) {
  166. textArea[0].focus();
  167. textArea[0].setSelectionRange(caretPos, caretPos);
  168. }
  169. else
  170. textArea[0].focus();
  171. }
  172. }
  173. }
  174.  
  175. $(textArea).on('input', function () {
  176. caretPos = GetCaretPosition(textArea[0])
  177. currentWord = ReturnWord($(textArea).val(), caretPos).replace(wordsConnector, " ");
  178.  
  179. if (currentWord == "wordsConnector") {
  180. $(textArea).val($(textArea).val().replace("wordsConnector", ""));
  181. wordsConnector = prompt("Type a Character that You want to use as a Connector for Multiple-Word-Search.", wordsConnector);
  182. GM_setValue("wordsConnector", wordsConnector);
  183. }
  184. else if (currentWord == "changePrefix") {
  185. $(textArea).val($(textArea).val().replace("changePrefix", ""));
  186. prefix = prompt("Type a Character that You want to use as a Prefix for using the AutoComplete.", prefix);
  187. GM_setValue("changePrefix", prefix);
  188. }
  189. else if (currentWord.length > 2 && lastSearched != currentWord && currentWord[0] == prefix) {
  190. currentWord = currentWord.substring(1);
  191. searchQuery(currentWord);
  192. lastSearched = currentWord;
  193. }
  194. });
  195.  
  196. $(textArea).catcomplete({
  197. delay: 500,
  198. minLength: 3,
  199. source: function (request, response) {
  200. response($.ui.autocomplete.filter(
  201. autoComplete, currentWord));
  202. },
  203. focus: function () {
  204. return false;
  205. },
  206. select: function (event, ui) {
  207. let insertAutoComplete = $(textArea).val().substring(0, caretPos - currentWord.length - 1) + ui.item.value + $(textArea).val().substr(caretPos);
  208. $(textArea).val(insertAutoComplete);
  209. setCaretPosition(caretPos + ((ui.item.value).length - currentWord.length));
  210. autoComplete = [];
  211. currentWord = "";
  212. return false;
  213. }
  214. });
  215.  
  216. } else {
  217. setTimeout(init, 0);
  218. }
  219. })();
  220.  
  221. let oldURL;
  222.  
  223. (function () {
  224. let pushState = history.pushState;
  225. let replaceState = history.replaceState;
  226.  
  227. history.pushState = function () {
  228. pushState.apply(history, arguments);
  229. window.dispatchEvent(new Event("pushstate"));
  230. window.dispatchEvent(new Event("locationchange"));
  231. };
  232.  
  233. history.replaceState = function () {
  234. replaceState.apply(history, arguments);
  235. window.dispatchEvent(new Event("replacestate"));
  236. window.dispatchEvent(new Event("locationchange"));
  237. };
  238.  
  239. window.addEventListener("popstate", function () {
  240. window.dispatchEvent(new Event("locationchange"));
  241. });
  242. })();
  243.  
  244. $(window).on("load", function () {
  245. GM_setValue("oldURL", $(location).attr("pathname").split("/")[1]);
  246. });
  247.  
  248. window.addEventListener("locationchange", function () {
  249. oldURL = GM_getValue("oldURL");
  250.  
  251. if (
  252. (oldURL != $(location).attr("pathname").split("/")[1]) &&
  253. ($(location).attr("pathname").split("/")[1] == "user" || $(location).attr("pathname").split("/")[1] == "home" || $(location).attr("pathname").split("/")[1] == "forum" || $(location).attr("pathname").split("/")[1] == "activity")
  254. ) {
  255. GM_setValue("oldURL", $(location).attr("pathname").split("/")[1]);
  256. location.reload();
  257. } else GM_setValue("oldURL", $(location).attr("pathname").split("/")[1]);
  258. });