Однажды зимним вечером я пришел домой от друга с пачкой заполненных эмпешками компактов. Перегнать их на свой жесткий диск не составило большого труда. После первых часов эйфории наступила пора систематизировать все ЭТО, но тут меня ждало разочарование: все файлы назывались каким-то странным цифровым кодом (с расширением *.mp3, естественно). Для того чтобы узнать, что за песня, приходилось запускать Winamp и смотреть по названиям (служебная информация, включенная в файл и отображаемая в окне программы).

Ситуацию надо было как-то спасать. На помощь пришел Perl со своим модулем MP3::info. Где его брать? На CPAN, конечно. Исследуемый модуль предназначен для управления выборкой и записью информации об MP3-файлах. Подключается к скрипту аналогично прочим Perl-модулям.

use MP3::Info — Описание вызова функции get_mp3tag (FILE [, VERSION, RAW_V2]), где FILE — название файла, а VERSION, RAW_V2 — т. н. ID3-тэг, необязательная информация о версии заголовка. От него зависит количество служебной информации, записываемой в mp3-файл. В принципе, Perl обрабатывает версию автоматически и выбирает только ту информацию, которая может там быть. А с помощью функции remove_mp3tag (FILE [, VERSION, BUFFER]) вообще можно его удалить, и файл будет на 128 байт короче (экономия места на винте :-)). Но хватит теории. Пишем программу.

#! /usr/bin/perl -w use MP3::Info; # подключаем модуль # перебираем все файлы по шаблону в текущем каталоге while ($file= <*.mp3>) { my $tag = get_mp3tag($file) or die "No TAG info"; # $title = $tag->{TITLE}; # выбираем название песни $title=~ s/\s+/_/g; # заменяем пробелы на знак подчеркивания rename "$file", "$title.mp3"; # переименовываем файл }

Вот и все — скрипт читает тэг и в соответствии с ним переименовывает файл. Для большего удобства можно извлечь и название альбома —$tag->{ALBUM}, — создать каталог с таким именем и перенести все файлы туда. На практике название альбома пишут реже, однако можете попробовать. Еще можно проверить наличие TITLE вообще (с помощью функции defined или while ($title)), и при отсутствии оного перейти к следующему файлу, но с этим Perl и сам отлично справляется.

Все это хорошо работает с названиями, напечатанными латиницей и под Windows, а для Linux, как всегда, существует проблема кодировок: если заголовки представлены в CP1251, то в Linux'е вы увидите абракадабру. Поэтому необходимо добавить следующие строки в текст программы.

$win1251= '\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7'. '\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf'. '\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7'. '\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf'. '\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7'. '\xe8\xe9\xea\xeb\xec\xed\xee\xef'. '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7'. '\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'. '\xa8\xb8'; $koi8= '\xe1\xe2\xf7\xe7\xe4\xe5\xf6\xfa'. '\xe9\xea\xeb\xec\xed\xee\xef\xf0'. '\xf2\xf3\xf4\xf5\xe6\xe8\xe3\xfe'. '\xfb\xfd\xff\xf9\xf8\xfc\xe0\xf1'. '\xc1\xc2\xd7\xc7\xc4\xc5\xd6\xda'. '\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0'. '\xd2\xd3\xd4\xd5\xc6\xc8\xc3\xde'. '\xdb\xdd\xdf\xd9\xd8\xdc\xc0\xd1'. '\xb3\xa3'; sub win_koi{ local($var)=@_; eval "\$var=~ tr/$win1251/$koi8/;"; return $var; } # это все добавить после заголовка # а это перед rename "$file", "$title.mp3"; $title = win_koi($title);

Выглядит страшно, да? Первыми идут объявления скаляров, которые содержат шестнадцатеричную кодировку всех букв русского алфавита в СР1251 и КОI8 соответственно. Затем объявляется функция, которая осуществляет перекодирование. Здесь используется операция транслитерации. Она производит замену символов первого списка на символы той же позиции второго. А после всего следует вызов функции перекодировки для каждой строки текста.

Теперь разберем обратную проблему. В современных проигрывателях можно выбрать сразу песни одного исполнителя или стиля, но вот незадача — самая большая группа оказывается в папке Untitled, а перебирать файлы вручную почему-то не хочется :-). И здесь нам опять же поможет MP3::Info с Perl’ом. Вызов соответствующей функции выглядит так:

set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM]);

Параметры очевидны: файл — название — песни — артист — альбом — год — комментарий — жанр — номер дорожки. Все поля имеют 30-байтовый предел, так что сильно не увлекайтесь.

#! /usr/bin/perl -w use MP3::Info; # подключаем модуль ($art, $alb, $y, $c, $g) = @ARGV; # выбираем аргументы командной строки # перебираем в цикле все файлы текущего каталога while ($file = <*.mp3>) { my $tag = get_mp3tag($file) ; # получаем информацию из файла $title = $tag->{TITLE}; $artist = $art || $tag->{ARTIST}; $album = $alb || $tag->{ALBUM}; $year = $y || $tag->{YEAR}; $comment= $c || $tag->{COMMENT}; $genre = $g || $tag->{GENRE}; # записываем информацию в файл set_mp3tag($file, $title ,$artist ,$album , $year, $comment , $genre ); }

Небольшое пояснение. В Perl'е, как и в С, любое непустое и ненулевое значение соответствует условию «истина», нулевое и пустое — условию «ложь». Это мы и используем при вызове программы. Команда выглядит так:

# perl vachaprograma.pl артист альбом год коментарий жанр

Название песни пропущено, оставлено извлеченное из файла значение — мы ведь собираемся пройтись по всем песням текущего каталога. Если какой-нибудь пункт необходимо пропустить, то на его месте поставьте «0» (нуль), и тогда в действие вступит обычный алгоритм работы оператора ИЛИ: если первый аргумент «ложь», то результат будет равняться второму операнду, т. е. значению, которое мы извлекли из файла. Если параметр состоит из двух и более слов, то заключите их в кавычки.

И в заключение еще одна функция — она выбирает из файла информацию, которую невозможно изменить: время звучания, битрейт, версия, стерео\моно, частота и еще много чего, в зависимости от версии.

Описание ее таково:

get_mp3info (FILE);

Вот так можно узнать время звучания файла

my $info = get_mp3info($file); printf "$file время звучания %d:%d\n", $info->{MM}, $info->{SS};

В принципе, это все — если заинтересовались, почитайте документацию к модулю — и вперед. Ведь юзер должен быть чуточку ленив — ровно настолько и в том смысле, чтобы не лениться автоматизировать монотонные операции (зачем же тогда компьютер?), а клаву лучше всего использовать для боев с товарищами по локалке.