27
28
use GNUpod::FileMagic;
30
use vars qw(%opts %dupdb);
32
print "gnupod_addsong.pl Version 0.94rc1 (C) 2002-2004 Adrian Ulrich\n";
32
use constant MACTIME => 2082931200; #Mac EPOCH offset
33
use vars qw(%opts %dupdb_normal %dupdb_lazy $int_count);
35
print "gnupod_addsong.pl Version ###__VERSION__### (C) Adrian Ulrich\n";
37
$int_count = 3; #The user has to send INT (Ctrl+C) x times until we stop
34
39
$opts{mount} = $ENV{IPOD_MOUNTPOINT};
35
40
#Don't add xml and itunes opts.. we *NEED* the mount opt to be set..
36
GetOptions(\%opts, "help|h", "mount|m=s", "restore|r", "duplicate|d");
41
GetOptions(\%opts, "version", "help|h", "mount|m=s", "decode=s", "restore|r", "duplicate|d", "disable-v2", "disable-v1",
42
"set-artist=s", "set-album=s", "set-genre=s", "set-rating=i", "set-playcount=i",
43
"set-songnum", "playlist|p=s");
44
GNUpod::FooBar::GetConfig(\%opts, {'decode'=>'s', mount=>'s', duplicate=>'b',
45
'disable-v1'=>'b', 'disable-v2'=>'b', 'set-songnum'=>'b'},
49
usage("\n--decode needs 'pcm' 'mp3' 'aac' or 'aacbm' -> '--decode=mp3'\n") if $opts{decode} && $opts{decode} !~ /^(mp3|aac|aacbm|pcm|crashme)$/;
38
50
usage() if $opts{help};
51
version() if $opts{version};
53
$SIG{'INT'} = \&handle_int;
42
54
if($opts{restore}) {
43
55
print "If you use --restore, you'll *lose* your playlists\n";
44
56
print " Hit ENTER to continue or CTRL+C to abort\n\n";
46
$opts{duplicate} = 1; #Don't skip dups on restore
58
delete($opts{decode}); #We don't decode anything
59
$opts{duplicate} = 1; #Don't skip dups on restore
60
$opts{decode} = undef; #Do not encode, only native files are on an iPod
47
61
startup(glob("$opts{mount}/iPod_Control/Music/*/*"));
49
63
elsif($ARGV[0] eq "-" && @ARGV == 1) {
70
84
$opts{_no_sync} = $opts{restore};
72
86
my $con = GNUpod::FooBar::connect(\%opts);
73
usage($con->{status}."\n") if $con->{status} || !@files;
75
unless($opts{restore}) {
76
GNUpod::XMLhelper::doxml($con->{xml}) or usage("Failed to parse $con->{xml}\n");
81
#We are ready to copy each file..
87
usage($con->{status}."\n") if $con->{status} || !@files;
89
unless($opts{restore}) { #We parse the old file, if we are NOT restoring the iPod
90
GNUpod::XMLhelper::doxml($con->{xml}) or usage("Failed to parse $con->{xml}, did you run gnupod_INIT.pl?\n");
93
if ($opts{playlist}) { #Create this playlist
94
print "> Adding songs to Playlist '$opts{playlist}'\n";
95
GNUpod::XMLhelper::addpl($opts{playlist}); #Fixme: this may printout a warning..
100
#We are ready to copy each file..
82
101
foreach my $file (@files) {
102
#Skip all songs if user sent INT
87
my $fh = GNUpod::FileMagic::wtf_is($file);
108
my ($fh,$media_h,$converter) = GNUpod::FileMagic::wtf_is($file, {noIDv1=>$opts{'disable-v1'},
109
noIDv2=>$opts{'disable-v2'},
110
decode=>$opts{'decode'}},$con);
90
print STDERR "* Skipping '$file', unknown file type\n";
113
warn "* [****] Skipping '$file', unknown file type\n";
117
my $wtf_ftyp = $media_h->{ftyp}; #'codec' .. maybe ALAC
118
my $wtf_frmt = $media_h->{format}; #container ..maybe M4A
119
my $wtf_ext = $media_h->{extension}; #Possible extensions (regexp!)
121
#wtf_is found a filetype, override data if needed
122
$fh->{artist} = $opts{'set-artist'} if $opts{'set-artist'};
123
$fh->{album} = $opts{'set-album'} if $opts{'set-album'};
124
$fh->{genre} = $opts{'set-genre'} if $opts{'set-genre'};
125
$fh->{rating} = $opts{'set-rating'} if $opts{'set-rating'};
126
$fh->{playcount} = $opts{'set-playcount'} if $opts{'set-playcount'};
127
$fh->{songnum} = 1+$addcount if $opts{'set-songnum'};
129
#Set the addtime to unixtime(now)+MACTIME (the iPod uses mactime)
130
#This breaks perl < 5.8 if we don't use int(time()) !
131
$fh->{addtime} = int(time())+MACTIME;
134
#Check for duplicates
135
if(!$opts{duplicate} && (my $dup = checkdup($fh,$converter))) {
136
print "! [!!!] '$file' is a duplicate of song $dup, skipping file\n";
137
create_playlist_now($opts{playlist}, $dup); #We also add duplicates to a playlist..
141
## Ok, file is not a duplicate
145
print "> Converting '$file' from $wtf_ftyp into $opts{decode}, please wait...\n";
146
my $path_of_converted_file = GNUpod::FileMagic::kick_convert($converter,$file, uc($opts{decode}), $con);
147
unless($path_of_converted_file) {
148
print "! [!!!] Could not convert $file\n";
152
#Ok, we got a converted file, fillout the gaps
153
my($conv_fh, $conv_media_h) = GNUpod::FileMagic::wtf_is($path_of_converted_file, undef, $con);
156
warn "* [***] Internal problem: $converter did not produce valid data.\n";
157
warn "* [***] Something is wrong with $path_of_converted_file (file not deleted, debug it! :) )\n";
161
#We didn't know things like 'filesize' before...
162
$fh->{time} = $conv_fh->{time};
163
$fh->{bitrate} = $conv_fh->{bitrate};
164
$fh->{srate} = $conv_fh->{srate};
165
$fh->{filesize} = $conv_fh->{filesize};
166
$wtf_frmt = $conv_media_h->{format}; #Set the new format (-> container)
167
$wtf_ext = $conv_media_h->{extension}; #Set the new possible extension
168
#BUT KEEP ftyp! (= codec)
170
$file = $path_of_converted_file; #Point $file to new file
95
(${$fh}{path}, my $target) = GNUpod::XMLhelper::getpath($opts{mount}, $file, keepfile=>$opts{restore});
97
if(!$opts{duplicate} && (my $dup = checkdup($fh))) {
98
print "! '$fh->{title}' is a duplicate of song $dup, skipping file\n";
175
(${$fh}{path}, my $target) = GNUpod::XMLhelper::getpath($opts{mount}, $file,
176
{format=>$wtf_frmt, extension=>$wtf_ext, keepfile=>$opts{restore}});
179
if(!defined($target)) {
180
warn "*** FATAL *** Skipping '$file' , no target found!\n";
101
if($opts{restore} || File::Copy::copy($file, $target)) {
102
print "+ $file ($fh->{album} / $fh->{title})\n";
105
GNUpod::XMLhelper::mkfile($fmh,{addid=>1}); #Try to add an id
182
elsif($opts{restore} || File::Copy::copy($file, $target)) {
183
printf("+ [%-4s][%3d] %-32s | %-32s | %-24s\n",
184
uc($wtf_ftyp),1+$addcount, $fh->{title}, $fh->{album},$fh->{artist});
186
my $id = GNUpod::XMLhelper::mkfile({file=>$fh},{addid=>1}); #Try to add an id
187
create_playlist_now($opts{playlist}, $id);
188
$addcount++; #Inc. addcount
108
190
else { #We failed..
109
print STDERR "-- FATAL -- Could not copy $file to $target: $! ... skipping\n";
191
warn "*** FATAL *** Could not copy '$file' to '$target': $!\n";
193
unlink($file) if $converter; #File is in $tmp if $converter is set...
114
if($addcount) { #We have to modify the xmldoc
115
print "> Writing new XML File\n";
116
GNUpod::XMLhelper::writexml($con->{xml});
198
if($opts{playlist} || $addcount) { #We have to modify the xmldoc
199
print "> Writing new XML File, added $addcount file(s)\n";
200
GNUpod::XMLhelper::writexml($con);
118
203
print "\n Done\n";
208
#############################################################
209
# Add item to playlist
210
sub create_playlist_now {
211
my($plname, $id) = @_;
213
if($plname && $id >= 0) {
214
#Broken-by-design: We don't have a ID-Pool for playlists..
215
#-> Create a fake_entry
216
my $fake_entry = GNUpod::XMLhelper::mkfile({ add => { id => $id } }, { return=>1 });
218
foreach(GNUpod::XMLhelper::getpl_content($plname)) {
219
if($_ eq $fake_entry) {
223
GNUpod::XMLhelper::mkfile({ add => { id => $id } },{"plname"=>$plname}) unless $found;
121
229
## XML Handlers ##
123
$dupdb{"$_[0]->{file}->{bitrate}/$_[0]->{file}->{time}/$_[0]->{file}->{filesize}"}= $_[0]->{file}->{id}||-1;
231
$dupdb_normal{lc($_[0]->{file}->{title})."/$_[0]->{file}->{bitrate}/$_[0]->{file}->{time}/$_[0]->{file}->{filesize}"}= $_[0]->{file}->{id}||-1;
233
#This is worse than _normal, but the only way to detect dups *before* re-encoding...
234
$dupdb_lazy{lc($_[0]->{file}->{title})."/".lc($_[0]->{file}->{album})."/".lc($_[0]->{file}->{artist})}= $_[0]->{file}->{id}||-1;
124
236
GNUpod::XMLhelper::mkfile($_[0],{addid=>1});
146
276
Usage: gnupod_addsong.pl [-h] [-m directory] File1 File2 ...
149
-m, --mount=directory : iPod mountpoint, default is \$IPOD_MOUNTPOINT
150
-r, --restore : Restore the iPod (create a new GNUtunesDB from scratch)
151
-d, --duplicate : Allow duplicate files
278
-h, --help display this help and exit
279
--version output version information and exit
280
-m, --mount=directory iPod mountpoint, default is \$IPOD_MOUNTPOINT
281
-r, --restore Restore the iPod (create a new GNUtunesDB from scratch)
282
-d, --duplicate Allow duplicate files
283
-p, --playlist=string Add songs to this playlist
284
--disable-v1 Do not read ID3v1 Tags (MP3 Only)
285
--disable-v2 Do not read ID3v2 Tags (MP3 Only)
286
--decode=pcm|mp3|aac|aacbm Convert FLAC Files to WAVE/MP3 or AAC 'on-the-fly'
287
--set-artist=string Set Artist (Override ID3 Tag)
288
--set-album=string Set Album (Override ID3 Tag)
289
--set-genre=string Set Genre (Override ID3 Tag)
290
--set-rating=int Set Rating
291
--set-playcount=int Set Playcount
292
--set-songnum Override 'Songnum/Tracknum' field
294
Report bugs to <bug-gnupod\@nongnu.org>
300
gnupod_addsong.pl (gnupod) ###__VERSION__###
301
Copyright (C) Adrian Ulrich 2002-2004
303
This is free software; see the source for copying conditions. There is NO
304
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.