source: flacrip/trunk/flactrack @ 26

Last change on this file since 26 was 17, checked in by peter, 10 years ago

changed MBZ_DISCID to MUSICBRAINZ_DISCID, to match the standard MusicBrainz-Vorbis tag mappings

  • Property svn:executable set to *
File size: 4.5 KB
RevLine 
[1]1#!/usr/bin/perl -w
2use strict;
3
4# extract one or more tracks from a FLAC file using its embedded cuesheet
5# save those tracks as wav or mp3 files
6# can also run them through a sox filter
7# TODO: separate sox filter for each track!
8
[11]9use FindBin;
10use lib "$FindBin::RealBin/lib";
11
[4]12use Getopt::Long qw{:config no_ignore_case};
[10]13use File::Spec::Functions qw{catfile splitpath};
[4]14use File::Path;
15use Audio::FLAC::Header;
[3]16use MusicBrainz;
[15]17use Text::Unidecode;
[1]18
19GetOptions(
20    'D=s' => \my %TRACKS,
21    't=s' => \my $TYPE,
22    'x=s' => \my $SOX_FILTER,
[4]23    'all|a' => \my $ALL,
24    'dir|d=s' => \my $DIRECTORY,
[15]25    'ascii-tags' => \my $ASCII_TAGS,
[1]26);
27
28my $FLAC_FILE = shift or die "Need a flac file to decode";
29
30# default to mp3
31$TYPE ||= 'mp3';
32
[4]33# default the directory to be named like the flac file
34($DIRECTORY ||= $FLAC_FILE) =~ s/\.flac$//;
35
36my $flac = Audio::FLAC::Header->new($FLAC_FILE) or die "Can't read FLAC header from $FLAC_FILE\n";
37
[1]38# for getting track metadata from MusicBrainz
[3]39my $info;
[4]40if ($ALL || $TYPE eq 'mp3') {
[13]41    (my $properties_file = $FLAC_FILE) =~ s/\.flac$/.properties/;
42    if (-e $properties_file) {
43        require Config::Properties;
[1]44
[15]45        # the properties are in UTF-8; mark them as such so unidecode works correctly later
46        my $properties = Config::Properties->new(file => $properties_file, encoding => 'utf8');
[13]47        $info = $properties->getProperties;
48    } else {
49
[17]50        my $discid = $flac->tags('MUSICBRAINZ_DISCID') or warn "No MUSICBRAINZ_DISCID tag in $FLAC_FILE\n" if $flac;
51        #TODO: calculate TOC and DISCID from cuesheet if there is no MUSICBRAINZ_DISCID tag present
[13]52
53        $info = get_musicbrainz_info($discid);
54    }
[12]55    exit unless $info;
[10]56
57    # if we have metadata, change the directory name to ARTIST.DATE.ALBUM, so it will sort nicely
58    my $base_dir = (splitpath($DIRECTORY))[1];
59    my $album_dir = join('.', map { to_filename($_) } @{$info}{qw{ALBUMARTISTSORT ORIGINALDATE ALBUM}});
60    # need to append "disc#" if this is a multidisc album
61    if ($info->{DISCTOTAL} > 1) {
62        $album_dir .= '.disc_' . $info->{DISCNUMBER};
63    }
64    $DIRECTORY = catfile($base_dir, $album_dir);
65    #die $DIRECTORY;
[1]66}
67
[4]68if ($ALL) {
69    die "Use of --all requires a --directory\n" unless $DIRECTORY;
[5]70    die "No track info found on MusicBrainz for $FLAC_FILE\n" unless $info;
[4]71    use YAML;
72    my $cuesheet = $flac->cuesheet;
73    my $count = scalar grep { /TRACK \d\d/ } @{ $flac->cuesheet };
74    print "Found $count tracks\n";
75    #TODO: default to just 01, 02, etc. if there is no $info
76    %TRACKS = map {
[13]77        $_ => catfile($DIRECTORY, sprintf('%02d.%s', $_, to_filename($info->{sprintf 'TRACK%02d.TITLE', $_})))
[4]78    } (1 .. $count);
[5]79    #print Dump(\%TRACKS);
80    for my $tracknum (sort { $a <=> $b } keys %TRACKS) {
81        printf "%2d: %s\n", $tracknum, $TRACKS{$tracknum};
82    }
[4]83    mkpath($DIRECTORY);
84}
85
[5]86#TODO: all the option of sorting by tracknum or not
87#while (my ($tracknum, $title) = each %TRACKS) {
88for my $tracknum (sort { $a <=> $b } keys %TRACKS) {
[1]89    if ($tracknum !~ /^\d+$/) {
90        warn "Don't know what to do with track number '$tracknum'";
91        next;
92    }
93    my $start = $tracknum . '.1';
94    my $end = $tracknum + 1 . '.1';
95    my $cmd = qq{flac -d --cue $start-$end $FLAC_FILE -o - };
96
97    if ($SOX_FILTER) {
98        $cmd .= qq{| sox -t wav - -t wav - $SOX_FILTER };
99    }
100
[5]101    my $title = quotemeta($TRACKS{$tracknum});
[1]102    if ($TYPE eq 'mp3') {
103        # bitrate of 192
104        $cmd .= qq{| lame -b 192};
105        # if there is track info, add it as ID3 tags
[3]106        if ($info) {
[13]107            my $track_key = sprintf 'TRACK%02d', $tracknum;
[15]108            $cmd .= sprintf q{ --tt %s --ta %s --tl %s --ty %d --tn %d},
109                quote($ASCII_TAGS ? unidecode($info->{"$track_key.TITLE"}) : $info->{"$track_key.TITLE"}),
110                quote($ASCII_TAGS ? unidecode($info->{"$track_key.ARTIST"}) : $info->{"$track_key.ARTIST"}),
111                quote($ASCII_TAGS ? unidecode($info->{ALBUM}) : $info->{ALBUM}),
112                ($info->{ORIGINALDATE} =~ /^(\d\d\d\d)/)[0],
[1]113                $tracknum;
114        }
115        $cmd .= qq{ - $title.mp3};
116    } elsif ($TYPE eq 'wav') {
117        $cmd .= qq{> $title.wav};
118    } else {
119        die "Unknown type: $TYPE\n";
120    }
121    #die $cmd;
122    system $cmd;
[5]123    die "\nFLAC decoding canceled\n" if ($? & 127);
[1]124
125    print "\n" if $SOX_FILTER;
126}
127
128sub quote {
129    my ($string) = @_;
130    $string =~ s/"/\\"/g;
131    return qq{"$string"};
132}
[4]133
134sub to_filename {
135    my @strings = @_;
136    return map {
[10]137        s/&/ and /g;
[15]138        unidecode($_);
[4]139        s/[^a-z0-9-_ ]+//gi;
140        s/ +/_/g;
141        lc;
142    } @strings;
143}
Note: See TracBrowser for help on using the repository browser.