generated at
URLを外部リンク記法に変換するUserScript (TamperMonkeyなし)
hr
URLを外部リンク記法に変換するUserScript
scrapbox-url-customizer-2とは違って、TamperMonkeyなしで実行できる
mobileでURLを外部リンク記法に変換するPage menuから変換部分のみを抜き出した

対応している機能
URLを外部リンク記法に変換する
api/embed-text/urlを使っている
Tweetを展開する
api/embed-text/twitterを使っている

限界
UTF-8以外の文字コードは文字化けする
api/embed-text/urlの実装の問題
Nota側で実装を直してもらう以外解決方法がない
scrapbox-url-customizer-2だとだいたい対応している
2022-03-03 12:23:32 ひらめいた。2重でproxy serverを経由するのはどうだ?
URLをparameterにつけてアクセスすると、そのページのタイトルを <title> にしてHTMLを返すserver
これをapi/embed-text/urlで取得する
2022-06-19 17:24:30 でもこんなことするくらいなら、直接Scrapboxのコードに手を加えたほうが早いよなあtakker

2022-06-19
18:23:34
URLが見つからないときは即座に処理を終了する
hasURL を追加した

$ deno check --remote -r=https://scrapbox.io "https://scrapbox.io/api/code/takker/URLを外部リンク記法に変換するUserScript_(TamperMonkeyなし)/mod.ts"
mod.ts
import { useStatusBar } from "../scrapbox-userscript-std/dom.ts"; import { getWebPageTitle, getTweetInfo } from "../scrapbox-userscript-std/rest.ts"; import type { TweetInfo } from "../scrapbox-jp%2Ftypes/rest.ts"; const checkRegExp = /(https?:\/\/\S+)/; export const hasURL = (text: string): boolean => checkRegExp.test(text); export const convert = async (text: string): Promise<string> => { if (!hasURL(text)) return text; const { render, dispose } = useStatusBar(); render( { type: "spinner" }, { type: "text", text: "convert URLs..."}, ); let count = 0; try { const result = await Promise.all( text.split(checkRegExp).map(async (fragment) => { if (!/^https?:\/\/\S+/.test(fragment)) return fragment; let url: URL; try { url = new URL(fragment); } catch(e: unknown) { if (e instanceof TypeError) return fragment; throw e; } if (isTwitterURL(url)) { const result = await getTweetInfo(url); if (!result.ok) return fragment; count++; return formatTweet(url, result.value); } const result = await getWebPageTitle(url); if (!result.ok) return fragment; count++; const title = result.value .replace(/\s/g, " ") // スペースと改行を全て半角スペースにする .replaceAll("[", "[") .replaceAll("]", "]"); return `[${url} ${title}]`; }) ); render( { type: "check-circle" }, { type: "text", text: `Converted ${count} URLs.`}, ); return result.join(""); } catch(e: unknown) { render( { type: "exclamation-triangle" }, { type: "text", text: e instanceof Error ? `${e.name} ${e.message}` : `Unknown error! (see developper console)`, }, ); console.error(e); throw e; } finally { setTimeout(() => dispose(), 1000); } };

Tweetのformat
assets/index.jsからパクってきた
mod.ts
const isTwitterURL = (url: string | URL) => /^https:\/\/(?:www\.|mobile\.|m\.|)twitter\.com\/([A-Za-z0-9_]*)\/(?:status|statuses)\/\d+/.test(url.toString()); const escapeForEmbed = (text: string) => text .replace(/\b/gm, "") .replace(/[\s\r\n\u2028\u2029]+/gm, " ") .replace(/\s*[[\]`]\s*/g, " ") .trim(); const formatTweet = (url: URL, tweet: TweetInfo) => [ `[${escapeForEmbed(tweet.screenName)}(@${escapeForEmbed(tweet.userName)}) ${url.origin}${url.pathname}]`, ...tweet.description.split("\n").map((line) => `> ${escapeForEmbed(line)}`), ...(tweet.images.length > 0 ? [`> ${tweet.images.map((image) => `[${image}]`)}`] : []), ].join("\n");

#2023-03-29 17:31:03
#2022-06-19 17:19:16