北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

iPod nanoにアルバム単位でランダムに曲を突っ込む

iTunesに10GB以上曲が入っていてiPod nanoに入りきらないので、スマートプレイリストでランダムで曲を突っ込んでいる。しかしランダムに突っ込むと、アーティスト→アルバムと選択したときにそのアルバムに入ってる曲が少ないため、目的の曲がなくてがっかりするパターンが多い。そこで、いっそのこと曲をランダムに突っ込むのではなく、アルバムをランダムで選んで、その中に入ってる曲をまるごとiPodに突っ込もうと考えた。

でもって、作ったのが以下*1 *2


#!/usr/local/bin/perl
use utf8;
use Encode;
use strict;
use Mac::AppleScript qw(RunAppleScript);

#=======================================
# サブ
#=======================================
# カナと濁点が別れてるのを戻す
sub kana_change($$){
my $s;
if($_[0]){
$s = unpack('U*', $_[0]);
$s +=1;
}elsif($_[1]){
$s = unpack('U*', $_[1]);
$s +=2;
}

return pack('U*', $s);
}


#=======================================
# メイン
#=======================================
# iTunesの音楽ディレクトリ
my $dir = '/XXXXXX/iTunes/iTunes Music/';
# つっこむアルバムの枚数
my $album_num = 10;
local *DIR;

# iTunesが起動してなかったら終了
(my $has_itunes_launched = qx{ps -x -c -o "command" | grep -c '^iTunes¥$'}) =~ tr/¥r¥n//d;
exit if(! $has_itunes_launched);

# ディレクトリを舐めてアーティストのリストを出す
my @artist_dirs;
opendir(DIR, $dir) || die;
while(my $f = readdir(DIR)){
next if($f =~ /^¥./ || ! -d ($dir . $f));
push(@artist_dirs, $dir . $f)
}
closedir(DIR);

# さらにもぐってアルバムのリストを出す
my @albums;
foreach my $art_dir(@artist_dirs){
opendir(DIR, $art_dir) || die;
while(my $f = readdir(DIR)){
next if($f =~ /^¥./ || ! -d ($art_dir . '/' . $f));
$f = Encode::decode('utf8', $f);
$f =~ s/"/¥¥"/g;
# 正規化されちゃってるので戻す
$f =~ s/([うか-こさ-そた-とは-ほウカ-コサ-ソタ-トハ-ホゝヽ])¥x{3099}|([は-ほハ-ホ])¥x{309A}/kana_change($1, $2)/ge;
push(@albums, $f)
}
closedir(DIR);
}

# アルバムをランダムで選択
foreach(0 .. $#albums){
my $n = int(rand() * @albums);
my $tmp = $albums[$n];
$albums[$n] = $albums[$_];
$albums[$_] = $tmp;
}

# AppleScriptを作る
my $script = sprintf(<<__APPLE__, join(' or ', map {qq/album is "$_"/} @albums[0 .. $album_num - 1] ) ); tell application "iTunes" activate try display dialog "iPod投入曲(気紛)プレイリストを作成しますか?" set this_playlist to playlist "iPod投入曲(気紛)" display dialog "プレイリストを作成中です。" buttons {""} default button 1 giving up after 1 tell source "ライブラリ" -- 曲を削除 tell this_playlist delete every track end tell -- 該当するアルバムのみ追加 tell playlist "ライブラリ" duplicate (every track whose %s) to this_playlist end tell end tell display dialog "完了しました。" buttons {"OK"} default button 1 giving up after 2 on error error_message number error_number if the error_number is not -128 then beep display dialog error_message buttons {"OK"} default button 1 end if end try end tell __APPLE__ # 実行 RunAppleScript(encode('cp932', $script));

AppleScriptこちらで、ファイル名の正規化への対処はこちらをお借りしました。感謝です。

AppleScriptを見つけたんで、こりゃあ簡単かなと思ったらかなりハマり。まず、ファイル名のUNICODEをアップルスクリプトsjisにしようと思ったら、「が」とかが「か゛」みたいに正規化ってやつがされてるらしく、まずそこで苦戦。

で、つぎにLibraryフォルダにこのスクリプトを書き出してみたのだけど、iTunesから実行できずにハマり。どうやら、スクリプトエディタでコンパイルしないと実行できる形式にはならないみたい。しかたないから、Mac::AppleScriptの力を借りてperlから直接実行。CPANは偉大です。

*1:バックスラッシュは¥で表記してますんで注意

*2:アルバムの名前によっては、unicodesjisの変換の都合で取り出せない恐れも