2012年5月20日日曜日

[Ruby] iTunes - ディレクトリ構成から、MP3タグを更新

転んでもただでは起きないよw


2012年05月16日水曜日 に音楽ファイルが消えてしまったけど、復元はできた。 
復元できたファイルは、曲名が復元できなかったので整理は後回し。 

MP3タグを付けてない音楽ファイルは別のHDDに入っていたので無事だったので、 
消えた音楽ファイルの場所にファイルを同期。 
ファイル名は元通り。ただMP3タグは付いてない。。。

MP3タグ付けは気の遠くなる作業で、さらに気が遠くなる。。。それを考えると・・・orz
そうだ!自動化だ! と思い、昨日1日調査と実装してました。 

因みに言語は、Rubyです。 

取りあえず、完成しました。 

以下で動作確認済みです。
・Windows 7 Professional 64bit
・Ruby 1.9.3p194
・iTunes 10.6.1.7

曲名、トラック番号、アルバム名、グループのタグ付けをファイルパスからMP3タグを付けるようなプログラムを作りました。 
こんなディレクトリ構成しているのは、きっと珍しいから、たぶんこのコードは使えないと思います。

一応、参考になればと思い、コードを以下に公開しておきます。

※2012/05/22更新
iTunes_mp3tag_update.rb
# -*- encoding: utf-8 -*-
# -------------------------------------------------------------------------------
# iTunes_mp3tag_update.rb
# iTunes - ディレクトリ構成によって、MP3タグを更新。
# 更新するMP3タグ : 曲名、トラック番号、アルバム名、グループ名
# (c) 2012 shiro
#
# 動作確認済み:
#   Windows 7 Professional 64bit
#   Ruby 1.9.3p194
#   iTunes 10.6.1.7
#
# ex) 以下のようなディレクトリ構成で有効です。
# Music/
# ├ グループ名2
#    ├ 01.アルバム名1
#    | ├ 01.曲名1.mp3
#    | └ 02.曲名2.mp3
#    └ 02.アルバム名2
#       ├ DISC-1
#       | ├ 01.曲名3.mp3
#       | └ 02.曲名4.mp3
#       └ DISC-2
#          ├ 01.曲名5.mp3
#          └ 02.曲名6.mp3
# -------------------------------------------------------------------------------

require 'win32ole'
require 'pathname'

class String
  # 半角記号だとフォルダ名、ファイル名に使用できない文字を半角文字に変換
  def normalize
    self.tr("&%}{#|><”?*:/","&%}{#|><\"?*:/").tr("¥","\\")
  end
end

# 音楽ファイル
ITTrackKindFile = 1
# 変更された曲数
modify_count = 0
# 例外数
exception_count = 0
exception_text = []
# 削除数
deleted_tracks = 0

# iTunes 初期化
itunes_app  = WIN32OLE.new("iTunes.Application")
# メインライブラリ
playlist = itunes_app.LibraryPlayList
# 特定のプレイリスト
#playlist = itunes_app.LibrarySource.Playlists.ItemByName("無題のプレイリスト")
start_time = Time.now

begin
  # プレイリスト内のトラックを取得
  tracks = playlist.Tracks

  if playlist
    #プレイリスト中の曲数
    num_tracks = tracks.Count

    num_tracks.downto(1) do |i|
      track = tracks.Item(i)
      begin
        if track.Kind == ITTrackKindFile
          if track.Location == ""
            # デッドリンク削除
            track.Delete()
            deleted_tracks += 1
          else
            # 変更フラグ
            modify_flag = false

            # 曲名取得
            track_name = track.Name
            # ファイル場所取得
            path = Pathname.new(track.Location)

            # 曲名更新
            file_name = path.basename(".mp3").to_s
            song_name = file_name.gsub(/^\d\d(|\d)\./,"").encode("utf-8").normalize

            if /^\d\d(|\d)\./ =~ track_name && file_name == track_name || track_name.encode("utf-8") != song_name
              p "Before Name : #{track.Name}"
              p "After Name : #{song_name}"
              # iTunesの自動補完機能対応
              track.Name = "#{song_name}_dummy".upcase
              # 曲名を変更
              track.Name = song_name
              modify_flag = true
              p "Name Updated."
            end

            # トラック番号更新
            file_name =~ /^\d\d(|\d)\./
            track_number = $&.to_i
            tn = track.TrackNumber
            if tn == 0 || tn != track_number
              # トラック番号を変更
              track.TrackNumber = track_number
              modify_flag = true
              p "TrackNumber Updated."
            end

            album_name = ""
            album_path = nil
            if /^[Dd][Ii][Ss][Cc]-\d(|\d)/ =~ path.dirname.basename.to_s
              # 複数ディスクの場合
              disc_path = path.dirname
              album_disc = disc_path.basename.to_s.upcase
              album_path = disc_path.dirname
              album_name = "#{album_path.basename.to_s.gsub(/^\d\d\./,"")} #{album_disc}".encode("utf-8").normalize
            else
              # 複数ディスクでない場合
              album_path = path.dirname
              album_name = album_path.basename.to_s.gsub(/^\d\d\./,"").encode("utf-8").normalize
            end

            # アルバム更新
            album = track.Album
            if album  == "" || album.encode("utf-8") != album_name
              # iTunesの自動補完機能対応
              track.Album = "#{album_name}_dummy".upcase
              track.Album = album_name
              modify_flag = true
              p "Album Updated."
            end

            # グループ更新
            circle = track.Grouping
            circle_name = album_path.parent.basename.to_s.encode("utf-8").normalize
            if circle == "" || circle.encode("utf-8") != circle_name
              # iTunesの自動補完機能対応
              track.Grouping = "#{circle_name}_dummy".upcase
              track.Grouping = circle_name
              modify_flag = true
              p "Grouping Updated."
            end

            # 更新した場合は、曲のファイルパスをコンソールに出力
            if modify_flag
              modify_count += 1
              p "#{path.to_s} updated!"
#              File.open('updated.log','a'){|f|
#                f.write "#{path.to_s}\n"
#              }
            end
          end
        end
      rescue => e
        exception_count += 1
        exception_text << "#{track.Location} : #{e}"
      end
    end
  end
  p "#{modify_count} updated!"
  if exception_count > 0
    exception_text.each do |exception|
      p exception
    end
    p "#{exception_count} exceptions."
  end
  if deleted_tracks > 1
    p "#{deleted_tracks} files deleted."
  elsif deleted_tracks == 1
    p "1 file deleted."
  end
  p "Processing has been completed!"
rescue NoMethodError => e
  p e
  p "No playlist!"
rescue WIN32OLERuntimeError => e
  p e
  p "WIN32OLERuntimeError"
ensure
  finish_time = Time.now
  p "start time : #{ start_time }"
  p "finish time : #{ finish_time }"
  p "#{finish_time - start_time} sec."
end

参考URL

0 件のコメント:

コメントを投稿