863 lines
17 KiB
Perl
Executable File
863 lines
17 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
|
|
# (c) 2002 Armin Obersteiner <armin@xos.net>
|
|
# License: GPL v2
|
|
|
|
use MP3::Info;
|
|
use Unicode::String qw( latin1 utf16 );
|
|
use Shell qw ( find gzip );
|
|
use Getopt::Std;
|
|
use File::Copy;
|
|
use Filesys::DiskFree;
|
|
|
|
use Data::Dumper qw (Dumper);
|
|
|
|
use strict;
|
|
|
|
my $version="0.68";
|
|
|
|
#
|
|
# options & config
|
|
#
|
|
|
|
my %opt;
|
|
getopts("fcnh",\%opt);
|
|
|
|
if($opt{h}) {
|
|
print <<"EOF";
|
|
$0 [-c] [-f] [Search Pattern 1] [Search Pattern 2] ...
|
|
|
|
-c create: create directory structure on plain ipod before syncing
|
|
(default: you get a warning if there is no ipod structure)
|
|
|
|
-f force: rename ipod and use it with $0 before syncing
|
|
(default: an unknown ipod stays untouched)
|
|
|
|
-n name check: checks mp3 names for possible illegal characters
|
|
|
|
Search Patterns: for each search pattern a playlist is created
|
|
(case insensitive)
|
|
EOF
|
|
exit;
|
|
}
|
|
|
|
my $buffer = 5*1024*1024; # leave some MB free for iTunesDB
|
|
|
|
my @required = qw ( SYNCMODE PLAYLISTDIR IPODDIR BACKUPDIR );
|
|
|
|
my $rc=readrc("$ENV{HOME}/.ipod/config",\@required);
|
|
|
|
#print Dumper($rc);
|
|
|
|
|
|
#
|
|
# check ipod name
|
|
#
|
|
|
|
my ($ipod_name, $real_name, $computer_name)=get_ipodname($rc->{IPODDIR});
|
|
unless($ipod_name) {
|
|
die "IPOD dir not found: $rc->{IPODDIR}" unless $opt{c};
|
|
}
|
|
|
|
#
|
|
# check ipod dirs (recreate them if necessary)
|
|
#
|
|
|
|
mkdir "$rc->{IPODDIR}/iPod_Control",0755 unless(-d "$rc->{IPODDIR}/iPod_Control");
|
|
mkdir "$rc->{IPODDIR}/iPod_Control/Music",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Music");
|
|
mkdir "$rc->{IPODDIR}/iPod_Control/iTunes",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/iTunes");
|
|
mkdir "$rc->{IPODDIR}/iPod_Control/Device",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Device");
|
|
for(0..19) {
|
|
my $d=sprintf "%.2d",$_;
|
|
mkdir "$rc->{IPODDIR}/iPod_Control/Music/F$d",0755 unless(-d "$rc->{IPODDIR}/iPod_Control/Music/F$d");
|
|
}
|
|
|
|
unless($opt{c}) {
|
|
print STDERR "IPOD name: $ipod_name\n";
|
|
print STDERR "Synced by: $real_name\n";
|
|
print STDERR "Synced on: $computer_name\n";
|
|
|
|
if($rc->{WRITEDEVICEINFO} && !$opt{f}) {
|
|
my $exit=0;
|
|
unless($rc->{IPODNAME} eq $ipod_name) {
|
|
$exit=1;
|
|
print STDERR "Your IPOD name: $rc->{IPODNAME}\n";
|
|
}
|
|
unless($rc->{REALNAME} eq $real_name) {
|
|
$exit=1;
|
|
print STDERR "Your real name: $rc->{REALNAME}\n";
|
|
}
|
|
unless($rc->{COMPUTERNAME} eq $computer_name) {
|
|
$exit=1;
|
|
print STDERR "Your computer: $rc->{COMPUTERNAME}\n";
|
|
}
|
|
die "names mismatch, use -f to override" if $exit;
|
|
}
|
|
print STDERR "\n";
|
|
}
|
|
|
|
#
|
|
# write ipod name
|
|
#
|
|
|
|
if($rc->{WRITEDEVICEINFO}) {
|
|
set_ipodname(
|
|
$rc->{IPODDIR},$rc->{BACKUPDIR},
|
|
$rc->{IPODNAME},$rc->{REALNAME},$rc->{COMPUTERNAME}
|
|
);
|
|
$ipod_name=$rc->{IPODNAME};
|
|
}
|
|
|
|
#
|
|
# check for songs
|
|
#
|
|
|
|
my %songs;
|
|
my %check;
|
|
|
|
my $dir;
|
|
$dir=$rc->{IPODDIR}."/iPod_Control/Music";
|
|
$dir=$rc->{SYNCDIR} if($rc->{SYNCMODE} >= 2);
|
|
|
|
my %tosync;
|
|
if(($rc->{SYNCLIST}) && ($rc->{SYNCMODE} == 2)) {
|
|
open IN,$rc->{SYNCLIST} or die "all-playlist: $rc->{SYNCLIST} not found";
|
|
while(<IN>) {
|
|
chomp;
|
|
$tosync{$_}=1;
|
|
}
|
|
close IN;
|
|
}
|
|
|
|
my @mp3s;
|
|
if(($rc->{SYNCMODE} == 3)) {
|
|
my @pl=find("$rc->{PLAYLISTDIR}/* 2>/dev/null");
|
|
my %test;
|
|
|
|
for my $p (@pl) {
|
|
chomp $p;
|
|
my ($n) = $p =~ /.*\/(.*?)$/;
|
|
open IN,$p or die "playlist: $p could not be opened";
|
|
while(<IN>) {
|
|
unless($test{$_}) {
|
|
push @mp3s,$_;
|
|
$test{$_}=1;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
@mp3s=find($dir);
|
|
}
|
|
|
|
for(@mp3s) {
|
|
chomp $_;
|
|
next unless(/\.(m|M)(p|P)3$/);
|
|
my $name=$_;
|
|
|
|
if(keys %tosync) {
|
|
next unless($tosync{$name});
|
|
}
|
|
|
|
if($opt{n}) {
|
|
die "illegal character in filename [$name]\n" unless ($name =~ /^[A-Za-z0-9\.\-_\/\,]+$/);
|
|
}
|
|
|
|
s/\://g;
|
|
s/.*\///g;
|
|
$songs{$name}{name}=$_;
|
|
if($rc->{SYNCMODE} >= 2) {
|
|
$songs{$name}{dir}="F".hash($_);
|
|
} else {
|
|
($songs{$name}{dir}) = $name =~ /\/(F\d\d)\//;
|
|
}
|
|
|
|
{
|
|
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
|
$atime,$mtime,$ctime,$blksize,$blocks) = stat($name);
|
|
$songs{$name}{size}=$size;
|
|
$songs{$name}{date}=$mtime;
|
|
}
|
|
|
|
my $tag;
|
|
$tag = get_mp3tag($name) unless($rc->{ALWAYSTEMPLATES});
|
|
|
|
my ($artist,$album,$title,$order,$_dummy_);
|
|
|
|
if($tag) {
|
|
# print Dumper($tag);
|
|
# YEAR ARTIST COMMENT TRACKNUM TITLE ALBUM GENRE
|
|
$artist=$tag->{ARTIST};
|
|
$album=$tag->{ALBUM};
|
|
$title=$tag->{TITLE};
|
|
$order=$tag->{TRACKNUM};
|
|
$order=$1 if($order =~ /(\d+)\s*\//);
|
|
|
|
} else {
|
|
for(sort {length($b) <=> length($a)} keys %{$rc->{FILETEMPLATES}}) {
|
|
if(my @x = $name =~ /$_/) {
|
|
my $c=0;
|
|
for my $x (@x) {
|
|
#print "\$$rc->{FILETEMPLATES}->{$_}->[$c]=\"$x\";\n";
|
|
eval "\$$rc->{FILETEMPLATES}->{$_}->[$c]=\"$x\";";
|
|
die "eval error: $@" if($@);
|
|
$c++;
|
|
}
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
unless($title) {
|
|
die "no title found in: $name";
|
|
}
|
|
|
|
$title =~ s/_/ /g;
|
|
$artist =~ s/_/ /g;
|
|
$album =~ s/_/ /g;
|
|
|
|
$songs{$name}{title}=$title;
|
|
$songs{$name}{artist}="";
|
|
$songs{$name}{album}="";
|
|
$songs{$name}{order}=0;
|
|
$songs{$name}{artist}=$artist if $artist;
|
|
$songs{$name}{album}=$album if $album;
|
|
$songs{$name}{order}=$order if $order;
|
|
|
|
my $info = get_mp3info ($name);
|
|
|
|
$songs{$name}{size}=$info->{SIZE};
|
|
$songs{$name}{bitrate}=$info->{BITRATE};
|
|
$songs{$name}{duration}=int($info->{SECS}*1000);
|
|
$songs{$name}{vbr}=$info->{VBR};
|
|
|
|
#print Dumper($info);
|
|
|
|
my $n=$songs{$name}{dir}."/".$songs{$name}{name};
|
|
unless($check{$n}) {
|
|
$check{$n}=1;
|
|
} else {
|
|
die "songname: $songs{$name}{name} not unique";
|
|
}
|
|
}
|
|
|
|
#
|
|
# deleting unwanted songs
|
|
#
|
|
|
|
my %known;
|
|
for(keys %songs) {
|
|
$known{$songs{$_}{name}}=1;
|
|
}
|
|
|
|
#print Dumper(\%known);
|
|
|
|
my @ipod = find ("$rc->{IPODDIR}/iPod_Control/Music");
|
|
my @todel;
|
|
for(@ipod) {
|
|
next unless (/\.mp3$/i);
|
|
chomp;
|
|
|
|
my ($name) = $_ =~ /\/([^\/]+\.mp3)$/i;
|
|
unless($known{$name}) {
|
|
push @todel,$_;
|
|
}
|
|
}
|
|
|
|
my $del;
|
|
if($rc->{DELETEASK} && @todel) {
|
|
for(@todel) {
|
|
print "del: $_\n";
|
|
}
|
|
print "Do you really want to delete this songs? (y/N) ";
|
|
my $in=<STDIN>;
|
|
chomp $in;
|
|
$del=1 if($in =~ /^y$/i);
|
|
} else {
|
|
$del=1;
|
|
}
|
|
|
|
if($del) {
|
|
for(@todel) {
|
|
print STDERR "deleting: $_\n";
|
|
unlink($_);
|
|
}
|
|
}
|
|
|
|
#
|
|
# copy songs
|
|
#
|
|
|
|
my $main_sl="";
|
|
my $main_pl="";
|
|
my $index=500;
|
|
|
|
#print Dumper(\%songs);
|
|
|
|
my $df = new Filesys::DiskFree;
|
|
|
|
SONGS: for my $song (keys %songs) {
|
|
my $attr;
|
|
my $out="";
|
|
my $attr_c=3;
|
|
|
|
if($rc->{SYNCMODE} >= 2) {
|
|
my $to = "$rc->{IPODDIR}/iPod_Control/Music/$songs{$song}{dir}/$songs{$song}{name}";
|
|
#my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
|
# $atime,$mtime,$ctime,$blksize,$blocks) = stat($to);
|
|
#$size=0 unless $size;
|
|
#print "checking: $song [$songs{$song}{size}] -> $to [$size]\n";
|
|
#if($size != $songs{$song}{size}) {
|
|
|
|
unless(-e $to) {
|
|
print STDERR "syncing: $songs{$song}{name}\n";
|
|
# cp "\"$song\" \"$to\"";
|
|
|
|
$df->df();
|
|
my $free=$df->avail($rc->{IPODDIR});
|
|
|
|
if($free-$songs{$song}{size}-$buffer>0) {
|
|
copy($song,$to);
|
|
} else {
|
|
print STDERR "no space availiable for: $songs{$song}{name} [$songs{$song}{size}]\n";
|
|
delete $songs{$song};
|
|
next SONGS;
|
|
}
|
|
}
|
|
}
|
|
|
|
$songs{$song}{index}=$index;
|
|
|
|
$out.=create_mhod($songs{$song}{title},1);
|
|
|
|
if($songs{$song}{artist}) {
|
|
$attr_c++;
|
|
$out.=create_mhod($songs{$song}{artist},4);
|
|
}
|
|
if($songs{$song}{album}) {
|
|
$attr_c++;
|
|
$out.=create_mhod($songs{$song}{album},3);
|
|
}
|
|
|
|
$out.=create_mhod("MPEG audio file",6);
|
|
$out.=create_mhod(":iPod_Control:Music:".$songs{$song}{dir}.":".$songs{$song}{name},2);
|
|
|
|
$out=create_mhit(
|
|
$attr_c,length($out),$index,$songs{$song}{vbr},
|
|
$songs{$song}{date},$songs{$song}{size},
|
|
$songs{$song}{duration},$songs{$song}{order},
|
|
$songs{$song}{bitrate}
|
|
).$out;
|
|
|
|
$main_sl.=$out;
|
|
|
|
$main_pl.=create_mhod_mhip($songs{$song}{index});
|
|
|
|
$index++;
|
|
}
|
|
|
|
#print Dumper(\%songs);
|
|
|
|
my %playlists;
|
|
my @pl=find("$rc->{PLAYLISTDIR}/* 2>/dev/null");
|
|
|
|
for my $p (@pl) {
|
|
chomp $p;
|
|
my ($n) = $p =~ /.*\/(.*?)$/;
|
|
open IN,$p or die "playlist: $p could not be opened";
|
|
while(<IN>) {
|
|
my $song=$_;
|
|
chomp $song;
|
|
|
|
unless($songs{$song}) {
|
|
print STDERR "ignoring song in playlist [$p], [$song] does not exist in syncdir or ipod full\n";
|
|
} else {
|
|
$playlists{$n}{raw}.=create_mhod_mhip($songs{$song}{index});
|
|
$playlists{$n}{count}++;
|
|
}
|
|
}
|
|
close IN;
|
|
}
|
|
|
|
#
|
|
# creating search pattern playlists
|
|
#
|
|
|
|
for my $pattern (@ARGV) {
|
|
my @list;
|
|
for(keys %songs) {
|
|
push @list,$songs{$_}{index} if($_ =~ /$pattern/i);
|
|
}
|
|
unless(@list) {
|
|
print STDERR "nothing for searchpattern: $pattern found\n";
|
|
} else {
|
|
my ($name)=$pattern=~/(\S\S\S+)/;
|
|
unless(length($name)>=3) {
|
|
$name=$pattern;
|
|
$name =~ s/[^A-Za-z0-9]//g;
|
|
}
|
|
for(@list) {
|
|
$playlists{$name}{raw}.=create_mhod_mhip($_);
|
|
$playlists{$name}{count}++;
|
|
}
|
|
print STDERR @list." songs for searchpattern: $pattern found\n";
|
|
}
|
|
}
|
|
|
|
#print Dumper(\%playlists);
|
|
|
|
#
|
|
# build the pieces together
|
|
#
|
|
|
|
my $output;
|
|
|
|
my $song_c=keys %songs;
|
|
|
|
print STDERR "\nFound songs: $song_c\n";
|
|
|
|
my $tmp=create_mhlt($song_c).$main_sl;
|
|
$main_sl=create_mhsd(96+length($tmp),1).$tmp;
|
|
|
|
print STDERR "Songlist created\n";
|
|
|
|
my $pl_c=keys %playlists;
|
|
|
|
print STDERR "\nFound additional playlists: $pl_c\n";
|
|
|
|
$tmp=create_mhlp($pl_c+1).create_playlist_main($ipod_name,$song_c).$main_pl;
|
|
print STDERR "\nMain playlist created: $song_c songs\n\n";
|
|
|
|
for(keys %playlists) {
|
|
$tmp.=create_playlist($_,$playlists{$_}{count}).$playlists{$_}{raw};
|
|
print STDERR "Playlist \"$_\" created: $playlists{$_}{count} songs\n";
|
|
}
|
|
|
|
$main_pl=create_mhsd(96+length($tmp),2).$tmp;
|
|
|
|
|
|
$output=create_mhbd(104+length($main_sl.$main_pl)).$main_sl.$main_pl;
|
|
|
|
# backup old iTunesDB
|
|
if(-e "$rc->{IPODDIR}/iPod_Control/iTunes/iTunesDB") {
|
|
my $t=time();
|
|
copy("$rc->{IPODDIR}/iPod_Control/iTunes/iTunesDB","$rc->{BACKUPDIR}/iTunesDB_$t");
|
|
gzip("$rc->{BACKUPDIR}/iTunesDB_$t");
|
|
}
|
|
|
|
open OUT,">".$rc->{IPODDIR}."/iPod_Control/iTunes/iTunesDB" or die "cannot write iTunesDB";
|
|
print OUT $output;
|
|
close OUT;
|
|
|
|
print STDERR "\niTunesDB created.\n";
|
|
exit;
|
|
# END
|
|
|
|
|
|
#
|
|
# internal subroutines
|
|
#
|
|
|
|
sub create_mhbd {
|
|
my ($size) = @_;
|
|
|
|
my $r= "mhbd";
|
|
$r.= pack "V",104;
|
|
$r.= pack "V",$size;
|
|
$r.= pack "V",1;
|
|
$r.= pack "V",1;
|
|
$r.= pack "V",2;
|
|
for(1..20) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub create_mhlp {
|
|
my ($count) = @_;
|
|
|
|
my $r= "mhlp";
|
|
$r.= pack "V",92;
|
|
$r.= pack "V",$count;
|
|
for(1..20) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub create_playlist {
|
|
my ($name,$anz) = @_;
|
|
|
|
my $ipod_name=create_mhod($name,1);
|
|
|
|
my $r= "mhyp";
|
|
$r.= pack "V",108;
|
|
$r.= pack "V",108+648+length($ipod_name)+$anz*(76+44);
|
|
$r.= pack "V",2;
|
|
$r.= pack "V",$anz;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",3088620292;
|
|
$r.= pack "V",2317718671;
|
|
$r.= pack "V",3655876446;
|
|
for(1..18) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
$r.= "mhod";
|
|
$r.= pack "V",24;
|
|
$r.= pack "V",648;
|
|
$r.= pack "V",100;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",12714187; # ?? 12714187
|
|
$r.= pack "V",26215000;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",65736;
|
|
$r.= pack "V",1; # ?? 1
|
|
$r.= pack "V",6; # ?? 6
|
|
$r.= pack "V",0; # ?? 0
|
|
$r.= pack "V",2555905; # ?? 2555905
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",13107202;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",3276813;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",8192004;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",8192003;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",5242888;
|
|
for(1..107) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",140;
|
|
for(1..19) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r.$ipod_name;
|
|
}
|
|
|
|
sub create_playlist_main {
|
|
my ($name,$anz) = @_;
|
|
|
|
my $ipod_name=create_mhod($name,1);
|
|
|
|
my $r= "mhyp";
|
|
$r.= pack "V",108;
|
|
$r.= pack "V",108+648+length($ipod_name)+$anz*(76+44);
|
|
$r.= pack "V",2;
|
|
$r.= pack "V",$anz;
|
|
$r.= pack "V",1;
|
|
$r.= pack "V",3087491191;
|
|
$r.= pack "V",837788566;
|
|
$r.= pack "V",62365;
|
|
for(1..18) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
$r.= "mhod";
|
|
$r.= pack "V",24;
|
|
$r.= pack "V",648;
|
|
$r.= pack "V",100;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",13172927; # ?? 12714187
|
|
$r.= pack "V",26215000;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",65736;
|
|
$r.= pack "V",5; # ?? 1
|
|
$r.= pack "V",6; # ?? 6
|
|
$r.= pack "V",3; # ?? 0
|
|
$r.= pack "V",1179649; # ?? 2555905
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",13107202;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",3276813;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",8192004;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",8192003;
|
|
for(1..3) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",5242888;
|
|
for(1..107) {
|
|
$r.= pack "V",0;
|
|
}
|
|
$r.= pack "V",140;
|
|
for(1..19) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r.$ipod_name;
|
|
}
|
|
|
|
sub create_mhod_mhip {
|
|
my ($ref) = @_;
|
|
|
|
my $r= "mhip";
|
|
$r.= pack "V",76;
|
|
$r.= pack "V",76;
|
|
$r.= pack "V",1;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",$ref-1;
|
|
$r.= pack "V",$ref;
|
|
$r.= pack "V",3088619525;
|
|
for(1..11) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
$r.="mhod";
|
|
$r.= pack "V",24;
|
|
$r.= pack "V",44;
|
|
$r.= pack "V",100;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",$ref-1;
|
|
for(1..4) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub create_mhsd {
|
|
my ($size,$type) = @_;
|
|
|
|
my $r="mhsd";
|
|
$r.= pack "V",96;
|
|
$r.= pack "V",$size;
|
|
$r.= pack "V",$type;
|
|
for(1..20) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub create_mhlt {
|
|
my ($count) = @_;
|
|
|
|
my $r="mhlt";
|
|
$r.= pack "V",92;
|
|
$r.= pack "V",$count;
|
|
for(1..20) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub create_mhit {
|
|
my ($arttr_c,$attr_s,$index,$vbr,$date,$size,$dur,$order,$bitrate) = @_;
|
|
|
|
my $r="mhit";
|
|
$r.= pack "V",156;
|
|
$r.= pack "V",156+$attr_s;
|
|
$r.= pack "V",$arttr_c;
|
|
$r.= pack "V",$index;
|
|
$r.= pack "V",1;
|
|
$r.= pack "V",0;
|
|
my $type=256;
|
|
$type+=1 if($vbr);
|
|
$r.= pack "V",$type;
|
|
$r.= pack "V",$date+2082844800;
|
|
$r.= pack "V",$size;
|
|
$r.= pack "V",$dur;
|
|
$r.= pack "V",$order;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",0;
|
|
$r.= pack "V",$bitrate;
|
|
$r.= pack "V",2890137600;
|
|
for(1..23) {
|
|
$r.= pack "V",0;
|
|
}
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub create_mhod {
|
|
my ($string,$type) = @_;
|
|
my $len=length($string);
|
|
|
|
my $r="mhod";
|
|
$r.= pack "V",24;
|
|
$r.= pack "V",(40+2*$len);
|
|
$r.= pack "V",$type;
|
|
$r.= pack "V2",0;
|
|
$r.= pack "V",1;
|
|
$r.= pack "V",(2*$len);
|
|
$r.= pack "V2",0;
|
|
|
|
my $u=latin1($string);
|
|
$u->byteswap;
|
|
$r.= $u->utf16;
|
|
|
|
return $r;
|
|
}
|
|
|
|
sub set_ipodname {
|
|
my ($dev,$backup,$name,$real,$cpu)=@_;
|
|
$dev.="/iPod_Control/iTunes/DeviceInfo";
|
|
|
|
my $file;
|
|
|
|
for(1..384) {
|
|
$file.=pack "V",0;
|
|
}
|
|
|
|
my $l=length($name);
|
|
substr($file,0,2)=pack "v",$l;
|
|
my $u=latin1($name);
|
|
$u->byteswap;
|
|
substr($file,2,$l*2)=$u->utf16;
|
|
|
|
$l=length($real);
|
|
substr($file,512,2)=pack "v",$l;
|
|
$u=latin1($real);
|
|
$u->byteswap;
|
|
substr($file,514,$l*2)=$u->utf16;
|
|
|
|
$l=length($cpu);
|
|
substr($file,1024,2)=pack "v",$l;
|
|
$u=latin1($cpu);
|
|
$u->byteswap;
|
|
substr($file,1026,$l*2)=$u->utf16;
|
|
|
|
if(-e $dev) {
|
|
my $t=time();
|
|
copy($dev,"$backup/DeviceInfo_$t");
|
|
gzip("$backup/DeviceInfo_$t");
|
|
}
|
|
open IPOD,">$dev" or die "cannot write DeviceInfo";
|
|
print IPOD $file;
|
|
close IPOD;
|
|
}
|
|
|
|
sub get_ipodname {
|
|
my $dev=shift;
|
|
$dev.="/iPod_Control/iTunes/DeviceInfo";
|
|
my $file;
|
|
my $buff;
|
|
|
|
open IPOD,$dev or return undef;
|
|
while (read(IPOD, $buff, 8 * 2**10)) {
|
|
$file.=$buff;
|
|
}
|
|
close IPOD;
|
|
|
|
my $l=unpack "v",substr($file,0,2);
|
|
my $s=substr($file,2,$l*2);
|
|
my $u=utf16($s);
|
|
$u->byteswap;
|
|
my $name=$u->latin1;
|
|
|
|
$l=unpack "v",substr($file,512,2);
|
|
$s=substr($file,514,$l*2);
|
|
$u=utf16($s);
|
|
$u->byteswap;
|
|
my $realname=$u->latin1;
|
|
|
|
$l=unpack "v",substr($file,1024,2);
|
|
$s=substr($file,1026,$l*2);
|
|
$u=utf16($s);
|
|
$u->byteswap;
|
|
my $computername=$u->latin1;
|
|
|
|
return ($name,$realname,$computername);
|
|
}
|
|
|
|
sub hash {
|
|
my $string=shift;
|
|
my $key;
|
|
|
|
my $len=length($string);
|
|
|
|
for(my $j=$len-1 ; $j>1 ; $j--) {
|
|
$key+=ord(substr($string,$j,1));
|
|
}
|
|
|
|
return sprintf "%.2d",(substr($key,length($key)-2,2) % 20);
|
|
}
|
|
|
|
sub readrc {
|
|
my $file = shift;
|
|
my $req = shift;
|
|
my $rc;
|
|
|
|
my $sub;
|
|
|
|
open IN,$file or die "cannot open rc file: $file";
|
|
while(<IN>) {
|
|
next if /^\s*$/;
|
|
next if /^\s*#/;
|
|
|
|
if(/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
|
|
my $k=$1;
|
|
my $n=$2;
|
|
($n) = $n =~ /^\"(.*?)\"$/ if($n =~ /\"/);
|
|
unless($sub) {
|
|
$rc->{$k}=$n;
|
|
} else {
|
|
($k) = $k =~ /^\"(.*?)\"$/ if($k =~ /\"/);
|
|
my @n=split /,/,$n;
|
|
for(@n) {
|
|
s/^\s+//g;
|
|
s/\s+$//g;
|
|
s/^\"//;
|
|
s/\"$//;
|
|
}
|
|
$rc->{$sub}->{$k}=\@n;
|
|
}
|
|
} elsif (/^\s*(\S+)\s*\{/) {
|
|
$sub=$1;
|
|
} elsif (/^\s*}/) {
|
|
$sub=undef;
|
|
}
|
|
}
|
|
|
|
if($rc->{SYNCMODE} == 2) {
|
|
push @$req,"SYNCDIR";
|
|
}
|
|
if($rc->{WRITEDEVICEINFO} == 1) {
|
|
push @$req,("IPODNAME","REALNAME","COMPUTERNAME");
|
|
}
|
|
if($rc->{ALWAYSTEMPLATES} == 1) {
|
|
push @$req,"FILETEMPLATES";
|
|
}
|
|
|
|
for my $d (keys %$rc) {
|
|
if($d =~ /DIR$/) {
|
|
$rc->{$d} =~ s/\~/$ENV{HOME}/;
|
|
}
|
|
}
|
|
$rc->{SYNCLIST} =~ s/\~/$ENV{HOME}/ if $rc->{SYNCLIST};
|
|
|
|
for(@$req) {
|
|
die "RC PARAMETER: $_ not found" unless($rc->{$_});
|
|
}
|
|
return $rc;
|
|
}
|