Multi-Platform Search Buttons for DLsite

Adds a compact, open-by-default dropdown menu for search buttons on DLsite pages, with grouped buttons for gaming forums, correct favicons, and a design that matches DLsite's aesthetic.

Verze ze dne 13. 05. 2025. Zobrazit nejnovější verzi.

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Multi-Platform Search Buttons for DLsite
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Adds a compact, open-by-default dropdown menu for search buttons on DLsite pages, with grouped buttons for gaming forums, correct favicons, and a design that matches DLsite's aesthetic.
// @author       FunkyJustin
// @match        https://www.dlsite.com/maniax/work/=/product_id/*
// @match        https://www.dlsite.com/pro/work/=/product_id/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Inject CSS styles
    const style = document.createElement('style');
    style.innerHTML = `
        :root {
            --button-bg-start: #D6BCFA; /* Light purple */
            --button-bg-end: #FBB6CE; /* Soft pink */
            --button-text: #f5f5f5; /* Off-white for better contrast */
            --button-shadow: rgba(0, 0, 0, 0.1);
            --button-border: #B794F4; /* Softer border color */
            --dropdown-bg: #f9f9f9;
        }
        .search-btn {
            display: inline-flex;
            align-items: center;
            padding: 4px 8px;
            margin: 2px;
            background: linear-gradient(45deg, var(--button-bg-start), var(--button-bg-end));
            color: var(--button-text);
            text-decoration: none;
            border-radius: 12px;
            border: 1px solid var(--button-border);
            box-shadow: 0 2px 4px var(--button-shadow);
            font-family: Arial, sans-serif;
            font-size: 15px;
            font-weight: bold;
            transition: box-shadow 0.2s, opacity 0.3s;
        }
        .search-btn:hover {
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
            opacity: 0.95;
        }
        .search-btn img {
            width: 18px;
            height: 18px;
            margin-right: 6px;
        }
        .circle-btn-wrapper .search-btn {
            padding: 3px 6px; /* Smaller padding for circle buttons */
            font-size: 14px; /* Smaller font size for circle buttons */
        }
        .dropdown-container {
            max-width: 600px; /* Limit width to align left */
            margin-top: 10px;
            margin-bottom: 20px;
        }
        .dropdown-toggle {
            display: flex;
            align-items: center;
            padding: 5px 10px;
            background-color: #E91E63; /* Matches DLsite's pink */
            color: #fff;
            border: none;
            border-radius: 12px;
            font-family: Arial, sans-serif;
            font-size: 14px;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        .dropdown-toggle:hover {
            background-color: #C2185B;
        }
        .dropdown-toggle::after {
            content: '▼';
            margin-left: 5px;
            transition: transform 0.2s;
        }
        .dropdown-toggle.collapsed::after {
            transform: rotate(180deg);
        }
        .dropdown-content {
            display: block; /* Open by default */
            background-color: var(--dropdown-bg);
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            padding: 10px;
            margin-top: 5px;
        }
        .dropdown-content.hidden {
            display: none;
        }
        .button-group {
            margin-bottom: 8px;
        }
        .group-label {
            font-family: Arial, sans-serif;
            font-size: 14px;
            font-weight: bold;
            color: #333;
            margin-bottom: 5px;
        }
        .button-group-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(100px, auto));
            gap: 5px;
        }
        .circle-btn-wrapper {
            display: inline-flex;
            flex-wrap: wrap; /* Allow wrapping to prevent stretching */
            align-items: center;
            margin-left: 10px;
            margin-bottom: 15px;
            margin-right: 5px; /* Small margin to prevent overlap */
            max-width: fit-content; /* Prevent stretching and empty space */
        }
    `;
    document.head.appendChild(style);

    // Icon URLs for each website
    const icons = {
        f95zone: 'https://f95zone.to/favicon.ico',
        ryuugames: 'https://www.ryuugames.com/wp-content/uploads/2020/05/cropped-ryuugames_logo-1-32x32.png',
        otomi: 'https://otomi-games.com/favicon.ico'
    };

    // Function to create a styled button
    function createButton(text, url, iconUrl) {
        const a = document.createElement('a');
        a.className = 'search-btn';
        a.href = url;
        a.target = '_blank';
        a.title = text; // Tooltip
        if (iconUrl) {
            const img = document.createElement('img');
            img.src = iconUrl;
            img.alt = '';
            a.appendChild(img);
        }
        a.appendChild(document.createTextNode(text));
        return a;
    }

    // Main function to add buttons
    function addSearchButtons() {
        // Extract game/circle info
        const gameTitleEl = document.querySelector('h1#work_name');
        const circleNameEl = document.querySelector('span[itemprop="brand"] a');
        if (!gameTitleEl || !circleNameEl) {
            console.warn('Required elements not found.');
            return;
        }

        const gameTitle = gameTitleEl.innerText.trim();
        const circleName = circleNameEl.innerText.trim();
        const productIdMatch = window.location.href.match(/product_id\/([^\/]+)/);
        const productId = productIdMatch ? productIdMatch[1].replace('.html', '') : '';

        // Define search URLs
        const urls = {
            f95zoneGame: `https://f95zone.to/sam/latest_alpha/#/cat=games/page=1/search=${encodeURIComponent(gameTitle)}`,
            f95zoneForum: `https://f95zone.to/search/?q=${encodeURIComponent(gameTitle)}&t=post&c[child_nodes]=1&c[nodes][0]=2&c[title_only]=1&o=relevance`,
            f95zonePID: `https://f95zone.to/search/?q=${encodeURIComponent(productId)}`,
            f95zoneCircle: `https://f95zone.to/sam/latest_alpha/#/cat=games/page=1/creator=${encodeURIComponent(circleName)}`,
            otomiGame: `https://otomi-games.com/?s=${encodeURIComponent(gameTitle)}`,
            otomiPID: `https://otomi-games.com/?s=${encodeURIComponent(productId)}`,
            otomiCircle: `https://otomi-games.com/?s=${encodeURIComponent(circleName)}`,
            ryuuGame: `https://www.ryuugames.com/?s=${encodeURIComponent(gameTitle)}`,
            ryuuPID: `https://www.ryuugames.com/?s=${encodeURIComponent(productId)}`,
            ryuuCircle: `https://www.ryuugames.com/?s=${encodeURIComponent(circleName)}`
        };

        // Create buttons with correct icons
        const buttons = {
            f95Game: createButton('Search on F95Zone', urls.f95zoneGame, icons.f95zone),
            f95Forum: createButton('Search on F95Zone Forums', urls.f95zoneForum, icons.f95zone),
            f95PID: createButton('Search Product ID on F95Zone', urls.f95zonePID, icons.f95zone),
            otomiGame: createButton('Search on OtomiGames', urls.otomiGame, icons.otomi),
            otomiPID: createButton('Search Product ID on OtomiGames', urls.otomiPID, icons.otomi),
            otomiCircle: createButton('Search Circle on OtomiGames', urls.otomiCircle, icons.otomi),
            ryuuGame: createButton('Search on Ryuugames', urls.ryuuGame, icons.ryuugames),
            ryuuPID: createButton('Search Product ID on Ryuugames', urls.ryuuPID, icons.ryuugames),
            f95Circle: createButton('Search Circle on F95Zone', urls.f95zoneCircle, icons.f95zone),
            ryuuCircle: createButton('Search Circle on Ryuugames', urls.ryuuCircle, icons.ryuugames)
        };

        // Append title buttons in a dropdown menu
        const titleContainer = document.querySelector('.base_title_br');
        if (titleContainer) {
            const dropdownContainer = document.createElement('div');
            dropdownContainer.className = 'dropdown-container';

            // Create toggle button
            const toggleButton = document.createElement('button');
            toggleButton.className = 'dropdown-toggle';
            toggleButton.textContent = 'Search Options';
            toggleButton.addEventListener('click', () => {
                dropdownContent.classList.toggle('hidden');
                toggleButton.classList.toggle('collapsed');
            });

            // Create dropdown content
            const dropdownContent = document.createElement('div');
            dropdownContent.className = 'dropdown-content';

            // F95Zone group
            const f95Group = document.createElement('div');
            f95Group.className = 'button-group';
            const f95Label = document.createElement('div');
            f95Label.className = 'group-label';
            f95Label.textContent = 'F95Zone';
            const f95Grid = document.createElement('div');
            f95Grid.className = 'button-group-grid';
            [buttons.f95Game, buttons.f95Forum, buttons.f95PID].forEach(btn => f95Grid.appendChild(btn));
            f95Group.appendChild(f95Label);
            f95Group.appendChild(f95Grid);

            // OtomiGames group
            const otomiGroup = document.createElement('div');
            otomiGroup.className = 'button-group';
            const otomiLabel = document.createElement('div');
            otomiLabel.className = 'group-label';
            otomiLabel.textContent = 'OtomiGames';
            const otomiGrid = document.createElement('div');
            otomiGrid.className = 'button-group-grid';
            [buttons.otomiGame, buttons.otomiPID].forEach(btn => otomiGrid.appendChild(btn));
            otomiGroup.appendChild(otomiLabel);
            otomiGroup.appendChild(otomiGrid);

            // Ryuugames group
            const ryuuGroup = document.createElement('div');
            ryuuGroup.className = 'button-group';
            const ryuuLabel = document.createElement('div');
            ryuuLabel.className = 'group-label';
            ryuuLabel.textContent = 'Ryuugames';
            const ryuuGrid = document.createElement('div');
            ryuuGrid.className = 'button-group-grid';
            [buttons.ryuuGame, buttons.ryuuPID].forEach(btn => ryuuGrid.appendChild(btn));
            ryuuGroup.appendChild(ryuuLabel);
            ryuuGroup.appendChild(ryuuGrid);

            // Append groups to dropdown content
            dropdownContent.appendChild(f95Group);
            dropdownContent.appendChild(otomiGroup);
            dropdownContent.appendChild(ryuuGroup);

            // Append toggle button and content to container
            dropdownContainer.appendChild(toggleButton);
            dropdownContainer.appendChild(dropdownContent);
            titleContainer.appendChild(dropdownContainer);
        }

        // Append circle buttons side by side
        const circleWrapper = document.createElement('span');
        circleWrapper.className = 'circle-btn-wrapper';
        [buttons.f95Circle, buttons.ryuuCircle, buttons.otomiCircle].forEach(btn => circleWrapper.appendChild(btn));
        circleNameEl.insertAdjacentElement('afterend', circleWrapper);
    }

    // Use MutationObserver to detect when required elements are available
    const observer = new MutationObserver((mutations, obs) => {
        if (document.querySelector('h1#work_name') && document.querySelector('span[itemprop="brand"] a')) {
            addSearchButtons();
            obs.disconnect();
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
})();