MP3 の ID3 タグをいじってみようとするがうまくいかず
MP3*1 には、アーティストや曲名の情報を記述するための
ID3 タグという規格がある。
僕の音楽ディレクトリの中にある MP3 ファイルの名前を、
「アーティスト - 曲名.mp3」に統一したいなぁと前から思っていたので、
今回それを Ruby でやってみることにした。
とりあえず ID3 タグをいじれるっぽいライブラリをインストールする。
> gem install id3lib-ruby
なんかいくつかバージョンがあるらしく選択項目が出てきたので、
一番バージョンの新しい mswin32 用のを選択した。
http://id3lib-ruby.rubyforge.org/ を見た感じでは、
filename = "世界に一つだけの花.mp3" tag = ID3Lib::Tag.new(filename) tag.title #=> "世界に一つだけの花"
って感じで使えるらしい。
早速簡単なスクリプトを書いて実行してみる。
が、うまくいかない・・・。
とりあえず今できているのは、
ディレクトリのパスを指定して、
それ以下に含まれる MP3 ファイルの一覧を出力するところまで。
覚えたての Find モジュールも使ってみた。
Find モジュールを使うとディレクトリの再帰処理が楽チン。
require "find" require "rubygems" require "id3lib" # IGNORES の要素は読み飛ばすディレクトリのパス IGNORES = [/\./, /\.\./] def list_title(topdir) Find.find(topdir){|path| if FileTest.directory?(path) dir, base = File.split(path) IGNORES.each{|re| # re に base がマッチする場合 path を読み飛ばす Find.prune if re =~ base } else if /\.mp3$/ =~ path filename = File.basename(path) # ファイル名の先頭にある余計な数字を除去 filename.sub!(/^\d+[- ]/, '') ## tag が nil なのがおかしい # tag = ID3Lib::Tag.new(filename) # puts tag.title #=> nil puts filename end end } end topdir = "E:/音楽/" list_title(topdir)
なんで tag が nil になっちゃうんだろう?
これさえ何とかなれば大丈夫だと思うんだけどなぁ。
追記
うまくいった!
問題はID3Lib::Tag.new()の引数にファイル名を与えていたことだった。
パスを与えないとダメみたい。
考えてみればすごい当たり前のことだった。
他にも余分なコードとかあったので削って書き直した。
以下が修正後のコード。
# list-id3tag.rb # # 指定したパス以下に含まれるMP3のID3タグを読み取り、 # その一覧を出力する。 # # usage: ruby list_id3tag.rb [topdir] require "find" require "rubygems" require "id3lib" # IGNORES の要素は読み飛ばすディレクトリのパス IGNORES = [/\./, /\.\./] def list_id3tag(topdir) Find.find(topdir){|path| if FileTest.directory?(path) dir, base = File.split(path) IGNORES.each{|re| # re に base がマッチする場合 path を読み飛ばす Find.prune if re =~ base } else if /\.mp3$/ =~ path tag = ID3Lib::Tag.new(path) puts tag.title puts tag.artist puts tag.album puts tag.track puts tag.year puts tag.genre puts end end } end topdir = ARGV[0] || "E:/音楽/" list_id3tag(topdir)
出力結果の例はこんな感じ。
これで一曲分。
こんなのがドドドーっと一覧になって出力される。
この道わが旅(II) すぎやまこういち SYMPHONIC SUITE 「DRAGONQUEST」 BEST SELECTION〜ROTO〜 8 1997 Game
あれ?そういえば当初の目的はまだ達成されてないような・・・。
*1:大文字で書くのが正しいらしい