概要
つぶやき(タイムライン上のノート)のテキストに X(Twitter)のツイートURLが含まれていた場合、<blockquote class="twitter-tweet"> と Twitter の公式ウィジェットスクリプトを使ってツイートを埋め込み表示する機能を追加した。
既存の YouTube 埋め込み機能(extractYouTubeVideoIds / stripYouTubeUrls)と同じパターンで実装した。
背景と目的
これまで、つぶやきにツイートの URL を貼り付けても単なるテキストとして表示されるだけだった。ツイートの内容を確認するには URL を開く必要があった。
この機能により、タイムライン上でツイートをインラインで読めるようになった。
実装内容
対応する URL の形式
以下の形式の URL を自動検出する:
https://twitter.com/{username}/status/{tweetId}https://x.com/{username}/status/{tweetId}
追加した関数と変数
YouTube 埋め込みと同じ設計パターンで、以下の3要素を実装した。
extractXTweetUrls(text)
テキスト中の X/Twitter ツイート URL をすべて抽出して返す。クエリパラメータやフラグメントは除去し、https://twitter.com/{user}/status/{id} の正規形に統一する。ツイート ID は数字のみ(最大20桁)に制限する。
stripXUrls(text)
テキストから X/Twitter URL をすべて除去した文字列を返す。埋め込みが成功した URL をテキスト中に重複して表示しないための処理。
isEmbedOnly
YouTube URL と X/Twitter URL をすべて除去した後のテキストが空かどうかを判定するフラグ。true のときはつぶやきのテキスト枠を表示せず、埋め込みのみを表示する。
なお、YouTube 埋め込みに使っていた isYouTubeOnly は、この isEmbedOnly に統合して廃止した。X と YouTube が混在する投稿でも正しく動作する。
表示の仕組み
<blockquote class="twitter-tweet" data-theme="dark" data-dnt="true">
<a href="{tweetUrl}"></a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
X の公式ウィジェット(platform.twitter.com/widgets.js)が blockquote をインタラクティブなカードに変換する。ウィジェットスクリプトは、ツイート埋め込みが存在するページにのみ条件付きで挿入する。
data-dnt="true" を指定してトラッキングをオプトアウトする。
変更したファイル
src/components/TimelineItem.astro— タイムライン上の表示(ダークテーマ)src/pages/notes/[id].astro— 個別ページの表示(ライトテーマ)
個別ページは白背景のため data-theme="light" を指定している。
セキュリティ対策
ツイート ID の厳密な検証
URL から抽出したツイート ID を <blockquote> の href に設定する前に、数字のみ(最大20桁)であることを正規表現で検証する。これにより、URL に細工された文字列がそのまま DOM に流れ込むことを防ぐ。
if (/^\d{1,20}$/.test(tweetId)) {
urls.push(`https://twitter.com/${match[1]}/status/${tweetId}`);
}
ユーザー名の長さ制限
URL パターンのユーザー名部分を \w{1,50} に制限し、異常に長い文字列でのマッチを防ぐ。
クエリパラメータの除去
?s=21 などのトラッキングパラメータが付いたツイート URL も正規形(パラメータなし)に正規化してから出力する。
テキスト表示の仕様まとめ
| 投稿内容 | テキスト枠 | 埋め込み |
|---|---|---|
| テキストのみ | 表示 | なし |
| テキスト + YouTube URL | URL 省略して表示 | YouTube |
| テキスト + X URL | URL 省略して表示 | X ツイート |
| YouTube URL のみ | 非表示 | YouTube |
| X URL のみ | 非表示 | X ツイート |
| YouTube + X URL のみ | 非表示 | YouTube + X ツイート |
URL のみの投稿でテキスト枠を非表示にする処理は、YouTube 埋め込みの実装時に導入した isYouTubeOnly フラグを発展させて isEmbedOnly に統合した。