NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name WatchAnything // @namespace https://openuserjs.org/users/Pasha13666 // @version 1.1.3 // @description [shikimori.one] Кнопка открытия случайного аниме из списка // @author NekoNekoNyan // @match http://shikimori.me/* // @match https://shikimori.me/* // @match http://shikimori.one/* // @match https://shikimori.one/* // @match http://shikimori.org/* // @match https://shikimori.org/* // @updateURL https://openuserjs.org/meta/Pasha13666/WatchAnything.meta.js // @homepageURL https://github.com/neko-neko-nyan/WatchAnything // @run-at document-body // @license MIT // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_log // @copyright 2018-2023, NekoNekoNyan (https://github.com/neko-neko-nyan) // ==/UserScript== const LIST_NAMES = ['planned', 'watching', 'completed', 'on_hold', 'dropped']; function WatchAnything(){ this.onRandomClicked = this.onRandomClicked.bind(this); this.triggerChange = this.triggerChange.bind(this); } WatchAnything.prototype.triggerChange = function(){ if (!document.body || !document.body.classList.contains("p-user_rates")) return; GM_log("[WatchAnything] Starting / loading..."); if (location.href !== this.prevUrl) { this.prevUrl = location.href; this.onUrlChanged(); } this.bindToLists(); } WatchAnything.prototype.onUrlChanged = function (){ const url = window.location.pathname.split('/'); this.data = {}; this.kind = url[3]; for (let i = 4; i < url.length; i+=2) { const k = url[i], v = url[i + 1]; if (k !== 'order-by') this.data[k] = v; } this.data.censored = false; this.data.limit = 50; this.csrf = document.querySelector('meta[name=csrf-token]').content; } WatchAnything.prototype.bindToLists = function (){ for (let i = 0; i < 5; i++){ const $header = document.querySelector('.status-' + i); if (!$header || $header.children[1].classList.contains('wa-link')) continue; const $link = document.createElement('div'); $link.classList = "b-options-floated wa-link"; $link.innerHTML = '<a href="#" class="action">рандом</a>'; $link.dataset.listName = LIST_NAMES[i]; $link.addEventListener('click', this.onRandomClicked); $link.addEventListener('auxclick', this.onRandomClicked); $header.children[1].before($link); } } WatchAnything.prototype.onRandomClicked = function(e) { const newTab = e.which !== 1; const $link = e.currentTarget; e.preventDefault(); this.loadList(1, $link.dataset.listName, function(c){ c = c[Math.floor(Math.random() * c.length)]; GM_log("[WatchAnything] Opening random selected:", c.russian || c.name); if (newTab) window.open(location.origin + c.url, '_blank', ''); else window.location.pathname = c.url; }); if (newTab) e.stopImmediatePropagation(); } WatchAnything.prototype.loadList = function(page, mylist, fn){ const ajax = new XMLHttpRequest(); const data = new Object(this.data); data.page = page; data.mylist = mylist; ajax.open("GET", location.origin + '/api/' + this.kind + 's?' + Object.keys(data).map(key => key + '=' + data[key]).join('&'), true); ajax.setRequestHeader('X-CSRF-Token', this.csrf); ajax.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); ajax.setRequestHeader('X-Userscript', 'WatchAnything'); ajax.onreadystatechange = () => { if (ajax.readyState !== 4 || ajax.status !== 200) return; const cnt = JSON.parse(ajax.responseText); if (cnt.length === 50) { if (page % 5 === 0) setTimeout(() => this.loadList(page + 1, mylist, function(c){ fn(cnt.concat(c)); }), 1000); else this.loadList(page + 1, mylist, function(c){ fn(cnt.concat(c)); }); } else fn(cnt); } ajax.send(); } document.head.append(GM_addStyle(".wa-link { right: 90px; }")); const wa = new WatchAnything; document.addEventListener('ready', wa.triggerChange); document.addEventListener('page:load', wa.triggerChange); document.addEventListener('turbolinks:load', wa.triggerChange); wa.triggerChange();