Apache-MP3

 view release on metacpan or  search on metacpan

MP3/Playlist.pm  view on Meta::CPAN

package Apache::MP3::Playlist;
# $Id: Playlist.pm,v 1.6 2006/01/03 19:37:52 lstein Exp $
# generates playlists in cookies

use strict;
use vars qw(@ISA $VERSION);
use Apache2::Const qw(:common REDIRECT HTTP_NO_CONTENT HTTP_NOT_MODIFIED);
use File::Basename 'dirname','basename','fileparse';
use CGI qw(:standard);
use Apache::MP3::Sorted;
use CGI::Session;

@ISA = 'Apache::MP3::Sorted';
$VERSION = 1.05;

sub run {
  my $self = shift;
  my $result = $self->process_playlist;
  return $result if defined $result;
  $self->SUPER::run();
}

sub list_directory {
  my $self = shift;
  $self->r->headers_out->add(Expires => CGI::Util::expires('now'));
  $self->SUPER::list_directory(@_);
}

sub process_playlist {
  my $self = shift;
  my $r = $self->r;
  my @playlist;
  my $changed;

  my $playlist = $self->retrieve_playlist;

  if (param('Clear All')) {
    @$playlist = ();
    $changed++;
  }

  if (param('Clear Selected')) {
    my %clear = map { $_ => 1 } param('file') or return HTTP_NO_CONTENT;
    @$playlist = grep !$clear{$_},@$playlist;
    $changed++;
  }

  if (param('Add All to Playlist')) {
    my %seen;
    @$playlist = grep !$seen{$_}++,(@$playlist,@{$self->find_mp3s});
    $changed++;
  }

  if (param('Add to Playlist')) {
    my $dir = dirname($r->uri);
    my @new = param('file') or return HTTP_NO_CONTENT;
    my %seen;
    @$playlist = grep !$seen{$_}++,(@$playlist,map {"$dir/$_"} @new);
    $changed++;
  }

  if (param('Play Selected') and param('playlist')) {
    my @uris = param('file') or return HTTP_NO_CONTENT;
    return $self->send_playlist(\@uris);
  }

  if (param('Shuffle All') and param('playlist')) {
    return HTTP_NO_CONTENT unless @$playlist;
    my @list = @$playlist;
    return $self->send_playlist(\@list,'shuffle');
  }

  if (param('Play All') and param('playlist')) {
    return HTTP_NO_CONTENT unless @$playlist;
    my @list = @$playlist;
    return $self->send_playlist(\@list);
  }

  if ($changed) {
    $self->flush;
    (my $uri = $r->uri) =~ s!playlist\.m3u$!!;
    $self->path_escape(\$uri);
    my $rand = int rand(100000);
    $r->headers_out->add(Location => "$uri?$rand");
    return REDIRECT;
  }

MP3/Playlist.pm  view on Meta::CPAN

  return;
}

sub retrieve_playlist {
  my $self = shift;
  my $r    = $self->r;

  my $session = $self->session;
  $session->param(playlist=>[]) unless $session->param('playlist');

  my $playlist = $session->param('playlist');
  $r->err_headers_out->add('Set-Cookie' => CGI::Cookie->new(-name=>'apache_mp3',
							    -value=>$session->id,
							   ));
  $playlist;
}

sub session {
  my $self = shift;
  local $CGI::Session::NAME = 'apache_mp3';
  return $self->{session} ||= CGI::Session->new();
}

sub flush {
  my $self = shift;
  $self->session->flush;
}

