generated at
scrapbox-embed-tweet
Xになってから定期的にTweet埋め込みが死ぬようになったのでしばらく借りる
公式フォーマットに近づけた
画像はまだよくわからない

scrapbox-url-customizerが上位互換なので置き換えた


script.js
import {insertText} from '/api/code/takker/scrapbox-insert-text-2/script.js'; import {convertWholeText} from '../scrapbox-embed-tweet/convert.js'; scrapbox.PopupMenu.addButton({ title: text => /https:\/\/twitter\.com\S+\/status\/\d+/.test(text) ? 'X' : // Font Awesomeでないと文字化けします '', onClick: text => { if (!/https:\/\/twitter\.com\S+\/status\/\d+/.test(text)) return; // URLがなければ何もしない Promise.all(text.split('\n').map(line => { const matches = line.match(/^\s+|.*/g); const indent = /^\s+$/.test(matches[0])? matches[0] : ''; const content = /^\s+$/.test(matches[0])? matches[1] : matches[0]; console.log([indent,content]); return convertWholeText(content, indent) })).then(lines => insertText(lines.join('\n'))); // 入力しやすいよう選択範囲を先に消しておく return ''; }, });

convert.js
import {getTweetInfo} from '/api/code/takker/scrapbox-embed-tweet/getTweetInfo.js'; // 複数のURLを含んだテキストをまとめて変換する export async function convertWholeText(text,indent) { const tweetRegExp = /https:\/\/twitter\.com\S+\/status\/\d+(?:\?s=\d+)?/g; const urls = text.match(tweetRegExp) ?? []; if (urls.length === 0) return undefined; const tweets = (await Promise.all(urls.map(url => getTweetInfo({tweetUrl: url})))) .map(tweetInfo => convert({tweetInfo,indent,})); console.log(tweets); let map = {}; for (const originalUrl of urls) { const i = urls.indexOf(originalUrl); if (!tweets[i]) break; map[originalUrl]= tweets[i]; } //console.log(map); const result = text.replace(tweetRegExp, match => map[match] ?? match); //console.log(result); return result; }

convert.js
function convert({tweetInfo, indent}) { return [...tweetInfo.content.map((text, i) => { if(i===0) return `${indent}> [${tweetInfo.author.name} ${tweetInfo.date.href}]: ${text}` return `> ${text}` } )].join('\n'); }