~ubuntu-branches/ubuntu/feisty/gnupod-tools/feisty

« back to all changes in this revision

Viewing changes to src/gnupod_addsong.pl

  • Committer: Bazaar Package Importer
  • Author(s): Brian Nelson
  • Date: 2005-04-05 09:10:01 UTC
  • mto: (2.1.1 sarge)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050405091001-vjtr9oktjemr6mn6
Tags: upstream-0.98
ImportĀ upstreamĀ versionĀ 0.98

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
###__PERLBIN__###
1
2
#  Copyright (C) 2002-2004 Adrian Ulrich <pab at blinkenlights.ch>
2
3
#  Part of the gnupod-tools collection
3
4
#
27
28
use GNUpod::FileMagic;
28
29
use Getopt::Long;
29
30
use File::Copy;
30
 
use vars qw(%opts %dupdb);
31
 
 
32
 
print "gnupod_addsong.pl Version 0.94rc1 (C) 2002-2004 Adrian Ulrich\n";
 
31
 
 
32
use constant MACTIME => 2082931200; #Mac EPOCH offset
 
33
use vars qw(%opts %dupdb_normal %dupdb_lazy $int_count);
 
34
 
 
35
print "gnupod_addsong.pl Version ###__VERSION__### (C) Adrian Ulrich\n";
 
36
 
 
37
$int_count = 3; #The user has to send INT (Ctrl+C) x times until we stop
33
38
 
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");
37
 
 
 
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'},
 
46
                          "gnupod_addsong");
 
47
 
 
48
 
 
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};
39
 
 
40
 
 
41
 
 
 
51
version() if $opts{version};
 
