Greasy Fork 支持简体中文。

GC Giveaway Search/Filters

Adds search bar and pre-made filters, including full relic list. Adds checkbox to hide entered giveaways. Persists through reload

// ==UserScript==
// @name         GC Giveaway Search/Filters
// @version      1.2
// @description  Adds search bar and pre-made filters, including full relic list. Adds checkbox to hide entered giveaways. Persists through reload
// @author       spiderpool1855
// @match        https://www.grundos.cafe/giveaways/
// @license      MIT
// @grant        none
// @namespace https://greasyfork.org/users/1295622
// ==/UserScript==


(function() {
    'use strict';

    let page = 2;  // Start from the first page
    let loading = false;
    
    // Function to disable the page's loadMoreItems function
    function disablePageLoader() {
        if (window.loadMoreItems) {
            console.log('Disabling the page\'s loadMoreItems function.');
            window.loadMoreItems = function() {
                console.log('loadMoreItems function has been disabled.');
            };
        } else {
            console.log('loadMoreItems function not found.');
        }
    }

    function loadAllItems() {
        if (loading) return;  // Prevent overlapping fetches
        loading = true;

        const url = `/giveaways/?page=${page}&active=true`;

        fetch(url, {
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                }
            })
            .then(response => response.json())
            .then(data => {
                const container = document.querySelector('.giveaway-grid-container');
                const initialItemCount = container.children.length;

                container.insertAdjacentHTML('beforeend', data.items_html);

                const newItemCount = container.children.length;

                if (newItemCount > initialItemCount) {
                    // Continue loading items
                    if (data.has_next) {
                        page += 1;
                        setTimeout(loadAllItems, 100);  // Delay before loading the next page
                    } else {
                        console.log('All items have been loaded.');
                        disablePageLoader();  // Disable further loading after the last page
                    }
                } else {
                    console.log('No new items found, stopping.');
                    disablePageLoader();  // Disable further loading if no new items found
                }
            })
            .catch(error => {
                console.error('Error loading more items:', error);
            })
            .finally(() => {
                loading = false;  // Allow the next load to proceed
            });
    }

    // Start loading all items from the first page
    loadAllItems();

})();



