Feeder - 貼り付けて画像投稿

コピーした画像や画像のアドレスを貼り付けるだけでアップロードできるスクリプトです。

As of 2021-05-27. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Feeder - 貼り付けて画像投稿
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @license      MIT
// @description  コピーした画像や画像のアドレスを貼り付けるだけでアップロードできるスクリプトです。
// @author       You
// @match        *.x-feeder.info/*
// @exclude      *.x-feeder.info/*/sp
// @exclude      *.x-feeder.info/*/settings/*
// @icon         https://www1.x-feeder.info/favicon.ico
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.xmlHttpRequest
// ==/UserScript==

'use strict'
const SIZE_SAVE_KEY = 'size',
    PASTE_AREA_LABEL_TEXT = 'ここに貼り付け',
    POST_URL = 'post_picture_xhr.php'

const main = async () => {
    const scrollData = {
        old: [window.pageXOffset, window.pageYOffset],
        cur: [window.pageXOffset, window.pageYOffset]
    }
    window.addEventListener('scroll', () => {
        [scrollData.old[0], scrollData.old[1]] = scrollData.cur
        scrollData.cur[0] = window.pageXOffset
        scrollData.cur[1] = window.pageYOffset
    })

    const h = (() => {
        const e = document.createElement('div')
        e.style.padding = '1em'
        e.style.borderRadius = '5px'
        e.style.backgroundColor = '#C0C0C0'
        const parNode = document.getElementById('main_right')
        parNode.insertBefore(e, parNode.firstChild)
        return e
    })()

    const selectSize = await (async () => {
        const label = document.createElement('label')
        label.textContent = 'サイズ '
        h.appendChild(label)

        const e = document.createElement('select')
        for (const [i, v] of ['縮小しない', '84 x 84', '168 x 168(デフォルト)', '252 x 252', '336 x 336', '420 x 420'].entries()) {
            const opt = document.createElement('option')
            opt.textContent = v
            opt.value = i.toString()
            e.appendChild(opt)
        }
        e.addEventListener('change', e => void GM.setValue(SIZE_SAVE_KEY, e.target.value))
        const val = await GM.getValue(SIZE_SAVE_KEY)
        e.value = val || '2'
        label.appendChild(e)
        return e
    })()

    h.appendChild(document.createElement('hr'))

    const pasteArea = (() => {
        const label = document.createElement('div')
        label.textContent = PASTE_AREA_LABEL_TEXT
        h.appendChild(label)

        const e = document.createElement('div')
        e.contentEditable = true
        e.style.height = '3em'
        e.style.borderRadius = '5px'
        e.style.boxShadow = '0px 0px 2.5px 0px #000000 inset'
        e.style.caretColor = 'transprent'
        e.style.backgroundColor = 'gray'
        label.appendChild(e)
        return e
    })()

    const btnArea = (() => {
        const e = document.createElement('div')
        e.style.display = 'none'
        h.appendChild(e)
        e.appendChild(document.createElement('hr'))
        e.appendChild(document.createTextNode('画像を削除'))
        e.appendChild(document.createElement('br'))
        return e
    })()

    for (const e of h.getElementsByTagName('hr')) e.style.margin = '5px'

    new MutationObserver(([record]) => {
        const e = record.addedNodes[0]
        pasteArea.innerHTML = ''
        window.scrollTo(...scrollData.old)
        if (e === void 0 || (('tagName' in e) && e.tagName !== 'IMG')) return
        GM.xmlHttpRequest({
            method: 'GET',
            responseType: 'blob',
            url: e.src || e.textContent,
            onload: async res => {
                if (res.status >= 200 && res.status < 400) {
                    const fd = new FormData()
                    fd.append('frame_size', selectSize.value)
                    fd.append('picture', res.response)
                    const body = await (await fetch(POST_URL, { method: 'POST', body: fd })).text(),
                        m = body.match(/^([1-9][0-9]*),([0-9a-f]{16})$/)
                    if (m === null) {
                        console.error(body)
                        alert(body)
                        return
                    }
                    const [id, hash] = m.slice(1),
                        inputArea = document.getElementById(unsafeWindow.newActiveForm),
                        pos = inputArea.selectionStart
                    inputArea.value = `${inputArea.value.substr(0, pos)}[P:${id}]${inputArea.value.substr(pos, inputArea.value.length)}`
                    btnArea.style.display = 'block'
                    const btn = document.createElement('button')
                    btn.textContent = id
                    btnArea.appendChild(btn)
                    btn.addEventListener('click', async e => {
                        const fd = new FormData()
                        fd.append('id', id)
                        fd.append('hash', hash)
                        await fetch(POST_URL, { method: 'POST', body: fd })
                        e.target.parentNode.removeChild(e.target)
                        if (btnArea.getElementsByTagName('button').length === 0) btnArea.style.display = 'none'
                    })
                } else {
                    console.error(res)
                    alert('画像を取得できませんでした')
                }
            }
        })
    }).observe(pasteArea, { childList: true })
}

main().catch(console.error)