52
 
 
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";
45
57
 <STDIN>;
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/*/*"));
48
62
}
49
63
elsif($ARGV[0] eq "-" && @ARGV == 1) {
51
65
 my @files = ();
52
66
  while(<STDIN>) {
53
67
   chomp;
54
 
   push(@files, $_);
 
68
   push(@files, $_); #This eats memory, but it isn't so bad...
55
69
  }
56
70
  startup(@files);
57
71
}
70
84
 $opts{_no_sync} = $opts{restore};
71
85
 
72
86
 my $con = GNUpod::FooBar::connect(\%opts);
73
 
usage($con->{status}."\n") if $con->{status} || !@files;
74
 
 
75
 
unless($opts{restore}) {
76
 
 GNUpod::XMLhelper::doxml($con->{xml}) or usage("Failed to parse $con->{xml}\n");
77
 
}
78
 
 
79
 
my $addcount = 0;
80
 
 
81
 
#We are ready to copy each file..
 
87
 usage($con->{status}."\n") if $con->{status} || !@files;
 
88
 
 
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");
 
91
 }
 
92
 
 
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..
 
96
 } 
 
97
 
 
98
 my $addcount = 0;
 
99
 
 
100
 #We are ready to copy each file..
82
101
 foreach my $file (@files) {
83
 
    #Skip dirs..
 
102
    #Skip all songs if user sent INT
 
103
    next if !$int_count;
 
104
    #Skip all dirs
84
105
    next if -d $file;
85
106
    
86
107
    #Get the filetype
87
 
    my $fh = GNUpod::FileMagic::wtf_is($file);
88
 
    
 
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);
 
111
 
89
112
    unless($fh) {
90
 
     print STDERR "* Skipping '$file', unknown file type\n";
91
 
     next;
92
 
    }
93
 
   
 
113
    warn "* [****] Skipping '$file', unknown file type\n";
 
114
     next;
 
115
    }
 
116
    
 
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!)
 
120
   
 
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'};
 
128
   
 
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;
 
132
 
 
133
 
 
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..
 
138
    next;
 
139
   }
 
140
 
 
141
   ## Ok, file is not a duplicate
 
142
 
 
143
   
 
144
   if($converter) {
 
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";
 
149
     next;
 
150
    }
 
151
 
 
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);
 
154
    
 
155
    unless($conv_fh) {
 
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";
 
158
     next;
 
159
    }
 
160
    
 
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)
 
169
    
 
170
    $file = $path_of_converted_file; #Point $file to new file
 
171
   }
 
172
 
 
173
 
94
174
   #Get a path
95
 
   (${$fh}{path}, my $target) = GNUpod::XMLhelper::getpath($opts{mount}, $file, keepfile=>$opts{restore});
96
 
   #Copy the file
97
 
   if(!$opts{duplicate} && (my $dup = checkdup($fh))) {
98
 
    print "! '$fh->{title}' is a duplicate of song $dup, skipping file\n";
99
 
    next;
 
175
   (${$fh}{path}, my $target) = GNUpod::XMLhelper::getpath($opts{mount}, $file, 
 
176
                                                           {format=>$wtf_frmt, extension=>$wtf_ext, keepfile=>$opts{restore}});
 
177
 
 
178
   
 
179
   if(!defined($target)) {
 
180
    warn "*** FATAL *** Skipping '$file' , no target found!\n";
100
181
   }
101
 
   if($opts{restore} || File::Copy::copy($file, $target)) {
102
 
     print "+ $file ($fh->{album} / $fh->{title})\n";
103
 
     my $fmh;
104
 
     $fmh->{file} = $fh;
105
 
     GNUpod::XMLhelper::mkfile($fmh,{addid=>1}); #Try to add an id
106
 
     $addcount++;
 
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});
 
185
     
 
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
107
189
   }
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";
110
192
   }
111
 
   
 
193
   unlink($file) if $converter; #File is in $tmp if $converter is set...
112
194
 }
113
195
 
114
 
if($addcount) { #We have to modify the xmldoc
115
 
 print "> Writing new XML File\n";
116
 
 GNUpod::XMLhelper::writexml($con->{xml});
117
 
}
 
196
 
 
197
 
 
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);
 
201
 }
 
202
 
118
203
 print "\n Done\n";
119
204
}
120
205
 
 
206
 
 
207
 
 
208
#############################################################
 
209
# Add item to playlist
 
210
sub create_playlist_now {
 
211
 my($plname, $id) = @_;
 
212
 
 
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 });
 
217
   my $found = 0;
 
218
   foreach(GNUpod::XMLhelper::getpl_content($plname)) {
 
219
     if($_ eq $fake_entry) {
 
220
       $found++; last;
 
221
     }
 
222
   }
 
223
   GNUpod::XMLhelper::mkfile({ add => { id => $id } },{"plname"=>$plname}) unless $found;
 
224
 }
 
225
}
 
226
 
 
227
 
 
228
 
121
229
## XML Handlers ##
122
230
sub newfile {
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;
 
232
 
 
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;
 
235
 
124
236
 GNUpod::XMLhelper::mkfile($_[0],{addid=>1});
125
237
}
126
238
 
133
245
###############################################################
134
246
# Check if the file is a duplicate
135
247
sub checkdup {
136
 
 my($fh) = @_;
137
 
 return $dupdb{"$fh->{bitrate}/$fh->{time}/$fh->{filesize}"};
138
 
}
 
248
 my($fh, $from_lazy) = @_;
 
249
 
 
250
 return  $dupdb_lazy{lc($_[0]->{title})."/".lc($_[0]->{album})."/".lc($_[0]->{artist})}
 
251
   if $from_lazy;
 
252
   
 
253
 return $dupdb_normal{lc($fh->{title})."/$fh->{bitrate}/$fh->{time}/$fh->{filesize}"};
 
254
}
 
255
 
 
256
 
 
257
################################################################
 
258
#Sighandler
 
259
sub handle_int {
 
260
 if($int_count) {
 
261
  warn "RECEIVED SIGINT (CTRL+C): gnupod_addsong.pl is still working! hit CTRL+C again $int_count time(s) to quit.\n";
 
262
  $int_count--;
 
263
 }
 
264
 else {
 
265
  warn "..wait.. cleaning up..\n";
 
266
 }
 
267
}
 
268
 
139
269
 
140
270
###############################################################
141
271
# Basic help
145
275
$rtxt
146
276
Usage: gnupod_addsong.pl [-h] [-m directory] File1 File2 ...
147
277
 
148
 
   -h, --help             : This ;)
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
152
 
 
153
 
EOF
154
 
}
155
 
 
156
 
 
157
 
 
158
 
 
 
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
 
293
 
 
294
Report bugs to <bug-gnupod\@nongnu.org>
 
295
EOF
 
296
}
 
297
 
 
298
sub version {
 
299
die << "EOF";
 
300
gnupod_addsong.pl (gnupod) ###__VERSION__###
 
301
Copyright (C) Adrian Ulrich 2002-2004
 
302
 
 
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.
 
305
 
 
306
EOF
 
307
}
159
308