(function() {
    'use strict';

    // Pre-made queries - You can add more here and it will add checkboxes for them
    const queries = ['Paint', 'Potion', 'Stamp', 'Map', 'Negg'];

    // Relic query list
    const relicList = ["Air Faerie Crown" , "Air Faerie Token" , "Ancient Lupe Wand" , "Aquatic Gem" , "Army Math Tools" , "Attack Cape" , "Attack Fork" , "Bag of Occult Jelly" , "Battle Plunger" , "Battle Quill" , "Bit of Evil Clown" , "Blizzard Ring" , "Blood Grub" , "Boom Sticks" , "Brain Tree Branch" , "Brain Tree Knife" , "Brain Tree Mace" , "Brain Tree Root" , "Brain Tree Splinters" , "Cabbage of Mystery" , "Candy Club" , "Castle Defenders Shield" , "Castle Defenders Sword" , "Caustic Potion" , "Charles' Torch" , "Cobrall Wand" , "Dark Faerie Dagger" , "Dark Faerie Token" , "Donny's Mallet" , "Earth Faerie Dagger" , "Earth Faerie Token" , "Earth Stone Gem" , "Elephante Lamp" , "Eraser of the Dark Faerie" , "Exploding Space Bugs" , "Faerie Eraser" , "Fat Red Pen" , "Fire Faerie Token" , "Fire Stone Gem" , "Frostbite Dart" , "Fumpu Leaf Medallion" , "Garin's Sword" , "Genie Orb" , "Ghost Lupe Sword" , "Golden Aisha Wand" , "Golden Meepit Statue" , "Golden Pirate Amulet" , "Good Snowball" , "Grarrg Tooth" , "Great Snowball" , "Grundo Gavel" , "Halloween Aisha Bucket" , "Happy Anniversary Negg" , "Happy Negg Eraser" , "Hawk Bracelet" , "Hawk Wand" , "Iced Wand" , "Iceray Bracelet" , "Irregulation Chainmail" , "Jar of Spiders" , "King Kelpbeards Blessing" , "Lava Rock" , "Legendary von Roo Ring" , "Light Faerie Dagger" , "Light Faerie Token" , "Magic Branch" , "Magnus Club" , "Malice Potion" , "Melting Mirror" , "Monotonous Dial" , "Mystical Fish Lobber" , "Mystic Guitar" , "Mystic Jelly Bean Necklace" , "Neutron Wand" , "Nimmo Finger" , "Official Prissy Miss Hair Brush" , "Patched Magic Hat" , "Pear of Disintegration" , "Petpet Bone" , "Platinum Dubloon" , "Poké Ball" , "Power Negg Eraser" , "Pumpkin Stick" , "Radish Bow" , "Rainbow Cybunny Wand" , "Rainbow Kacheek Pendant" , "Rainbow Negg Eraser" , "Rainbow Pteri Feather" , "Reinvented Wheel" , "Ring of the Lost" , "Robo Sloth Fist of Power" , "Royal Wedding Ring" , "Rusty Garden Pitchfork" , "Rutabaga Lance" , "Scarab Amulet" , "Scroll of Ultimate Knowledge" , "Snowager Pendant" , "Snowager Sleep Ray" , "Snow Beast Horn" , "Snowflake Pendant" , "Snowglobe Staff" , "Soul Stone" , "Space Amulet" , "Space Faeries Shield" , "Space Faerie Token" , "Spider Grundo Sword" , "Spirited Fiddle" , "Spooky Slime" , "Squash Club" , "Staff of Brain" , "Starry Scorchio Wand" , "Superior Battle Plunger" , "Trident of Chiazilla" , "Trusty Hand Cannon" , "Tyrannian Amulet" , "Ultra Fire Gem" , "Wand of the Snow Faerie" , "Water Faerie Dagger" , "Water Faerie Token" , "Wind Up Rat" , "Witches Orb" , "Wooden Compass" , "Zucchini Bat"];

    // Create the filter div
    const filterContainer = document.createElement('div');
    filterContainer.style.margin = '20px 0';

    // Creates searchbar
    const searchBar = document.createElement('input');
    searchBar.setAttribute('type', 'text');
    searchBar.setAttribute('placeholder', 'Search giveaways...');
    searchBar.style.marginRight = '10px';
    searchBar.style.width = '25%';

    // Load previous search from localstorage
    searchBar.value = localStorage.getItem('searchQuery') || '';

    // Save current query to local storage and initiates filter
    searchBar.addEventListener('input', () => {
        localStorage.setItem('searchQuery', searchBar.value);
        filterGiveaways();
    });

    filterContainer.appendChild(searchBar);

    // Create the "Open" checkbox - Open means that it hides "Entered" giveaways
    const hideEnteredCheckbox = document.createElement('input');
    hideEnteredCheckbox.setAttribute('type', 'checkbox');
    hideEnteredCheckbox.setAttribute('id', 'hideEntered');
    hideEnteredCheckbox.checked = JSON.parse(localStorage.getItem('hideEntered')) || false;

    const hideEnteredLabel = document.createElement('label');
    hideEnteredLabel.setAttribute('for', 'hideEntered');
    hideEnteredLabel.textContent = 'Open';

    filterContainer.appendChild(hideEnteredCheckbox);
    filterContainer.appendChild(hideEnteredLabel);

    // Save "Open" checkbox status to local storage
    hideEnteredCheckbox.addEventListener('change', () => {
        localStorage.setItem('hideEntered', hideEnteredCheckbox.checked);
        filterGiveaways();
    });

    // Create checkboxes for pre-made queries
    queries.forEach(query => {
        const checkbox = document.createElement('input');
        checkbox.setAttribute('type', 'checkbox');
        checkbox.setAttribute('id', `filter${query.replace(/\s+/g, '')}`);
        checkbox.checked = JSON.parse(localStorage.getItem(`filter${query.replace(/\s+/g, '')}`)) || false;

        const label = document.createElement('label');
        label.setAttribute('for', `filter${query.replace(/\s+/g, '')}`);
        label.textContent = query;

        filterContainer.appendChild(checkbox);
        filterContainer.appendChild(label);

        // Save pre-made query checkbox statuses to local storage
        checkbox.addEventListener('change', () => {
            localStorage.setItem(`filter${query.replace(/\s+/g, '')}`, checkbox.checked);
            filterGiveaways();
        });
    });

    // Create the "Relic" checkbox
    const relicCheckbox = document.createElement('input');
    relicCheckbox.setAttribute('type', 'checkbox');
    relicCheckbox.setAttribute('id', 'filterRelic');
    relicCheckbox.checked = JSON.parse(localStorage.getItem('filterRelic')) || false;

    const relicLabel = document.createElement('label');
    relicLabel.setAttribute('for', 'filterRelic');
    relicLabel.textContent = 'Relic';

    filterContainer.appendChild(relicCheckbox);
    filterContainer.appendChild(relicLabel);

    // Save "Relic" checkbox status to local storage
    relicCheckbox.addEventListener('change', () => {
        localStorage.setItem('filterRelic', relicCheckbox.checked);
        filterGiveaways();
    });



    // Insert the filter container
    const parentElement = document.querySelector('.giveaway-grid-container').parentNode;
    parentElement.insertBefore(filterContainer, document.querySelector('.giveaway-grid-container'));

    // Filter function
    searchBar.addEventListener('input', filterGiveaways);

    function filterGiveaways() {
        const query = searchBar.value.toLowerCase();
        const hideEntered = hideEnteredCheckbox.checked;
        const relicCheckboxChecked = relicCheckbox.checked;

        document.querySelectorAll('.giveaway-item').forEach(item => {
            let text = item.querySelector('h3')?.textContent.toLowerCase() || '';
            const status = item.querySelector('p.state')?.textContent.toLowerCase() || '';

            let showItem = true;

            // Filter by "Open" checkbox
            if (hideEntered && status.includes('entered')) {
                showItem = false;
            }

            // Filter by pre-made queries
            if (queries.some(query => {
                const checkbox = document.getElementById(`filter${query.replace(/\s+/g, '')}`);
                return checkbox.checked && !text.includes(query.toLowerCase());
            })) {
                showItem = false;
            }

            // Filter by "Relic" checkbox
            const relicMatches = relicList.some(relic => text.includes(relic.toLowerCase()));
            if (relicCheckboxChecked && !relicMatches) {
                showItem = false;
            }

            // Filter by search query
            if (query && !text.includes(query)) {
                showItem = false;
            }

            // Show all items if no filters are checked
            const anyCheckboxChecked = queries.some(q => document.getElementById(`filter${q.replace(/\s+/g, '')}`).checked) || relicCheckboxChecked || hideEntered;
            if (!anyCheckboxChecked && !query) {
                showItem = true;
            }

            item.style.display = showItem ? '' : 'none';
        });
    }

    // Initial filter on page load
    filterGiveaways();
})();