Greasy Fork

Greasy Fork is available in English.

Pixiv Artwork Opener (Tampermonkey)

自动读取剪切板打开Pixiv作品。/ Prompt user to open Pixiv artwork from clipboard.

// ==UserScript==
// @name         Pixiv Artwork Opener (Tampermonkey)
// @namespace    https://github.com/Koishi0425/chrome-extension-Pixiv-Artwork-Opener
// @version      1.2
// @description  自动读取剪切板打开Pixiv作品。/ Prompt user to open Pixiv artwork from clipboard.
// @author       Glamorgan
// @match        https://www.pixiv.net/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=pixiv.net
// @grant        GM_addStyle
// @grant        GM_notification
// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

let clipboardChecked = false;

(async function() {
    'use strict';

    // 检查是否已经读取过剪贴板
    if (clipboardChecked) return;

    clipboardChecked = true;

    // Function to get clipboard content with error notification
    async function getClipboardText() {
        try {
            const text = await navigator.clipboard.readText();
            return text;
        } catch (err) {
            GM_notification({
                title: "Pixiv Artwork Opener",
                text: "Failed to read clipboard contents.",
                timeout: 4000,
                onclick: () => { window.focus(); }
            });
            console.error('Failed to read clipboard contents: ', err);
            return null;
        }
    }

    // Function to validate if the text is 8 or 9 digit number or a valid Pixiv URL
    function isValidPixivId(text) {
        const idRegex = /^\d{8,9}$/;
        const urlRegex = /pixiv\.net\/artworks\/(\d{8,9})/;
        if (idRegex.test(text)) {
            return text;
        } else if (urlRegex.test(text)) {
            return text.match(urlRegex)[1];
        }
        return null;
    }

    // Function to create a custom confirmation dialog
    function showConfirmationDialog(artworkId, callback) {
        // Create overlay
        const overlay = document.createElement('div');
        const overlayStyles = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 9999;
            animation: fadeIn 0.5s;
        `;
        overlay.style.cssText = overlayStyles;

        // Create dialog box
        const dialog = document.createElement('div');
        const dialogStyles = `
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            text-align: center;
            width: 300px;
            color: black;
        `;
        dialog.style.cssText = dialogStyles;

        // Add content to the dialog
        dialog.innerHTML = `
            <h3 style="margin-bottom: 10px; color: black;">Pixiv Artwork Detected</h3>
            <p style="margin-bottom: 20px; color: black;">We found an Artwork ID: <strong>${artworkId}</strong>. Would you like to open it?</p>
            <button id="confirm-btn" style="padding: 5px 10px; margin-right: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px;">Yes</button>
            <button id="cancel-btn" style="padding: 5px 10px; background-color: #f44336; color: white; border: none; border-radius: 4px;">No</button>
        `;

        // Append the dialog to the overlay
        overlay.appendChild(dialog);
        document.body.appendChild(overlay);

        // Add event listeners to the buttons
        document.getElementById('confirm-btn').addEventListener('click', function() {
            callback(true);
            overlay.style.animation = "fadeOut 0.5s";
            setTimeout(() => document.body.removeChild(overlay), 500);
        });

        document.getElementById('cancel-btn').addEventListener('click', function() {
            callback(false);
            overlay.style.animation = "fadeOut 0.5s";
            setTimeout(() => document.body.removeChild(overlay), 500);
        });
    }

    // Function to check if URL contains specific parameter
    function hasUrlParameter(param) {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.has(param);
    }

    // Main logic to prevent duplicate detection using URL parameters
    if (!hasUrlParameter('from_clipboard')) {
        setTimeout(async () => {
            const text = await getClipboardText();
            const pixivId = isValidPixivId(text);
            if (pixivId) {
                // Show custom dialog
                showConfirmationDialog(pixivId, function(confirmed) {
                    if (confirmed) {
                        // Append a parameter to avoid future clipboard detection
                        const pixivUrl = `https://www.pixiv.net/artworks/${pixivId}?from_clipboard=true`;
                        window.location.href = pixivUrl;
                    }
                });
            }
        }, 500);
    }
})();

// CSS for fade-in and fade-out animations
GM_addStyle(`
    @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
    }

    @keyframes fadeOut {
        from { opacity: 1; }
        to { opacity: 0; }
    }
`);