line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MP3::Tag::File; |
2
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
18
|
use strict; |
|
6
|
|
|
|
|
6
|
|
|
6
|
|
|
|
|
129
|
|
4
|
6
|
|
|
6
|
|
16
|
use Fcntl; |
|
6
|
|
|
|
|
5
|
|
|
6
|
|
|
|
|
1084
|
|
5
|
6
|
|
|
6
|
|
22
|
use File::Basename; |
|
6
|
|
|
|
|
7
|
|
|
6
|
|
|
|
|
264
|
|
6
|
6
|
|
|
6
|
|
19
|
use vars qw /$VERSION @ISA/; |
|
6
|
|
|
|
|
6
|
|
|
6
|
|
|
|
|
9935
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
$VERSION="1.00"; |
9
|
|
|
|
|
|
|
@ISA = 'MP3::Tag::__hasparent'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=pod |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
MP3::Tag::File - Module for reading / writing files |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $mp3 = MP3::Tag->new($filename); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
($title, $artist, $no, $album, $year) = $mp3->parse_filename(); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
see L |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
MP3::Tag::File is designed to be called from the MP3::Tag module. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
It offers possibilities to read/write data from files via read(), write(), |
30
|
|
|
|
|
|
|
truncate(), seek(), tell(), open(), close(); one can find the filename via |
31
|
|
|
|
|
|
|
the filename() method. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=cut |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# Constructor |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub new_with_parent { |
39
|
87
|
|
|
87
|
0
|
115
|
my ($class, $filename, $parent) = @_; |
40
|
87
|
50
|
33
|
|
|
474
|
return undef unless -f $filename or -c $filename; |
41
|
87
|
|
|
|
|
300
|
return bless {filename => $filename, parent => $parent}, $class; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
*new = \&new_with_parent; # Obsolete handler |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Destructor |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub DESTROY { |
48
|
81
|
|
|
81
|
|
96
|
my $self=shift; |
49
|
81
|
50
|
33
|
|
|
687
|
if (exists $self->{FH} and defined $self->{FH}) { |
50
|
0
|
|
|
|
|
0
|
$self->close; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# File subs |
55
|
|
|
|
|
|
|
|
56
|
860
|
|
|
860
|
0
|
6214
|
sub filename { shift->{filename} } |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub open { |
59
|
270
|
|
|
270
|
0
|
245
|
my $self=shift; |
60
|
270
|
|
|
|
|
228
|
my $mode= shift; |
61
|
270
|
100
|
66
|
|
|
834
|
if (defined $mode and $mode =~ /w/i) { |
62
|
99
|
|
|
|
|
109
|
$mode=O_RDWR; # read/write mode |
63
|
|
|
|
|
|
|
} else { |
64
|
171
|
|
|
|
|
159
|
$mode=O_RDONLY; # read only mode |
65
|
|
|
|
|
|
|
} |
66
|
270
|
50
|
|
|
|
421
|
unless (exists $self->{FH}) { |
67
|
270
|
|
|
|
|
447
|
local *FH; |
68
|
270
|
50
|
|
|
|
376
|
if (sysopen (FH, $self->filename, $mode)) { |
69
|
270
|
|
|
|
|
563
|
$self->{FH} = *FH; |
70
|
270
|
|
|
|
|
652
|
binmode $self->{FH}; |
71
|
|
|
|
|
|
|
} else { |
72
|
0
|
|
|
|
|
0
|
warn "Open `" . $self->filename() . "' failed: $!\n"; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} |
75
|
270
|
|
|
|
|
950
|
return exists $self->{FH}; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub close { |
80
|
330
|
|
|
330
|
0
|
300
|
my $self=shift; |
81
|
330
|
100
|
|
|
|
1117
|
if (exists $self->{FH}) { |
82
|
265
|
|
|
|
|
2239
|
close $self->{FH}; |
83
|
265
|
|
|
|
|
1480
|
delete $self->{FH}; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub write { |
88
|
66
|
|
|
66
|
0
|
81
|
my ($self, $data) = @_; |
89
|
66
|
50
|
|
|
|
116
|
if (exists $self->{FH}) { |
90
|
66
|
|
|
|
|
193
|
local $\ = ''; |
91
|
66
|
|
|
|
|
47
|
print {$self->{FH}} $data; |
|
66
|
|
|
|
|
339
|
|
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub truncate { |
96
|
0
|
|
|
0
|
0
|
0
|
my ($self, $length) = @_; |
97
|
0
|
0
|
|
|
|
0
|
if ($length<0) { |
98
|
0
|
|
|
|
|
0
|
my @stat = stat $self->{FH}; |
99
|
0
|
|
|
|
|
0
|
$length = $stat[7] + $length; |
100
|
|
|
|
|
|
|
} |
101
|
0
|
0
|
|
|
|
0
|
if (exists $self->{FH}) { |
102
|
0
|
|
|
|
|
0
|
truncate $self->{FH}, $length; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub size { |
107
|
44
|
|
|
44
|
0
|
45
|
my ($self) = @_; |
108
|
44
|
50
|
|
|
|
378
|
return -s $self->{FH} if exists $self->{FH}; |
109
|
0
|
|
|
|
|
0
|
return -s ($self->filename); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub seek { |
113
|
301
|
|
|
301
|
0
|
333
|
my ($self, $pos, $whence)=@_; |
114
|
301
|
50
|
|
|
|
512
|
$self->open unless exists $self->{FH}; |
115
|
301
|
|
|
|
|
743
|
seek $self->{FH}, $pos, $whence; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub tell { |
119
|
44
|
|
|
44
|
0
|
43
|
my ($self, $pos, $whence)=@_; |
120
|
44
|
50
|
|
|
|
83
|
return undef unless exists $self->{FH}; |
121
|
44
|
|
|
|
|
113
|
return tell $self->{FH}; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub read { |
125
|
343
|
|
|
343
|
0
|
316
|
my ($self, $buf_, $length) = @_; |
126
|
343
|
50
|
|
|
|
502
|
$self->open unless exists $self->{FH}; |
127
|
343
|
|
|
|
|
2580
|
return read $self->{FH}, $$buf_, $length; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub is_open { |
131
|
185
|
|
|
185
|
0
|
638
|
return exists shift->{FH}; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# keep the old name |
135
|
|
|
|
|
|
|
*isOpen = \&is_open; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# read and decode the header of the mp3 part of the file |
138
|
|
|
|
|
|
|
# the raw content of the header fields is stored, the values |
139
|
|
|
|
|
|
|
# are not interpreted in any way (e.g. layer==3 means 'Layer I' |
140
|
|
|
|
|
|
|
# as specified in the mp3 format) |
141
|
|
|
|
|
|
|
sub get_mp3_frame_header { |
142
|
0
|
|
|
0
|
0
|
0
|
my ($self, $start) = @_; |
143
|
|
|
|
|
|
|
|
144
|
0
|
0
|
|
|
|
0
|
$start = 0 unless $start; |
145
|
|
|
|
|
|
|
|
146
|
0
|
0
|
|
|
|
0
|
if (exists $self->{mp3header}) { |
147
|
0
|
|
|
|
|
0
|
return $self->{mp3header}; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
0
|
$self->seek($start, 0); |
151
|
0
|
|
|
|
|
0
|
my ($data, $bits)=""; |
152
|
0
|
|
|
|
|
0
|
while (1) { |
153
|
0
|
|
|
|
|
0
|
my $nextdata; |
154
|
0
|
|
|
|
|
0
|
$self->read(\$nextdata, 512); |
155
|
0
|
0
|
|
|
|
0
|
return unless $nextdata; # no header found |
156
|
0
|
|
|
|
|
0
|
$data .= $nextdata; |
157
|
0
|
0
|
|
|
|
0
|
if ($data =~ /(\xFF[\xE0-\xFF]..)/) { |
158
|
0
|
|
|
|
|
0
|
$bits = unpack("B32", $1); |
159
|
0
|
|
|
|
|
0
|
last; |
160
|
|
|
|
|
|
|
} |
161
|
0
|
|
|
|
|
0
|
$data = substr $data, -3 |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
0
|
|
|
|
|
0
|
my @fields; |
165
|
0
|
|
|
|
|
0
|
for (qw/11 2 2 1 4 2 1 1 1 2 2 1 1 2/) { |
166
|
0
|
|
|
|
|
0
|
push @fields, oct "0b" . substr $bits, 0, $_; |
167
|
0
|
0
|
|
|
|
0
|
$bits = substr $bits, $_ if length $bits > $_; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
0
|
$self->{mp3header}={}; |
171
|
0
|
|
|
|
|
0
|
for (qw/sync version layer proctection bitrate_id sampling_rate_id padding private |
172
|
|
|
|
|
|
|
channel_mode mode_ext copyright original emphasis/) { |
173
|
0
|
|
|
|
|
0
|
$self->{mp3header}->{$_}=shift @fields; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
return $self->{mp3header} |
177
|
0
|
|
|
|
|
0
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# use filename to determine information about song/artist/album |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=pod |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=over 4 |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item parse_filename() |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
($title, $artist, $no, $album, $year) = $mp3->parse_filename($what, $filename); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
parse_filename() tries to extract information about artist, title, |
191
|
|
|
|
|
|
|
track number, album and year from the filename. (For backward |
192
|
|
|
|
|
|
|
compatibility it may be also called by deprecated name |
193
|
|
|
|
|
|
|
read_filename().) |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
This is likely to fail for a lot of filenames, especially the album will |
196
|
|
|
|
|
|
|
be often wrongly guessed, as the name of the parent directory is taken as |
197
|
|
|
|
|
|
|
album name. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
$what and $filename are optional. $what maybe title, track, artist, album |
200
|
|
|
|
|
|
|
or year. If $what is defined parse_filename() will return only this element. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
If $filename is defined this filename will be used and not the real |
203
|
|
|
|
|
|
|
filename which was set by L with |
204
|
|
|
|
|
|
|
Cnew($filename)>. Otherwise the actual filename is used |
205
|
|
|
|
|
|
|
(subject to configuration variable C). |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Following formats will be hopefully recognized: |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
- album name/artist name - song name.mp3 |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
- album_name/artist_name-song_name.mp3 |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
- album.name/artist.name_song.name.mp3 |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
- album name/(artist name) song name.mp3 |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
- album name/01. artist name - song name.mp3 |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
- album name/artist name - 01 - song.name.mp3 |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
If artist or title end in C<(NUMBER)> with 4-digit NUMBER, it is considered |
222
|
|
|
|
|
|
|
the year. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=cut |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
*read_filename = \&parse_filename; |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub return_parsed { |
229
|
136
|
|
|
136
|
0
|
118
|
my ($self,$what) = @_; |
230
|
136
|
50
|
|
|
|
214
|
if (defined $what) { |
231
|
136
|
100
|
|
|
|
317
|
return $self->{parsed}{album} if $what =~/^al/i; |
232
|
109
|
100
|
|
|
|
1021
|
return $self->{parsed}{artist} if $what =~/^a/i; |
233
|
85
|
100
|
|
|
|
220
|
return $self->{parsed}{no} if $what =~/^tr/i; |
234
|
53
|
100
|
|
|
|
133
|
return $self->{parsed}{year} if $what =~/^y/i; |
235
|
17
|
|
|
|
|
64
|
return $self->{parsed}{title}; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
0
|
0
|
|
|
|
0
|
return $self->{parsed} unless wantarray; |
239
|
0
|
|
|
|
|
0
|
return map $self->{parsed}{$_} , qw(title artist no album year); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub parse_filename { |
243
|
80
|
|
|
80
|
1
|
90
|
my ($self,$what,$filename) = @_; |
244
|
80
|
50
|
|
|
|
117
|
unless (defined $filename) { |
245
|
80
|
|
|
|
|
130
|
$filename = $self->filename; |
246
|
80
|
|
|
|
|
65
|
my $e; |
247
|
80
|
0
|
33
|
|
|
136
|
if ($e = $self->get_config('decode_encoding_filename') and $e->[0]) { |
248
|
0
|
|
|
|
|
0
|
require Encode; |
249
|
0
|
|
|
|
|
0
|
$filename = Encode::decode($e->[0], $filename); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
80
|
|
|
|
|
84
|
my $pathandfile = $filename; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
$self->return_parsed($what) if exists $self->{parsed_filename} |
255
|
80
|
100
|
66
|
|
|
294
|
and $self->{parsed_filename} eq $filename; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# prepare pathandfile for easier use |
258
|
80
|
|
|
|
|
146
|
my $ext_rex = $self->get_config('extension')->[0]; |
259
|
80
|
|
|
|
|
376
|
$pathandfile =~ s/$ext_rex//; # remove extension |
260
|
80
|
|
|
|
|
84
|
$pathandfile =~ s/ +/ /g; # replace several spaces by one space |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Keep two last components of the file name |
263
|
80
|
|
|
|
|
1271
|
my ($file, $path) = fileparse($pathandfile, ""); |
264
|
80
|
|
|
|
|
894
|
($path) = fileparse($path, ""); |
265
|
80
|
|
|
|
|
100
|
my $orig_file = $file; |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# check which chars are used for seperating words |
268
|
|
|
|
|
|
|
# assumption: spaces between words |
269
|
|
|
|
|
|
|
|
270
|
80
|
50
|
|
|
|
155
|
unless ($file =~/ /) { |
271
|
|
|
|
|
|
|
# no spaces used, find word seperator |
272
|
80
|
|
|
|
|
110
|
my $Ndot = $file =~ tr/././; |
273
|
80
|
|
|
|
|
65
|
my $Nunderscore = $file =~ tr/_/_/; |
274
|
80
|
|
|
|
|
69
|
my $Ndash = $file =~ tr/-/-/; |
275
|
80
|
50
|
33
|
|
|
276
|
if (($Ndot>$Nunderscore) && ($Ndot>1)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
276
|
0
|
|
|
|
|
0
|
$file =~ s/\./ /g; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
elsif ($Nunderscore > 1) { |
279
|
0
|
|
|
|
|
0
|
$file =~ s/_/ /g; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
elsif ($Ndash>2) { |
282
|
0
|
|
|
|
|
0
|
$file =~ s/-/ /g; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# check wich chars are used for seperating parts |
287
|
|
|
|
|
|
|
# assumption: " - " is used |
288
|
|
|
|
|
|
|
|
289
|
80
|
|
|
|
|
62
|
my $partsep = " - "; |
290
|
|
|
|
|
|
|
|
291
|
80
|
50
|
|
|
|
134
|
unless ($file =~ / - /) { |
292
|
80
|
50
|
|
|
|
203
|
if ($file =~ /-/) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
293
|
0
|
|
|
|
|
0
|
$partsep = "-"; |
294
|
|
|
|
|
|
|
} elsif ($file =~ /^\(.*\)/) { |
295
|
|
|
|
|
|
|
# replace brackets by - |
296
|
0
|
|
|
|
|
0
|
$file =~ s/^\((.*?)\)/$1 - /; |
297
|
0
|
|
|
|
|
0
|
$file =~ s/ +/ /; |
298
|
0
|
|
|
|
|
0
|
$partsep = " - "; |
299
|
|
|
|
|
|
|
} elsif ($file =~ /_/) { |
300
|
23
|
|
|
|
|
22
|
$partsep = "_"; |
301
|
|
|
|
|
|
|
} else { |
302
|
57
|
|
|
|
|
54
|
$partsep = "DoesNotExist"; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# get parts of name |
307
|
80
|
|
|
|
|
104
|
my ($title, $artist, $no, $album, $year)=("","","","",""); |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# try to find a track-number in front of filename |
310
|
80
|
50
|
|
|
|
199
|
if ($file =~ /^ *(\d+)[\W_]/) { |
311
|
0
|
|
|
|
|
0
|
$no=$1; # store number |
312
|
0
|
|
|
|
|
0
|
$file =~ s/^ *\d+//; # and delete it |
313
|
0
|
0
|
|
|
|
0
|
$file =~ s/^$partsep// || $file =~ s/^.//; |
314
|
0
|
|
|
|
|
0
|
$file =~ s/^ +//; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
80
|
100
|
|
|
|
146
|
$file =~ s/_+/ /g unless $partsep =~ /_/; #remove underscore unless they are needed for part seperation |
318
|
80
|
|
|
|
|
235
|
my @parts = split /$partsep/, $file; |
319
|
80
|
100
|
|
|
|
120
|
if (@parts == 1) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
320
|
57
|
|
|
|
|
58
|
$title=$parts[0]; |
321
|
57
|
50
|
33
|
|
|
238
|
$no = $file if $title and $title =~ /^\d{1,2}$/; |
322
|
|
|
|
|
|
|
} elsif (@parts == 2) { |
323
|
23
|
50
|
|
|
|
70
|
if ($parts[0] =~ /^\d{1,2}$/) { |
|
|
100
|
|
|
|
|
|
324
|
0
|
|
|
|
|
0
|
$no = $parts[0]; |
325
|
0
|
|
|
|
|
0
|
$title = $file; |
326
|
|
|
|
|
|
|
} elsif ($parts[1] =~ /^\d{1,2}$/) { |
327
|
3
|
|
|
|
|
4
|
$no = $parts[1]; |
328
|
3
|
|
|
|
|
4
|
$title = $file; |
329
|
|
|
|
|
|
|
} else { |
330
|
20
|
|
|
|
|
17
|
$artist=$parts[0]; |
331
|
20
|
|
|
|
|
15
|
$title=$parts[1]; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
} elsif (@parts > 2) { |
334
|
0
|
|
|
|
|
0
|
my $temp = ""; |
335
|
0
|
|
|
|
|
0
|
$artist = shift @parts; |
336
|
0
|
|
|
|
|
0
|
foreach (@parts) { |
337
|
0
|
0
|
|
|
|
0
|
if (/^ *(\d+)\.? *$/) { |
338
|
0
|
0
|
|
|
|
0
|
$artist.= $partsep . $temp if $temp; |
339
|
0
|
|
|
|
|
0
|
$temp=""; |
340
|
0
|
|
|
|
|
0
|
$no=$1; |
341
|
|
|
|
|
|
|
} else { |
342
|
0
|
0
|
|
|
|
0
|
$temp .= $partsep if $temp; |
343
|
0
|
|
|
|
|
0
|
$temp .= $_; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
} |
346
|
0
|
|
|
|
|
0
|
$title=$temp; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
80
|
|
|
|
|
77
|
$title =~ s/ +$//; |
350
|
80
|
|
|
|
|
65
|
$artist =~ s/ +$//; |
351
|
80
|
|
|
|
|
62
|
$no =~ s/ +$//; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Special-case names like audio12 etc created by some software |
354
|
|
|
|
|
|
|
# (cdda2wav, gramofile, etc) |
355
|
80
|
50
|
100
|
|
|
368
|
$no = $+ if not $no and $title =~ /^(\d+)?(?:audio|track|processed)\s*(\d+)?$/i and $+; |
|
|
|
66
|
|
|
|
|
356
|
|
|
|
|
|
|
|
357
|
80
|
|
|
|
|
69
|
$no =~ s/^0+//; |
358
|
|
|
|
|
|
|
|
359
|
80
|
50
|
|
|
|
114
|
if ($path) { |
360
|
0
|
0
|
|
|
|
0
|
unless ($artist) { |
361
|
0
|
|
|
|
|
0
|
$artist = $path; |
362
|
|
|
|
|
|
|
} else { |
363
|
0
|
|
|
|
|
0
|
$album = $path; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
# Keep the year in the title/artist (XXXX Should we?) |
367
|
80
|
50
|
33
|
|
|
255
|
$year = $1 if $title =~ /\((\d{4})\)/ or $artist =~ /\((\d{4})\)/; |
368
|
|
|
|
|
|
|
|
369
|
80
|
|
|
|
|
103
|
$self->{parsed_filename} = $filename; |
370
|
80
|
|
|
|
|
266
|
$self->{parsed} = { artist=>$artist, song=>$title, no=>$no, |
371
|
|
|
|
|
|
|
album=>$album, title=>$title, year => $year}; |
372
|
80
|
|
|
|
|
198
|
$self->return_parsed($what); |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=pod |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
=item title() |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
$title = $mp3->title($filename); |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
Returns the title, guessed from the filename. See also parse_filename(). (For |
383
|
|
|
|
|
|
|
backward compatibility, can be called by deprecated name song().) |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
$filename is optional and will be used instead of the real filename if defined. |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=cut |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
*song = \&title; |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub title { |
392
|
13
|
|
|
13
|
1
|
18
|
my $self = shift; |
393
|
13
|
|
|
|
|
32
|
return $self->parse_filename("title", @_); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=pod |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=item artist() |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
$artist = $mp3->artist($filename); |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
Returns the artist name, guessed from the filename. See also parse_filename() |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
$filename is optional and will be used instead of the real filename if defined. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=cut |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub artist { |
409
|
12
|
|
|
12
|
1
|
12
|
my $self = shift; |
410
|
12
|
|
|
|
|
34
|
return $self->parse_filename("artist", @_); |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=pod |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=item track() |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
$track = $mp3->track($filename); |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
Returns the track number, guessed from the filename. See also parse_filename() |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$filename is optional and will be used instead of the real filename if defined. |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=cut |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub track { |
426
|
22
|
|
|
22
|
1
|
539
|
my $self = shift; |
427
|
22
|
|
|
|
|
46
|
return $self->parse_filename("track", @_); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=item year() |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
$year = $mp3->year($filename); |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
Returns the year, guessed from the filename. See also parse_filename() |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
$filename is optional and will be used instead of the real filename if defined. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=cut |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub year { |
441
|
19
|
|
|
19
|
1
|
18
|
my $self = shift; |
442
|
19
|
|
|
|
|
50
|
my $y = $self->parse_filename("year", @_); |
443
|
19
|
50
|
|
|
|
28
|
return $y if length $y; |
444
|
19
|
|
|
|
|
61
|
return; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=pod |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=item album() |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
$album = $mp3->album($filename); |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Returns the album name, guessed from the filename. See also parse_filename() |
454
|
|
|
|
|
|
|
The album name is guessed from the parent directory, so it is very likely to fail. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
$filename is optional and will be used instead of the real filename if defined. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=cut |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub album { |
461
|
14
|
|
|
14
|
1
|
14
|
my $self = shift; |
462
|
14
|
|
|
|
|
27
|
return $self->parse_filename("album", @_); |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=item comment() |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
$comment = $mp3->comment($filename); # Always undef |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=cut |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
14
|
1
|
|
sub comment {} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=item genre() |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
$genre = $mp3->genre($filename); # Always undef |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=cut |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
22
|
1
|
|
sub genre {} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
1; |