この記事はtraP 夏のブログリレー 1日目の記事です。俺たちの夏はこれからだ
こんにちは、@d_etteiu8383です。最近は@eyemono.moeと名乗ってます。
本記事では、Node.jsを使ったiCalendarファイルの生成・配信にチャレンジした話をします。
作ったもの:https://nijisanji-streams-ics.pages.dev
にじさんじが多すぎる
2024年6月15日から同25日の十日間にかけて、「にじさんじGTA」と呼ばれるGTAオンラインサーバーが運営されました。その名の通り、にじさんじに所属するライバーのみが参加できるサーバーで、総勢116名ものライバーによる群像劇が展開されました。
このにじさんじGTAにおける全ライバーの全配信アーカイブ784本の総再生時間は5075時間(=211日)にも及びます[1]。1日に14時間観てちょうど1年かかるぐらい。マジで????信じられなくて10回ぐらい数えなおした。マジっぽい。
所属ライバー自体も188名となり(記事執筆時点)、そろそろデレマス登場アイドルを超えてしまうほどの大所帯になっています(VirtuaReal含めるとデレマス超える)。
そんなにじさんじライバーの配信を追いかけるのは大変です。にじさんじ公式からもライブスケジュールが公開されていますが、このページでは各ライバーの配信内容/時刻を確認できるのみで、自分の予定と照らし合わせるには不便です。
そこで、iCalendarファイルを生成してカレンダーアプリにライバーの配信予定を登録できるようにしてみました。
iCalendarファイルとは
iCalendarはカレンダー/スケジュール情報を表現するためのフォーマットです。RFC5545で規定されており、.ics
拡張子を持ちます。
実体はシンプルなテキストファイルで、以下のような内容を持ちます。
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:-//eyemono.moe//NONSGML nijsanji-ics//JA
METHOD:PUBLISH
X-WR-CALNAME:にじさんじ Live Streams
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:01J537YB1YMR7KDD217NN0HPBE
SUMMARY:*. 5周年┊みんなとはじめて話した日ˎˊ˗( 天宮こころ / にじさんじ )
DTSTAMP:20240816T033257Z
DTSTART:20240813T133000Z
DTEND:20240813T152600Z
DESCRIPTION:by 天宮こころ\, at https://www.youtube.com/watch?v=YF4Uwe431yI
URL:https://www.youtube.com/watch?v=YF4Uwe431yI
END:VEVENT
END:VCALENDAR
詳細な仕様については以下の記事が詳しいため、そちらを参照してください。
iCalendarの配信
カレンダーアプリによっては、URLを登録するだけでiCalendarファイルを取得して表示できるものがあります。Googleカレンダーでも「URLで追加」ができますね。
iCalendarの配信側は、単にMIME Typeをtext/calendar
に設定したHTTPレスポンスを返すだけでOKです。
やったこと
- にじさんじ公式のライブスケジュールページから情報を取得
- iCalendarファイルを生成
- Cloudflare Pagesで配信
やっていることはシンプルですが、実際にやってみると何点か詰まるところがありました。
ORGANIZERを設定するときはmailto
を指定する
iCalendarのOrganizerプロパティには、そのイベントの主催者の情報を記述します。
ORGANIZER;CN=John Smith:mailto:jsmith@example.com
上記のように、CN
(=common name)を指定することで主催者名を設定できます。そのため、当初は配信ライバーの名前をここに設定しようとしていたのですが、名前だけを設定したiCalendarファイルを生成した場合、Googleカレンダーでのインポートに失敗するようになってしまいました。別のカレンダーアプリで確認したところ、どうやらパースエラーが発生していたようでした。
改めてRFCを確認するとorganizerは以下のように規定されていました(必要部分のみ記載)
organizer = "ORGANIZER" orgparam ":" cal-address CRLF
cal-address = uri
; The value is a URI as defined by [RFC3986] or any other
; IANA-registered form for a URI. When used to address an Internet
; email transport address for a calendar user, the value MUST be a
; mailto URI, as defined by [RFC2368]. No additional content value
; encoding (i.e., BACKSLASH character encoding, see Section 3.3.11)
; is defined for this value type.
orgparam = *(
;
; The following are OPTIONAL,
; but MUST NOT occur more than once.
;
(";" cnparam) / (";" dirparam) / (";" sentbyparam) /
(";" languageparam) /
;
; The following is OPTIONAL,
; and MAY occur more than once.
;
(";" other-param)
;
)
cnparam = "CN" "=" param-value
; dirparam, sentbyparam, languageparam, other-paramについては省略
organizerに設定できる値にはCalendar User Address(cal-address
)が指定されており、これにはRFC2368で規定されているmailto URIが指定されている必要があったようです。
残念ながらにじさんじライバーのメールアドレスは知らないのでorganizerプロパティは空にしています。
参考:https://zenn.dev/hibikine/articles/a9471dc69ab007
文字コードはUTF-8を指定する
iCalendarのデフォルトの文字セットはUTF-8になっています(3.1.4. Character Set)。最初これに気付かず文字化けホラー配信予定カレンダーが生まれていました。
できたもの
簡単にフロントも作成しました。選択したライバーの配信予定のみを取得できるようになっています。
フレームワークとしてSolidStartを使用しています。
iCalendarファイルの生成にはadamgibbons/icsを使用しています。当初は「ただのテキストファイルだし自分で書けるやろ」と思っていましたが、予想以上に仕様が複雑だったため、結局こちらのライブラリを使用しました。
SolidStartのapi routeを使用し、GET /api/ics
でiCalendarファイルを配信しています。
今回のオチ
これでライバーの配信予定をGoogleカレンダーに取り込むことができるようになりました。
...が、
- にじさんじ公式のライブスケジュールはライバーがYoutubeで立てた枠を取得している
- → ライバーが枠を立てるのが遅いとスケジュールが取得できない
- GoogleカレンダーによるiCalendarファイルの自動更新は1日に1回
つまり、ライバーが配信の1日前には枠を立てておかないと、Googleカレンダーにはその配信予定が反映されないということです。
いかがでしたか?
いかがでしたか?
今回はNode.jsを使ってiCalendarファイルを生成・配信してみました!
残念ながら、予定の確認には不向きであるという結果になってしまいました・・・
明日の夏のブログリレー担当者は@kashiwadeさん, @tatyamさん, @Alt--erさんです。楽しみ~
https://wikiwiki.jp/nijisanji/Grand Theft Autoまとめ/GTA5/にじさんじGTA/配信一覧内に記載のある配信アーカイブの再生時間を加算して得られた値。叶さんについてはTwitchで配信されていましたが、(めんどくさかったので)Youtubeにアップされた切り抜き動画の再生時間を採用しています。再生時間取得に使用したスクリプト:https://gist.github.com/eyemono-moe/3b73f491986dbdfa23824f0f6c50076b ↩︎