(身から出た錆?に追われて疲れた話: 僕しか使っていないソフトの話で普遍性がないが、なるべく一般的に書く。)
数日前、PCを再起動した後に、Linux用音楽プレーヤーgmusicbrowser(GMB, 「僕版」)の再生履歴を自作の音楽再生履歴・感想記録システムMlhiのwebで見たら、アルバム画像がおかしいのに気付いた。別のアルバムの画像が表示されていた。実はこれは今年の3月頃にも起こっていて、GMBの曲の番号(ID)が詰められた(昔のBASICのリナンバーみたいなもの)ため、MlhiのDBに登録されたIDとずれて、別の曲のアルバム画像がGMBから取得・表示されることが分かったので、その時はIDを詰める処理をスキップするようにして解決したと思っていた。
僕としては、ユニーク(重複しない)かつ不変であるべきIDを詰める(変える)なんて意図が理解できない※。詰める理由はライブラリ内の曲が削除されたからだと想像しているのだが、IDは整数で、今は少なくとも32ビット(64ビットだって行けるだろう)だから、少なくとも2000万、あるいは4000万曲には割り当てられるから、使い放題だ。だから、曲を削除してもIDを詰める必要は全くない。にも関わらず、なぜそんな危険で無駄なことをするのだろうか。まあ、作者の思想とか気の迷いなのだろう。
※こういうのが、いわゆる「想定外」問題だ。「普通はないよね」って思うことは、実はいくらでもあるのだ。普通なんて幻想だ。そして、全部「想定外」と言えば何でも許される訳ではなく、どこまで想定したかがポイントだ。偉い人たちは、そこが分かってない(、というかうまく逃げているのだろう)。
それから、そういう事態になってもなるべく破綻しないように作るのも、設計・開発者のセンスとか能力だ。
それに、曲の削除にしたって、個人で何千万曲も入れる訳じゃないから多少無効な曲があったって、(今もそうしているように)フラグだけ設定してエントリは削除せず、残しておいてもいい(それが気になるなら、DBの構造をちゃんとすべきなのだ)。
これに似た問題として、マイナンバーの番号不足を想像する。(以前書いたが、)僕の計算では遅かれ早かれ足りなくなると思うのだが、いつかリナンバーするのか、あるいは、また作り直すのか。
のだが、やっぱり再発した。こういう根深い問題は大抵再発して、なかなか直らないと相場が決まっているので、「やっぱり」と思うとともに結構がっかりした。
IDを詰めないようにしたつもりなのに、なぜかまだ詰めるようだ。もちろん、作者は行方不明で聞くことはできず、直してももらえないので、自分で解決するしかない。そして、3月に(いや、それ以前から)思ったが、GMBは超大嫌いなPerlで書かれているうえに、内部構造が妙に凝っていて理解不能なので、根本的に直すことができない。
仕方ないので、MlhiがGMBの曲を指定するのにGMBのIDでなく、別の新しいIDを使うことにした。結構大改造なので、なるべく避けたかった。まあ、そもそも、GMBのIDの仕様を確認もせずに勝手に(ユニークかつ)不変と思い込んで使った僕が悪いので、全く身から出た錆ではあるが、なかなか大変だった。
大改造だけど、なるべく変更を少なくしたかった。そこで、MlhiのDBの構造は変えず、GMBのIDを入れていたプレーヤー固有のトラックIDを格納するフィールド(カラム)に格納する内容を変えることにした。GMBのIDの代わりに、曲の音響的な特徴から生成したID(今までもMlhiのトラックID(メインのキー・ID)として使っていたもので、AcoustIDのfpcalcコマンドで計算している)を格納するようにした。GMBのIDと新しいIDはプリフィクスで識別できるようにして、同じフィールドに混在可能にした。なお、この新しいIDは、当然ながらGMBのDBにも登録し(フィールドを追加した)、GMBのIDがいくら変わっても(その新しいIDで)同じ曲が検索できるようにした。

