scrapbox-embed-tweet
twitterのtweet URLから直接scrapbox用の引用テキストを作るPopupMenu
/kn1cht/embed-tweetの改良版
install方法
code:import.js
import '/api/code/takker/scrapbox-embed-tweet/script.js';
他人のprojectからimportするのは安全上問題があるので、codeをコピペすることをおすすめします
その際ファイルパスを適宜変更して下さい
それからこのUserscriptをTamperMonkeyにinstallして下さい
使い方
tweet URLを含んだ文を選択して、PopupMenuのボタンを押すと変換される
https://gyazo.com/9056568ab97b86fe33ee30fe1e9a49ef
URLが複数入っていたときは、その全てを変換する
変換形式はscrapbox-embed-tweet#5fceff1b1280f00000ca7c8fをいじると変えられる
既知の問題
/icons/done.icon末尾についている?s=20などのURL parameterを除去できない
?s=\d+にだけ即席で対応しておいた
他のURL parameterは無理
類似UserScript
/kn1cht/embed-tweet
参考にしたscript
TamperMonkeyが不要な代わりに、埋め込み用HTMLを毎回手動で取得しなくてはならない
/ci7lus/tweet-card-upload-3
テキストではなくtwitterのscreenshotを貼り付けるscript
本UserScriptと同様、TemperMonkeyを使って外部APIを叩きにいっている
2021-06-12
12:34:35
/programming-notes/scrapbox-embed-tweet#60c3f4c7e5172d000067db25を反映した
revertscrapbox-embed-tweet#60be5b951280f00000678928
2021-06-08
02:46:58 取得した埋め込み用HTMLに<a>や<br>が見つからないときとエラーになってた
2021-05-26
15:02:24
libraryのupdate
tweet URLが無い時はボタンを非表示にする
UserScript
code:script.js
import {insertText} from '../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) ?
'\uf081' : // 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(matches0)? matches0 : '';
const content = /^\s+$/.test(matches0)? matches1 : matches0;
console.log(indent,content);
return convertWholeText(content, indent)
})).then(lines => insertText(lines.join('\n')));
// 入力しやすいよう選択範囲を先に消しておく
return '';
},
});
tweet情報を整形して返す
code: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 (!tweetsi) break;
maporiginalUrl= tweetsi;
}
//console.log(map);
const result = text.replace(tweetRegExp, match => mapmatch ?? match);
//console.log(result);
return result;
}
引用の形を決めるところ
この関数をいじってお好みのformatにしてください 
code:convert.js
function convert({tweetInfo, indent}) {
return [...tweetInfo.content.map(text => ${indent}> ${text}),
${indent}> \t${tweetInfo.signature}[${tweetInfo.date.href} ${tweetInfo.date.text}]].join('\n');
}
tweet取得処理
code:getTweetInfo.js
export async function getTweetInfo({tweetUrl} = {}) {
if (!window.getTweetInfo) {
alert('Please install "getTweetInfo" from https://scrapbox.io/api/code/takker/scrapbox-embed-tweet/temperMonkey.js');
return;
}
try {
const tweet = await window.getTweetInfo(https://publish.twitter.com/oembed?url=${tweetUrl})
.then(req => req.response);
// 埋め込み用HTMLを解析する
const dummy = document.createElement('div');
dummy.insertAdjacentHTML('beforeend', tweet.html);
console.log(tweet.html);
// <blockquote>を取得
const blockquote =dummy.getElementsByTagName('blockquote')?.0;
// 要素に分解
const contentDOM, signatureDOM, dateDOM = ...blockquote?.childNodes;
// tweet本文をscrapbox記法に変換
...contentDOM?.getElementsByTagName('a')
?.forEach?.(link => link.innerHTML = [${link.href} ${link.textContent}]);
...contentDOM?.getElementsByTagName('br')
?.forEach?.(br => br.innerHTML =\n);
// 各種情報を詰め込んで返す
return {
author: {
name: tweet.author_name,
url: tweet.author_url,
},
content: contentDOM?.textContent.split('\n'),
signature: signatureDOM?.textContent,
date : {
href: dateDOM?.href,
text: dateDOM?.textContent,
},
};
} catch(e) {
console.error(e);
}
}
TemperMonkeyに貼り付けるコード
url-info-proxyをコピペして少しいじった
code:temperMonkey.js
// ==UserScript==
// @name twitter-info-proxy
// @namespace https://scrapbox.io
// @version 0.1.1
// @description fetch the information of a tweet
// @author takker
// @match https://scrapbox.io/*
// @connect publish.twitter.com
// @grant GM_xmlhttpRequest
// @license MIT
// @copyright Copyright (c) 2020 takker
// ==/UserScript==
"use strict"
unsafeWindow.getTweetInfo = (url) => {
const u = new URL(url)
if (!'publish.twitter.com'.includes(u.hostname)) {
throw Error("unexpected url!")
}
return new Promise((r) => {
GM_xmlhttpRequest({
method: "GET",
url,
onload: (res) => r(res),
withCredentials: true,
responseType: "json",
})
})
};
scrapbox-embed-tweet実装案
#2021-06-12 12:34:29
#2021-06-08 02:46:43
#2021-05-26 15:03:42
#2021-01-17 10:35:42
#2021-12-08
#2020-11-14 15:25:27