// ==UserScript==
// @name 微信公众号封面一键提取
// @version 1.5
// @description 点击悬浮按钮提取微信公众号文章高清封面,支持复制/下载/打开(下载文件名=文章标题)
// @author 柒儿smile
// @include *://mp.weixin.qq.com/s*
// @match *://mp.weixin.qq.com/s*
// @grant none
// ==/UserScript==
(function () {
'use strict';
// 提取封面原图链接
function getCoverImageUrl() {
const meta = document.querySelector('meta[property="og:image"]');
if (!meta || !meta.content) return null;
return meta.content.replace(/\/\d+$/, '/0');
}
// 获取文章标题(去除公众号后缀)
function getArticleTitle() {
const titleEl = document.querySelector('.rich_media_title') ||
document.querySelector('h1') ||
document.querySelector('title');
if (!titleEl) return '公众号封面';
let title = titleEl.textContent.trim()
// 移除常见后缀
.replace(/\s*[-||]\s*微信公众号.*$/, '')
.replace(/\s*[-||]\s*微信公众平台.*$/, '');
// 过滤非法字符
title = title.replace(/[\\/:*?"<>|]/g, '_')
.replace(/\s+/g, ' ')
.trim();
return title.substring(0, 80) || '公众号封面';
}
// 复制到剪贴板
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
const success = document.execCommand('copy');
document.body.removeChild(textarea);
return success;
}
}
// Toast 提示
function showToast(message, type = 'info') {
const toast = document.createElement('div');
toast.textContent = message;
Object.assign(toast.style, {
position: 'fixed',
top: '20px',
left: '50%',
transform: 'translateX(-50%)',
background: type === 'error' ? 'rgba(245, 34, 45, 0.9)' : 'rgba(0,0,0,0.7)',
color: 'white',
padding: '10px 24px',
borderRadius: '24px',
fontSize: '14px',
lineHeight: '1.4',
zIndex: '9999999',
backdropFilter: 'blur(10px)',
whiteSpace: 'nowrap',
animation: 'coverToastFadeIn 0.3s ease',
pointerEvents: 'none'
});
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.3s';
setTimeout(() => toast.remove(), 300);
}, 1600);
}
// 下载图片(格式智能识别)
async function downloadImage(url, fileName) {
try {
let ext = '';
const fmtMatch = url.match(/wx_fmt=(\w+)/);
if (fmtMatch) {
ext = fmtMatch[1].toLowerCase();
if (ext === 'jpeg') ext = 'jpg';
} else {
const path = url.split('?')[0];
const lastSegment = path.split('/').pop();
if (lastSegment) {
const dotIndex = lastSegment.lastIndexOf('.');
if (dotIndex > -1) {
const candidate = lastSegment.substring(dotIndex + 1).toLowerCase();
if (/^(jpg|jpeg|png|gif|webp|bmp)$/.test(candidate)) {
ext = candidate;
}
}
}
}
if (!ext) ext = 'jpg';
const safeName = fileName.replace(/[\\/:*?"<>|]/g, '_').trim().substring(0, 80) || '公众号封面';
const response = await fetch(url);
if (!response.ok) throw new Error('Network error');
const blob = await response.blob();
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = `${safeName}.${ext}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(() => URL.revokeObjectURL(blobUrl), 1000);
return true;
} catch (e) {
window.open(url, '_blank');
return false;
}
}
// 弹窗
function showResultModal(coverUrl) {
const oldModal = document.getElementById('cover-extractor-modal');
if (oldModal) oldModal.remove();
const modal = document.createElement('div');
modal.id = 'cover-extractor-modal';
modal.innerHTML = `
${coverUrl}
`;
if (!document.getElementById('cover-modal-styles')) {
const style = document.createElement('style');
style.id = 'cover-modal-styles';
style.textContent = `
.cover-modal-backdrop {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.4); backdrop-filter: blur(6px);
display: flex; justify-content: center; align-items: center;
z-index: 10000000;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
animation: coverFadeIn 0.2s ease;
}
.cover-modal-card {
position: relative;
background: rgba(255,255,255,0.95); backdrop-filter: blur(20px);
border-radius: 20px; padding: 28px 24px 20px;
width: 90%; max-width: 420px;
box-shadow: 0 25px 50px rgba(0,0,0,0.25);
animation: coverCardSlide 0.25s ease;
}
.cover-modal-close-btn {
position: absolute;
top: 12px; right: 12px;
width: 32px; height: 32px;
border-radius: 50%;
background: rgba(0,0,0,0.05);
border: none;
font-size: 18px; color: #666;
cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: background 0.2s;
}
.cover-modal-close-btn:hover { background: rgba(0,0,0,0.1); }
.cover-modal-header {
display: flex; align-items: center; justify-content: center;
gap: 8px; margin-bottom: 20px;
}
.cover-modal-icon { font-size: 28px; }
.cover-modal-title {
margin: 0; font-size: 20px; font-weight: 600; color: #1a1a1a;
}
.cover-modal-url {
background: #f0f2f5; border-radius: 12px; padding: 14px;
margin-bottom: 24px; font-size: 14px; color: #555;
word-break: break-all; max-height: 140px; overflow-y: auto;
line-height: 1.5;
}
.cover-modal-actions {
display: flex; gap: 10px;
}
.cover-btn-primary, .cover-btn-download, .cover-btn-secondary {
flex: 1;
padding: 10px 12px; border-radius: 12px; font-size: 15px;
font-weight: 500; cursor: pointer; transition: all 0.2s;
border: none; outline: none; white-space: nowrap;
}
.cover-btn-primary {
background: #07c160; color: white; box-shadow: 0 2px 8px rgba(7,193,96,0.3);
}
.cover-btn-primary:hover { background: #06ad56; transform: translateY(-1px); }
.cover-btn-download {
background: #0d8bf1; color: white; box-shadow: 0 2px 8px rgba(13,139,241,0.3);
}
.cover-btn-download:hover { background: #0b7ad9; transform: translateY(-1px); }
.cover-btn-secondary {
background: #fff; color: #333; border: 1px solid #e0e0e0;
}
.cover-btn-secondary:hover { background: #f5f5f5; }
@keyframes coverFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes coverCardSlide {
from { opacity: 0; transform: translateY(15px) scale(0.96); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes coverToastFadeIn {
from { opacity: 0; transform: translate(-50%, -10px); }
to { opacity: 1; transform: translate(-50%, 0); }
}
`;
document.head.appendChild(style);
}
const backdrop = modal.querySelector('.cover-modal-backdrop');
const copyBtn = modal.querySelector('#copy-btn');
const downloadBtn = modal.querySelector('#download-btn');
const openBtn = modal.querySelector('#open-btn');
const closeBtn = modal.querySelector('#close-btn-top');
const closeModal = () => {
modal.remove();
document.removeEventListener('keydown', escHandler);
};
backdrop.addEventListener('click', (e) => {
if (e.target === backdrop) closeModal();
});
closeBtn.addEventListener('click', closeModal);
copyBtn.addEventListener('click', async () => {
const success = await copyToClipboard(coverUrl);
if (success) {
copyBtn.textContent = '✅ 已复制';
} else {
copyBtn.textContent = '❌ 复制失败';
copyBtn.style.background = '#f5222d';
}
setTimeout(closeModal, 800);
});
downloadBtn.addEventListener('click', async () => {
downloadBtn.textContent = '⏳ 下载中...';
downloadBtn.disabled = true;
const title = getArticleTitle();
await downloadImage(coverUrl, title);
closeModal();
});
openBtn.addEventListener('click', () => {
window.open(coverUrl, '_blank');
closeModal();
});
const escHandler = (e) => {
if (e.key === 'Escape') closeModal();
};
document.addEventListener('keydown', escHandler);
document.body.appendChild(modal);
}
// 悬浮按钮
function createFloatingButton() {
if (document.getElementById('cover-extractor-btn')) return;
const btn = document.createElement('div');
btn.id = 'cover-extractor-btn';
btn.innerHTML = '📸';
btn.title = '提取公众号封面高清图';
Object.assign(btn.style, {
position: 'fixed',
bottom: '80px',
right: '24px',
width: '50px',
height: '50px',
borderRadius: '50%',
background: 'rgba(255,255,255,0.7)',
backdropFilter: 'blur(10px)',
WebkitBackdropFilter: 'blur(10px)',
border: '1px solid rgba(255,255,255,0.3)',
boxShadow: '0 4px 16px rgba(0,0,0,0.12), 0 0 0 1px rgba(7,193,96,0.2)',
color: '#07c160',
fontSize: '26px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
cursor: 'pointer',
zIndex: '10000001',
userSelect: 'none',
transition: 'all 0.25s cubic-bezier(0.2, 0, 0, 1)'
});
btn.addEventListener('mouseenter', () => {
btn.style.transform = 'scale(1.15)';
btn.style.boxShadow = '0 8px 24px rgba(0,0,0,0.18), 0 0 0 2px rgba(7,193,96,0.3)';
btn.style.background = 'rgba(255,255,255,0.85)';
});
btn.addEventListener('mouseleave', () => {
btn.style.transform = 'scale(1)';
btn.style.boxShadow = '0 4px 16px rgba(0,0,0,0.12), 0 0 0 1px rgba(7,193,96,0.2)';
btn.style.background = 'rgba(255,255,255,0.7)';
});
btn.addEventListener('click', () => {
const coverUrl = getCoverImageUrl();
if (coverUrl) {
showResultModal(coverUrl);
} else {
showToast('未找到封面图片,请确认页面是否正确', 'error');
}
});
document.body.appendChild(btn);
}
function init() {
createFloatingButton();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
const observer = new MutationObserver(() => {
if (!document.getElementById('cover-extractor-btn')) {
createFloatingButton();
}
});
observer.observe(document.body, { childList: true, subtree: true });
})();