generated at
tweet2image-upload


ブラウザ拡張にUserScriptの導入が必要です: tweet2image-proxy

導入
usage.js
import('/api/code/ci7lus/tweet2image-upload/script.js');
コード中importにトップレベルawaitを使用しているため読み込みに失敗し、iOS Safariなどでは後述のimportに影響するかもしれません、 import() を用いてください

CHANGELOG
2024/10/21
tweet2imageしれっと復活させたので合わせてx.comのときに無効なURLって返さないようにしました
貼られるURL等は更新していません
2021/10/16
pdfの全てのページをGyazoにアップロードしてScrapboxに貼り付けるUserScriptと同様Gyazoへのアップロード時にOAuthモードを使用可能に
2021/8/20
UserScriptが入ってない場合に新しいタブで導入ページが開くようになりました
2021/7/22
2021/7/6
Font Awesome 5 Free 、バンドルされてる分だとBrandが抜けてる?っぽいのでsvgに置き換え
2021/06/10
Scrapbox側の変更で自動貼り付けに失敗するようになったので、プロンプトでコピーする形式に変更しました
2021/04/24
ホスト名変更、パス変更
now.shがvercel.appにリダイレクトされるようになったのでアップロードできなくなったのが修正されます
2020/10/3
ライセンスを明記
メッセージを全部日本語に(lang=ja&tz=9固定だし…)
アップロードのステータスがpdfの全てのページをGyazoにアップロードしてScrapboxに貼り付けるUserScript同様右上に出るように

ライセンス
このコードはMIT Licenseにて提供されます。
> MIT License Copyright (c) 2020 ci7lus

script.js
/* https://scrapbox.io/ci7lus/tweet2image-upload */ /* MIT License Copyright (c) 2020 ci7lus */ /*const style = document.createElement("style"); style.innerText = `@import "https://scrapbox.io/api/code/ci7lus/tweet2image-upload/style.css";`; document.body.appendChild(style);*/ import { insertText } from "/api/code/customize/scrapbox-insert-text/script.js" scrapbox.PageMenu.addMenu({ title: "tweet2image", image: "https://scrapbox.io/files/60e9891a6f8d0b0022457e87.svg", onClick: async () => { if (!window.get_tweet_card) { alert("UserScriptが入ってなさそうです?") window.open("https://scrapbox.io/ci7lus/tweet2image-proxy", "blank") return } const text = prompt("ツイートのURLを入力してください") if (text === null) return const gyazoClientId = "e2bd725244baa768eb100126fa2cd85910445778a25ba7ef1328608750b070d5" const tweetcard = "https://tweet2image.vercel.app" const m = text.match(/(twitter|x).com\/(.+)\/status\/(\d+)/) if (!m) { alert("無効な形式のURLです") return } const tweetAuthor = m[2] const tweetId = m[3] let imageData // 進捗表示エリア const progressArea = document.createElement("div") progressArea.style = "position: fixed; top: 0; right: 0; margin: 1rem; padding: 1rem; background: #FFF; color: 000; z-index: 9999;" progressArea.innerText = "ツイートの画像を取得中..." document.body.appendChild(progressArea) try { const tweet2imageUrl = `${tweetcard}/${tweetId}.jpg` console.log(tweet2imageUrl) const req = await window.get_tweet_card(tweet2imageUrl) if (req.status !== 200) { alert("Image fetch failed(!=200)") return } imageData = req.response } catch (e) { console.error(e) alert("ツイート画像の取得に失敗しました") document.body.removeChild(progressArea) return } const tweetUrl = `https://twitter.com/${tweetAuthor}/status/${tweetId}` // upload to gyazo try { progressArea.innerText = "Gyazoをチェックしています" let token = window.gyazoOAuthToken if (!token) { const project = await fetch( `https://scrapbox.io/api/projects/${scrapbox.Project.name}` ) const { gyazoTeamsName } = await project.json() if (gyazoTeamsName) { alert( "Gyazo Teamsを使ったことがないのでアップロードがおかしくなるかもしれません(可能であればTwitter@ci7lusまで動作確認報告お願いします)" ) } const gyazoOAuthToken = await fetch( `https://scrapbox.io/api/login/gyazo/oauth-upload/token?gyazoTeamsName=${ gyazoTeamsName || "" }`, { headers: { accept: "application/json, text/plain, */*", }, method: "GET", } ) const tokenResult = await gyazoOAuthToken.json() token = tokenResult.token window.gyazoOAuthToken = token } if (token) { progressArea.innerText = "Gyazoにアップロードしています…(OAuth)" const formData = new FormData() formData.append("access_token", token) formData.append("referer_url", tweetUrl) formData.append("title", tweetUrl) formData.append("imagedata", imageData) const upload = await fetch("https://upload.gyazo.com/api/upload", { headers: { accept: "application/json, text/plain, */*", }, referrerPolicy: "same-origin", body: formData, method: "POST", mode: "cors", credentials: "omit", }) const { permalink_url } = await upload.json() console.log(`${tweetUrl} -> ${permalink_url}`) insertText({ text: `[${permalink_url} ${tweetUrl}]` }) } else { progressArea.innerText = "Gyazoにアップロードしています…(EasyAuth)" const imageB64Data = await new Promise((res, rej) => { const reader = new FileReader() reader.onerror = rej reader.onload = () => { res(reader.result) } reader.readAsDataURL(imageData) }) const formData = new FormData() formData.append("client_id", gyazoClientId) formData.append("referer_url", tweetUrl) formData.append("imagedata", imageB64Data) const easyAuth = await fetch( `https://upload.gyazo.com/api/upload/easy_auth`, { method: "POST", mode: "cors", credentials: "include", body: formData, } ) const uploadResult = await easyAuth.json() const getImage = await fetch(uploadResult.get_image_url, { mode: "cors", credentials: "include", }) progressArea.innerText = "done!" console.log(`${tweetUrl} -> ${getImage.url}`) insertText({ text: `[${getImage.url} ${tweetUrl}]` }) } } catch (e) { console.error(e) alert("アップロードに失敗しました…") } finally { document.body.removeChild(progressArea) } }, })

style.css
a#tweet2image.tool-btn:hover { text-decoration: none; } a#tweet2image.tool-btn::before { position: absolute; left: calc(46px / 3 - 1px); content: "\f099"; font: 21px/46px "Font Awesome 5 Free"; font-weight: 900; }