Dokan(Windows 版 FUSE)で MP3Tunes Locker をマウントしてみる(失敗)

Dokan という WindowsFUSE を以下のサイトで見つけ、
非常におもしろそうだったのでとりあえず MP3Tunes Locker をマウントしてみることにした。
2008-05-27


locker.rb

require 'lib/dokanfs'
require 'lib/mp3tunes'
require 'kconv'
require 'open-uri'

class Locker

  def initialize
    @mp3tunes = MP3Tunes.new.login
  end

  def contents path
    if path == "/"
      @artists = @mp3tunes.artists unless @artists
      @artists_name = @artists.map do |a| a[0].tosjis end
      return @artists_name
    elsif path.split("/").size == 2
      @artists.each do |ar|
        if ar[0].tosjis == path.split("/")[1]
          @albums = @mp3tunes.albums(ar[1]) #unless @albums
          @albums_name = @albums.map do |al| al[0].tosjis end
          return @albums_name
        end
      end
    elsif path.split("/").size == 3
      @albums.each do |al|
        if al[0].tosjis == path.split("/")[2]
          @tracks = @mp3tunes.tracks(al[1]) #unless @tracks
          @tracks_name = @tracks.map do |tr|
            tr[:trackTitle].tosjis + ".mp3"
          end
          return @tracks_name
        end
      end
    end
    return []
  end

  def file? path
    path =~ /mp3/
  end

  def directory? path
    if path == "/"
      return true
    elsif path.split("/").size == 2
      return false unless @artists_name
      return @artists_name.index(path.split("/")[1]) != nil
    elsif path.split("/").size == 3
      return false unless @albums_name
      return @albums_name.index(path.split("/")[2]) != nil
    end
    false
  end

  def read_file path
    return "" unless @tracks
    if path.split("/").size == 4
      @tracks.each do |t|
        return open(t[:downloadURL]).read if t[:trackTitle].tosjis == path.split("/")[3][0..-5]
      end
    end
    ""
  end

  def size path
    return 4096 unless @tracks
    if path.split("/").size == 4
      @tracks.each do |t|
        return t[:trackFileSize].to_i if t[:trackTitle].tosjis == path.split("/")[3][0..-5]
      end
    end
    4096
  end
end

FuseFS.set_root(Locker.new)
FuseFS.mount_under("r")
FuseFS.run

使い方

  1. Dokanインストーラでインストール
  2. Dokan Ruby バインディング を DokanLibrary 以下に解凍
  3. sample 以下に locker.rb を lib 以下に mp3tunes.rb をコピー
  4. mp3tunes.rb のユーザ名とかを編集
  5. $ruby sample\locker.rb でマウント
  6. あまりの重さに絶望した!(ファイルの列挙までは行くけどコピーができない…)

失敗の原因

ファイル読み込み時に呼ばれる read_file が異常に重い。
一回のコピーで read_file は何度も呼ばれるらしく、
アクセスがある度に open-uri が MP3 ファイルをフルサイズで
ダウンロードしようとするため、アクセス過多でコピーが失敗する。


解決策としては、FuseFS 互換ライブラリ(dokanfs.rb)の使用をやめ
read_files の引数に offset と length を取る標準 API を使うようにする。
そして offset に従い、resume ダウンロードを行うようにすれば
ファイルのコピーまでは行くと思う(たぶん)


ただし、アーティスト名に"/"が含まれると階層がおかしくなったりという
お粗末なバグはそのまま。


どこかのスーパーハカーがもっとマシなものを作ってくれることに期待!(オイ