Author

Topic: [Script] Imgur papuntang TalkImg - automatic na aayusin ang broken images (Read 56 times)

hero member
Activity: 1176
Merit: 593
When life gets hard BUY Bitcoin!
Bagong update para sa mga gagamit ng script na ito. Dahil maintenance ngayon ang talkimg kaya hindi gagana ang script na nasa OP. Need ng few modifications na makikita nyo sa original thread specifically sa post na ito https://bitcointalksearch.org/topic/m.62246935 ni @TryNinja. Siguraduhin nyo na masusunod mabuti ang instruction nyo bago nyo irun ang script para walang maging problema.

Pwede nyo syang icontact sa telegram @tryninja o magcomment lang kayo dito/original thread para masolusyonan agad ang maeencounter nyong bug.
hero member
Activity: 2562
Merit: 659
Dimon6969
FYI lang, Naipost ko na din to sa original thread pero share ko nlng din dito. Pwede gamitin itong script sa Kiwi mobile browser para sa mga android user na walang access sa desktop katulad. Kailangan lng na naka open ang screen habang nagrurun yung script.

Download lang kayo ng Kiwi browser sa playstore >login sa Bitcointalk> developer tools> paste script.

Sobrang easy lang din pero yung duration ay nakadepende pa din sa dami ng image sa post history nyo. Sa IOS naman ay sa Safari browser pero need iallow pa sa desktop kayo hindi din feasible.
hero member
Activity: 1176
Merit: 593
When life gets hard BUY Bitcoin!
Original Thread by @TryNinja: https://bitcointalksearch.org/topic/script-imgur-to-talkimg-automatically-fix-your-broken-images-5452662

Sobrang useful nito lalo na sa mga mahilig magpost ng image gamit ang imgur dahil invalid image na ang lahat ng ating mga post.


Imgur papuntang TalkImg - automatic na aayusin ang broken images

Quote



Ang Imgur images ay na ngayon gumagana, kaya mapapansin nya na madami kayong mga post na broken images na kagaya nito:



Para sa konstekto: Imgur images ay biglang naging invalid?



Kaya gumawa si @TryNinja ng script na:

1. Na magsesearch sa iyong mga post ng direct link ng imgur.com (.png|.jpg|.jpeg);
2. Iuupload ulit ang imahe sa talkimg.com;
3. Babaguhin ang post ng panibagong link.

Paano ito gamitin:

1. Pumunta sa bitcointalk.org (kahit anong page).
2. Buksan ang browser developer tools sa Console tab (Ctrl+Shift+I or F12).
3. Paste ang script at pindutin ang Enter.
4. Iwanan ang page na nakabukas habang tumataakbo script  at, hanggang maari, huwag muna gamitin ang forum (kahit sa iba pang tabs) para maiwasan ang rate limiting errors.

Kung may error na magpakita, maaring ireport ito dito at/o paganahin muli ang script (ang proseso ay magsisimula muli, pero ang updated posts ay hindi na isasama dahil wala na itong imgur.com links).

Script:

- Maaari nyong palitan ang API key kung mayroon kayong account sa TalkImg. Pero kung wala, mayroong inihanda si @joker_josue para sa script.
- Maaari nyong palitan ang startPage variable kung gusto nyo simulan ang script galing sa specific page (i.e ang script ay nag error sa page 300 at gusto mo na magrestart galing doon).

