generated at
takker99-scrapbox-url-customizer-popup
from popup

takker99/scrapbox-url-customizerを使うボタンをPopupMenuに追加するUserScript

todoこれのようにpopupmenuでまとめたほうがわかりやすいかも

依存

2024/6/16

yosider用tweet format
myTweetFormatter.ts
import { RefTweet, processTweet } from "https://scrapbox.io/api/code/yosider-scripts/takker99%2Fscrapbox-url-customizer/internal.ts"; import { Tweet, TweetViaProxy, stringify } from "https://scrapbox.io/api/code/yosider-scripts/takker99%2Fscrapbox-url-customizer/mod.ts"; export const myTweetFormatter = async ( tweet: Tweet | RefTweet | TweetViaProxy, ): Promise<string> => { if ("images" in tweet) return stringify(tweet); // TODO: why? const { quote, ...processed } = processTweet(tweet); return [ ...(quote ? (await stringify(quote)).split("\n").map((line) => `> ${line}`) : []), ...(await stringify(processed)).split("\n").map((line) => `> ${line}`), ].join("\n"); };

script.ts
import { Scrapbox } from "https://scrapbox.io/api/code/yosider-scripts/scrapbox-jp%2Ftypes/userscript.ts"; import { insertText } from "https://scrapbox.io/api/code/yosider-scripts/scrapbox-userscript-std/dom.ts"; import { convert, convertGyazoURL, convertScrapboxURL, expandShortURL, formatTweet, formatURL, formatWikipedia, Middleware, redirectGoogleSearch, redirectWikiwand, shortenAmazonURL, } from "https://scrapbox.io/api/code/yosider-scripts/takker99%2Fscrapbox-url-customizer/mod.ts"; import { myTweetFormatter } from "https://scrapbox.io/api/code/yosider-scripts/takker99-scrapbox-url-customizer-popup/myTweetFormatter.ts"; declare const scrapbox: Scrapbox; // 毎回functionsを作るのは無駄なので、globalに保持しておく const middlewares: Middleware[] = [ redirectGoogleSearch, expandShortURL, redirectGoogleSearch, redirectWikiwand, shortenAmazonURL, convertScrapboxURL(), convertGyazoURL, formatTweet(myTweetFormatter), formatWikipedia, // code2svgでコードを画像にする (url) => { if (url.hostname === "raw.githubusercontent.com") { return `[https://code2svg.vercel.app/svg/${url.origin}${url.pathname}#.svg ${url}]`; } if (url.hostname !== "github.com") return url; const [user, repo, filepath] = url.pathname.match(/^\/([^\\]+)\/([^\\]+)\/blob\/(.+)$/)?.slice?.(1) ?? []; if (!user || !repo || !filepath) return url; const [, start, end] = url.hash.match(/L(\d+)-L(\d+)/) ?? url.hash.match(/L(\d+)/) ?? []; return `[https://code2svg.vercel.app/svg/${ start && end ? `L${start}-${end}/` : start ? `L${start}/` : "" }https://raw.githubusercontent.com/${user}/${repo}/${filepath}#.svg ${url}]`; }, formatURL(), ]; scrapbox.PopupMenu.addButton({ title: (text) => /https?:\/\/\S+/.test(text) ? "URL" : "", onClick: (text) => { const promise = convert(text, ...middlewares); if (typeof promise === "string") { // 文字列に違いがあるときのみ更新 return text === promise ? undefined : promise; } // 選択範囲に変換後の文字列を上書きする // 変換中に選択範囲が変わると、ずれた位置に挿入されるので注意 promise.then((converted) => { if (text === converted) return; return insertText(converted); }); return undefined; }, });

test

formatTweet.ts "images" in tweet で分岐していて、imagesがある場合はquoteやreplyToを使っていないように見えるが、画像や動画がある場合も正常に引用ツイートや返信先が表示されるのはなぜだろうyosider
"images" in tweetの分岐は、tweetオブジェクトがTweetViaProxy型かどうかを判定するために使われていて、画像や動画の有無によって引用ツイートや返信先の表示を制御しているわけではないclaude
TweetViaProxy型は、/api/embed-text/twitterエンドポイントから取得したツイートオブジェクトを表しており、このオブジェクトにはimagesプロパティがありますが、quoteやreplyToプロパティはありません。
一方、Tweet型やRefTweet型は、takker99/scrapbox-url-customizer/internal/getTweet.ts::getTweet()から取得したツイートオブジェクトを表しており、これらのオブジェクトにはquoteやreplyToプロパティが含まれています。