-
-
Save ninjastic/d560848568339e5a2d7a25ddffb578d5 to your computer and use it in GitHub Desktop.
Fixes bugged bbcode cauised by an older version of the Imgur to TalkImg script
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
(async () => { | |
// options | |
const startPage = 1 | |
const basePostHistoryUrl = 'https://bitcointalk.org/index.php?action=profile;sa=showPosts' | |
const decoder = new TextDecoder('windows-1252') | |
const parser = new DOMParser() | |
let lastReq | |
const tags = ['img', 'b', 'size', 'pre', 'left', 'center', 'right', 'url', 'i', 'u', 's', 'btc', 'glow', 'shadow', 'hr', 'font', 'color', 'flash', 'email', 'ftp', 'table', 'tr', 'td', 'sup', 'sub', 'tt', 'code', 'quote', 'list', 'li'] | |
const tagsRegexText = tags.map(tag => tag).join('|') | |
const tagsRegex = new RegExp(`\\[\\b(${tagsRegexText})\\b(=.*?)?(\\s.*?)?\\]`, 'g') | |
let emojiRegex = await fetch('https://proxy.ninjastic.space/?url=https://raw.githubusercontent.com/mathiasbynens/emoji-test-regex-pattern/main/dist/latest/javascript.txt').then(response => response.status === 200 ? response.text() : null) | |
if (!emojiRegex) { | |
console.log('%cERROR: Could not fetch Emoji regex', 'color: red; font-weight: bold;') | |
return | |
} | |
const encodeStr = (rawStr) => { | |
return rawStr.replace(new RegExp(`${emojiRegex}|[\u00A0-\u9999<>&]`, 'g'), (i) => `&#${i.codePointAt(0)};`) | |
} | |
const fetchThrottled = async (url, ...rest) => { | |
const timeRemaining = lastReq ? lastReq.getTime() + 1000 * 1 - new Date().getTime() : 0 | |
if (timeRemaining > 0) { | |
await new Promise(resolve => setTimeout(resolve, timeRemaining)) | |
} | |
lastReq = new Date() | |
return await fetch(url, ...rest) | |
} | |
const checkTopicLocked = async (topicId) => { | |
const url = `https://bitcointalk.org/index.php?action=post;topic=${topicId}` | |
const html = await fetchThrottled(url).then(async response => decoder.decode(await response.arrayBuffer())) | |
const $ = parser.parseFromString(html, 'text/html') | |
if ($.title === 'An Error Has Occurred!') { | |
return $.querySelector('#bodyarea > div:nth-child(1) > table > tbody > tr.windowbg > td')?.textContent.trim() | |
} | |
return undefined | |
} | |
const getSesc = async () => { | |
const html = await fetchThrottled('https://bitcointalk.org/more.php').then(async response => decoder.decode(await response.arrayBuffer())) | |
return html.match(/https\:\/\/bitcointalk\.org\/index\.php\?action=logout;sesc=(.*?)"\>/)?.at(1) | |
} | |
const getQuote = async ({ topicId, postId, sesc }) => { | |
const url = `https://bitcointalk.org/index.php?action=quotefast;xml;quote=${postId};topic=${topicId};sesc=${sesc}` | |
const html = await fetchThrottled(url).then(async response => decoder.decode(await response.arrayBuffer())) | |
const $ = parser.parseFromString(html, 'text/html') | |
const quote = $.querySelector('quote').textContent | |
return quote.replace(/^\[quote.*?\]\n?/, '').replace(/\[\/quote\]$/, '') | |
} | |
const editPost = async ({ topicId, postId, title, message, sesc }) => { | |
const formData = new FormData() | |
formData.append('topic', String(topicId)) | |
formData.append('subject', encodeStr(title)) | |
formData.append('message', encodeStr(message)) | |
formData.append('sc', sesc) | |
formData.append('goback', String(1)) | |
const { redirected } = await fetchThrottled(`https://bitcointalk.org/index.php?action=post2;msg=${postId}`, { method: 'POST', body: formData }) | |
return redirected | |
} | |
const removeElements = (parent, elementSelectors) => { | |
for (const elementSelector of elementSelectors) { | |
for (const element of [...parent.querySelectorAll(elementSelector)]) { | |
element.remove() | |
} | |
} | |
} | |
const getPosts = async (page) => { | |
const url = `${basePostHistoryUrl};start=${((page ?? 1) - 1) * 20}` | |
const html = await fetchThrottled(url).then(async response => decoder.decode(await response.arrayBuffer())) | |
const $ = parser.parseFromString(html, 'text/html') | |
const postElements = [...$.querySelectorAll('table[width="85%"] table[width="100%"] tbody')] | |
.filter(element => element.querySelector('.post')) | |
const posts = [] | |
for (const postElement of postElements) { | |
const titleElement = postElement.querySelector('tr[class=titlebg2] td:nth-child(2) a:last-child') | |
const title = titleElement.textContent.trim() | |
const [, topicId, postId] = titleElement.getAttribute('href').match(/topic=(\d+)\.msg(\d+)/) | |
const contentElement = postElement.querySelector('.post') | |
removeElements(contentElement, ['.code']) | |
const hasBuggedBbcode = contentElement.innerHTML.match(tagsRegex) | |
posts.push({ topicId, postId, title, hasBuggedBbcode }) | |
} | |
return posts.filter(post => post.hasBuggedBbcode) | |
} | |
const html = await fetchThrottled(basePostHistoryUrl).then(async response => response.text()) | |
const $ = parser.parseFromString(html, 'text/html') | |
const pages = [...$.querySelectorAll('.navPages[href*="sa=showPosts"]')] | |
.filter(element => !['«', '»'].includes(element.textContent)) | |
.reduce((elements, currentElement) => { | |
if(!elements.find(element => element.href === currentElement.getAttribute('href'))) { | |
elements.push({ element: currentElement, page: Number(currentElement.textContent), href: currentElement.getAttribute('href') }) | |
return elements | |
} | |
return elements | |
}, []) | |
const lastPageNum = pages[pages.length - 1].page ?? 1 | |
console.log('%cAutomatically fix your broken posts (sorry!)', 'color: #fff; font-weight: bold; background-color: blue;') | |
console.log('Number of Pages:', lastPageNum) | |
if (startPage > lastPageNum) { | |
console.log('%cERROR: startPage is greater than your number of pages, please check.', 'color: red; font-weight: bold;') | |
return | |
} | |
for await (const page of Array.from({ length: lastPageNum - startPage + 1 }).map((_, i) => startPage + i)) { | |
console.log(`--------------------\nGetting posts on page ${page}/${lastPageNum} (${Math.floor(page / lastPageNum * 100)}%)`) | |
const posts = await getPosts(page) | |
if (posts.length > 0) { | |
console.log(`Found ${posts.length} posts`, posts) | |
} | |
for await (const post of posts) { | |
const topicError = await checkTopicLocked(post.topicId) | |
if (topicError) { | |
console.log(`[${post.postId}] Skipping post because topic returned error:`, topicError) | |
continue | |
} | |
const sesc = await getSesc() | |
const currPost = await getQuote({ topicId: post.topicId, postId: post.postId, sesc }) | |
console.log(`[${post.postId}] Editing/refreshing post https://bitcointalk.org/index.php?topic=${post.topicId}.msg${post.postId}#msg${post.postId}`) | |
const edited = await editPost({ topicId: post.topicId, postId: post.postId, title: post.title, message: currPost, sesc }) | |
if (!edited) { | |
console.log(`[${post.postId}] Could not edit post (maybe locked?)...`) | |
} | |
} | |
} | |
console.log('-- Finished! --') | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment