ふるつき

v(*'='*)v かに

記事をランダムに表示するボタン作った

scrapboxのrandomボタンが好きなのではてなブログでも出したいと思って作った。うまくいっていれば→のサイドバーに出ています。

こういう感じのHTMLを書いて、HTMLモジュールってやつでおいている *1

<button onclick='javascript: fetch("/rss").then(r => r.text()).then(data => { const parser = new DOMParser(); return parser.parseFromString(data, "text/xml") }).then(dom => {const items = dom.querySelectorAll("channel>item"); const item = items[ Math.floor(Math.random() * items.length) ]; location.href = item.querySelector("link").innerHTML; })' style="font-size: 120%; border: none; background: none; cursor: pointer;">🔄</button>

後から考えると関連記事モジュールでも十分な気がする

2022-02-01 追記

id:hogashi さんに「sitemap.xmlというやつを読めば全記事網羅できるよ」ということを教えてもらった。確かにと思ったの sitemap.xml を使うバージョンも作りました。このブログの→のボタンもこちらのロジックを使うように変更した

<button onclick='javascript: fetch("/sitemap.xml").then(r => r.text()).then(data => { const parser = new DOMParser(); return parser.parseFromString(data, "text/xml") }).then(dom => { const locs = dom.querySelectorAll("sitemap loc"); return fetch(locs[Math.floor(Math.random() * locs.length)].innerHTML)}).then(r => r.text()).then(data => { const parser = new DOMParser(); return parser.parseFromString(data, "text/xml") }).then(dom => { const urls = dom.querySelectorAll("url loc"); location.href = urls[ Math.floor(Math.random() * urls.length) ].innerHTML; })' style="font-size: 120%; border: none; background: none; cursor: pointer;">🔄</button>

はてなブログのsitemapは年月ごとに分割されているので、全記事を取ろうとするとこれまでにエントリを書いた月の数だけfetchが走ることになってしまう。それはちょっと嫌なので、まずどのsitemapを使うかをランダムに選んでから、月ごとのsitemapを読んでその中からエントリをランダムに選ぶというロジックにしてみた。これならfetchは2回で済む。

この方法だと、1記事だけ書いた月のエントリに比べて、n ( > 1)記事書いた月のエントリが出現する確率が小さくなってしまって確率に偏りが生まれてしまう。引き続きうそランダムということになってしまうが、 /rss を使っていた時には出現確率0%のエントリが存在していたのに対して、この方法では全てのエントリが0より大きい確率で出現することを考えると、偏りとしては小さくなっているはずなのでこれでよしとした。

ちなみにsitemapにはsitemap_common.xml というのも存在して、ここにはブログのトップページやaboutページへのリンクが載っている。このページを弾くような処理は入れていないので、ランダムに辿っているとこれらのページが出てくることもある。あたりだと思ってください

*1:よくみると/rssの出力を雑にパースしているだけなので真に昔の記事は取れてない。うそランダムです