使用Ctrl+V自动从剪贴板中上传Pin图
// ==UserScript==
// @name Pinterest Quick Pin
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 使用Ctrl+V自动从剪贴板中上传Pin图
// @author Tz
// @license MIT
// @match https://*.pinterest.com/*
// @match https://pinterest.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=pinterest.com
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// === 配置常量 ===
const CFG = {
uploadUrl: 'https://www.pinterest.com/pin-creation-tool/',
key: 'gemini_pin_cache',
width: '1500px' // 上传窗口宽度
};
// === 通用工具函数 ===
const setStyle = (el, styles) => Object.assign(el.style, styles);
// 黑白纯文本提示框
const showToast = (msg) => {
let t = document.getElementById('g-toast');
if (!t) {
t = document.createElement('div');
t.id = 'g-toast';
setStyle(t, {
position: 'fixed', top: '20px', left: '50%', transform: 'translateX(-50%)',
background: 'rgba(0,0,0,0.85)', color: '#fff', padding: '8px 20px',
borderRadius: '4px', zIndex: '9999999', fontSize: '14px', pointerEvents: 'none',
transition: 'opacity 0.2s', opacity: '0', fontFamily: 'sans-serif'
});
document.body.appendChild(t);
}
t.innerText = msg;
t.style.opacity = '1';
clearTimeout(t.timer);
t.timer = setTimeout(() => { t.style.opacity = '0'; }, 2000);
};
// =================================================================
// 逻辑 A:主页面 (监听 Ctrl+V)
// =================================================================
if (window.top === window.self) {
let modal, iframe;
// 1. 状态指示灯 (左下角小灰点)
const dot = document.createElement('div');
setStyle(dot, {
position: 'fixed', bottom: '10px', left: '10px', width: '6px', height: '6px',
borderRadius: '50%', background: '#999', zIndex: '9999', opacity: '0.4', pointerEvents: 'none'
});
document.body.appendChild(dot);
// 2. 弹出上传窗口
const openModal = () => {
if (!modal) {
// 背景遮罩
modal = document.createElement('div');
setStyle(modal, {
position: 'fixed', top: '0', left: '0', width: '100vw', height: '100vh',
background: 'rgba(0,0,0,0.75)', zIndex: '999999', display: 'flex',
justifyContent: 'center', alignItems: 'center'
});
// 容器
const box = document.createElement('div');
setStyle(box, {
width: CFG.width, maxWidth: '98vw', height: '92vh', background: '#fff',
borderRadius: '20px', overflow: 'hidden', position: 'relative'
});
// Iframe
iframe = document.createElement('iframe');
iframe.src = CFG.uploadUrl;
setStyle(iframe, { width: '100%', height: '100%', border: 'none' });
box.appendChild(iframe);
modal.appendChild(box);
document.body.appendChild(modal);
// 点击背景关闭
modal.onclick = (e) => { if(e.target === modal) modal.style.display = 'none'; };
}
modal.style.display = 'flex';
// 强制刷新 iframe 以触发自动填入逻辑
if (iframe.contentWindow.location.href !== 'about:blank') iframe.contentWindow.location.reload();
};
// 3. 监听粘贴事件
window.addEventListener('paste', (e) => {
const tag = document.activeElement.tagName;
if (['INPUT', 'TEXTAREA'].includes(tag) || document.activeElement.isContentEditable) return;
const item = Array.from(e.clipboardData.items).find(i => i.kind === 'file' && i.type.startsWith('image/'));
if (item) {
e.preventDefault();
const reader = new FileReader();
reader.onload = () => {
try {
localStorage.setItem(CFG.key, reader.result);
openModal(); // 打开弹窗
} catch (err) { showToast('图片过大,无法缓存'); }
};
reader.readAsDataURL(item.getAsFile());
} else {
showToast('剪贴板中无图片');
}
});
// 4. 监听 ESC 键退出
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal) modal.style.display = 'none';
});
}
// =================================================================
// 逻辑 B:Iframe 内部 (自动填入)
// =================================================================
else if (window.location.href.includes('pin-creation-tool') || window.location.href.includes('pin-builder')) {
//隐藏滚动条
const style = document.createElement('style');
style.innerHTML = `body { overflow: hidden !important; }`; // 强制隐藏 body 的滚动条
document.head.appendChild(style);
//轮询检测并填入
const timer = setInterval(() => {
const b64 = localStorage.getItem(CFG.key);
const input = document.querySelector('input[type="file"]');
if (b64 && input) {
clearInterval(timer);
// Base64 转 File
const arr = b64.split(','), bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
for (let i = 0; i < n; i++) u8arr[i] = bstr.charCodeAt(i);
const file = new File([u8arr], "pasted_image.png", { type: arr[0].match(/:(.*?);/)[1] });
// 触发上传
const dt = new DataTransfer(); dt.items.add(file);
input.files = dt.files;
input.dispatchEvent(new Event('change', { bubbles: true }));
localStorage.removeItem(CFG.key); // 清除缓存
showToast('图片已自动填入');
}
}, 300);
}
})();