[Wallhaven] Subscription Tools

Adds a useful "tool box" to the top of the side bar on the subscriptions page (Filter Subs by name, sort them by amount, toggle on/off visibility of subs with 0 new wallpapers)

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         [Wallhaven] Subscription Tools
// @namespace    NooScripts
// @author       NooScripts
// @version      1.6
// @description  Adds a useful "tool box" to the top of the side bar on the subscriptions page (Filter Subs by name, sort them by amount, toggle on/off visibility of subs with 0 new wallpapers)
// @license MIT
// @match        https://wallhaven.cc/subscription*
// @grant        none
// ==/UserScript==

window.addEventListener('load', () => {
    'use strict';

    // Create container for search tools
    const container = document.createElement('div');
    container.id = 'custom-tag-filter';
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.alignItems = 'center';
    container.style.gap = '8px';
    container.style.padding = '10px';
    container.style.background = '#111';
    container.style.zIndex = '9999';

    // Search input
    const input = document.createElement('input');
    input.type = 'text';
    input.placeholder = 'Filter tags...';
    input.style.padding = '6px';
    input.style.width = '100%';
    input.style.background = '#222';
    input.style.color = '#fff';
    input.style.border = '1px solid #555';
    input.style.borderRadius = '4px';

    // Create a container for buttons
    const buttonsContainer = document.createElement('div');
    buttonsContainer.style.display = 'flex';
    buttonsContainer.style.gap = '8px';
    buttonsContainer.style.width = '100%';
    buttonsContainer.style.margin = 'auto';

    // Reset button
    const resetBtn = document.createElement('button');
    resetBtn.textContent = 'Reset';
    resetBtn.style.padding = '6px 10px';
    resetBtn.style.background = '#333';
    resetBtn.style.color = '#fff';
    resetBtn.style.border = '1px solid #555';
    resetBtn.style.borderRadius = '4px';
    resetBtn.style.cursor = 'pointer';
    resetBtn.style.flex = '1';

    // Toggle style button
    const toggleBtn = document.createElement('button');
    toggleBtn.style.padding = '6px 10px';
    toggleBtn.style.background = '#333';
    toggleBtn.style.color = '#fff';
    toggleBtn.style.border = '1px solid #555';
    toggleBtn.style.borderRadius = '4px';
    toggleBtn.style.cursor = 'pointer';
    toggleBtn.style.flex = '1';

    // Append buttons to the buttons container
    buttonsContainer.appendChild(resetBtn);
    buttonsContainer.appendChild(toggleBtn);

    // Append input and buttons container to the main container
    container.appendChild(input);
    container.appendChild(buttonsContainer);

    // Insert above .sidebar-background
    const sidebarBg = document.querySelector('.sidebar-background');
    if (sidebarBg && sidebarBg.parentNode) {
        sidebarBg.parentNode.insertBefore(container, sidebarBg);
    } else {
        console.warn('⚠️ Could not find sidebar');
    }

    // Initialize styleEnabled from localStorage or default to true
    let styleEnabled = localStorage.getItem('styleEnabled') !== null
        ? JSON.parse(localStorage.getItem('styleEnabled'))
        : true;

    const styleSheet = document.createElement('style');
    document.head.appendChild(styleSheet);

    // Set initial button text and stylesheet based on styleEnabled
    toggleBtn.textContent = styleEnabled ? 'Show Empty' : 'Hide Empty';
    styleSheet.textContent = styleEnabled ? `
        .blocklist.subscription-list li:is([class=""]) {
            display: none !important;
        }
    ` : '';

    // Load saved input text from localStorage
    input.value = localStorage.getItem('filterText') || '';
    if (input.value) performFiltering(); // Apply filter if there's saved text

    // Add or remove the CSS to hide empty <li> elements
    function toggleStyle() {
        styleEnabled = !styleEnabled;
        localStorage.setItem('styleEnabled', JSON.stringify(styleEnabled)); // Save to localStorage

        if (styleEnabled) {
            styleSheet.textContent = `
                .blocklist.subscription-list li:is([class=""]) {
                    display: none !important;
                }
            `;
            toggleBtn.textContent = 'Show Empty';
        } else {
            styleSheet.textContent = '';
            toggleBtn.textContent = 'Hide Empty';
        }
    }

    // Function to get all li elements in blocklist
    function getTagItems() {
        return Array.from(document.querySelectorAll('ul.blocklist.subscription-list li'));
    }

    // Perform filtering based on input
    function performFiltering() {
        const term = input.value.toLowerCase().trim();
        localStorage.setItem('filterText', input.value); // Save input text to localStorage
        const items = getTagItems();
        items.forEach(li => {
            const tag = li.querySelector('.tagname');
            if (!tag) return;
            const tagText = tag.textContent.toLowerCase();
            li.style.display = tagText.includes(term) ? '' : 'none';
        });
    }

    // Reset the filter
    function resetFilter() {
        const items = getTagItems();
        items.forEach(li => li.style.display = '');
        input.value = '';
        localStorage.setItem('filterText', ''); // Clear saved input text
    }

    // Add event listeners
    input.addEventListener('input', performFiltering);
    resetBtn.addEventListener('click', resetFilter);
    toggleBtn.addEventListener('click', toggleStyle);
});



