{
  "ogp": {
    "url": "https://assets.st-note.com/production/uploads/images/124849191/rectangle_large_type_2_285e871a111d0c06567c04c21fc2b9a6.png?width=800",
    "width": 800,
    "height": 419
  },
  "$type": "com.whtwnd.blog.entry",
  "blobs": [
    {
      "name": "1702819170953-qc4jIdquzb.png",
      "blobref": {
        "ref": {
          "code": 85,
          "version": 1,
          "hash": {
            "0": 18,
            "1": 32,
            "2": 2,
            "3": 234,
            "4": 156,
            "5": 95,
            "6": 150,
            "7": 157,
            "8": 255,
            "9": 126,
            "10": 58,
            "11": 150,
            "12": 234,
            "13": 115,
            "14": 2,
            "15": 209,
            "16": 110,
            "17": 131,
            "18": 243,
            "19": 160,
            "20": 185,
            "21": 114,
            "22": 141,
            "23": 197,
            "24": 50,
            "25": 175,
            "26": 38,
            "27": 226,
            "28": 251,
            "29": 112,
            "30": 45,
            "31": 59,
            "32": 184,
            "33": 137
          }
        },
        "size": 67424,
        "mimeType": "image/png",
        "original": {
          "$type": "blob",
          "ref": {
            "$link": "bafkreiac5kof7fu5757dvfxkombnc3ud6oqls4unyuzk6jxc7nyc2o5yre"
          },
          "mimeType": "image/png",
          "size": 67424
        }
      },
      "encoding": "image/png"
    }
  ],
  "theme": "github-light",
  "title": "SNS「Bluesky」のカスタムフィードがいろいろできるので「リツイート直後のツイートを表示するやつ」をつくった話",
  "content": "本記事は[Bluesky Advent Calendar 2023](https://adventar.org/calendars/9443)の[18日目のnote記事](https://note.com/dolciss/n/n90024fcd4132)の複製です。\n\n# はじめに\n私([@l-tan.dolciss.net](https://l-tan.dolciss.net/))がBlueskyにやってきたのは3月の半ば、ちょうどNostrを中心に招待が始まったらしいと見かけて、たまたまTwitterで招待コードを運良くもらうことができました。\n\n当時は多くの技術者の方々によって、さまざまなクライアントがいっせいに作られており、「結局どのクライアントを使えばどの機能が使えるねん」となって、各クライアントの機能比較表的なものを作ったりしておりました。(今もたまに更新してはいますが、新しいクライアントや細かい機能まではさすがに追い切れていないです……)\nhttps://dolciss.notion.site/c03ea75995154731bc17192b340d2427?v=a5a7a90abca34fd897c74b767974dcde&pvs=4\n\nその中でやはりBlueskyの特筆的な機能といえばカスタムフィードでしょう。\n\n# カスタムフィードについて\nという話はアドベントカレンダー内の記事で何度も出てきていますが、シンプルに「ユーザーがカスタマイズできるPostの一覧(タイムライン)」と捉えています。\n\n仕組みとしてはクライアントが「このフィードの内容が欲しい」とサーバーに問い合わせて、サーバーが「フィードのPostの一覧」を返して、クライアントがそのPostを一覧表示するだけです。\n\n## SkyFeedのFeedBuilderの登場\nいくらユーザーがカスタマイズできるとは言っても、そのカスタマイズしたフィードを返すためのサーバが必要でした。そんな中、サードパーティークライアントの1つであるSkyFeedに、サーバー代わりとなるFeedBuilder機能が登場しました。(当時のPostを掘り起こしてみると7月の頭だったっぽい)\nhttps://bsky.app/profile/did:plc:6zpjzzdzet62go7lnaoq4xog/post/3jzvjnjx3ix2e\n\nここでさまざまな条件を指定して登録すると、SkyFeedのサーバーが条件に沿ったフィードを代わりに返してくれます。対象のPostは最大7日間とはいえ全てのPostを検索したりできること、検索に正規表現が使えるなど多機能だったこともあり、急いで解説や設定項目一覧を書いたりもしました。\nhttps://scrapbox.io/Bluesky/SkyFeed%E3%81%AEFeed_Builder%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%95%E3%82%A3%E3%83%BC%E3%83%89%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8B\n\n## よりシンプルなgoodfeedsも\nSkyFeedとほぼ同時期だったと思うのですが、[goodfeeds](https://track.goodfeeds.co/)というサービスも登場し、こちらは検索ワードを3つまで指定することで、goodfeedsのサーバーが検索結果をフィードとして返してくれます。こちらは自分のアカウントではなく、@track.goodfeeds.coのアカウントに登録される形になります。\n\n# リツイート直後のツイートを表示するやつ\nようやく本題です、海外はなさそうな文化な気がしますが、リプライや引用をすると元投稿者に通知がいくので、リツイートしてその内容について別途ツイートすることがあります。\n\nそこで自分の作品などがリツイートされたときに、そのアカウントを見に行って、なにか感想がつぶやかれていないか探すことがよくあり、それを集めてくれるのが「[リツイート直後のツイートを表示するやつ](https://retweets.pronama.jp/)」でした。\n\nでした、というのは件のTwitterAPIの仕様変更によりサービスが終了(休止)してしまい……ちなみにMisskey/Calckey向けに同様の「[creasky](https://creasky.net/note_after_renote/)」(リノート直後のノート表示)というのもあります。\n\n## リポスト直後のポストが流れてくるフィード\nそのリツイート直後のツイートを、カスタムフィードで実現できないかと考えて作ったのが「リポスト直後のポストが流れてくるフィード」、さすがに長かったので短く「[RepostNextPost](https://bsky.app/profile/did:plc:6zpjzzdzet62go7lnaoq4xog/feed/rp-next-post)」です。\n\nリツイート直後のツイートは(動作から推察ですが)指定されたツイートをリツイートしているユーザーのツイートをリツイート時まで取得し、直後のツイートを拾っているようです。\nですが今回はフィード購読者のPostからリポストした人を……というのも大変なので、[公式のフィードジェネレーター](https://github.com/bluesky-social/feed-generator)の仕組みを使いました。\n\n素のサンプルでは、BGS(今はRelay)からPostの情報をリアルタイムに受け取って、必要なPost(”alf”と含まれているもの)をデータベースに記録し、それをクライアントに返すようになっています。\nこのリアルタイムに受け取れる情報にはRepostやLikeも一緒に流れてくるので、これを利用することで実現しました。\n\n## 実際の流れ\n1. まずカスタムフィードを見た人(購読者)を覚えておく\n2. 購読者のPostがリポストされたらリポストした人を覚える\n3. リポストした人が通常のPostをしたらそれを購読者のリポスト直後のポストとして記録、それ以外の別リポストやリプライの場合は覚えたものを忘れる\n4. 購読者が再度カスタムフィードを見たら、記録したリストを返してあげる\n\nという感じで、もうちょっとうまいことできるやろと思いつつ、愚直にコードを書いたら動いたのでそのままだったり……\n\nちなみに当初試行錯誤していたのが次の図です(このときは一定時間経ったら流石に別の話題でしょとかも考えていたけれど実装していません)\n![RepostNextPostの流れ図](https://inkcap.us-east.host.bsky.network/xrpc/com.atproto.sync.getBlob?did=did:plc:6zpjzzdzet62go7lnaoq4xog&cid=bafkreiac5kof7fu5757dvfxkombnc3ud6oqls4unyuzk6jxc7nyc2o5yre)\n\n詳しくは、雑ではありますがソースコードをGitHubに置いてありますので、こちらを参照……あともし私が途絶えた場合にはこちらをお使いください。(2024/02/08 リポジトリ名を変えたので修正)\n\nhttps://github.com/dolciss/rp-next-post\n\n(2024/02/08 追記)\nもとのリポストも含まれる[RepostNextPost+](https://bsky.app/profile/did:plc:6zpjzzdzet62go7lnaoq4xog/feed/rp-next-post-p)もあります\n\nただし公式など「フィード内の同じPostに対するRepostは最新(最古)のみ表示」しているクライアントでは個々にRepostが挟みこまれないため、リポストをまとめない[TOKIMEKI](https://tokimeki.blue/)・[SkyFeed](https://skyfeed.app/)・[Graysky](https://graysky.app/)・[Skychat](https://skychat.social/)・[Ucho-ten](https://ucho-ten.net/)あたりのクライアントをお使いください。\n\n# さいごに\nこのカスタムフィードで、すこしでもお力添えできれば幸いです。みなさまよいBlueskyライフを!",
  "createdAt": "2024-06-01T06:28:28.498Z",
  "visibility": "public"
}