Apache-MP3

 view release on metacpan or  search on metacpan

MP3.pm  view on Meta::CPAN


# stream the indicated file
sub stream {
  my $self = shift;
  my $r = $self->r;

  return DECLINED unless -e $r->filename;  # should be $r->finfo

  unless ($self->stream_ok) {
    $r->log_reason('AllowStream forbidden');
    return FORBIDDEN;
  }

  if ($self->check_stream_client and !$self->is_stream_client) {
    my $useragent = $r->headers_in->{'User-Agent'};
    $r->log_reason("CheckStreamClient is true and $useragent is not a streaming client");
    return FORBIDDEN;
  }

  my $mime = $r->content_type;
  my $file = $r->filename;
  my $url  = $r->uri;

  my $info = $self->fetch_info($file,$mime);
  return DECLINED unless $info;  # not a legit mp3 file?
  my $fh = $self->open_file($file) || return DECLINED;
  binmode($fh);  # to prevent DOS text-mode foolishness

  my $size = -s $file;
  my $bitrate = $info->{bitrate};
  if ($self->can('bitrate') && $self->bitrate) {
    ($bitrate = $self->bitrate) =~ s/ kbps//i;
    # quick approximation
    $size = int($size * ($bitrate / $info->{bitrate}));
  }
  my $description = $info->{description};
  my $genre       = $info->{genre} || $self->lh->maketext('unknown');

  my $range = 0;
  $r->headers_in->{"Range"}
    and $r->headers_in->{"Range"} =~ m/bytes=(\d+)/
    and $range = $1
    and seek($fh,$range,0);

  # Look for a descriptive file that has the same base as the mp3 file.
  # Also look for various index files.
  my $icyurl = $self->stream_base(1);
  my $base   = basename($file);
  $base =~ s/\.\w+$//;  # get rid of suffix
  my $dirbase  = dirname($file);
  my $urlbase  = dirname($url);
  foreach ("$base.html","$base.htm","index.html","index.htm") {
    my $file = "$dirbase/$_";
    if (-r $file) {
      $icyurl .= "$urlbase/$_";
      last;
    }
  }

  $r->assbackwards(1);
  $r->connection->keepalive(1);
  $r->connection->keepalives($r->connection->keepalives+1);

  $r->print("ICY ". ($range ? 206 : 200) ." OK$CRLF");
  $r->print("icy-notice1: <BR>This stream requires a shoutcast/icecast compatible player.<BR>$CRLF");
  $r->print("icy-notice2: Apache::MP3<BR>$CRLF");
  $r->print("icy-name: $description$CRLF");
  $r->print("icy-genre: $genre$CRLF");
  $r->print("icy-url:$icyurl$CRLF");
  $r->print("icy-pub:1$CRLF");
  $r->print("icy-br:$bitrate$CRLF");
  $r->print("Accept-Ranges: bytes$CRLF");
  $r->print("Content-Range: bytes $range-" . ($size-1) . "/$size$CRLF")
    if $range;
  $r->print("Content-Length: $size$CRLF");
  $r->print("Content-Type: $mime$CRLF");
  $r->print("$CRLF");
  return OK if $r->header_only;

  if (my $timeout = $self->stream_timeout) {
    my $seconds  = $info->{seconds};
    $seconds ||= 60;  # shouldn't happen
    my $fraction = $timeout/$seconds;
    my $bytes    = int($fraction * $size);
    while ($bytes > 0) {
      my $data;
      my $b = read($fh,$data,2048) || last;
      $bytes -= $b;
      $r->print($data);
    }
    return OK;
  } else {
    my $data;
    $r->print($data) while read($fh,$data,2048);
  }

  return OK;
}


# this generates a playlist for the MP3 player
sub send_playlist {
  my $self = shift;
  my ($urls,$shuffle) = @_;

  return HTTP_NO_CONTENT unless $urls && @$urls;
  my $r    = $self->r;
  my $base = $self->stream_base;

  $r->content_type('audio/mpegurl');
  return OK if $r->header_only;

  # local user
  my $local = $self->playlocal_ok && $self->is_local;
  $self->shuffle($urls) if $shuffle;
  $r->print("#EXTM3U$CRLF");
  my $stream_parms = $self->stream_parms;
  foreach (@$urls) {
    $self->path_escape(\$_);
    my $subr = $r->lookup_uri($_) or next;
    my $file = $subr->filename;
    my $type = $subr->content_type;



( run in 0.674 second using v1.01-cache-2.11-cpan-df04353d9ac )