📝
Nostrの投稿を取得して自サイトで時系列順に並べてみる
更新履歴
2023/2/10 <script>
のsrc
をCDNのリンクに変更
筆者について
pubkey: npub1tcrsspumwynmtp80r9aezp9dzwy4m079xkauccvfvx74fgegaxtsylxlgc
完成したデモ(雑)
ihasq.com/nostr-posts-viewer にあります
深夜に意識朦朧としながら書いたのでかなり杜撰です
実装内容
・Hexに変換したユーザIDで複数リレーから投稿を取得
・取得した投稿を時系列順に並び替えて表示
index.html
<body>
<div class="container">
<header>@ihasq's trackable latest nostr posts:<br></header>
</div>
<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
<!-- nostr-toolsはcdnにもある -->
<script src="main.js"></script>
</body>
main.js
const container = document.querySelector(".container");
// 複数リレーから非同期に取得する場合はpool()を使う
const pool = window.NostrTools.pool();
// poolに登録するurl一覧
const relays = [
"wss://relay.snort.social",
"wss://relay.nostr.bg",
"wss://nos.lol",
"wss://nostr.fmt.wiz.biz",
"wss://nostr.wine"
];
let postIdList = [];
let postIdPast = [];
let postDatePast = [0];
let postDOM = [];
let clear = 0;
relays.forEach(async url => {
let postIdListBuffer = [];
// 複数リレーに繋ぐにはensureRelay()メソッドが必要らしい
let relay = pool.ensureRelay(url);
// 以下通常通り
await relay.connect();
relay.on('connect', () => {
console.log(`connected to ${relay.url}`)
});
relay.on('error', () => {
console.log(`failed to connect to ${relay.url}`)
});
let sub = relay.sub([
{
"authors": ["5e0708079b7127b584ef197b9104ad13895dbfc535bbcc618961bd54a328e997"],
"kinds": [1]
}
]);
let postCreatedDate = [0];
sub.on('event', event => {
postIdListBuffer.push(event);
});
sub.on('eose', () => {
sub.unsub()
// EOSEしたリレーが半数を超えるまでとにかく送りまくる
if(clear <= relays.length / 2)contract(postIdListBuffer);
});
});
// forEach asyncから受け取ったコンテンツリストをとりあえずconcat()しておく
const contract = buffer => {
postIdList = postIdList.concat(buffer)
clear++;
// リレーの半数以上がEOSEした瞬間に締め切ってソート処理を開始
if(clear > relays.length / 2){
console.log(postIdList)
postIdList.forEach(e => {
// idで重複していないか確認
if(!postIdPast.includes(e.id)){
postIdPast.push(e.id)
postDOM.push(e)
postDatePast.push(e.created_at)
}
})
postIdPast = [];
// あらかじめ入れておいた[0]を削除
postDatePast.shift();
console.log(postDatePast)
// created_atで昇順に並び替え
postDatePast.sort((a,b)=> a - b)
let dom, date;
postDatePast.forEach(e=>{
dom = postDOM.find(f => f.created_at === e)
if(!postIdPast.includes(dom.content)){
postIdPast.push(dom.content)
date = new Date(dom.created_at * 1000);
document.querySelector("header").insertAdjacentHTML("afterend",`
<div class="line">
<div class="id">${date.toLocaleDateString()} ${date.toLocaleTimeString()} ID: ${dom.id}<br></div>
${dom.content}<br>
</div>
`)
}
})
}
}
一連の作業を通して得た知識
EOSE
:リレーから送られる「もうこれ以上送るものはないお」という便利なイベント
課題点
・キャッシュせず更新毎に取得するので通信量が馬鹿にならない
Discussion