您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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. F95Zone forum and product ID buttons open f95zone.to in a focused tab on left-click and unfocused tab on middle-click, fetch search IDs, and redirect to results in the same tab. Supports simultaneous searches without interference and ensures button text is highlightable.
// ==UserScript== // @name Multi-Platform Search Buttons for DLsite // @namespace http://tampermonkey.net/ // @version 3.30.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. F95Zone forum and product ID buttons open f95zone.to in a focused tab on left-click and unfocused tab on middle-click, fetch search IDs, and redirect to results in the same tab. Supports simultaneous searches without interference and ensures button text is highlightable. // @author FunkyJustin // @match https://www.dlsite.com/maniax/work/=/product_id/* // @match https://www.dlsite.com/pro/work/=/product_id/* // @match https://f95zone.to/* // @grant GM_openInTab // @license MIT // ==/UserScript== (function() { 'use strict'; // Check if on f95zone.to to handle search if (window.location.href.includes('f95zone.to')) { const urlParams = new URLSearchParams(window.location.search); const query = urlParams.get('query'); if (query) { const form = document.createElement('form'); form.method = 'POST'; form.action = 'https://f95zone.to/search/search'; form.style.display = 'none'; const inputs = { 'keywords': query, 'order': 'relevance', '_xfToken': document.querySelector('input[name="_xfToken"]')?.value || '' }; for (const [name, value] of Object.entries(inputs)) { const input = document.createElement('input'); input.type = 'hidden'; input.name = name; input.value = value; form.appendChild(input); } document.body.appendChild(form); fetch(form.action, { method: 'POST', body: new FormData(form), redirect: 'follow' }) .then(response => { const finalUrl = response.url; const match = finalUrl.match(/\/search\/(\d+)\//); if (match && match[1]) { const searchId = match[1]; const searchUrl = `https://f95zone.to/search/${searchId}/?q=${encodeURIComponent(query)}&o=relevance`; window.location.href = searchUrl; // Redirect in same tab } else { console.error('Could not extract search ID for query:', query, 'URL:', finalUrl); alert('Failed to fetch search ID for "' + query + '". Redirecting to fallback URL.'); window.location.href = `https://f95zone.to/search/?q=${encodeURIComponent(query)}&o=relevance`; } }) .catch(error => { console.error('Error performing search for query:', query, error); alert('Error fetching search ID for "' + query + '". Redirecting to fallback URL.'); window.location.href = `https://f95zone.to/search/?q=${encodeURIComponent(query)}&o=relevance`; }) .finally(() => { document.body.removeChild(form); }); } return; } // Inject CSS styles for DLsite const style = document.createElement('style'); style.innerHTML = ` :root { --button-bg-start: #D6BCFA; --button-bg-end: #FBB6CE; --button-text: #f5f5f5; --button-shadow: rgba(0, 0, 0, 0.1); --button-border: #B794F4; --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: #800080 !important; /* Match purple color of original non-forum buttons */ 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; cursor: pointer; appearance: none; /* Reset browser-specific button styles */ -webkit-appearance: none; -moz-appearance: none; background-clip: padding-box; user-select: auto !important; /* Allow text selection */ } .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; font-size: 14px; } .dropdown-container { max-width: 600px; margin-top: 10px; margin-bottom: 20px; position: relative; } .dropdown-toggle { display: flex; align-items: center; padding: 5px 10px; background-color: #E91E63; 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: flex; align-items: center; margin-top: 5px; gap: 5px; } .version-label { position: absolute; top: 5px; right: 5px; font-family: Arial, sans-serif; font-size: 12px; color: #666; } `; 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, queryOrUrl, iconUrl, isF95Forum = false) { const element = isF95Forum ? document.createElement('button') : document.createElement('a'); element.className = 'search-btn'; element.title = text; if (isF95Forum) { element.type = 'button'; // Ensure button behavior element.addEventListener('mousedown', (event) => { if (event.button === 0 || event.button === 1) { // Left or middle-click event.preventDefault(); // Open tab with query in URL parameter GM_openInTab(`https://f95zone.to/?query=${encodeURIComponent(queryOrUrl)}`, { active: event.button === 0, setParent: true }); // Add small delay to prevent browser overload return new Promise(resolve => setTimeout(resolve, 100)); } }); } else { element.href = queryOrUrl; element.target = '_blank'; } if (iconUrl) { const img = document.createElement('img'); img.src = iconUrl; img.alt = ''; element.appendChild(img); } element.appendChild(document.createTextNode(text)); return element; } // Main function to add buttons function addSearchButtons() { 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#?$/, '') : ''; const buttons = { f95Game: createButton('Search on F95Zone', `https://f95zone.to/sam/latest_alpha/#/cat=games/page=1/search=${encodeURIComponent(gameTitle)}`, icons.f95zone), f95Forum: createButton('Search on F95Zone Forums', gameTitle, icons.f95zone, true), f95PID: createButton('Search Product ID on F95Zone Forums', productId, icons.f95zone, true), f95Circle: createButton('Search Circle on F95Zone', `https://f95zone.to/sam/latest_alpha/#/cat=games/page=1/creator=${encodeURIComponent(circleName)}`, icons.f95zone), f95ForumCircle: createButton('Search Circle on F95Zone Forums', circleName, icons.f95zone, true), otomiGame: createButton('Search on OtomiGames', `https://otomi-games.com/?s=${encodeURIComponent(gameTitle)}`, icons.otomi), otomiPID: createButton('Search Product ID on OtomiGames', `https://otomi-games.com/?s=${encodeURIComponent(productId)}`, icons.otomi), otomiCircle: createButton('Search Circle on OtomiGames', `https://otomi-games.com/?s=${encodeURIComponent(circleName)}`, icons.otomi), ryuuGame: createButton('Search on Ryuugames', `https://www.ryuugames.com/?s=${encodeURIComponent(gameTitle)}`, icons.ryuugames), ryuuPID: createButton('Search Product ID on Ryuugames', `https://www.ryuugames.com/?s=${encodeURIComponent(productId)}`, icons.ryuugames), ryuuCircle: createButton('Search Circle on Ryuugames', `https://www.ryuugames.com/?s=${encodeURIComponent(circleName)}`, icons.ryuugames) }; const titleContainer = document.querySelector('.base_title_br'); if (titleContainer) { const dropdownContainer = document.createElement('div'); dropdownContainer.className = 'dropdown-container'; const toggleButton = document.createElement('button'); toggleButton.className = 'dropdown-toggle'; toggleButton.textContent = 'Search Options'; toggleButton.addEventListener('click', () => { dropdownContent.classList.toggle('hidden'); toggleButton.classList.toggle('collapsed'); }); const dropdownContent = document.createElement('div'); dropdownContent.className = 'dropdown-content'; const versionLabel = document.createElement('div'); versionLabel.className = 'version-label'; versionLabel.textContent = 'v3.30.0'; dropdownContainer.appendChild(versionLabel); 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); 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); 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); dropdownContent.appendChild(f95Group); dropdownContent.appendChild(otomiGroup); dropdownContent.appendChild(ryuuGroup); dropdownContainer.appendChild(toggleButton); dropdownContainer.appendChild(dropdownContent); titleContainer.parentNode.insertBefore(dropdownContainer, titleContainer.nextSibling); } const circleWrapper = document.createElement('span'); circleWrapper.className = 'circle-btn-wrapper'; [buttons.f95Circle, buttons.f95ForumCircle, buttons.ryuuCircle, buttons.otomiCircle].forEach(btn => circleWrapper.appendChild(btn)); circleNameEl.parentNode.insertBefore(circleWrapper, circleNameEl.nextSibling); } // Only run button creation on DLsite pages if (window.location.href.includes('dlsite.com')) { 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 }); } })();