您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Makes it easier to copy data from ThePosterDB
// ==UserScript== // @name ThePosterDB - Easy Links // @version 2.0.2 // @description Makes it easier to copy data from ThePosterDB // @author Journey Over // @license MIT // @match *://theposterdb.com/* // @require https://code.jquery.com/jquery-3.5.1.min.js // @require https://cdn.jsdelivr.net/gh/StylusThemes/Userscripts@5f2cbff53b0158ca07c86917994df0ed349eb96c/libs/gm/gmcompat.js // @grant GM.setClipboard // @grant GM.addStyle // @icon https://www.google.com/s2/favicons?sz=64&domain=theposterdb.com // @homepageURL https://github.com/StylusThemes/Userscripts // @namespace https://greasyfork.org/users/32214 // ==/UserScript== (function() { 'use strict'; // Constants and Configuration const CONFIG = { selectors: { gridPosters: '.col-6 .hovereffect', mainPoster: '#main_poster_container', copyLinkBtn: '.copy_poster_link', titleText: 'p.p-0.mb-1.text-break', overlay: 'div.overlay' }, attributes: { posterId: 'data-poster-id', clipboardText: 'data-clipboard-text' }, urls: { apiBase: 'https://theposterdb.com/api/assets' }, notifications: { duration: 3000, messages: { link: 'Link copied to clipboard', id: 'ID copied to clipboard', metadata: 'Metadata copied to clipboard' } } }; // CSS Styles const STYLES = ` .tpdb-notification { position: fixed; top: 10px; right: 10px; padding: 10px; background-color: #4caf50; color: white; z-index: 10000; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); transition: opacity 0.3s ease-in-out; } .tpdb-button-container { display: flex; justify-content: space-between; gap: 5px; margin-top: 5px; } .tpdb-button { flex: 1; text-align: center; cursor: pointer; padding: 5px 10px; border-radius: 5px; font-size: 1rem; color: white; border: 1px solid; transition: all 0.3s ease; } .tpdb-button:hover { transform: scale(1.05); } .tpdb-button-link { background-color: #28965a; border-color: #219150; } .tpdb-button-link:hover { background-color: #1e7948; } .tpdb-button-id { background-color: #007bff; border-color: #0056b3; } .tpdb-button-id:hover { background-color: #0056b3; } .tpdb-metadata-button { cursor: pointer !important; color: white; background: transparent; padding: 3px 8px; border-radius: 4px; font-size: 0.9rem; text-decoration: none; display: inline-block; border: 1px solid #5a6268; transition: all 0.3s ease; } .tpdb-metadata-button:hover { background-color: #5a6268; transform: scale(1.05); } `; /** * Utility class for common operations */ class Utils { static async fadeOut(element, duration) { element.style.opacity = '0'; await new Promise(resolve => setTimeout(resolve, duration)); element.remove(); } static createUrl(posterId) { return `${CONFIG.urls.apiBase}/${posterId}`; } static isValidPosterId(posterId) { return posterId && /^\d+$/.test(posterId); } } /** * Handles all notification-related functionality */ class NotificationManager { static show(message, duration = CONFIG.notifications.duration) { const notification = document.createElement('div'); notification.className = 'tpdb-notification'; notification.textContent = message; document.body.appendChild(notification); // Wait for the notification to be visible for `duration` ms before fading out setTimeout(() => { Utils.fadeOut(notification, 300); // Fade out over 300ms }, duration); } } /** * Manages poster data and operations */ class PosterData { constructor(element) { this.element = element; this.posterId = this.extractPosterId(); this.title = this.extractTitle(); this.year = this.extractYear(); } extractPosterId() { const overlay = this.element.querySelector(CONFIG.selectors.overlay); return overlay?.getAttribute(CONFIG.attributes.posterId); } extractTitle() { const titleElement = this.element.querySelector(CONFIG.selectors.titleText); return titleElement?.textContent.trim().replace(/\(\d{4}\)/, '').trim() || ''; } extractYear() { const titleElement = this.element.querySelector(CONFIG.selectors.titleText); const match = titleElement?.textContent.match(/\((\d{4})\)/); return match ? parseInt(match[1], 10) : null; } get apiUrl() { return Utils.createUrl(this.posterId); } toMetadata() { return ` "${this.title}":\n match:\n year: ${this.year || 'Unknown'}\n url_poster: "${this.apiUrl}"`; } } /** * Manages UI components and interactions */ class UIManager { constructor() { this.setupStyles(); this.initializeUI(); } setupStyles() { GMC.addStyle(STYLES); } createButton(text, className, clickHandler) { const button = document.createElement('button'); button.className = `tpdb-button ${className}`; button.textContent = text; button.addEventListener('click', clickHandler); return button; } createButtonContainer(posterId) { const container = document.createElement('div'); container.className = 'tpdb-button-container'; const linkButton = this.createButton('Copy Link', 'tpdb-button-link', () => { GMC.setClipboard(Utils.createUrl(posterId)); NotificationManager.show(CONFIG.notifications.messages.link); }); const idButton = this.createButton('Copy ID', 'tpdb-button-id', () => { GMC.setClipboard(posterId); NotificationManager.show(CONFIG.notifications.messages.id); }); container.append(linkButton, idButton); return container; } setupMainPosterButtons() { const copyLinkBtn = document.querySelector(CONFIG.selectors.copyLinkBtn); if (!copyLinkBtn) return; const posterId = copyLinkBtn.getAttribute(CONFIG.attributes.posterId); if (!Utils.isValidPosterId(posterId)) return; // Modify existing copy link button copyLinkBtn.setAttribute(CONFIG.attributes.clipboardText, Utils.createUrl(posterId)); copyLinkBtn.addEventListener('click', () => { NotificationManager.show(CONFIG.notifications.messages.link); }); // Add new ID button const idButton = document.createElement('button'); idButton.className = 'btn btn-outline-warning clipboard'; idButton.setAttribute(CONFIG.attributes.clipboardText, posterId); idButton.setAttribute('data-toggle', 'tooltip'); idButton.setAttribute('data-placement', 'top'); idButton.setAttribute('title', 'Copy Poster ID'); idButton.innerHTML = '<span class="d-none">Copy ID</span> <i class="fas fa-hashtag"></i>'; idButton.addEventListener('click', () => { NotificationManager.show(CONFIG.notifications.messages.id); }); copyLinkBtn.parentNode.insertBefore(idButton, copyLinkBtn.nextSibling); // Initialize clipboard.js if available if (window.ClipboardJS) { new ClipboardJS(idButton); } } setupGridPosters() { document.querySelectorAll(CONFIG.selectors.gridPosters).forEach(element => { const posterData = new PosterData(element); if (!Utils.isValidPosterId(posterData.posterId)) return; const container = this.createButtonContainer(posterData.posterId); element.parentElement.appendChild(container); }); } setupMetadataButton() { const posters = Array.from(document.querySelectorAll(CONFIG.selectors.gridPosters)) .map(element => new PosterData(element)) .filter(poster => Utils.isValidPosterId(poster.posterId)); if (posters.length === 0) return; const button = document.createElement('button'); button.className = 'tpdb-metadata-button'; button.textContent = 'Copy Metadata'; button.addEventListener('click', () => { const metadata = `metadata:\n\n${posters.map(p => p.toMetadata()).join('\n\n')}`; GMC.setClipboard(metadata); NotificationManager.show(CONFIG.notifications.messages.metadata); }); document.querySelector('div')?.appendChild(button); } initializeUI() { this.setupMainPosterButtons(); this.setupGridPosters(); this.setupMetadataButton(); } } // Initialize when DOM is ready $(document).ready(() => { new UIManager(); }); })();