Sonarr Anime Database Links

Adds AniList, MyAnimeList, SIMKL, AnimeBytes, nzbs.moe, and SeaDex links to Sonarr anime series pages

Size

6.3 KB

Version

1.1.10

Created

Jan 17, 2026

Updated

18 days ago

1// ==UserScript==
2// @name		Sonarr Anime Database Links
3// @description		Adds AniList, MyAnimeList, SIMKL, AnimeBytes, nzbs.moe, and SeaDex links to Sonarr anime series pages
4// @version		1.1.10
5// @match       http://192.168.1.50:8992/sonarr-anime/*
6// @match       https://sonarr-anime.flowsflow.com/*
7// @icon		http://192.168.1.50:8992/sonarr-anime/favicon.ico
8// ==/UserScript==
9(function() {
10    'use strict';
11
12    console.log('Sonarr Anime Database Links extension loaded');
13
14    let debounceTimer;
15    let lastProcessedTitle = '';
16
17    // Function to add anime database links in the toolbar
18    async function addAnimeLinks() {
19        // Check if we're on a series page
20        const titleElement = document.querySelector('.SeriesDetails-title-pJv1g');
21        if (!titleElement) {
22            console.log('Not on a series page');
23            return;
24        }
25
26        const seriesTitle = titleElement.textContent.trim();
27        
28        // Check if we already processed this title
29        if (lastProcessedTitle === seriesTitle && document.getElementById('anime-db-container')) {
30            console.log('Anime database links already exist for this title');
31            return;
32        }
33
34        // Remove old container if it exists
35        if (document.getElementById('anime-db-container')) {
36            console.log('Removing old anime database links');
37            document.getElementById('anime-db-container')?.remove();
38        }
39
40        console.log('Series title:', seriesTitle);
41        lastProcessedTitle = seriesTitle;
42
43        // Find the toolbar
44        const toolbar = document.querySelector('.PageToolbarSection-left-E_sPJ');
45        if (!toolbar) {
46            console.log('Toolbar not found');
47            return;
48        }
49
50        // Get AniList ID for SeaDex and nzbs.moe
51        const anilistId = await getAniListId(seriesTitle);
52
53        // Create container for anime database links
54        const container = document.createElement('div');
55        container.id = 'anime-db-container';
56        container.style.cssText = 'display: flex; gap: 8px; align-items: center; margin-left: 12px;';
57
58        // Create buttons with compact style
59        const buttons = [
60            { name: 'AniList', url: `https://anilist.co/search/anime?search=${encodeURIComponent(seriesTitle)}`, color: '#02A9FF' },
61            { name: 'MAL', url: `https://myanimelist.net/anime.php?q=${encodeURIComponent(seriesTitle)}`, color: '#2E51A2' },
62            { name: 'SIMKL', url: `https://simkl.com/search/?type=anime&q=${encodeURIComponent(seriesTitle)}`, color: '#0B0F10' },
63            { name: 'AB', url: `https://animebytes.tv/torrents.php?searchstr=${encodeURIComponent(seriesTitle)}&action=advanced&search_type=title`, color: '#E74C3C' },
64            { name: 'NZBs', url: anilistId ? `https://nzbs.moe/series/al/${anilistId}` : 'https://nzbs.moe/', color: '#FF6B35' },
65            { name: 'SeaDex', url: anilistId ? `https://releases.moe/${anilistId}/` : 'https://releases.moe/about/', color: '#00D9FF' }
66        ];
67
68        buttons.forEach(btn => {
69            const button = document.createElement('button');
70            button.textContent = btn.name;
71            button.title = `Open on ${btn.name}`;
72            button.style.cssText = `
73                padding: 6px 12px;
74                background: ${btn.color};
75                color: white;
76                border: none;
77                border-radius: 4px;
78                cursor: pointer;
79                font-size: 13px;
80                font-weight: 500;
81                transition: opacity 0.2s;
82            `;
83            
84            button.addEventListener('mouseenter', () => {
85                button.style.opacity = '0.8';
86            });
87            
88            button.addEventListener('mouseleave', () => {
89                button.style.opacity = '1';
90            });
91            
92            button.addEventListener('click', (e) => {
93                e.preventDefault();
94                window.open(btn.url, '_blank');
95            });
96            
97            container.appendChild(button);
98        });
99
100        // Add separator before the container
101        const separator = document.createElement('div');
102        separator.className = 'PageToolbarSeparator-separator-N1WHF';
103        
104        // Insert at the end of the toolbar
105        toolbar.appendChild(separator);
106        toolbar.appendChild(container);
107
108        console.log('Anime database links added successfully to toolbar');
109    }
110
111    // Function to get AniList ID from anime title
112    async function getAniListId(title) {
113        const query = `
114            query ($search: String) {
115                Media(search: $search, type: ANIME) {
116                    id
117                }
118            }
119        `;
120
121        try {
122            const response = await fetch('https://graphql.anilist.co', {
123                method: 'POST',
124                headers: {
125                    'Content-Type': 'application/json',
126                    'Accept': 'application/json',
127                },
128                body: JSON.stringify({
129                    query: query,
130                    variables: { search: title }
131                })
132            });
133
134            const data = await response.json();
135            return data.data?.Media?.id || null;
136        } catch (error) {
137            console.error('Error fetching AniList ID:', error);
138            return null;
139        }
140    }
141
142    // Debounced version of addAnimeLinks
143    function debouncedAddAnimeLinks() {
144        clearTimeout(debounceTimer);
145        debounceTimer = setTimeout(() => {
146            addAnimeLinks();
147        }, 300);
148    }
149
150    // Function to initialize
151    function init() {
152        console.log('Initializing anime database links extension');
153        
154        // Try to add the links immediately
155        addAnimeLinks();
156
157        // Watch for navigation changes (Sonarr is a SPA)
158        const observer = new MutationObserver(function() {
159            debouncedAddAnimeLinks();
160        });
161
162        // Observe the main content area for changes
163        const contentArea = document.querySelector('.PageContent-content-C67P9') || document.body;
164        observer.observe(contentArea, {
165            childList: true,
166            subtree: true
167        });
168
169        console.log('Observer set up for dynamic content');
170    }
171
172    // Wait for the page to be ready
173    if (document.readyState === 'loading') {
174        document.addEventListener('DOMContentLoaded', init);
175    } else {
176        init();
177    }
178})();
Sonarr Anime Database Links | Robomonkey