Filelist.io Size Filter

Add sliders and dropdown menus to filter filelist.io results by size

// ==UserScript==
// @name         Filelist.io Size Filter
// @version      0.2
// @description  Add sliders and dropdown menus to filter filelist.io results by size
// @author       konvar
// @match        https://filelist.io/browse.php*
// @grant        none
// @namespace https://greasyfork.org/users/1228860
// ==/UserScript==

(function () {
    'use strict';

    // Your existing HTML block
    const existingForm = document.querySelector('table tbody tr td form');

    // Create a div to hold sliders and dropdown menus
    const filterContainer = document.createElement('div');
    filterContainer.style.display = 'flex';
    filterContainer.style.justifyContent = 'center';
    filterContainer.style.alignItems = 'center';
    filterContainer.style.flexWrap = 'wrap'; // Allow flex items to wrap
    filterContainer.style.marginTop = '10px'; // Adjust the top margin
    filterContainer.style.marginBottom = '10px'; // Adjust the bottom margin

    // Create dropdown menus for minimum and maximum size
    const minSizeDropdown = createDropdown('Min Size:', 'minSizeDropdown', ['KB', 'MB', 'GB', 'TB']);
    const maxSizeDropdown = createDropdown('Max Size:', 'maxSizeDropdown', ['KB', 'MB', 'GB', 'TB']);

    // Set default values for dropdowns if not present in localStorage
    minSizeDropdown.value = localStorage.getItem('minSizeDropdown') || 'KB';
    maxSizeDropdown.value = localStorage.getItem('maxSizeDropdown') || 'TB';

    // Create sliders for minimum and maximum size
    const minSizeSlider = createSlider('Min Size:', 'minSizeSlider', 0, 999);
    const maxSizeSlider = createSlider('Max Size:', 'maxSizeSlider', 0, 999);

    // Append the div containing sliders and dropdown menus after the existing form
    existingForm.appendChild(filterContainer);

    // Function to create sliders
    function createSlider(labelText, sliderId, minValue, maxValue) {
        const sliderContainer = document.createElement('div');
        sliderContainer.style.display = 'flex';
        sliderContainer.style.flexDirection = 'row'; // Display label, slider, and value in a row
        sliderContainer.style.alignItems = 'center';
        sliderContainer.style.margin = '0 10px';

        const label = document.createElement('label');
        label.textContent = labelText;
        label.style.marginRight = '5px'; // Adjust margin for spacing
        sliderContainer.appendChild(label);

        const slider = document.createElement('input');
        slider.type = 'range';
        slider.id = sliderId;
        slider.min = minValue;
        slider.max = maxValue;
        slider.value = minValue;

        // Retrieve saved value from localStorage
        const savedValue = localStorage.getItem(sliderId);
        if (savedValue !== null) {
            slider.value = savedValue;
        }

        sliderContainer.appendChild(slider);

        // Display current value
        const valueSpan = document.createElement('span');
        valueSpan.id = sliderId + 'Value';
        valueSpan.textContent = `${parseFloat(slider.value).toFixed(2)} ${sliderId.includes('min') ? minSizeDropdown.value : maxSizeDropdown.value}`;
        valueSpan.style.marginLeft = '5px'; // Adjust margin for spacing
        sliderContainer.appendChild(valueSpan);

        // Add event listener to update the displayed value and save to localStorage
        slider.addEventListener('input', function () {
            const unit = sliderId.includes('min') ? minSizeDropdown.value : maxSizeDropdown.value;
            valueSpan.textContent = `${parseFloat(slider.value).toFixed(2)} ${unit}`;
            localStorage.setItem(sliderId, slider.value);

            // Call the function to filter results based on size
            filterTorrentResults(
                parseFloat(minSizeSlider.value),
                parseFloat(maxSizeSlider.value),
                minSizeDropdown.value,
                maxSizeDropdown.value
            );
        });

        // Append slider to the common div
        filterContainer.appendChild(sliderContainer);

        return slider;
    }

    // Function to create dropdown menus
    function createDropdown(labelText, dropdownId, options) {
        const dropdownContainer = document.createElement('div');
        dropdownContainer.style.display = 'flex';
        dropdownContainer.style.flexDirection = 'row'; // Display label, dropdown in a row
        dropdownContainer.style.alignItems = 'center';
        dropdownContainer.style.margin = '0 10px';

        const label = document.createElement('label');
        label.textContent = labelText;
        label.style.marginRight = '5px'; // Adjust margin for spacing
        dropdownContainer.appendChild(label);

        const dropdown = document.createElement('select');
        dropdown.id = dropdownId;

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

        // Retrieve saved value from localStorage
        const savedValue = localStorage.getItem(dropdownId);
        if (savedValue !== null) {
            dropdown.value = savedValue;
        }

        dropdownContainer.appendChild(dropdown);

        // Add event listener to update the displayed value and save to localStorage
        dropdown.addEventListener('change', function () {
            localStorage.setItem(dropdownId, dropdown.value);
            // Call the function to filter results based on size
            filterTorrentResults(
                parseFloat(minSizeSlider.value),
                parseFloat(maxSizeSlider.value),
                minSizeDropdown.value,
                maxSizeDropdown.value
            );
        });

        // Append dropdown to the common div
        filterContainer.appendChild(dropdownContainer);

        return dropdown;
    }

    // Add event listeners to dropdown menus
    minSizeDropdown.addEventListener('change', updateUnitAndFilter);
    maxSizeDropdown.addEventListener('change', updateUnitAndFilter);

    // Function to update the displayed filter values and unit
    function updateUnitAndFilter() {
        const minSizeUnit = minSizeDropdown.value;
        const maxSizeUnit = maxSizeDropdown.value;

        // Ensure that the minimum unit is smaller than or equal to the maximum unit
        if (minSizeDropdown.selectedIndex > maxSizeDropdown.selectedIndex) {
            // Swap the values if the order is incorrect
            const temp = minSizeDropdown.value;
            minSizeDropdown.value = maxSizeDropdown.value;
            maxSizeDropdown.value = temp;
        }

        // Update the displayed unit for the sliders
        document.getElementById('minSizeSliderValue').textContent = `${parseFloat(minSizeSlider.value).toFixed(2)} ${minSizeDropdown.value}`;
        document.getElementById('maxSizeSliderValue').textContent = `${parseFloat(maxSizeSlider.value).toFixed(2)} ${maxSizeDropdown.value}`;

        // Save the selected units to localStorage
        localStorage.setItem('minSizeDropdown', minSizeDropdown.value);
        localStorage.setItem('maxSizeDropdown', maxSizeDropdown.value);

        // Call the function to filter results based on size
        filterTorrentResults(
            parseFloat(minSizeSlider.value),
            parseFloat(maxSizeSlider.value),
            minSizeUnit,
            maxSizeUnit
        );
    }

   // Add event listener to update the displayed value and save to localStorage for minSizeSlider
    minSizeSlider.addEventListener('input', function () {
    const unit = minSizeDropdown.value;
    const maxValue = parseFloat(maxSizeSlider.value);

    // Update the displayed value
    const valueSpan = document.getElementById('minSizeSliderValue');
    valueSpan.textContent = `${parseFloat(minSizeSlider.value).toFixed(2)} ${unit}`;

    // Save to localStorage
    localStorage.setItem('minSizeSlider', minSizeSlider.value);

    // Check if the new minimum value is greater than the current maximum value
    if (parseFloat(minSizeSlider.value) > maxValue && minSizeDropdown.value === maxSizeDropdown.value) {
        // If yes, update the maximum slider to the new minimum value
        maxSizeSlider.value = minSizeSlider.value;
        // Update the displayed value for the maximum slider
        document.getElementById('maxSizeSliderValue').textContent = `${parseFloat(maxSizeSlider.value).toFixed(2)} ${unit}`;
        // Save to localStorage
        localStorage.setItem('maxSizeSlider', maxSizeSlider.value);
    }

    // Call the function to filter results based on size
    filterTorrentResults(
        parseFloat(minSizeSlider.value),
        parseFloat(maxSizeSlider.value),
        minSizeDropdown.value,
        maxSizeDropdown.value
    );
});


    // Function to update the displayed filter values
    function updateFilter() {
        const minSize = parseFloat(minSizeSlider.value);
        const maxSize = parseFloat(maxSizeSlider.value);

        // Update the displayed unit for the sliders
        document.getElementById('minSizeSliderValue').textContent = `${minSize.toFixed(2)} ${minSizeDropdown.value}`;
        document.getElementById('maxSizeSliderValue').textContent = `${maxSize.toFixed(2)} ${maxSizeDropdown.value}`;

        // Call the function to filter results based on size
        filterTorrentResults(minSize, maxSize, minSizeDropdown.value, maxSizeDropdown.value);
    }

    // Initial setup to set the correct unit for the sliders
    minSizeDropdown.value = localStorage.getItem('minSizeDropdown') || 'KB';
    maxSizeDropdown.value = localStorage.getItem('maxSizeDropdown') || 'KB';
    updateUnitAndFilter(); // Call the function to set the correct unit initially

    // Function to filter torrent results based on size
    function filterTorrentResults(minSize, maxSize, minSizeUnit, maxSizeUnit) {
        const torrentRows = document.querySelectorAll('.torrentrow');
        torrentRows.forEach((row) => {
            const sizeElement = row.querySelector('.torrenttable:nth-child(7) font.small');
            if (sizeElement) {
                const sizeText = sizeElement.textContent.trim(); // Extract size value
                const size = parseSize(sizeText, minSizeUnit);
                const sizeInMaxUnit = convertSize(size, minSizeUnit, maxSizeUnit);

                // Check if the size is greater than or equal to the min size slider
                // and less than or equal to the max size slider
                row.style.display = size >= minSize && sizeInMaxUnit <= maxSize ? '' : 'none';
            }
        });
    }

    // Function to parse sizes and convert them to the selected unit
    function parseSize(sizeText, sizeUnit) {
        const match = sizeText.match(/([\d.]+)\s*([KMGTP]B)/i);
        if (match) {
            const value = parseFloat(match[1]);
            const unit = match[2].toUpperCase();

            return convertSize(value, unit, sizeUnit);
        }
        return 0; // Default to 0 for unrecognized units
    }

    // Function to convert sizes to the selected unit
    function convertSize(value, fromUnit, toUnit) {
        const units = { KB: 1, MB: 1024, GB: 1024 * 1024, TB: 1024 * 1024 * 1024 };

        if (fromUnit in units && toUnit in units) {
            return (value * units[fromUnit]) / units[toUnit];
        }

        return value; // Default to the original value if units are not recognized
    }

    // Watch for changes in the content using MutationObserver
    const observer = new MutationObserver(() => {
        // Reapply filtering when the content changes
        filterTorrentResults(
            parseFloat(minSizeSlider.value),
            parseFloat(maxSizeSlider.value),
            minSizeDropdown.value,
            maxSizeDropdown.value
        );
    });

    // Configure and start the observer
    const config = { childList: true, subtree: true };
    observer.observe(document.body, config);
})();