1
0
Files
Userscripts/hitomi-language-filter.user.js
2025-09-29 20:43:32 +02:00

160 lines
5.1 KiB
JavaScript

// ==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();
}
})();