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 )