Mac-iPod-GNUpod
view release on metacpan or search on metacpan
GNUpod/iTunesDBwrite.pm view on Meta::CPAN
foreach my $chr (@{$hs->{data}}) {
my $string = undef;
#Fixme: this is ugly (same as read_spldata)
if($chr->{field} =~ /^(2|3|4|8|9|14|18)$/) {
$string = Unicode::String::utf8($chr->{string})->utf16;
}
else {
my ($from, $to) = $chr->{string} =~ /(\d+):?(\d*)/;
$to ||=$from;
$string = pack("H8");
$string .= pack("H8", _x86itop($from));
$string .= pack("H24");
$string .= pack("H8", _x86itop(1));
$string .= pack("H8");
$string .= pack("H8", _x86itop($to));
$string .= pack("H24");
$string .= pack("H8", _x86itop(1));
$string .= pack("H40");
# __hd($string);
}
if(length($string) > 254) { #length field is limited to 0xfe!
$@ .= "Splstring too long for iTunes, cropping\n";
$string = substr($string,0,254);
}
$cr .= pack("H6");
$cr .= pack("h2", _itop($chr->{field}));
$cr .= pack("H6", reverse("010000"));
$cr .= pack("h2", _itop($chr->{action}));
$cr .= pack("H94");
$cr .= pack("h2", _itop(length($string)));
$cr .= $string;
}
my $ret = "mhod";
$ret .= pack("h8", _itop(24)); #Size of header
$ret .= pack("h8", _itop(length($cr)+160)); #header+body size
$ret .= pack("h8", _itop(51)); #type
$ret .= pack("H16");
$ret .= "SLst"; #Magic
$ret .= pack("H8", reverse("00010001")); #?
$ret .= pack("h6");
$ret .= pack("h2", _itop(int(@{$hs->{data}}))); #HTM (Childs from cr)
$ret .= pack("h6");
$ret .= pack("h2", _itop($anymatch)); #anymatch rule on or off
$ret .= pack("h240");
$ret .= $cr;
return $ret;
}
# Render a playlist
sub r_mpl {
# Expects a hash w/ the following keys:
# name => $ name of the pl
# type => $ type of the pl
# ids => [] list of songids of in pl
# curid => $ current id in db
# splprefs => {} holds spl prefs
# spldata => {} holds spl data
my %dat = @_;
my ($pl, $fc, $mhp) = ('', 0, 0);
# Spls handled here
if(ref($dat{splprefs}) eq "HASH") {
my $spl = $dat{splprefs};
$pl .= mk_splprefmhod({
item => $spl->{limititem},
sort => $spl->{limitsort},
mos => $spl->{moselected},
liveupdate => $spl->{liveupdate},
value => $spl->{limitval},
checkrule => $spl->{checkrule}
});
$pl .= mk_spldatamhod({anymatch => $spl->{matchany}, data => $dat{spldata}});
$mhp=2;
}
foreach(@{$dat{ids}}) {
$dat{curid}++;
my $cmhip = mk_mhip({childs => 1, plid => $dat{curid}, sid => $_});
my $cmhod = mk_mhod({fqid => $_});
next unless (defined($cmhip) && defined($cmhod)); #mk_mhod needs to be ok
$fc++;
$pl .= $cmhip . $cmhod;
}
my $plsize = length($pl);
#mhyp appends a listview to itself
my $mhyp = mk_mhyp({
size => $plsize, name => $dat{name}, type => $dat{type}, files => $fc, mhods => $mhp
});
return $mhyp . $pl, $dat{curid};
}
# header for all files (like you use mk_mhlp for playlists)
sub mk_mhlt {
my ($hr) = @_;
my $ret = "mhlt";
$ret .= pack("h8", _itop(92)); #Header size (static)
$ret .= pack("h8", _itop($hr->{songs})); #songs in this itunesdb
$ret .= pack("H160", "00"); #dummy space
return $ret;
}
# header for ALL playlists
sub mk_mhlp {
my ($hr) = @_;
my $ret = "mhlp";
$ret .= pack("h8", _itop(92)); #Static header size
$ret .= pack("h8", _itop($hr->{playlists})); #playlists on iPod (including main!)
$ret .= pack("h160", "00"); #dummy space
return $ret;
}
# Creates an header for a new playlist (child of mk_mhlp)
sub mk_mhyp {
my($hr) = @_;
# We need to create a listview-layout and an mhod with the name. iTunes
# prefs for this PL & PL name (default PL has device name as PL name)
my $appnd = mk_mhod({stype=>"title", string=>$hr->{name}}).__dummy_listview();
##Child mhods calc..
##We create 2 mhod's here.. mktunes may have created more mhods.. so we
##have to adjust the childs here
my $cmh = 2+$hr->{mhods};
my $ret .= "mhyp";
$ret .= pack("h8", _itop(108)); #type
$ret .= pack("h8", _itop($hr->{size}+108+(length($appnd)))); #size
$ret .= pack("h8", _itop($cmh)); #mhods
$ret .= pack("h8", _itop($hr->{files})); #songs in pl
$ret .= pack("h8", _itop($hr->{type})); # 1 = main .. 0=not main
$ret .= pack("H8", "00"); #?
$ret .= pack("H8", "00"); #?
$ret .= pack("H8", "00"); #?
$ret .= pack("H144", "00"); #dummy space
return $ret.$appnd;
}
# header for new Playlist item (child if mk_mhyp)
sub mk_mhip {
my ($hr) = @_;
#sid = SongId
#plid = playlist order ID
my $ret = "mhip";
$ret .= pack("h8", _itop(76));
$ret .= pack("h8", _itop(76));
$ret .= pack("h8", _itop($hr->{childs})); #Mhod childs !
$ret .= pack("H8", "00");
$ret .= pack("h8", _itop($hr->{plid})); #ORDER id
$ret .= pack("h8", _itop($hr->{sid})); #song id in playlist
$ret .= pack("H96", "00");
return $ret;
}
#Convert utf8 (what we got from XML::Parser) to utf16 (ipod)
sub _ipod_string {
my $utf8 = shift;
my $utf16;
# We got utf8 from parser, the iPod likes utf16.., swapped..
if (UNIVERSAL::isa($utf8, 'Unicode::String')) {
$utf16 = $utf8->utf16;
}
else {
$utf16 = Unicode::String::utf8($utf8)->utf16;
}
$utf16 = Unicode::String::byteswap2($utf16);
return $utf16;
}
#returns a (dummy) timestamp in MAC time format
sub _mactime {
my $x = 1234567890;
return sprintf("%08X", $x);
}
( run in 0.741 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )