はじめに
この記事はUEC 2 Advent Calendar 2023の7日目の記事です。
昨日は俵屋宗達さんの記事「言葉で遊ぼうよ リポグラム編」でした!
https://note.com/tawaraya_so618/n/naa1284eaf9ca
リポグラムという言葉自体は知らなかったのに、すごく面白いと思いました。
ある文字を使わないまま文章を書くという言葉あそびは、
日本語の特徴をうまく使うのが凄いと思います。
ちなみにこの部分も「う」と「お」の間の文字の行の母音を使わないまま書きました。
大分難しかったと感じました。
よければ他の記事もご覧ください!
https://adventar.org/calendars/8704
概要
今期にどのアニメを見ているか、何曜日の何時から始まるかを簡単に確認したくなったのがこのサイトを作ろうと思ったきっかけです。
まるで履修登録のような感覚で、アニメを登録することができます。
また、簡単に他人と共有することもできます。
何気にちゃんとした
サイト||ブログ
を作るのはこれが初めてな気がします。
今回この記事では、このサイトを作るにあたってのこだわりポイントや、技術面でがんばったことをまとめていきたいと思います。最後までよろしくお願いします。
こだわりポイント
さっきからこのサイトと何度も言っていますが、なんと、この記事を書いているサイトが今回紹介するサイトそのものなんです。
左上のバツ印を押して右上の戻るボタンを押してみてください。メインページに飛ぶことができます。
よければあなたも好きなアニメを入れてぜひツイート(ポスト)してみてください!
それはそうとして、技術的な話としては記事ごとに固有のクエリを持たせて、それをURLに入れることで、外部からページを開いても特定の記事を表示することができます。
また、そのOGP処理を結構頑張りました。
このように、こだわりポイントを全部書いてたら多すぎて流石に日が暮れてしまいそうなので、仕方なく抜粋していきます(暇な人は良かったらとても汚いコードでも読んでいってください)。
まず、アニメのデータベースを用意する必要があったので、0から作りました。
具体的にはただ単に以下のような
JSONファイル
を書いているだけなのですが、
公式サイトのURLやキーワードは敢えて手動で入力しています。
"アニメタイトル(分類)": {
"aid": "230099xx",
"time": "24:00",
"koma": "mo1",
"url": "https://example.com/",
"kw": "略称など"
},
こうすることで、「今期はどんなアニメがあるのかなー」が自動的にできて一石二鳥です。
その作業のおかげで今まで自分が追っていなかった面白いアニメにたくさん出会うことが出来ました。
ティアムーン帝国物語はそのうちの一つです。こういう勘違いで上手く事が運ぶ系のアニメは個人的には好きです。
よければ見てみてください!
次に紹介するのは、今回記事を書くにあたって最も苦労したともいえる、プラットフォームの準備です。
自前のプラットフォームで記事を書くのは今回がはじめてなので、みんなどんな感じなのかなーと調べて見ました。
マークダウンから変換する方法や、mdxを使う方法がありそうですね。
しかし!
今回はなぜか(?)逆張りでHTMLのままいこうと決めました(mdxはまた別の機会にやろうと思います)。
まあコードブロックとかいろいろ自分で作ってみたかったというのもありますが…
ちなみに、コピー機能もつけてます。試しにコピーしてみてね
# (´・_・`)が なかまになりたそうに こちらをみている
# ゴヴィッショヌ in python
import random
def govisshonu():
logarray = []
dict = ["(", "´", "・", "_", "・", "`", ")"]
while True:
w = dict[random.randint(0, 6)]
logarray.append(w)
print(w, end = "")
if w == ")":
if "".join(logarray[-7:]) == "(´・_・`)":
print(f"\n{len(logarray)}文字目でゴヴィッショヌが完成しました!")
return
govisshonu() if __name__ == "__main__" else None
シンタックスハイライトには
Highlight.js
というのがすごく有能でした。
https://highlightjs.org/
いつもお世話になるDiscordやStack Overflowでも使われているそうです。
そして、毎回コードブロックのために長いコードを繰り返すのはめんどくさいので、JavaScript側で共通部分は挿入するようにしました。
...ちなみにこの少し上に表示されるはずである埋め込みのプレビューも(クロスオリジン問題を解決する手法は流石にググりましたが)がんばって実装しました。
その他にも、iOSの自動ズームを無効化したりレイアウトを超調整(⁉️)したりなどたくさんのこだわりがあります。
(ちなみに⁉️は環境によって絵文字で表示されなかったり周りの文字が太くなってる気がしますがすべてはゴママヨのせいです。)
OGP
前述したように、このサイトの目的は要するにアニメ一覧を表示するだけなので、Github Pagesで公開するつもりですべてを開発していました。
その方針でHTMLやJavaScriptも書いていたのですが、ある日、
OGP
なるものの存在を意識し始めました。(デカ文字長押ししてみてね)
確かに、URLを貼ったときに画像が表示されないのはちょっと寂しいですよね。
しかも、せっかくTwitter(𝕏)で共有してほしいのにユーザーごとの結果が反映されてないと面白くないので、動的にOGPを生成することにしました。
そして、それを可能にしてくれるのが例の…
そうです、あの
Next.js
です。
https://nextjs.org/
これを使うことで、サーバーサイドで動的にOGPを生成することができると分かりました。
これをSSRといいます。
多分最高レアなので、みんなも使ってみてね。
今回サイトをホストするサービスとしては、Vercelを選びました。
理由は単純で、無料で簡単に利用できるからです。
ちなみにNext.jsはVercelが開発したそうです。
何もかもが初めてなので、とりあえずサンプルコード、もとい先人たちの知恵をありがたく参考にさせてもらって何とか動的OGPの
実装をすることができました!
import { useState } from "react";
import { useRouter } from "next/router";
import Head from "next/head";
import Script from 'next/script';
const Home = () => {
const router = useRouter();
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "";
const [text, setText] = useState<string>();
const inputHandler = (e: { target: { value: string } }) => {
setText(e.target.value);
};
const ogImage = router.query.aid ? `${baseUrl}/api/ogp?aid=${router.query.aid}` : "/default.png";
return (
<div>
<Head>
<title>あにりしゅ!</title>
<meta charSet="utf-8" />
<meta name="description" content="アニメの履修登録を行うことができるサイトです。" />
<meta name="keywords" content="アニメ,あにめ,anime,ANIME,履修登録,course registration" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:type" content="website" />
<meta property="og:url" content={ baseUrl } />
<meta
property="og:image"
key="ogImage"
content= {ogImage}
/>
(後略)
ここでTypeScriptを使っていますが、これは手本にしたコードがTS(Trans Sexualではありません)だったからです。
まあ、型があって安心なので、不要な間違いを防ぐことができるという優秀な言語です。
だから、タイプスクリプトを使う必要があったんですね。
次に外部サイトからのOGP取得に取り掛かろうとしました。が、ここで問題が発生します。
そうです、nextではHTMLではなく、JSXでページの要素を書く必要があるのです。
当然、最初はHTMLで書いていたので、そのままでは動きません。
初めは素直に書き換える作業をするつもりでした。しかし、tableなどの制約が強くそのまま使えないことが分かり、
iframeの中にHTMLを埋め込むという荒業で
紛争を開始
しないことにしました(そのおかげで色々と煩雑になったのはまた別の話ですが)。
図1. 終わってる構造の例
しかし、この苦行を乗り越えたことで、上の図のように無事?外部サイトのOGPプレビュー機能を完成させることが出来ました!
これ、むしろ苦行の方のアドカレなのでは??
こんなハチャメチャなコードは書いたことないのですが、とりあえず以下のように、
iframe越しにメッセージを送りあう方針で実装しました。
function makeEmbed(id) {
// idの中の記事のすべてのaタグを探して、そのhrefの中身を抽出
let news_main_elm = $("#news_main").find("#" + id);
// 中略
parent.postMessage({ type: 'makeEmbed', links: links_array }, '*');
}
// メッセージ受信
window.addEventListener('message', async function (event) {
if (event.data.type === "makeEmbed") {
let links_array = event.data.links;
for (let url of links_array) {
let ogp_data = await getOGP(url);
let iframe = document.getElementById("iframe_main");
iframe.contentWindow.postMessage({ type: "ogp", ogp: ogp_data, url: url }, '*');
}
}
});
実装してみて、意外となんとかなるものなんだと思いました。
そうこうしているうちに、ついになんとかブログとして完成させることができました。
おすすめ
ここで、最近はまっている声優さんを紹介したいと思います。
まずは、
小倉唯
さんです。個人的お気に入り曲を紹介します(本当はMV貼りたかったけど埋め込み無効化されてた)。
耳に残るアニソンだと思いませんか?最近聞いた曲のなかで上位に入るくらい好きです。
ちなみに私はこの曲がきっかけでわたゆりを見始めました。
次は、Future Strikeという曲です。残念ながら動画は埋め込めなかったのでリンクを貼っておきます。
https://youtu.be/-rrxUPDS-l0
超かっこいいです。かわいい×かっこいいの最強コンビネーションです。
また、この曲の作曲者である俊龍さんは他にも「Shine In The Sky☆」などの人気曲を手掛けていて、すごいと思います。
また、
東山奈央
さんも好きです。こちらも個人的お気に入り曲を紹介します。
この曲はなんと、あのかいりきベアさんが作詞作編曲をしているんです!
このかっこよさが癖になりますよね~
この曲は、テレビアニメ「恋する小惑星」のOPです。アニメの雰囲気がきららっぽくてとても良いです。
全人類きららアニメを見ましょう。
と、こんな感じでiframeなどを自由にカスタマイズできるのがHTML(JSX)のメリットだと私は思います。
まとめ
いかかでしたか?
前半は技術の紹介、後半はただのオタクトークになってしまいましたが、
今回の記事をそろそろ締めたいと思います。
今回得たこと、それは自力でブログから用意するのは蠱滅だということが分かりました。
https://akaakuhub.github.io/Kometsu/
明日の記事は、らぼねこさんの「UECを周回プレイする方法」です。
周回プレイを現実でする方法があるのか、とても気になります...
もし成功したら是非ワザップに掲載してほしいですね。
https://sp.jp.wazap.com/
この記事はここまでです。拙い文章でしたが最後まで読んでいただきありがとうございました!