sub directory_bottom {
  my $self = shift;
  if ($self->playlist) {
    my $r = $self->r;
    my $uri = $r->uri;  # for self referencing
    $self->path_escape(\$uri);

    my $descriptions = $self->lookup_descriptions($self->playlist);
    my @ok = grep { $descriptions->{$_} } $self->playlist;

    print
      a({-name=>'playlist'}),
      table({-width=>'100%',-border=>1},
	    Tr({-class=>'playlist'},
	       td({-class=>'playlist'},
		  h3($self->x('Current Playlist')),
		  start_form(-action=>"${uri}playlist.m3u",-method=>'GET'),
		  checkbox_group(-class=>'playlist',
				 -name      => 'file',
				 -linebreak => 1,
				 -value     => \@ok,
				 -labels    => $descriptions),
		  submit(-name=>'Clear All',-value=>$self->x('Clear All')),
		  submit(-class=>'playlist',-name=>'Clear Selected',-value=>$self->x('Clear Selected')),
		  submit(-class=>'playlist',-name=>'Play Selected',-value=>$self->x('Play Selected')),
		  submit(-class=>'playlist',-name=>'Shuffle All',-value=>$self->x('Shuffle All')),
		  submit(-class=>'playlist',-name=>'Play All',-value=>$self->x('Play All')),
		  hidden(-name=>'playlist',-value=>1,-override=>1),
		  end_form(),
		  ))
	   );
  }
  $self->SUPER::directory_bottom(@_);
}

sub control_buttons {
  my $self = shift;
  return (
	  $self->{possibly_truncated}
	  ? ()
	  : (submit({-class=>'playlist',
		     -name=>'Add to Playlist',
		     -value=>$self->x('Add to Playlist')}),
	     submit({-class=>'playlist',
		     -name=>'Add All to Playlist',
		     -value=>$self->x('Add All to Playlist')
		    })
	    ),
	  submit(-name=>'Play Selected',
		 -value=>$self->x('Play Selected')
		),
	  submit(-name=>'Shuffle All',
		 -value=>$self->x('Shuffle All')
		),
	  submit(-name=>'Play All',
		-value=>$self->x('Play All'))
	 );
}

sub lookup_descriptions {
  my $self = shift;
  my $r = $self->r;
  my %d;
  for my $song (@_) {
    next unless my $sub  = $r->lookup_uri($song);
    next unless my $file = $sub->filename;
    next unless -r $file;
    next unless my $info = $self->fetch_info($file,$sub->content_type);
    $d{$song} = " $info->{description}";
  }
  return \%d;
}

sub directory_top {
  my $self = shift;
  $self->SUPER::directory_top(@_);
  my @p = $self->playlist;
  print div({-align=>'CENTER'},
	    a({-href=>'#playlist',-class=>'playlist'},$self->x('Playlist contains [quant,_1,song,songs].', scalar(@p))),br,
	    $self->{possibly_truncated} ? font({-color=>'red'},
					       strong($self->x('Your playlist is now full. No more songs can be added.'))) : '') 
    if @p;
}

sub playlist {
  my $self = shift;
  my @p = $self->{playlist} ? @{$self->{playlist}} : ();
  $self->{playlist} = shift if @_;
  return unless @p;
  return wantarray ? @p : \@p;
}

1;

=head1 NAME

Apache::MP3::Playlist - Manage directories of MP3 files with sorting and persistent playlists

=head1 SYNOPSIS

 # httpd.conf or srm.conf
 AddType audio/mpeg    mp3 MP3

 # httpd.conf or access.conf
 <Location /songs>
   SetHandler perl-script
   PerlHandler Apache::MP3::Playlist
   PerlSetVar  SortField     Title
   PerlSetVar  Fields        Title,Artist,Album,Duration
 </Location>

=head1 DESCRIPTION

Apache::MP3::Playlist subclasses Apache::MP3::Sorted to allow the user
to build playlists across directories.  Playlists are stored in
cookies and are persistent for the life of the browser.  See
L<Apache::MP3> and L<Apache::MP3::Sorted> for details on installing
and using.

=head1 CUSTOMIZATION

The "playlist" class in the F<apache_mp3.css> cascading stylesheet
defines the color of the playlist area and associated buttons.

=head1 METHODS

Apache::MP3::Playlist overrides the following methods:

 run(), directory_bottom(), control_buttons() and directory_top().

It adds several new methods:

=over 4

=item $result = $mp3->process_playlist



( run in 1.688 second using v1.01-cache-2.11-cpan-63c85eba8c4 )