Code:
(async () => {

    // options
    const startPage = 1
    const useProxy = true
    const apiKey = 'chv_AiD_124562a509c5fadffba3e15a3a31f8241855c36609c497a325396124b370b138a1d5ecda8061410b4a3478bdf26b51c5589e23d7e277a15dedda70577ca79995'

    const uploadUrl = useProxy ? 'https://proxy.ninjastic.space/?url=https://talkimg.com/api/1/upload' : 'https://talkimg.com/api/1/upload'
    const decoder = new TextDecoder('windows-1252')
    const parser = new DOMParser()
    let lastReq

    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 decodeProxyImages = (html) => html.replaceAll(/img.*?src="(.*?)"\s/g, (text, imgUrl) => {
        const directImgUrl = imgUrl
            .replace(/https:\/\/ip\.bitcointalk\.org\/\?u=/, '')
            .replace(/&.*/, '')
        const decodedUrl = decodeURIComponent(directImgUrl)
        return text.replace(imgUrl, decodedUrl)
    })

    const encodeStr = (rawStr) => {
        return rawStr.replace(/[\u00A0-\u9999<>&]/g, (i) => `&#${i.charCodeAt(0)};`)
    }

    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.*?\]/, '').replace(/\[\/quote\]$/, '').trim()
    }

    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 getPosts = async (page) => {
        const url = `https://bitcointalk.org/index.php?action=profile;sa=showPosts;start=${((page ?? 1) - 1) * 20}`
        const html = await fetchThrottled(url).then(async response => decoder.decode(await response.arrayBuffer()))
        const decoded = decodeProxyImages(html)
        const $ = parser.parseFromString(decoded, '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')
            const links = [...new Set(contentElement.innerHTML.match(/https:\/\/i\.imgur\.com\/.*?\.(png|jpg|jpeg)/gi))] ?? []
            posts.push({ topicId, postId, title, links })
        }

        return posts
    }

    const uploadImage = async (image) => {
        const formData = new FormData()
        formData.append('type', 'file')
        formData.append('format', 'json')
        formData.append('source', image)

        const upload = await fetchThrottled(uploadUrl, {
            method: 'POST',
            headers: { 'X-API-Key': apiKey },
            mode: 'cors',
            body: formData,
        })

        const response = await upload.json()
        if (response.status_code === 200) {
            return { url: response.image.url, deleteUrl: response.image.delete_url }
        }

        console.log('Could not upload, error:', response?.error?.message ?? response)
        return undefined
    }
    
    const html = await fetchThrottled('https://bitcointalk.org/index.php?action=profile;sa=showPosts').then(async response => response.text())
    const $ = parser.parseFromString(html, 'text/html')
    const isLast = $.querySelector('.prevnext:last-child > a.navPages') === null

    const lastPageNum = isLast ?
        Number($.querySelector('tbody > tr.catbg3 > td > b').textContent) :
        Number($.querySelector('td[colspan] a.navPages:nth-last-child(2)')?.textContent ?? 1)

    console.log('%cImgur to TalkImg - automatically fix your broken images', 'color: #fff; font-weight: bold; background-color: blue;')
    console.log('Number of Pages:', lastPageNum)

    let numberUploads = 0

    if (startPage > lastPageNum) {
        throw Error('startPage is greater than your number of pages')
    }

    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).then(posts => posts.filter(post => post.links.length > 0))
        if (posts.length > 0) {
            console.log(`Found ${posts.length} posts and ${posts.flatMap(post => post.links).length} images`, posts)
        }
        for await (const post of posts) {
            const images = []
            for await (const link of post.links) {
                const image = await fetchThrottled(link).then(async response => response.blob())
                images.push(image)
            }

            const uploadedImages = []
            for await (const [index, image] of images.entries()) {
                if (numberUploads >= 20) {
                    numberUploads = 0
                    console.log('Upload API limited, waiting 1 minute...')
                    await new Promise(resolve => setTimeout(resolve, 1000 * 60))
                }

                console.log(`[${post.postId}] Uploading image...`)
                const uploaded = await uploadImage(image)
                if (uploaded?.url) {
                    numberUploads += 1
                    uploadedImages.push({ old: post.links[index], new: uploaded.url, deleteUrl: uploaded.deleteUrl })
                    console.log(`[${post.postId}] Uploaded:`, uploaded.url)
                }
            }
            
            if (uploadedImages.length > 0) {
                const sesc = await getSesc()
                const currPost = await getQuote({ topicId: post.topicId, postId: post.postId, sesc })
                let newContent = currPost

                for (const uploadedImage of uploadedImages) {
                    newContent = newContent.replaceAll(uploadedImage.old, uploadedImage.new)
                }

                console.log(`[${post.postId}] Editing 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: newContent, sesc })

                if (!edited) {
                    console.log(`[${post.postId}] Could not edit post (maybe locked?), deleting uploaded images...`)
                    for (const uploadedImage of uploadedImages) {
                        await fetchThrottled(uploadedImage.deleteUrl, { redirect: 'manual' })
                    }
                }
            } else {
                console.log(`[${post.postId}] No images were uploaded, skiping edit...`)
            }
        }
    }

    console.log('-- Finished! --')
})()

Other notes:

- Ito ay mag uupload at edit ng lahat ng imgur.com links na makikita sa iyonh post history (kasama na ang lahat ng post kahit naka quote sa ibang tao).
- Ang post sa loob ng locked topics ay hindi na kayang iedit, kaya mabubura ang mga bagong upload na imag para dito (upang makatipid ng space sa talkimg server).
- Ang TalkImg max size limit ay 2 MB, kaya maaring mag fail ang ibang image.
Jump to: