GC Giveaway Search/Filters

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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