Last active
February 14, 2025 08:29
-
-
Save shelllee/370ee8d78edbd8fc5ca638576463190f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Wechat Official Accounts Assistant | |
// @namespace http://tampermonkey.net/ | |
// @version 1.0 | |
// @description Auto load original images and copy information from Wechat Official Accounts articles | |
// @author Cline | |
// @match https://mp.weixin.qq.com/s/* | |
// @grant none | |
// @run-at document-start | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
let isLoading = false; | |
let initialScrollPosition = 0; | |
let hasCopied = false; | |
function smoothScrollTo(position) { | |
return new Promise(resolve => { | |
window.scrollTo({ | |
top: position, | |
behavior: 'smooth' | |
}); | |
const checkScrollEnd = setInterval(() => { | |
if (Math.abs(window.scrollY - position) < 10) { | |
clearInterval(checkScrollEnd); | |
resolve(); | |
} | |
}, 16); | |
setTimeout(() => { | |
clearInterval(checkScrollEnd); | |
resolve(); | |
}, 1000); | |
}); | |
} | |
async function smoothScroll() { | |
if (isLoading) return; | |
isLoading = true; | |
initialScrollPosition = window.scrollY; | |
const maxScroll = Math.max( | |
document.body.scrollHeight, | |
document.documentElement.scrollHeight | |
); | |
window.scrollTo(0, 0); | |
await new Promise(resolve => setTimeout(resolve, 100)); | |
await smoothScrollTo(maxScroll); | |
await new Promise(resolve => setTimeout(resolve, 100)); | |
processImages(); | |
await smoothScrollTo(initialScrollPosition); | |
isLoading = false; | |
} | |
function getOriginalImageUrl(url) { | |
let cleanUrl = url.split('?')[0]; | |
cleanUrl = cleanUrl.replace(/\/\d+$/, '/0'); | |
const isGif = url.includes('wx_fmt=gif'); | |
return `${cleanUrl}?wx_fmt=${isGif ? 'gif' : 'png'}`; | |
} | |
function processImages() { | |
const images = document.querySelectorAll('img'); | |
images.forEach(img => { | |
if(!img.dataset.processed && img.src) { | |
img.dataset.processed = 'true'; | |
img.src = getOriginalImageUrl(img.src); | |
} | |
}); | |
} | |
function parseDate(dateStr) { | |
dateStr = dateStr.replace(/\s+/g, ''); | |
const patterns = [ | |
/(\d{4})[-/](\d{1,2})[-/](\d{1,2})/, | |
/(\d{4})年(\d{1,2})月(\d{1,2})日/, | |
/(\d{1,2})[-/](\d{1,2})[-/](\d{4})/ | |
]; | |
for (const pattern of patterns) { | |
const match = dateStr.match(pattern); | |
if (match) { | |
let year, month, day; | |
if (match[1].length === 4) { | |
[, year, month, day] = match; | |
} else { | |
[, month, day, year] = match; | |
} | |
month = String(month).padStart(2, '0'); | |
day = String(day).padStart(2, '0'); | |
return `${year}.${month}.${day}`; | |
} | |
} | |
const now = new Date(); | |
return `${now.getFullYear()}.${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}`; | |
} | |
// Keep all text content: | |
// 1. Basic CJK: \u4e00-\u9fff | |
// 2. CJK Extension A: \u3400-\u4dbf | |
// 3. CJK Punctuation: \u3000-\u303f | |
function cleanText(text) { | |
if (!text) return ''; | |
return text | |
.trim() | |
.replace(/[^\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303fA-Za-z0-9\[\]【】\.-]/g, '_') | |
.replace(/^_+|_+$/g, '') | |
.replace(/_+/g, '_'); | |
} | |
function getArticleInfo() { | |
// Try SSR data first | |
if (window.__QMTPL_SSR_DATA__) { | |
const { nick_name, title, publishTime } = window.__QMTPL_SSR_DATA__; | |
if (nick_name && title) { | |
return { | |
accountName: nick_name, | |
title: title, | |
publishTime: publishTime || '' | |
}; | |
} | |
} | |
// Fallback to DOM elements | |
return { | |
accountName: document.querySelector('#js_name, .profile_nickname')?.textContent.trim() || '', | |
title: document.querySelector('#activity-name, .rich_media_title')?.textContent.trim() || '', | |
publishTime: document.querySelector('#publish_time')?.textContent.trim() || '' | |
}; | |
} | |
function tryToCopy() { | |
if (hasCopied) return; | |
const { accountName, title, publishTime } = getArticleInfo(); | |
if (!accountName || !title) return; | |
const formattedDate = parseDate(publishTime); | |
const result = cleanText(`${accountName}_${title}_${formattedDate}`); | |
if (navigator.clipboard && window.isSecureContext) { | |
navigator.clipboard.writeText(result).then(() => { | |
//hasCopied = true; | |
}); | |
} | |
} | |
// Initialize | |
if (document.readyState === 'loading') { | |
document.addEventListener('DOMContentLoaded', () => setTimeout(smoothScroll, 100)); | |
} else { | |
setTimeout(smoothScroll, 100); | |
} | |
// Check and copy text regularly | |
setInterval(tryToCopy, 1000); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment