Nyaa nzbs.moe Link Button

Adds a button to view anime on nzbs.moe using the AniList ID from Nyaa torrents

Size

5.1 KB

Version

1.0.1

Created

Jan 17, 2026

Updated

about 1 month ago

1// ==UserScript==
2// @name		Nyaa nzbs.moe Link Button
3// @description		Adds a button to view anime on nzbs.moe using the AniList ID from Nyaa torrents
4// @version		1.0.1
5// @match		https://nyaa.si/view/*
6// @icon		https://nyaa.si/static/favicon.png
7// @require		https://raw.githubusercontent.com/TalkingJello/moe-delicious-library/refs/heads/main/moe-delicious-library.json
8// ==/UserScript==
9(function() {
10    'use strict';
11    
12    console.log('nzbs.moe button extension loaded');
13    
14    async function fetchMoeLibrary() {
15        try {
16            const response = await fetch('https://raw.githubusercontent.com/TalkingJello/moe-delicious-library/refs/heads/main/moe-delicious-library.json');
17            const data = await response.json();
18            console.log('Moe library loaded successfully');
19            return data;
20        } catch (error) {
21            console.error('Failed to load moe library:', error);
22            return null;
23        }
24    }
25    
26    function findNzbsMoeId(anilistId, moeLibrary) {
27        if (!moeLibrary || !moeLibrary.data) {
28            console.log('Moe library data not available');
29            return null;
30        }
31        
32        // Search through the library to find matching AniList ID
33        for (const entry of moeLibrary.data) {
34            if (entry.sources && entry.sources.anilist) {
35                const anilistUrl = entry.sources.anilist;
36                const match = anilistUrl.match(/\/anime\/(\d+)/);
37                if (match && match[1] === anilistId) {
38                    return entry.id;
39                }
40            }
41        }
42        
43        console.log('No nzbs.moe ID found for AniList ID:', anilistId);
44        return null;
45    }
46    
47    async function addButton() {
48        // Check if button already exists
49        if (document.querySelector('.nzbs-moe-button')) {
50            console.log('nzbs.moe button already exists');
51            return;
52        }
53        
54        // Find the AniList link in the torrent description
55        const anilistLink = document.querySelector('a[href*="anilist.co/anime/"]');
56        
57        if (!anilistLink) {
58            console.log('AniList link not found');
59            return;
60        }
61        
62        // Extract the AniList ID from the URL
63        const anilistUrl = anilistLink.href;
64        const anilistIdMatch = anilistUrl.match(/\/anime\/(\d+)/);
65        
66        if (!anilistIdMatch) {
67            console.log('Could not extract AniList ID');
68            return;
69        }
70        
71        const anilistId = anilistIdMatch[1];
72        console.log('Found AniList ID:', anilistId);
73        
74        // Fetch the moe library and find the corresponding nzbs.moe ID
75        const moeLibrary = await fetchMoeLibrary();
76        const nzbsMoeId = findNzbsMoeId(anilistId, moeLibrary);
77        
78        if (!nzbsMoeId) {
79            console.log('Could not find nzbs.moe ID for AniList ID:', anilistId);
80            // Fallback to using AniList ID directly
81            const nzbsUrl = `https://nzbs.moe/series/al/${anilistId}`;
82            createButton(nzbsUrl, anilistLink);
83            return;
84        }
85        
86        // Create the nzbs.moe URL with the found ID
87        const nzbsUrl = `https://nzbs.moe/series/${nzbsMoeId}`;
88        console.log('nzbs.moe URL:', nzbsUrl);
89        
90        createButton(nzbsUrl, anilistLink);
91    }
92    
93    function createButton(nzbsUrl, anilistLink) {
94        // Find the container - typically the panel with torrent info
95        const container = anilistLink.closest('.panel-body') || anilistLink.closest('.col-md-5');
96        
97        if (!container) {
98            console.log('Container not found');
99            return;
100        }
101        
102        // Create the button
103        const nzbsButton = document.createElement('a');
104        nzbsButton.href = nzbsUrl;
105        nzbsButton.target = '_blank';
106        nzbsButton.className = 'nzbs-moe-button btn btn-primary btn-sm';
107        nzbsButton.textContent = 'View on nzbs.moe';
108        nzbsButton.style.cssText = 'margin-top: 10px; display: inline-block;';
109        
110        // Insert the button after the AniList link's parent element
111        const linkParent = anilistLink.parentElement;
112        if (linkParent) {
113            linkParent.insertAdjacentElement('afterend', nzbsButton);
114            console.log('nzbs.moe button added successfully');
115        } else {
116            console.log('Could not find parent element for button placement');
117        }
118    }
119    
120    function init() {
121        // Try to add button immediately
122        addButton();
123        
124        // Also observe for dynamic content loading
125        const observer = new MutationObserver(function() {
126            addButton();
127        });
128        
129        observer.observe(document.body, {
130            childList: true,
131            subtree: true
132        });
133        
134        // Stop observing after 10 seconds
135        setTimeout(() => {
136            observer.disconnect();
137            console.log('Stopped observing for changes');
138        }, 10000);
139    }
140    
141    // Wait for the page to load
142    if (document.readyState === 'loading') {
143        document.addEventListener('DOMContentLoaded', init);
144    } else {
145        init();
146    }
147})();