App-MHFS
view release on metacpan or search on metacpan
lib/MHFS/Plugin/MusicLibrary.pm view on Meta::CPAN
sub SendLibrary {
my ($self, $request) = @_;
# maybe not allow everyone to do these commands?
if($request->{'qs'}{'forcerefresh'}) {
say __PACKAGE__.": forcerefresh";
$self->BuildLibraries();
}
elsif($request->{'qs'}{'refresh'}) {
say __PACKAGE__.": refresh";
UpdateLibrariesAsync($self, $request->{'client'}{'server'}{'evp'}, sub {
say __PACKAGE__.": refresh done";
$request->{'qs'}{'refresh'} = 0;
SendLibrary($self, $request);
});
return 1;
}
# deduce the format if not provided
my $fmt = $request->{'qs'}{'fmt'};
if(! $fmt) {
$fmt = 'worklet';
my $fallback = 'musicinc';
if($request->{'header'}{'User-Agent'} =~ /Chrome\/([^\.]+)/) {
my $ver = $1;
# SharedArrayBuffer support with spectre/meltdown fixes was added in 68
# AudioWorklet on linux had awful glitching until somewhere in 92 https://bugs.chromium.org/p/chromium/issues/detail?id=825823
if($ver < 93) {
if(($ver < 68) || ($request->{'header'}{'User-Agent'} =~ /Linux/)) {
$fmt = $fallback;
}
}
}
elsif($request->{'header'}{'User-Agent'} =~ /Firefox\/([^\.]+)/) {
my $ver = $1;
# SharedArrayBuffer support with spectre/meltdown fixes was added in 79
if($ver < 79) {
$fmt = $fallback;
}
}
else {
# Hope for the best, assume worklet works
}
# leave this here for now to not break the segment based players
if($request->{'qs'}{'segments'}) {
$fmt = $fallback;
}
}
# route
my $qs = defined($request->{'qs'}{'ptrack'}) ? {'ptrack' => $request->{'qs'}{'ptrack'}} : undef;
if($fmt eq 'worklet') {
return $request->SendRedirect(307, 'static/music_worklet_inprogress/', $qs);
}
elsif($fmt eq 'musicdbjson') {
return $request->SendBytes('application/json', $self->{'musicdbjson'});
}
elsif($fmt eq 'musicdbhtml') {
return $request->SendBytes("text/html; charset=utf-8", $self->{'musicdbhtml'});
}
elsif($fmt eq 'gapless') {
$qs->{fmt} = 'musicinc';
return $request->SendRedirect(301, "music", $qs);
}
elsif($fmt eq 'musicinc') {
return $request->SendRedirect(307, 'static/music_inc/', $qs);
}
elsif($fmt eq 'legacy') {
say __PACKAGE__.": legacy";
return $request->SendBytes("text/html; charset=utf-8", $self->{'html'});
}
else {
return $request->Send404;
}
}
my $SEGMENT_DURATION = 5;
my %TRACKDURATION;
my %TRACKINFO;
sub SendTrack {
my ($request, $tosend) = @_;
if(defined $request->{'qs'}{'part'}) {
if(! HAS_MHFS_XS) {
say __PACKAGE__.": route not available without XS";
$request->Send503();
return;
}
if(! $TRACKDURATION{$tosend}) {
say __PACKAGE__.": failed to get track duration";
$request->Send503();
return;
}
say "no proc, duration cached";
my $pv = MHFS::XS::new($tosend);
$request->{'outheaders'}{'X-MHFS-NUMSEGMENTS'} = ceil($TRACKDURATION{$tosend} / $SEGMENT_DURATION);
$request->{'outheaders'}{'X-MHFS-TRACKDURATION'} = $TRACKDURATION{$tosend};
$request->{'outheaders'}{'X-MHFS-MAXSEGDURATION'} = $SEGMENT_DURATION;
my $samples_per_seg = $TRACKINFO{$tosend}{'SAMPLERATE'} * $SEGMENT_DURATION;
my $spos = $samples_per_seg * ($request->{'qs'}{'part'} - 1);
my $samples_left = $TRACKINFO{$tosend}{'TOTALSAMPLES'} - $spos;
my $res = MHFS::XS::get_flac($pv, $spos, $samples_per_seg < $samples_left ? $samples_per_seg : $samples_left);
$request->SendBytes('audio/flac', $res);
}
elsif(defined $request->{'qs'}{'fmt'} && ($request->{'qs'}{'fmt'} eq 'wav')) {
if(! HAS_MHFS_XS) {
say __PACKAGE__.": route not available without XS";
$request->Send503();
return;
}
my $pv = MHFS::XS::new($tosend);
my $outbuf = '';
my $wavsize = (44+ $TRACKINFO{$tosend}{'TOTALSAMPLES'} * ($TRACKINFO{$tosend}{'BITSPERSAMPLE'}/8) * $TRACKINFO{$tosend}{'NUMCHANNELS'});
my $startbyte = $request->{'header'}{'_RangeStart'} || 0;
my $endbyte = $request->{'header'}{'_RangeEnd'} // $wavsize-1;
say "start byte" . $startbyte;
say "end byte " . $endbyte;
say "MHFS::XS::wavvfs_read_range " . $startbyte . ' ' . $endbyte;
my $maxsendsize;
$maxsendsize = 1048576/2;
say "maxsendsize $maxsendsize " . ' bytespersample ' . ($TRACKINFO{$tosend}{'BITSPERSAMPLE'}/8) . ' numchannels ' . $TRACKINFO{$tosend}{'NUMCHANNELS'};
$request->SendCallback(sub{
my ($fileitem) = @_;
my $actual_endbyte = $startbyte + $maxsendsize - 1;
if($actual_endbyte >= $endbyte) {
$actual_endbyte = $endbyte;
$fileitem->{'cb'} = undef;
say "SendCallback last send";
( run in 1.461 second using v1.01-cache-2.11-cpan-39bf76dae61 )