GMBに曲の固有ID(utid)を追加した("Track ID"の列)。まだ再生していない曲("Today's girl")では空だが、再生すると自動で設定される(「ザ・ベスト」)。"ID"は従来のGMBのID(固有でない)。
また、そのようなDBの中身の変更をバッチ処理(SQL)で行うのは失敗のリスクがあったので※、使いながら自動的に変更するようにした。つまり、GMBでの曲の再生時(Mlhiへの履歴の登録時)に、既存の曲のプレーヤー固有のトラックIDのフィールドに昔のID(GMBのID)が入っていたら、新しいID(曲の特徴から生成したID)に入れ替えるのである。
※実際、MlhiのDBは確認のためにしかツールで開いていなかったのに、いつの間にかDBのエントリが一個空になっていた・・・ 間違って何か押したか、修正中に(あるいはもっと前に?)バグが出たのかは不明だ。 ← バックアップを調べたら、変更版を試している時に誤動作して消えたようだ。
なお、曲の特徴からIDを生成するのは、今まではMlhiに履歴を登録するプログラム(登録プログラム)で行っていたが、そのIDをGMBにも格納するようになったので、GMBで生成して登録プログラムに渡すようにした。
余談だが、PerlからID生成プログラムを実行する時、曲のファイル名に日本語が入っていると文字化けして、どうしても直らなかった。ごく当たり前のことすら普通にできないのでブチ切れそうになったが、仕方ないので、Base64でエンコードしてプログラムに渡すようにした。
もう、とにかくPerlなんて1文字だって見たくない!! 何もかもオカシくぐちゃぐちゃで※、見るだけでイライラが溜まる。Perlだったら断然Pythonの方がいい(でも、僕にはPHPが一番だ)w 良くあんなものでまともなプログラムが書けるものだ。そこには感心する。
※"my"や"our"なんてセンスが悪いし、関数(サブルーチン)の引数は(,)で囲い区切ってってもそうでなくてもいいなんて見難いし、$とか@とか%とか()とか[]とか{}とか=~とか\とか、とにかく記号が多過ぎて(しかも、それらの複合もある)、「いい加減にしろ!」だ。
GMBの場合の処理の流れの概要は、以下のようになる(Spotifyでは曲の固有IDがISRCになっている以外は概ね同様)。
曲の再生開始
GMB
- 開始から指定時間(例: 3秒)後に、以下を実行する(すぐにスキップした場合は登録しないようにしたかったため)。
- その曲に固有ID(utid)が設定されていなければ、音響的特徴から生成して、GMBの曲DBのutidフィールドに格納する。+
- Mlhiに再生開始を通知する(utidを指定)。
Mlhi(履歴登録プログラム)
- 指定された曲が以前再生したことのあるか(指定されたutidがトラックIDのエントリがDBに格納されているか)調べ、なければ(初めて再生する曲)そのエントリを作成する。その時、GMBから曲の情報(例: タイトル、アーティスト、アルバム)を取得する(utidで曲を指定する)。
- 以前再生したことのある曲の場合、DB内のプレーヤー固有のトラックIDがutidでなかったら、指定されたutidに置換する。+
- 再生開始日時をDBに記録する。また、再生回数を+1する。
曲の再生終了
GMB
- Mlhiに再生終了を通知(utidを指定)する。併せて完奏率も送る。
Mlhi(履歴登録プログラム)
- 再生終了日時と完奏率をDBに記録(追加)する。完奏率は、それまでの完奏率と合わせる処理をする(履歴表示時に平均の完奏率を求めるため)。
曲の再生履歴の表示
Mlhi(web)
- DBから再生履歴を抽出し、GMBの曲の場合には、アルバム画像のファイル名や曲の長さなど(履歴には関係なく自明なため)DBには格納していないが、履歴表示にはあった方がいい追加情報をGMBから取得する(utidで曲を指定する)。
- その他の情報(例: コメント、評価)をDBから抽出し、履歴と共に成形して表示する(→ 例)。
※今回追加した処理は項目の最後に"+"を付けて示した。
変更を少なくしようとはしたけれど(実際、処理の流れの本筋は何も変わっていない)、やっぱり結構多くなり、昔作ったのですっかり忘れていたこともあって大変で、4日くらい掛かった(ている)。その間は、例によって、気付くと一日が終わっていたり、食事中にもバグが見付かったりして、全く気が休まらなかった。更に、昔の誤り(しかも、関係ないところにも!)も結構あって、「どんなものでもテキトーに作ってはいかん」と思い知らされた。。。
とは言え、何でもきっちり作っていたら、終わらずに使えなくなってしまう(機会を逃す)ので、そこの見極めが難しい。そこら辺もセンスや能力なのだろう。
そして、動作確認して基本的にはOK(何度も戻って修正した)だったのだが、そもそもの、GMBのIDのリナンバーが起こらず、本当に効果があるのかが確かめられない。曲を削除しても強制終了しても、なぜか起こらない。どうにも挙動不審なプログラムで、そういうのを使い続けるのもどうかとは思うのだが、他にいいものがないので仕方ない(いつかは自分で作り直したいが、無理だろうな)。
問題の現象が再現しないのでは仕方ないので、定期的にGMBのIDのリナンバーが起こったかどうかを検出するように定期実行機能(crontab)に設定しておいて、起こったら改めてアルバム画像を確かめることにした。
なお、僕しか使っていないものなので、他の方では直ったどうかも判然としないからキャプチャを載せても意味がないが、以下のように直った(単なる自己満足で載せるw)。
図中の"FCM5:"で始まるのが、曲の特徴から生成したIDである(それをGMBの新しいIDにも使っているので、"GMB:FCM5:-"と略記している)。また、"AIM5:"はアルバムのIDである。
PS. 当然ではあるが、曲の特徴から生成するIDは、同じ曲(ファイル)ならいつ何回生成しても同じ値になり(昔生成した値と今回生成した値が同じだった)、まだ重複していないので、ちょっと感心した。
PS2. 誰も気にしてないはと思うが、僕が好きなのは80年代のコイズミまたはkyon2であって、現代のダサい小泉さんではない。この投稿は妙なタイミングになったが、そこのところははっきりさせたいw (5/11 19:28)
(5/11 9:10 画像を追加、わずかに加筆・変更; 18:52 処理の流れの概要を追加、その他に加筆)