【脱Xがんばる2026】Xで作成したリストをRSS化しObsidian上でTLのように閲覧する

Diaryobsidian

表題の通りです。

X、嫌ですよね。嫌という前提で話を進めます。毎年思うんですよ、今年こそは脱Xをしたいなと。
難しい理由はごまんとありますが私の場合は大きく3つ。

理由1:小説を書いており、告知をする必要があるので完全にやめることは難しい
理由2:おすすめ欄を無限に眺めてゾンビ化してしまう
理由3:結局みんなblueskyやその他のSNSに来てくれない

理由1については→告知はしゃーないので、告知だけは続ける
理由2については→Xそのものを開かないように習慣づけることで解決できそう
理由3については→今回の記事で行った方法である程度みんなの情報をXを見ずにして得ることが可能になる

って感じです。

また、私の場合はXの他にFedibirdとBlueskyとThreads(Instagram)とmixi2にアカウントを持っていますが、Xほど困っていません。
Fedibird→小説仲間がたくさんおり、投稿もすぐ追えるレベルのフォロー数なので時間泥棒感が少ない
Bluesky→上に同じ。あと、あんまり私にとって魅力的なポストは少ないのでまだなんとかなっている
Threads→メタがあんま好きじゃないしInstagramに疎いのでリール動画を延々と観るみたいなことが起こらない
mixi2→本当に限られた友人のみのつながりなのでTLがゆるやかだし困らない

……ということで、Xさえなんとかできれば今年はSNSに割く時間をだいぶ抑えられるなと考えました。
私は最近、Obsidianを自分のホームとして活用しているので理想はこれです。全てをObsidian上で完結させたい……。

「Obsidian上にXの追いたいアカウントのみのTLを疑似的に再現して、X上ではなくObsidian上で投稿を追う」

こんなことが本当に可能なのか、半信半疑でしたが、Geminiにとりあえず聞いてみたり、ググったりして、目ぼしい記事を見つけました。

RSSHubでXのTLをRSS化(PikaPods利用)|septendec

私が考えていたのは、XのタイムラインをRSS化できれば、Obsidianでいくらでも表示できるよなということでして、とりあえずXのTLをRSS化する記事を探しまくっていたらこの記事に辿りつきました。
なるほど、RSSHubというものがあるのか……と、この通りにやってみたものの、沼りました。
何回やっても404 not found。Geminiに聞いてみると、どうもXのアクセストークンを使用しているのが本当に本人か分からないからとX側で勝手にブロックされているっぽかったです。これはマジでどうにもならず。なるほど不審なアクセスと思われているわけか……どうにかならんもんかな、と思っていた矢先、Geminiがこんな提案をしてくれました。

私はほぼ毎日PCを使います。RSSHubにlocalhostからアクセスすれば、どう考えても本人なので弾かれるリスクが格段に減ります。じゃあこれでええやんけ、がんばってPikapodsとかVercelとかいじらんでよかったんや!
さっそく、やっていきます。

(Macでの話なので、Winではまたやり方微妙に違うと思いますが、あくまで私が試した方法を記しますね)


用意するもの
・Docker Desktop
・RSShubのセットアップ
・Xのアカウントと、そのアカウントで作成したリスト(非公開でOK)
・RSSフィード(私は結局、自分でスクリプトを組んで、後述するようにObsidian上にTLを再現してみました。RSSフィードあれば1投稿を1記事として拾ってくれるはずです)

てか、あとから知ったんですがこの記事に私のやったことがまんままとまっていたのでこれ参考にしてください。私の素人記事読むより多分有益。


SNSでの情報収集は誘惑が多くて大変、それRSSでやってみませんか?

Docker準備できたらターミナルにこれ打ち込みます。

docker run -d --name rsshub -p 1200:1200 \
  -e TWITTER_AUTH_TOKEN='あなたのトークン' \
  -e TWITTER_COOKIE='auth_token=...; ct0=...' \
  -e HTTP_BASIC_AUTH_NAME='admin' \
  -e HTTP_BASIC_AUTH_PASS='password123' \
  diygod/rsshub:latest

トークンというのは、Chromeなどで自分のXアカウントを開き、そのページでデベロッパーツールを開けばわかります。


Cookiesにauth_tokenとct0の値があるので、それをコピペしてください。

HTTP_BASIC_AUTH_NAME=’ここは好きに決めてOK’
HTTP_BASIC_AUTH_PASS=’これも好きに決めてOK’
TWITTER_COOKIE=’auth_token=ここにauth_tokenの値を入れる; ct0=ここにct0の値を入れる’
TWITTER_AUTH_TOKEN=’ここにauth_tokenの値を入れる’

テストをします。自分のPCでブラウザからこのリンクを開いて、ページが表示されたら成功です。自分の投稿を拾っているっぽかったら上手くいっています。
http://localhost:1200/twitter/user/自分のXアカウントのID

ただし、このリンクからは自分のツイートしか取得できないので、リストからツイートを取得するリンクをつくる必要がありますね。それがこちら。

http://localhost:1200/twitter/list/リストID

これで、X上で特定のリストに入れた人の投稿を追うことの出来る、あなた(のPCから)しか使えないリンクの完成です。リストIDは、ブラウザでリストを表示したときに出てくるURLの末尾の番号です。

Geminiからのありがたいお言葉も、シェアー。

あとは、各々好きにRSSフィードなどで情報を得ればいいと思いますが、いくつかTipsを。
・リストは非公開で大丈夫。
・Xの当該アカウントを一度ログアウトすると、トークンが変わりますのでご注意を。ログアウトしたらトークン設定しなおす必要があります。
・鍵アカウントは、おそらく自分がフォローしているアカウントであればツイートは表示されます。フォローしていないやつは流石に無理ちゃうかな(試してない)。

