// ==UserScript== // @name Hitomi.la Language Filter // @namespace https://git.ponywave.de/Akamaru/Userscripts // @version 1.1 // @description Filter manga by language on hitomi.la // @author Akamaru // @match https://hitomi.la/* // @icon https://www.google.com/s2/favicons?domain=hitomi.la&sz=32 // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @updateURL https://git.ponywave.de/Akamaru/Userscripts/raw/branch/master/hitomi-language-filter.user.js // @downloadURL https://git.ponywave.de/Akamaru/Userscripts/raw/branch/master/hitomi-language-filter.user.js // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // Available languages const languages = { 'all': 'All Languages', 'english': 'English', 'japanese': 'Japanese', 'chinese': 'Chinese', 'korean': 'Korean', 'spanish': 'Spanish', 'french': 'French', 'german': 'German', 'russian': 'Russian', 'italian': 'Italian', 'portuguese': 'Portuguese', 'thai': 'Thai', 'vietnamese': 'Vietnamese', 'polish': 'Polish', 'indonesian': 'Indonesian', 'turkish': 'Turkish' }; // Get saved language preference (default: english) let selectedLanguage = GM_getValue('selectedLanguage', 'english'); // Create language selector UI function createLanguageSelector() { const container = document.createElement('div'); container.id = 'language-filter-container'; container.style.cssText = ` position: fixed; top: 10px; right: 10px; z-index: 10000; background: #fff; border: 2px solid #333; border-radius: 5px; padding: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.3); `; const label = document.createElement('label'); label.textContent = 'Language: '; label.style.fontWeight = 'bold'; const select = document.createElement('select'); select.style.cssText = ` padding: 5px; border: 1px solid #ccc; border-radius: 3px; margin-left: 5px; `; // Add options for (const [code, name] of Object.entries(languages)) { const option = document.createElement('option'); option.value = code; option.textContent = name; if (code === selectedLanguage) { option.selected = true; } select.appendChild(option); } // Handle language change select.addEventListener('change', function() { selectedLanguage = this.value; GM_setValue('selectedLanguage', selectedLanguage); filterGalleries(); }); container.appendChild(label); container.appendChild(select); document.body.appendChild(container); } // Filter galleries based on selected language function filterGalleries() { // Find all gallery items (both classes used on the site) const galleries = document.querySelectorAll('.gallery, .dj, .manga'); galleries.forEach(gallery => { if (selectedLanguage === 'all') { gallery.style.display = ''; return; } // Check for language link in format /index-LANGUAGE.html const languageTag = gallery.querySelector('a[href*="/index-"][href$=".html"]'); if (!languageTag) { gallery.style.display = 'none'; return; } const href = languageTag.getAttribute('href'); const langMatch = href.match(/\/index-([^.]+)\.html/); if (langMatch && langMatch[1]) { const galleryLang = langMatch[1].toLowerCase(); if (galleryLang === selectedLanguage) { gallery.style.display = ''; } else { gallery.style.display = 'none'; } } else { gallery.style.display = 'none'; } }); } // Register menu command for quick access GM_registerMenuCommand('Change Language Filter', function() { const newLang = prompt('Enter language code:\n' + Object.entries(languages).map(([code, name]) => `${code} - ${name}`).join('\n')); if (newLang && languages[newLang]) { selectedLanguage = newLang; GM_setValue('selectedLanguage', selectedLanguage); location.reload(); } }); // Initialize function init() { createLanguageSelector(); filterGalleries(); // Watch for dynamic content loading const observer = new MutationObserver(function(mutations) { filterGalleries(); }); observer.observe(document.body, { childList: true, subtree: true }); } // Wait for page to load if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();