Twitter(現X)の前後ポストを表示する
by
onk
05/20 [2024/05/20 12:12:37]
個別 Tweet の URL から前後 1 時間の投稿を RT を含めて表示する
/*
* @title Twitter(現X)の前後ポストを表示する
* @description 個別 Tweet の URL から前後 1 時間の投稿を RT を含めて表示する
* @include https://twitter.com/*
* @license MIT License
* @javascript_url
*/
const TWITTER_EPOCH = BigInt(1288834974657);
// 'YYYY-MM-DD_HH:mm:ss'形式で日付をフォーマット
const formatTwitterDate = (date) => {
const pad2 = (n) => n.toString().padStart(2, '0');
const year = date.getFullYear();
const month = pad2(date.getMonth() + 1);
const day = pad2(date.getDate());
const hour = pad2(date.getHours());
const minute = pad2(date.getMinutes());
const second = pad2(date.getSeconds());
return `${year}-${month}-${day}_${hour}:${minute}:${second}`;
}
// Snowflake ID 文字列を受け取り、前後 60 分の since, until を返す
const getSearchRange = (snowflakeStr) => {
const snowflake = BigInt(snowflakeStr);
// 41 bits: millisec from TWITTER_EPOCH
// 10 bits: worker_id
// 12 bits: sequence number
// なので 22 bit 右シフトする
const timestamp = Number((snowflake >> BigInt(22)) + TWITTER_EPOCH);
return {
since: formatTwitterDate(new Date(timestamp - 60 * 60 * 1000)), // 60 分前
until: formatTwitterDate(new Date(timestamp + 60 * 60 * 1000)), // 60 分後
};
}
const main = () => {
const match = location.href.match(/https:\/\/twitter\.com\/(?<name>[^/]+)\/status\/(?<snowflake>\d+)/);
if (!match) {
alert('このページは Twitter の個別 Tweet ではありません');
return;
}
const range = getSearchRange(match.groups.snowflake);
const query = `from:${match.groups.name} since:${range.since} until:${range.until} include:nativeretweets`;
location.href = `https://twitter.com/search?f=live&q=${encodeURIComponent(query)}`;
}
main();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。