私の場合は、Obsidianにてこのような仕様でTLのログをとることにしました。


・「Twitter_Archive」というフォルダを作成し、そのなかに一日分のTLを溜める「Twitter_yyyy-mm-dd.md」というファイルを作成していく。→Templaterでスクリプトを作成
・Obsidianを起動した際にそのスクリプトが実行されるように設定。
・画像はリンクのみ(元ツイートが消えたら画像も消える)取得して表示。
・テキストのみで比較的メモリを食わないので、一旦ぜんぶアーカイブしてみる。

Templatesを溜めているフォルダに新しく「Twitter_Auto_Collector.md」を作成。
中身↓

<%*
// --- 設定項目 ---
const rssUrl = "http://localhost:1200/twitter/list/自分のリストのID";
const folderPath = "Twitter_Archive"; 

const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const fileName = `Twitter_${dateStr}.md`;
const filePath = `${folderPath}/${fileName}`;

async function fetchAndCreate() {
    const folder = app.vault.getAbstractFileByPath(folderPath);
    if (!folder) await app.vault.createFolder(folderPath);
    if (app.vault.getAbstractFileByPath(filePath)) return;

    try {
        const response = await requestUrl({ url: rssUrl });
        const text = response.text;
        const parser = new DOMParser();
        const xml = parser.parseFromString(text, "text/xml");
        const items = xml.querySelectorAll("item");
        
        if (items.length === 0) return;

        let fileContent = `---\ntype: twitter-log\ndate: ${dateStr}\n---\n\n# Twitter Timeline (${dateStr})\n\n`;
        
        items.forEach(item => {
            // --- ユーザー名の抽出ロジック ---
            // RSShubは通常 "User Name: content" という形式のtitleか、authorタグを持っています
            const rawTitle = item.querySelector("title")?.textContent || "";
            const author = item.querySelector("author")?.textContent || item.querySelector("dc\\:creator")?.textContent || "";
            
            // タイトルが "Name: content" 形式なら ":" より前を取得、なければauthorを使用
            let userName = author || rawTitle.split(":")[0] || "Unknown";
            
            const description = item.querySelector("description")?.textContent || "";
            const link = item.querySelector("link")?.textContent || "";
            const pubDateStr = item.querySelector("pubDate")?.textContent || "";
            const pubDate = new Date(pubDateStr).toLocaleString("ja-JP");

            fileContent += `<div class="tweet-card">
    <div class="tweet-header">@${userName}</div>
    <div class="tweet-content">${description}</div>
    <div class="tweet-footer">
        <a href="${link}">${pubDate}</a>
    </div>
</div>\n\n`;
        });
        
        await app.vault.create(filePath, fileContent);
        new Notice(`Twitterログを更新しました`);
        
    } catch (e) {
        console.error(e);
    }
}

setTimeout(() => {
    fetchAndCreate();
}, 3000); 
%>

あと、見た目をTLっぽくするためにcssスニペットを追加します。

twitter-style.cssの中身↓

.tweet-card {
    border: 1px solid var(--background-modifier-border);
    border-radius: 10px;
    padding: 12px;
    margin: 10px 0;
    background-color: var(--background-primary-alt);
}
.tweet-header {
    font-weight: bold;
    color: #1da1f2; /* Twitter(X)っぽい青色 */
    font-size: 1.0em;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--background-modifier-border);
    padding-bottom: 4px;
}
.tweet-content {
    font-size: 1em;
    line-height: 1.5;
}
.tweet-content img {
    border-radius: 8px;
    margin-top: 8px;
    display: block;
    
    /* 比率維持のための設定 */
    width: auto;           /* 横幅を自動(元画像の比率)に */
    max-width: 100%;       /* 枠からはみ出さないように */
    height: auto;          /* 高さも自動に */
    object-fit: contain;   /* 枠内に収める */
}

/* 引用ツイート(rsshub-quote)内の画像も同様に修正 */
.rsshub-quote img {
    width: auto;
    max-width: 100%;
    height: auto;
    border-radius: 4px;
}
.tweet-footer {
    font-size: 0.8em;
    color: var(--text-muted);
    margin-top: 8px;
}


Templaterの設定画面で、Startup templatesにTwitter_Auto_Collector.mdを追加。
Obsidianを再起動すると、無事にTLが完成しました!!!!

画像もこの通り綺麗に表示されます。
私の技術的な限界もありますが、この表示形式の良いところは「アイコンが表示されない」ところかなと思っていて、必要以上にアテンションを喚起されず、追いたいフォロワーのツイートだけを淡々と確認することができるようになりました。

まだ作ったばっかりで仕様をいろいろ確認しているところですが、同じ日に複数回Obsidianを再起動してもその日の「Twitter_yyyy-MM-dd.md」が既に存在する場合はアップデート等はしてくれないっぽいです。一旦ファイルを消して、再起動をかければ新しく「その時間までのツイート」を読み込んだ新しいファイルをつくってくれます。
あと、どのくらい前までのツイートを読みとってくれるのかもまだよく分かっておらず、明日以降試してみて、同じツイートが複数回取得されているようだったらまた対策を考えようかなと思っていますが、基本的にさほどツイートがだぶって取得されても困りはしない気がするので放置するかも。

これで、他SNSにいないのでXに行かないと投稿を確認できなかった人たちの情報を、Xに直接アクセスせずに得られるようになりました。この調子で、今年はXを見る頻度を減らしていきたいと思います。告知はもちろんしますが、なるべくメインで呟くSNSもBlueskyやFedibirdなどに移行していきたい感じです。
Xにアカウントを残したままにする必要はありますが、脱Xをゆるっとやりたい方は試してみては。

ありがとうございました。