您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a button to convert Twitter image URLs to SauceNAO search URLs. Instantly searches for single image tweets, and shows a dropdown for multiple images.
// ==UserScript== // @name Twitter Image to SauceNAO // @namespace http://yourwebsite.com // @version 3.2 // @description Adds a button to convert Twitter image URLs to SauceNAO search URLs. Instantly searches for single image tweets, and shows a dropdown for multiple images. // @author FunkyJustin // @match https://twitter.com/* // @match https://x.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; function convertToSauceNAOUrl(imageUrl) { const encodedUrl = encodeURIComponent(imageUrl); return `https://saucenao.com/search.php?url=${encodedUrl}`; } function createSauceNAODropdown(imageUrls, button) { const dropdown = document.createElement('div'); dropdown.className = 'saucenao-dropdown'; dropdown.style.position = 'absolute'; dropdown.style.backgroundColor = 'white'; dropdown.style.border = '1px solid #ccc'; dropdown.style.zIndex = '10000'; dropdown.style.boxShadow = '0px 4px 6px rgba(0, 0, 0, 0.1)'; dropdown.style.maxHeight = '200px'; dropdown.style.overflowY = 'auto'; dropdown.style.padding = '4px'; dropdown.style.fontSize = '14px'; imageUrls.forEach((imageUrl, index) => { const menuItem = document.createElement('div'); menuItem.style.padding = '8px'; menuItem.style.cursor = 'pointer'; menuItem.style.color = '#000'; menuItem.innerText = `Search Image ${index + 1}`; menuItem.addEventListener('click', () => { const saucenaoUrl = convertToSauceNAOUrl(imageUrl); window.open(saucenaoUrl, '_blank'); dropdown.remove(); }); dropdown.appendChild(menuItem); }); const searchAllItem = document.createElement('div'); searchAllItem.style.padding = '8px'; searchAllItem.style.cursor = 'pointer'; searchAllItem.style.color = '#000'; searchAllItem.innerText = 'Search All Images'; searchAllItem.addEventListener('click', () => { imageUrls.forEach(imageUrl => { const saucenaoUrl = convertToSauceNAOUrl(imageUrl); window.open(saucenaoUrl, '_blank'); }); dropdown.remove(); }); dropdown.appendChild(searchAllItem); button.parentNode.style.position = 'relative'; button.parentNode.appendChild(dropdown); const buttonRect = button.getBoundingClientRect(); dropdown.style.bottom = `${button.offsetTop}px`; dropdown.style.left = `${button.offsetLeft}px`; document.addEventListener('click', (event) => { if (!dropdown.contains(event.target) && event.target !== button) { dropdown.remove(); } }, { once: true }); return dropdown; } function addSauceNAOBtn() { const articles = document.querySelectorAll('article'); articles.forEach(article => { const images = article.querySelectorAll('img[src*="pbs.twimg.com/media"]'); const imageUrls = Array.from(images).map(img => img.src); if (imageUrls.length > 0) { const container = article.querySelector('div[role="group"]'); if (container) { const existingButton = container.querySelector('.saucenao-button'); if (!existingButton) { const button = document.createElement('div'); button.className = 'saucenao-button'; button.style.display = 'inline-block'; button.style.marginLeft = '8px'; button.style.cursor = 'pointer'; button.style.color = 'rgb(29, 155, 240)'; button.innerText = 'SauceNAO'; const dropdownIcon = document.createElement('span'); dropdownIcon.innerText = ' ▼'; // Dropdown icon dropdownIcon.style.display = imageUrls.length > 1 ? 'inline' : 'none'; // Show only if multiple images button.appendChild(dropdownIcon); // Add the icon to the button button.addEventListener('click', (event) => { event.stopPropagation(); event.preventDefault(); if (imageUrls.length === 1) { const saucenaoUrl = convertToSauceNAOUrl(imageUrls[0]); window.open(saucenaoUrl, '_blank'); } else { document.querySelectorAll('.saucenao-dropdown').forEach(el => el.remove()); createSauceNAODropdown(imageUrls, button); } }); container.appendChild(button); } } } }); } const observer = new MutationObserver((mutations) => { mutations.forEach(() => { addSauceNAOBtn(); }); }); observer.observe(document.body, { childList: true, subtree: true }); addSauceNAOBtn(); })();