Apache-MP3-Skin

 view release on metacpan or  search on metacpan

Skin.pm  view on Meta::CPAN

package Apache::MP3::Skin;
# Subclasses Apache::MP3::Playlist and through the magic
# of HTML::Template allows Apache::MP3 to be skinned.

use strict;
use HTML::Template;
use Apache::Constants qw(:common REDIRECT HTTP_NO_CONTENT DIR_MAGIC_TYPE);
use constant COVERIMAGE   => 'cover.jpg';
use CGI qw(param escape);
use Apache::MP3::Playlist;
use Apache::File ();
use Apache::URI ();
use File::Basename 'dirname','basename';


use vars qw(@ISA $VERSION);
@ISA = 'Apache::MP3::Playlist';

$VERSION = '0.91';

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

  if (my $cookies = CGI::Cookie->parse($r->header_in('Cookie'))) {
    my $playlist = $cookies->{playlist};
    @playlist = $playlist->value if $playlist;
    if ($playlist[-1] && 
	$r->lookup_uri($playlist[-1])->content_type ne 'audio/mpeg') {
      $self->{possibly_truncated}++;
      pop @playlist;  # get rid of the last
    }
  }

  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;
    # The line below is the only line that's different than SUPER::process_playlist
    @playlist = grep !$seen{$_}++,(@playlist,map {(m/^\//) ? "$_" : "$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;
    return $self->send_playlist(\@playlist,'shuffle');
  }

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

  if ($changed) {
    my $c = CGI::Cookie->new(-name  => 'playlist',
			     -value => \@playlist);
    tied(%{$r->err_headers_out})->add('Set-Cookie' => $c);
    (my $uri = $r->uri) =~ s!playlist\.m3u$!!;
    $self->path_escape(\$uri);
    $r->err_header_out(Location => $uri);
    return REDIRECT;
  }

  $self->playlist(@playlist);
  return;
}


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

  if (param('Shuffle Selected')) {
    return HTTP_NO_CONTENT unless my @files = param('file');
    $self->shuffle(\@files);
    my $uri = dirname($r->uri);
    $self->send_playlist([map { (m/^\//) ? "$_" : "$uri/$_" } @files]);
    return OK;
  }  
  
  return $self->SUPER::run();
  
}



# override the list_directory in Apache::MP3, see if there's a skin file.
# if there's a skin file, we'll handle it otherwise pass it back (SUPER)
# to Apache::MP3 
sub list_directory {
  my $self = shift;
  my $dir  = shift;
  return DECLINED unless my ($directories,$mp3s,$playlists) 
    = $self->read_directory($dir);

  if ($self->r->header_only) {
    $self->r->send_http_header('text/html');
    return OK;
  }
  
  my $skin = $self->get_skin_path($dir);
  
  if ($skin) {
    $self->r->send_http_header('text/html');
    
    # open the html template
    my $template = HTML::Template->new(filename => $skin, die_on_bad_params=>0, loop_context_vars=>1);
    
    $self->set_template_params($template, $dir, $directories, $mp3s);
    # print the template
    my $page = $template->output;

    #add the javascript tag
    my $script_tag = "<SCRIPT language=\"JavaScript\" src=\"".$self->default_dir."/apache_mp3_skin.js\"></SCRIPT>";

    
    $page =~ s!(</HEAD[^>]*>)!$script_tag$1!oi;
    $page =~ s!(<BODY[^>]*>)!$1<FORM NAME="apache_mp3_skin">!oi;
    $page =~ s!(</BODY[^>]*>)!</FORM>$1!oi;
    
    print $page;

  } else {
    return $self->SUPER::list_directory($dir);
  }

  return OK;
}



sub set_template_params {
  my ($self, $template, $dir, $directories, $mp3s) = @_;
  my @inner_loops;
  my $params_ref = $self->set_dir_context_params($template, $dir, $self->r->uri, $directories, $mp3s, \@inner_loops);
  $template->param( $params_ref );
  return;
}



sub set_dir_context_params {
  my ($self, $template, $dir, $uri, $directories, $mp3s, $inner_loops, $count) = @_;
  
  # Warning: Hack following.  A double '//' is creeping into $uri.  Remove it.  
  if ($uri) {
    $uri =~ s/\/\//\//g;
  }
  my @param_names;
  my @inners = @$inner_loops;
  if ($#inners > -1) {
    @param_names = $template->query(loop => $inner_loops);
  } else {
    @param_names = $template->query();  
  }

  my %params;
    
  foreach (@param_names) {
    my $p = lc $_;
    if ($p =~ m/^__\S*__$/) {
        $params{$_} = $self->set_loop_params($p,$count);
	} elsif ($p eq "is_dir") {
  	    $params{$_} = "1";
	} elsif ($p eq "is_mp3") {
  	    $params{$_} = "0";
    } else {
        $params{$_} = $self->set_context_params($p, $template, $dir, $uri, $directories, $mp3s, $inner_loops);    
    }
  }
  return \%params;
}




sub set_mp3_context_params {
  my ($self, $template, $dir, $uri, $directories, $mp3s, $inner_loops, $song_file, $song, $count, $on_playlist) = @_;
  
  # Warning: Hack following.  A double '//' is creeping into $uri.  Remove it.  
  if ($uri) {
    $uri =~ s/\/\//\//g;
  }
  

Skin.pm  view on Meta::CPAN


Iterate through the path from the top (or home) directory as
defined by PerlSetVar to the current Directory.  Useful for making
breadcrumb trails.

=item PATH_BACKWARD

Same as PATH_FORWARD but the loops starts with the current
directory and goes up the file tree to the top (or home) directory.

=item HOME_DIRS

Loop through all the directories in the top (or home) directory.
Useful for creating persistent global nav.

=item MP3S

Loop through all the MP3s in the current directory.

=item DIRS

Loop through all the DIRs in the current directory.

=item PLAYLIST

Loop through all the MP3s in the current browser's playlist.

=item DIRS_AND_MP3S

Loop through all the directories and then all the MP3s in the current directory. Use 
the IS_DIR variable to test whether a given iteration is a directory or MP3.

=item MP3S_AND_DIRS

Same and DIRS_AND_MP3S except all the MP3s come before directories.

=back

=head1 ABOUT FRAMES

A skin can be composed of multiple template files.  The default template should contain the 
framset and the source's for each from should end with "?skin=thisframe.tmpl" where 
thisframe.tmpl is the name of the file to be used to skin that frame.  Links inside 
thisframe.tmpl will also need to end in "?skin=thisframe.tmpl" to maintain their look.

=head1 ABOUT FORMS

A open form and closing form tag is automatically added to every page.  Do not include
any forms tags in your skin files.  You can include form input fields and they will be part
of the apache_mp3_skin form.  Use document.apache_mp3_skin to refer to the form object
in any JavaScript that you have.

=head1 METHODS

Apache::MP3::Skin overrides the following methods:

=over 4

=item list_directory() 

Checks to see if this is a skin file, if not hands off to SUPER::list_directory().
If there is a skin files, gets it, processes it, adds in the <SCRIPT> and <FORM> 
tags and the prints it.

=item run()

Looks for the "Shuffle Selected" parameter and handles the request if there is one.
Otherwise, sends to SUPER::run().

=item process_playlist()

Same as SUPER::process_playlist with only one line changed.  If there is an 'Add to
Playlist' param.  file param values that begin with '/' are not prepended with the
current uri and are treated as document root relative.

=back

And adds the following:

=over 4

=item set_template_params()

Called by list_directory, this begins the process of filling in the template params.
set_template_params sets the current directory context to the uri of the request and 
calls set_dir_context_params.

=item set_dir_context_params()

Loops through the parameters required for the template, sending special loop variables to
set_loop_params and most of the rest to set_context_params

=item set_mp3_context_params()

Called by loop_mp3s and loop_playlist, set_mp3_context_params iterates through the
parameters being requested in each loop iteration.  Those that are file context are handled,
special loop variables are sent to set_loop_params, and the rest go to set_context_params.

=item set_loop_params()

Called by set_mp3_context_params and set_dir_context_params, set_loop_params takes the
name of a special loop variable, and the current loop count and return the appropriate
value for the special loop variable.

=item set_context_params()

The workhorse. set_context_params takes in the name of the current parameter being queried
along with context information and returns the appropriate values.  Handles all global variables,
directory context variables, and loops.

=item loop_dirs_and_mp3s()

Called by set_context_params for the loops DIRS_AND_MP3S and MP3S_AND_DIRS.  Loops through
all the dirs and mp3s calling either iterate_dirs() or set_mp3_context_params()
for each as necessary.

=item loop_home_dirs()

Called by set_context_params for the HOME_DIRS loop.  Gets a list of directories in 
HomePath and send it to iterate_dirs().

=item loop_dirs()

Called by set_context_params for the DIRS loop.  Gets a list of directories in the current
directory and sends it to iterate_dirs().

=item loop_path()

Called by set_context_params for PATH_FORWARD and PATH_BACKWARDS loops.  Gets a list of 
directories from the HomePath to the current directory context.  Reverses them if necessary.
And then sends them to iterate_dirs().



( run in 1.029 second using v1.01-cache-2.11-cpan-140bd7fdf52 )