// ==UserScript== // @name Find on Nyaa // @namespace MALFindNya // @version 2.7 // @description Will open nyaa on a new window and search for the anime title // @author Samu // @match https://myanimelist.net/anime/* // @match https://myanimelist.net/anime.php?id=* // @match https://anilist.co/* // @match https://kitsu.io/* // @match https://*.anime-planet.com/* // @match https://*.animenewsnetwork.com/* // @match https://anidb.net/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @downloadURL none // ==/UserScript== /** icon source https://icons8.com/icon/82838/external-link **/ //** SETTINGS **// let sortBy = "seeders"; // "comments", "size", "id", "seeders", "leechers", or "downloads" let filter = "0"; // 0 = No Filter | 1 = No remakes | 2 = Trusted Only let category = "AnimeEnglishTranslated"; // Check values below let favoriteGroups = ["Judas", "Erai-raws"]; // List is ordered, favorite should be first let searchPrefix = ""; let searchSufix = ""; //** END OF SETTINGS **// // Category values const cat = { Allcategories: "0_0", Anime: "1_0", AnimeMusicVideo: "1_1", AnimeEnglishTranslated: "1_2", AnimeNonEnglishTranslated: "1_3", Raw: "1_4", Audio: "2_0", Lossless: "2_1", Lossy: "2_2", Literature: "3_0", LiteratureEnglishTranslated: "3_1", LiteratureNonEnglishTranslated: "3_2", LiteratureRaw: "3_3", LiveAction: "4_0", LiveActionEnglishTranslated: "4_1", IdolPromotionalVideo: "4_2", LiveActionNonEnglishTranslated: "4_3", LiveActionRaw: "4_4", Pictures: "5_0", Graphics: "5_1", Photos: "5_2", Software: "6_0", Applications: "6_1", Games: "6_2", }; const sites = [ { host: "myanimelist.net", selector: ".title-name", }, { host: "anilist.co", path: "/anime/", selector: ".page-content .header .content > h1", dark: true, }, { host: "kitsu.io", path: "/anime/", selector: ".media--title h3", }, { host: "anime-planet.com", path: "/anime/", selector: "#siteContainer h1", dark: true, }, { host: "animenewsnetwork.com", path: "/encyclopedia/anime.php", selector: "#page_header", filter: /\([a-zA-Z0-9 ]+\)/, }, { host: "anidb.net", path: "/anime/", selector: "h1.anime", dark: true, filter: /^Anime:\s/, }, ]; const buttonId = "FindOnNyaaButtonId"; const imgKey = "ImgData"; let buttonIcon = getIcon(); (function() { 'use strict'; GM_registerMenuCommand("Add Custom Icon", uploadImage, "h"); if (typeof buttonIcon !== "string") { GM_registerMenuCommand("Remove Custom Icon", removeImage, "h"); } let pushState = history.pushState; let replaceState = history.replaceState; history.pushState = function() { pushState.apply(history, arguments); window.dispatchEvent(new Event('pushstate')); window.dispatchEvent(new Event('locationchange')); }; history.replaceState = function() { replaceState.apply(history, arguments); window.dispatchEvent(new Event('replacestate')); window.dispatchEvent(new Event('locationchange')); }; window.addEventListener('popstate', function() { window.dispatchEvent(new Event('locationchange')) }); let host = window.location.host; let path = window.location.pathname; window.addEventListener('locationchange', function() { path = window.location.pathname; lookForTitleElement(host, path); }); lookForTitleElement(host, path); })(); function lookForTitleElement(host, path) { for (let i = 0; i < sites.length; i++) { let site = sites[i]; if (host.endsWith(site.host) && (site.path == undefined || path.startsWith(site.path))) { waitForElm(site.selector).then(elm => init(elm, site.dark, site.filter)); break; } } let nyaaButton = document.getElementById(buttonId); if (nyaaButton != null) { nyaaButton.parentElement.removeChild(nyaaButton); } } function init(element, dark = false, filter) { let url = createUrl(element, filter); let nyaaButton = document.getElementById(buttonId); if (nyaaButton == null) { nyaaButton = createButton(url, dark); element.appendChild(nyaaButton); } else { nyaaButton.setAttribute("href", url); } } function createButton(url, dark) { let button = document.createElement("a"); button.id = buttonId; button.setAttribute("href", url); button.setAttribute("target", "_blank"); button.setAttribute("rel", "noopener"); button.setAttribute("title", "Search on Nyaa"); button.setAttribute("style", "margin-left: 10px;height: 10px;width: 10px;display: inline-flex;transform: scale(1.8);vertical-align: top;margin-top: 7px;"); if (typeof buttonIcon === "string") { button.innerHTML = buttonIcon; dark && button.querySelector("svg").setAttribute("fill", "#fff"); } else { button.appendChild(buttonIcon); } return button; } function createUrl(element, titleFilter) { let textFragment = ":~:text=" + favoriteGroups.join("&text="); let title = element.textContent.replace(titleFilter, "").trim().replace(/[^a-zA-Z0-9]+/g, "+").trim(); let query = [searchPrefix, title, searchSufix].join(" ").trim(); let queryURI = encodeURI(query); let baseUrl = "https://nyaa.si/"; let path = `?f=${filter}&c=${cat[category]}&s=${sortBy}&o=desc&q=${queryURI}`; return baseUrl + path + "#" + textFragment; } function waitForElm(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } function getIcon() { let userImg = GM_getValue(imgKey); if (userImg == null) { return ``; } let imgElement = document.createElement("img"); imgElement.src = userImg; return imgElement; } function uploadImage() { let input = document.createElement("input"); input.type = "file"; input.addEventListener("change", onImageUploaded); input.click(); } function onImageUploaded(e) { let file = this.files[0]; new Promise((resolve, reject) => { const reader = new FileReader() reader.onloadend = () => resolve(reader.result) reader.onerror = reject reader.readAsDataURL(file) }) .then(result => { GM_setValue(imgKey, result); window.location.reload(); }) .catch(err => alert(err)); } function removeImage() { GM_setValue(imgKey, null); window.location.reload(); }