「taglib-ruby」を使う

# 背景
[前回と同じ](https://qiita.com/hakua-doublemoon/items/abe6cbf11340f2805d41)。
JewelCaseは音楽ファイルを使うアプリなので、flacとmp3のタグの解析にこの`taglib-ruby`を使います。

# 詳細
## ドキュメントなど
rubygem: https://rubygems.org/gems/taglib-ruby/versions/0.5.2-x86-mingw32?locale=ja
github.io: https://robinst.github.io/taglib-ruby/
rubydoc: https://rubydoc.info/gems/taglib-ruby

インストールするときは`apt-get install libtag1-dev`など、libtagのインストールも必要です。
（Dockerで使うときも下記のようにインストールしてあります）

```DockerFile
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client libtag1-dev
```
## 基本的な使い方
基本的にブロックの中で使用します。

### flacファイルの情報を得る
``` app/models/MusicFile.rb
        TagLib::FLAC::File.open(fpath) do |flac|
            tag = flac.tag
            ret = {
                :album => tag.album,     # アルバム名
                :artist => tag.artist,   # アーティスト名
                :genre => tag.genre,     # ジャンル
                :track_no => tag.track,  # トラック番号
                :title => tag.title,     # 曲名
            }
        end
```

### mp3ファイルの情報を得る

mp3のID3タグはV1とV2があり、確認しながら読み取ります。

``` app/models/MusicFile.rb
        TagLib::MPEG::File.open(fpath) { |mpeg| # mpegとして開く
            if  mpeg.id3v2_tag?  then
                tag = mpeg.id3v2_tag
                ret = {
                    :album => tag.album,
                    :artist => tag.artist,
                    :genre => tag.genre,
                    :track_no => tag.track,
                    :title => tag.title,
                }
            elsif  mpeg.id3v1_tag?  then # V1の場合もある
                tag = mpeg.id3v1_tag
                # 省略
            else # どちらでもない？
                # 適当に処理する
            end
```

## あまり使われない？項目名のタグを得る
私は曲のアーティスト名とは別にアルバムアーティストを音楽ファイルにつけていますが、あまり使われないのか、音楽ファイルによってサポートされない場合があるためか、`TagLib::Tag`で取得することができません。
そこでflacとmp3ではそれぞれ下記のように取得します。

``` ruby:flacの場合
            ret = ""
            TagLib::FLAC::File.open(fpath) do |flac|
                return ret if not flac.xiph_comment?
                fl = flac.xiph_comment.field_list_map
                ret = fl["ALBUMARTIST"]
            end
            ret
```

``` ruby:mp3の場合
            ret = ""
            TagLib::MPEG::File.open(fpath) do |mpeg|
                return ret if mpeg.id3v1_tag? # id3v1も取得できるだろうが面倒なので無視
                return ret if not mpeg.id3v2_tag? # どうしようもないので無視
                tag = mpeg.id3v2_tag
                ret = tag.frame_list("TPE2")
            end
            ret
```

flacの`field_list_map`で使えるフィールド名は[metaflac](https://xiph.org/flac/documentation_tools_metaflac.html)で使うフィールド名と同じと思われます。
mp3の`frame_list`で使えるフィールド名（フレーム名）は[ID3v2](https://id3.org/id3v2.4.0-frames)の仕様に従っていると思われます。

## ジャケット画像を抽出する
flacでは`picture_list`メソッドにより`TagLib::FLAC::Picture`の配列を取得できます（複数のジャケット画像がつけられるらしい）。

``` ruby
            TagLib::FLAC::File.open(fpath) { |flac|
                pics = flac.picture_list
            }
```

ジャケット画像はjpegだったりpngだったりいろいろですが、`mime_type`でMIME Type識別子（文字列）を返してくれるので判別は簡単です。

``` ruby
                    case pic.mime_type
                    when /.*png/
                        ext = '.png'
                    when /.*jpeg/, /.*jpg/
                        ext = '.jpeg'
                    when /.*bmp/
                        ext = '.bmp'
                    else
                        puts "mine: " + pic.mime_type
                    end
```

画像データはPictureクラスの`data`で取得できます。画像データそのものなので、適当な描画ライブラリに渡したり、バイナリでファイル出力して画像ファイルを作成できます。

``` ruby
                        IO::binwrite(JACKET_PATH + name + ".png", pic.data)
```

mp3の場合は`picture_list`みたいなメソッドは使えませんが、APICフレームを取得すればジャケット画像を抽出したことになります。
（APICはID3v2でID3v1には無いっぽい）

``` ruby
            TagLib::MPEG::File.open(fpath) { |mpeg|
                return ret if mpeg.id3v1_tag?
                return ret if not mpeg.id3v2_tag?

                tag = mpeg.id3v2_tag
                pics = tag.frame_list('APIC')
                if  pics.length > 0  then # これも配列として取得できる
                    pic = pics[0]
```

オブジェクトを取得したあとの扱いはflacの場合と同じです。