Sleazy Fork is available in English.

Koharu Artist URL Collector

Collect URLs from koharu.to artist pages and store them in GM_storage

// ==UserScript==
// @name         Koharu Artist URL Collector
// @namespace    https://koharu.to/
// @version      1.7.1.4
// @description  Collect URLs from koharu.to artist pages and store them in GM_storage
// @license      MIT
// @author       viatana35
// @match        https://hoshino.one/?s=artist*
// @match        https://hoshino.one/?s=circle*
// @match        https://shupogaki.moe/?s=artist*
// @match        https://shupogaki.moe/?s=circle*
// @match        https://niyaniya.moe/?s=artist*
// @match        https://niyaniya.moe/?s=circle*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_download
// ==/UserScript==

(function () {
    'use strict';

    const urlKey = 'koharuUrls';
    const continueKey = 'continue_treatment';
    const artistsLibKey = 'artists_lib';
    let urlList = GM_getValue(urlKey, []);
    let continueTreatment = GM_getValue(continueKey, false);
    let artistsLib = GM_getValue(artistsLibKey, []);

    // Function to process the current page and store English articles
    function processPage() {
        const articles = document.querySelectorAll('article');
        articles.forEach(article => {
            const isEnglish = article.querySelector('a > header > h3 > span > svg[id="flag-icons-gb"]');
            if (isEnglish) {
                const articleUrl = article.querySelector('a').href;
                if (!urlList.includes(articleUrl)) {
                    urlList.push(articleUrl);
                }
            }
        });

        // Save the updated URL list
        GM_setValue(urlKey, urlList);
    }

    // Function to navigate to the next page
    function goToNextPage() {
        const paginationList = document.querySelector('footer nav.pagination ul');
        if (paginationList) {
            const paginationItems = paginationList.children;
            const lastItem = paginationItems[paginationItems.length - 1]; // On prend le dernier élément de la liste

            const nextPageLink = lastItem.querySelector('a');
            if (nextPageLink) {
                const currentPageNumber = parseInt(new URL(window.location.href).searchParams.get('page') || '1', 10);
                const nextPageNumber = parseInt(new URL(nextPageLink.href).searchParams.get('page'), 10);

                if (nextPageNumber === currentPageNumber + 1) {
                    console.log(currentPageNumber, "->", nextPageNumber);
                    GM_setValue(continueKey, true);
                    window.location.href = nextPageLink.href;
                } else {
                    console.log("end of treatment 1");
                    saveArtistData();
                    GM_setValue(continueKey, false); // Pas de page suivante
                }
            } else {
                saveArtistData();
                GM_setValue(continueKey, false); // Pas de lien pour la page suivante
            }
        }
        else
        {
            console.log("end of treatment 2");
            saveArtistData();
            GM_setValue(continueKey, false); // Pas de page suivante
        }
    }

    function treatArtist() {
        // If there is no pagination list, check if the URL contains "&page"
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.has('page')) {
            showPopup("please go to page one to treat artist");
        } else {
            console.log("beginning of the treatment");
            processPage();
            goToNextPage();
        }
    }


    function getArtistName() {
        const urlParams = new URLSearchParams(window.location.search);
        let artistName = null;

        // Check for 's' parameter
        if (urlParams.has('s')) {
            const searchQuery = decodeURIComponent(urlParams.get('s'));
            console.log(searchQuery);
            // Extract the artist or circle name from the search query
            const match = searchQuery.match(/(artist|circle):(?:"(.+)"|\^(.+)\$)/);
            console.log(match);
            if (match && (match[2] || match[3])) {
                artistName = match[2] || match[3];
                // Remove caret and dollar sign characters from the artist name
                artistName = artistName.replace(/[\^$]/g, '');
            }
        }

        return artistName;
    }







    function showPopup(message) {
        const popup = document.createElement('div');
        popup.id = 'popup';
        popup.style.position = 'fixed';
        popup.style.top = '50%';
        popup.style.left = '50%';
        popup.style.transform = 'translate(-50%, -50%)';
        popup.style.backgroundColor = '#f1f1f1';
        popup.style.padding = '20px';
        popup.style.border = '1px solid #ccc';
        popup.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
        popup.style.zIndex = '1001';
        popup.style.textAlign = 'center';
        popup.style.opacity = '0';
        popup.style.transition = 'opacity 0.3s ease-in-out';
        popup.textContent = message;

        document.body.appendChild(popup);

        // Fade in the popup
        setTimeout(() => {
            popup.style.opacity = '1';
        }, 10);

        // Fade out and remove the popup after 5 seconds
        setTimeout(() => {
            popup.style.opacity = '0';
            setTimeout(() => {
                document.body.removeChild(popup);
            }, 300);
        }, 5000);
    }



    // Function to save the current artist's data
    function saveArtistData() {
        const artistName = getArtistName();
        console.log(artistName);
        if (artistName && urlList.length > 0) {
            const artistData = {
                artist: artistName,
                lst_dl: urlList
            };

            artistsLib = GM_getValue(artistsLibKey, []);
            // Add the artist data to the artistsLib
            artistsLib.push(artistData);

            // Save the updated artistsLib
            GM_setValue(artistsLibKey, artistsLib);

            // Clear the URL list for the next artist
            GM_setValue(urlKey, []);
            urlList = [];

            showPopup(`Artist ${artistName} has been processed.`);

            clearButton.disabled = false;

        }
    }

    // Function to handle automatic processing if continue_treatment is true
    function handleAutoProcessing() {
        console.log(continueTreatment);
        if (continueTreatment) {
            processPage();
            goToNextPage();
        }
    }

    // Function to download the artists_lib as a JSON file
    function downloadArtistsLib() {
        const artistsLibData = GM_getValue(artistsLibKey, []);
        const jsonContent = JSON.stringify(artistsLibData, null, 2); // Pretty print JSON with indentation
        const blob = new Blob([jsonContent], { type: 'application/json' });
        const url = URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.href = url;
        a.download = 'artists_lib.json';
        a.click();

        URL.revokeObjectURL(url); // Clean up the URL object
    }

    // Create a container for the buttons
    const buttonContainer = document.createElement('div');
    buttonContainer.style.position = 'sticky';
    buttonContainer.style.top = '0';
    buttonContainer.style.backgroundColor = '#f1f1f1';
    buttonContainer.style.padding = '10px';
    buttonContainer.style.zIndex = 1000;
    buttonContainer.style.display = 'flex';
    buttonContainer.style.justifyContent = 'center';
    buttonContainer.style.alignItems = 'center';
    document.body.prepend(buttonContainer);

    // Create a button to process the artist's pages
    const processButton = document.createElement('button');
    processButton.textContent = 'Traiter l\'artiste';
    processButton.style.margin = '0 10px';
    processButton.style.padding = '10px';
    processButton.style.backgroundColor = '#4CAF50';
    processButton.style.color = 'white';
    processButton.style.border = 'none';
    processButton.style.cursor = 'pointer';
    processButton.onclick = () => {
        GM_setValue(continueKey, true);
        treatArtist();
    };
    buttonContainer.appendChild(processButton);

    // Create a button to clear the list and artists_lib
    const clearButton = document.createElement('button');
    clearButton.textContent = 'Clear list';
    clearButton.style.margin = '0 10px';
    clearButton.style.padding = '10px';
    clearButton.style.backgroundColor = '#f44336';
    clearButton.style.color = 'white';
    clearButton.style.border = 'none';
    clearButton.style.cursor = 'pointer';
    clearButton.disabled = artistsLib.length === 0;
    clearButton.onclick = () => {
        if (confirm('Do you really want to clear the list ?')) {
            GM_deleteValue(urlKey);
            GM_deleteValue(artistsLibKey);
            urlList = [];
            artistsLib = [];
            clearButton.disabled = true;
            showPopup("list cleared");
        }
    };
    buttonContainer.appendChild(clearButton);

    // Create a button to download the artists_lib JSON
    const downloadButton = document.createElement('button');
    downloadButton.textContent = 'Download the list';
    downloadButton.style.margin = '0 10px';
    downloadButton.style.padding = '10px';
    downloadButton.style.backgroundColor = '#2196F3';
    downloadButton.style.color = 'white';
    downloadButton.style.border = 'none';
    downloadButton.style.cursor = 'pointer';
    downloadButton.onclick = downloadArtistsLib;
    buttonContainer.appendChild(downloadButton);

    // Enable the clear button if the list contains elements
    if (artistsLib.length > 0) {
        clearButton.disabled = false;
    }

    // Wait for DOM to fully load before executing handleAutoProcessing
    window.onload = () => {
        handleAutoProcessing();
    };

})();