//Script 2: Sort Subscriptions By Number

function sortListItems(descending) {
    const container = document.querySelector('[data-storage-id="tagsubscriptions"]');
    if (!container) {
        console.error('Tag subscriptions container not found.');
        return;
    }

    const listItems = Array.from(container.querySelectorAll('.blocklist[class*="subscription-list"] [class*="has-"]'));

    listItems.sort((a, b) => {
        const valueA = parseInt(a.querySelector('small').textContent);
        const valueB = parseInt(b.querySelector('small').textContent);

        return descending ? valueB - valueA : valueA - valueB;
    });

    listItems.forEach((item) => {
        const parent = item.parentNode;
        parent.appendChild(item);
    });
}

function createDropdown(labelText, options, onChange) {
    const dropdown = document.createElement('select');

    options.forEach(option => {
        const optionElement = document.createElement('option');
        optionElement.value = option.value;
        optionElement.text = option.text;
        dropdown.appendChild(optionElement);
    });

    dropdown.addEventListener('change', onChange);

    const label = document.createElement('label');
    label.style.marginRight = '10px';
    label.appendChild(document.createTextNode(labelText + ': '));
    label.appendChild(dropdown);

    return label;
}

function handleSortDropdownChange() {
    if (this.value === 'default') {
        localStorage.removeItem('subscriptionSortOrder');
        location.reload();
        return;
    }

    const descending = this.value === 'desc';
    sortListItems(descending);
    localStorage.setItem('subscriptionSortOrder', descending ? 'desc' : 'asc');
}

function handleDisplayDropdownChange() {
    const existingStyle = document.getElementById('display-filter-style');
    if (existingStyle) {
        existingStyle.remove();
    }

    let css = '';
    switch (this.value) {
        case 'sfw':
            css = `
                [class="has-new "]:has([class="tagname sketchy"]) {display: none!important;}
                [class="has-new "]:has([class="tagname nsfw"]) {display: none!important;}
            `;
            break;
        case 'sketch':
            css = `
                [class="has-new "]:has([class="tagname sfw"]) {display: none!important;}
                [class="has-new "]:has([class="tagname nsfw"]) {display: none!important;}
            `;
            break;
        case 'nsfw':
            css = `
                [class="has-new "]:has([class="tagname sfw"]) {display: none!important;}
                [class="has-new "]:has([class="tagname sketchy"]) {display: none!important;}
            `;
            break;
    }

    if (css) {
        const style = document.createElement('style');
        style.id = 'display-filter-style';
        style.textContent = css;
        document.head.appendChild(style);
    }

    localStorage.setItem('subscriptionDisplayFilter', this.value);
}

function initializeDropdown() {
    const sortDropdownOptions = [
        { value: 'default', text: 'Default' },
        { value: 'desc', text: 'Most to Least' },
        { value: 'asc', text: 'Least To Most' }
    ];

    const displayDropdownOptions = [
        { value: 'all', text: 'All' },
        { value: 'sfw', text: 'Only SFW' },
        { value: 'sketch', text: 'Only Sketch' },
        { value: 'nsfw', text: 'Only NSFW' }
    ];

    const sortDropdown = createDropdown('Sort Order', sortDropdownOptions, handleSortDropdownChange);
    const displayDropdown = createDropdown('Display', displayDropdownOptions, handleDisplayDropdownChange);

    const container = document.createElement('div');
    container.id = 'sort-dropdown-container';
    container.style.padding = '0px 0px 8px 0px';
    container.style.marginBottom = '10px';
    container.style.backgroundColor = '#111111';
    container.style.borderBottom = '1px solid #4a4a4a';
    container.style.fontSize = '12px';
    container.style.display = 'flex';
    container.style.alignItems = 'center';
    container.style.gap = '10px';

    container.appendChild(sortDropdown);
    container.appendChild(displayDropdown);

    const sidebarBackground = document.querySelector('.sidebar-background');
    if (sidebarBackground) {
        sidebarBackground.insertBefore(container, sidebarBackground.firstChild);
    } else {
        console.error('.sidebar-background element not found.');
    }

    const sortOrder = localStorage.getItem('subscriptionSortOrder');
    if (sortOrder === 'desc') {
        sortDropdown.querySelector('select').value = 'desc';
        sortListItems(true);
    } else if (sortOrder === 'asc') {
        sortDropdown.querySelector('select').value = 'asc';
        sortListItems(false);
    }

    const displayFilter = localStorage.getItem('subscriptionDisplayFilter');
    if (displayFilter) {
        displayDropdown.querySelector('select').value = displayFilter;
        handleDisplayDropdownChange.call(displayDropdown.querySelector('select'));
    }
}

initializeDropdown();