GC Giveaway Search/Filters

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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();
})();