Sleazy Fork is available in English.

coomer-optimizer

Improves coomer.party

// ==UserScript==
// @name         coomer-optimizer
// @namespace    https://coomer.su/
// @version      3.2
// @description  Improves coomer.party
// @match        https://coomer.su/*
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @license      MIT
// @run-at       document-end
// @homepage     https://greasyfork.org/en/scripts/468758-coomer-optimizer
// ==/UserScript==

(function () {
    'use strict';

    GM_addStyle('.card--dislike {border-color: hsl(0, 100%, 50%); border-style: solid; border-width: 2px; }');
    GM_addStyle('.card--nevermet {border-color: hsl(120, 100%, 20%); border-style: solid; border-width: 2px; }');


    /**
     * Extract the summary object from the URL
     */
    const extractSummary = function (url, orUser) {
        let m = url.match(/user\/([^\/]+)/);
        if (m) {
            let userKey = key(m[1]);
            let summary = JSON.parse(localStorage.getItem(userKey));
            if (summary && !summary.user) {
                summary.user = m[1];
            }
            // console.debug('URL: ', url, " --> key: ", userKey, " --> summary: ", summary);
            return summary ? summary : (orUser ? m[1] : summary);
        } else {
            // console.debug('URL: ', url, " --> no user");
            return false;
        }

    }

    const key = function (_usr) {
        return `copt_${_usr}`;
    }

    const getEl = function(_root_el, _tag, _class) {
        let _el;
        if (_root_el.tagName == _tag.toUpperCase() && _root_el.classList.contains(_class)) {
            _el = _root_el;
        } else if (_root_el.querySelector) {
            _el = _root_el.querySelector(`${_tag}.${_class}`);
        }
        return _el;
    }

    const rootOptimizer = function (_root) {
        let userPageURLMatch = window.location.pathname.match(/\/user\/([^/]+)$/);
        let userPostsPageURLMatch = window.location.pathname.match(/\/user\/([^/]+)\/post/);
        let artistsPageURLMatch = window.location.pathname.match(/\/artists/);
        let postsPageURLMatch = window.location.pathname.match(/\/posts/);

        //user page
        if (userPageURLMatch || userPostsPageURLMatch) {
            let pageUser = false;
            let userPageCSSPrefix = false;
            if (userPageURLMatch) {
                pageUser = userPageURLMatch[1];
                userPageCSSPrefix = 'user-header';
            } else if (userPostsPageURLMatch) {
                pageUser = userPostsPageURLMatch[1];
                userPageCSSPrefix = 'post';
            }
            console.debug(`User page detected for ${pageUser}`);

            //adding styles
            GM_addStyle('span.user-header__dislike-icon::before { content: "\uD83D\uDC4E"; }');

            let pageUserKey = key(pageUser);

            let today = new Date().toISOString().split('T')[0]; // Get the current date in ISO format

            //load or create the summary data for the user
            let summary = localStorage.getItem(pageUserKey);
            //If no summary data, we create it
            if (!summary) {
                summary = {
                    user: pageUser,
                    visits: 1,
                    previousVisit: false,
                    lastVisit: today,
                    disliked: false
                };
            } else {
                summary = JSON.parse(summary);
            }

            //Increment the number of visits if the page has been visited not today
            if (summary.lastVisit !== today) {
                summary.visits += 1;
                summary.previousVisit = summary.lastVisit;
                summary.lastVisit = today;
                if (!summary.user) {
                    summary.user = pageUser;
                }
            }

            //Store the summary
            console.debug(`User ${pageUser}:`, summary);
            localStorage.setItem(pageUserKey, JSON.stringify(summary));

            //header optimization ====================================================

            //summary text
            let summaryElement = document.createElement('span');
            if (summary.previousVisit) {
                summaryElement.textContent = `- Visited ${summary.visits} times, last visit on ${summary.previousVisit}`;
            } else {
                summaryElement.textContent = `- First time visit`;
            }

            // dislike button
            let dislikeButton = document.createElement('button');
            dislikeButton.type = 'button';
            dislikeButton.className = `${userPageCSSPrefix}__favourite`;

            let iconElement = document.createElement('span');
            iconElement.className = `${userPageCSSPrefix}__fav-icon`
            iconElement.textContent = summary.disliked ? '👍🏻' : '👎';
            dislikeButton.appendChild(iconElement);

            let textElement = document.createElement('span');
            textElement.className = `${userPageCSSPrefix}__fav-text`;
            textElement.textContent = summary.disliked ? 'Un-dislike' : 'Dislike';
            dislikeButton.appendChild(textElement);
            dislikeButton.addEventListener('click', () => {
                summary.disliked = !summary.disliked;
                localStorage.setItem(pageUserKey, JSON.stringify(summary));
                iconElement.textContent = summary.disliked ? '👍🏻' : '👎';
                textElement.textContent = summary.disliked ? 'Un-dislike' : 'Dislike';
            });

            let _summary_element, _parent_cssClass;
            if (userPageURLMatch) {
                _summary_element = document.createElement('div');
                _summary_element.appendChild(summaryElement);
                _parent_cssClass = `${userPageCSSPrefix}__info`
            } else {
                _summary_element = summaryElement;
                _parent_cssClass = `${userPageCSSPrefix}__published`
            }

            //header
            let _pardiv = getEl(_root, 'div', _parent_cssClass);
            if (_pardiv) {
                _pardiv.appendChild(_summary_element);
            }

            //actions
            let _actdiv = getEl(_root, 'div', `${userPageCSSPrefix}__actions`);
            if (_actdiv) {
                _actdiv.appendChild(dislikeButton);
            }

            // footer optimization ======================================================================

            // bottom header repeater
            let navMenu = getEl(_root, 'nav', 'post__nav-links');
            let commentSection = getEl(_root, 'footer', 'post__footer');

            if (navMenu && commentSection) {
                commentSection.appendChild(navMenu.cloneNode(true));
            }

            // user post page
            if (userPostsPageURLMatch
                && (_root.querySelectorAll || _root.tagName == 'H2')) {
                // var headers = _root.getElementsByTagName('h2');
                var headers = _root.tagName == 'H2' ? [_root] : _root.querySelectorAll('h2');
                for (var i = 0; i < headers.length; i++) {
                    if (headers[i].innerHTML == 'Downloads') {
                        let copyDownloadsButton = document.createElement('button');
                        copyDownloadsButton.type = 'button';
                        copyDownloadsButton.className = `${userPageCSSPrefix}__favourite`;

                        let textElement = document.createElement('span');
                        textElement.className = `${userPageCSSPrefix}__fav-text`;
                        textElement.textContent = 'Copy';
                        copyDownloadsButton.appendChild(textElement);
                        copyDownloadsButton.addEventListener('click', () => {
                            var attachemnts = '';
                            var c = 0;
                            document.querySelectorAll('a.post__attachment-link').forEach(l => {
                                attachemnts += l.href + '\n';
                                c++;
                            });
                            GM_setClipboard(attachemnts);
                            console.log('copied (', c, ')');
                        });

                        headers[i].appendChild(copyDownloadsButton);
                    }
                }
            }

        } else if (/* artist pages */ artistsPageURLMatch) {
            console.debug('Artist list page detected');

            let enrichUserCard = function (c) {
                let summary = extractSummary(c.href);
                if (summary) {
                    c.className += ' co-parsed';

                    let serviceLabel = c.querySelector('span.user-card__service');
                    let visitedLabel = serviceLabel.cloneNode(true);
                    visitedLabel.textContent = `# ${summary.visits}`;
                    visitedLabel.style.marginLeft = '4px';
                    visitedLabel.style.backgroundColor = 'rgb(240, 140, 207)';
                    serviceLabel.insertAdjacentElement('afterend', visitedLabel);

                    if (summary.previousVisit) {
                        let daysAfterLabel = visitedLabel.cloneNode(true);
                        let daysFromLastVisit = Math.floor((new Date() - new Date(summary.previousVisit)) / (1000 * 60 * 60 * 24));
                        daysAfterLabel.textContent = `📅 ${daysFromLastVisit}`
                        daysAfterLabel.title = `Last visit on ${summary.previousVisit}`;
                        visitedLabel.insertAdjacentElement('afterend', daysAfterLabel);
                    }

                    if (summary.disliked) {
                        c.className += ' card--dislike';
                    }
                } else {
                    c.className += ' card--nevermet';
                }
            }

            if (_root.tagName == 'A' && _root.classList.contains('user-card')) {
                enrichUserCard(_root);
            } else if (_root.querySelectorAll) {
                _root.querySelectorAll('a.user-card').forEach(card => {
                    enrichUserCard(card);
                });
            }
        } else if (/*post list pages */ postsPageURLMatch) {
            console.debug('Post list page detected');

            let enrichCard = function(card) {
                let summary = extractSummary(card.querySelector('a').href, true);
                console.debug(summary);
                if (summary) {
                    card.className += ' co-parsed';

                    //if there is a summary
                    if (summary.user) {
                        console.debug('sum', summary);
                        //replace attachment number with username
                        card.querySelector('footer > div').textContent = `${summary.user} (${summary.visits})`;

                        if (summary.disliked) {
                            card.className += ' card--dislike';
                        }
                    } else {
                        card.querySelector('footer > div').textContent = summary;
                        card.className += ' card--nevermet';
                    }
                }
            }

            if (_root.tagName == 'ARTICLE' && _root.classList.contains('post-card')) {
                enrichCard(_root);
            } else if (_root.querySelectorAll) {
                _root.querySelectorAll('article.post-card').forEach(card => {
                    enrichCard(card);
                })
            }

        }

    }

    // Create a MutationObserver to watch for changes in the DOM
    var observer = new MutationObserver(function (mutationsList, observer) {
        for (const mutation of mutationsList) {

            if (mutation.type === 'childList'
                && mutation.target
                && mutation.addedNodes.length > 0) {

                let _root = mutation.addedNodes[0];
                rootOptimizer(_root);
            }
        }
    });


    // Define the options for the observer
    const observerOptions = {
        childList: true,
        subtree: true
    };

    // Start observing the document body for changes
    observer.observe(document.body, observerOptions);

})();