From 854cfc11b1568139c5e2ad64d8f6cdbad8004819 Mon Sep 17 00:00:00 2001 From: Akamaru Date: Mon, 29 Sep 2025 20:43:32 +0200 Subject: [PATCH] Hitomi.la Language Filter --- hitomi-language-filter.user.js | 160 +++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 hitomi-language-filter.user.js diff --git a/hitomi-language-filter.user.js b/hitomi-language-filter.user.js new file mode 100644 index 0000000..ec19c1e --- /dev/null +++ b/hitomi-language-filter.user.js @@ -0,0 +1,160 @@ +// ==UserScript== +// @name Hitomi.la Language Filter +// @namespace https://git.ponywave.de/Akamaru/Userscripts +// @version 1.0 +// @description Filter manga by language on hitomi.la +// @author Akamaru +// @match https://hitomi.la/* +// @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(); + } +})(); \ No newline at end of file