The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package WWW::Webjay;

use 5.008004;
use strict;
use warnings;
use Carp;
use Getopt::Std;
use Data::Dumper;
use HTML::Entities;
use HTTP::Cookies;
use LWP::UserAgent;
use URI::Escape;

our $VERSION = '0.1_1';
our $VERSION = eval $VERSION;

# For creation of a new Webjay object.
sub new {
	my ($class, %params) = @_;
	my $self = {};

	croak "Client description not set with client_page param!" unless $params{client_page};

	$self->{DEBUG} = 0;
	$self->{COOKIEJAR} = ".webjaycookies";

	# Create the User Agent:
	$self->{UA} = LWP::UserAgent->new || die "Unable to create LWP::UserAgent";
	$self->{UA}->agent($params{client_page});
	$self->{UA}->cookie_jar(HTTP::Cookies->new(file => $self->{COOKIEJAR}, autosave => 1));
	
	$self->{USERNAME} = $params{username};
	$self->{PASSWORD} = $params{password};
	$self->{CLIENTPAGE} = $params{client_page};
	
	bless ($self, $class);
	return $self;
}

# Set or retrieve the client description page.
sub client_page	{
	my $self = shift;
	if (@_)	{ $self->{CLIENTPAGE} = shift	}
	return $self->{CLIENTPAGE};
}

# Set or retrieve the username.
sub username	{
	my $self = shift;
	if (@_)	{ $self->{USERNAME} = shift	}
	return $self->{USERNAME};
}

# Set the password (cannot retrieve).
sub password	{
	my $self = shift;
	if (@_)	{ $self->{PASSWORD} = shift	}
	return undef;
}

###########################################################
# To Create A Playlist
#
# If the URI of the playlist is not set,
# and there is a title in the GET arguments,
# create a playlist by that title and return the short-name.
# 
# Args:
# 	title			text [MAX LENGTH 255] [REQUIRED]
# 	public			public OR private [default: public] [REQUIRED]
# 	description		text [MAX LENGTH 255] [OPTIONAL]
# 	m3u				Newline separated list of URLs of playlist entries [MAX LENGTH 40K] [OPTIONAL]
#
# Returns:
# 	201	on success
# 	4xx on failure
# 	5xx on failure
#
sub create_playlist	{
	my ($self, %params) = @_;
	my $title = $params{title};
	my $public = $params{public};
	my $description = $params{description};
	my $m3u = $params{m3u};

	# Return "bad request" status code on missing params
	$public = "public" unless $public;
	confess "The 'title' parameter is REQUIRED." unless ($title);

	my $req = HTTP::Request->new(POST => 'http://webjay.org/api/new/playlists');
	$req->content_type('application/x-www-form-urlencoded');
	$req->authorization_basic($self->username(), $self->password());
	$req->content('title=' . uri_escape(encode_entities($title)) .
				'&public=' . uri_escape($public).
				'&description=' . uri_escape(encode_entities($description)).
				'&m3u=' . uri_escape($m3u).
				'');
	
	my $res = $self->{UA}->request($req);
	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return $res->code;
}

###########################################################
# To Modify A Playlist
#
# POST to the API URL (for example:
#  http://webjay.org/api/by/yourname/short-name
# ) of the playlist that you want to change.
# 
# Args:
# 	shortname		Short-name of the playlist
# 	title			text [MAX LENGTH 255]
# 	public			public OR private [MAX LENGTH 255]
# 	description		text [MAX LENGTH 255]
# 	m3u				Newline-separated list of URLs of playlist entries [MAX LENGTH 40K]
#
# Returns:
# 	200	on success
# 	4xx on failure
# 	5xx on failure
#
sub modify_playlist	{
	my ($self, %params) = @_;
	my $shortname = $params{shortname};
	my $title = $params{title};
	my $public = $params{public};
	my $description = $params{description};
	my $m3u = $params{m3u};

	# Return "bad request" status code on missing params
	confess "The 'shortname' parameter is REQUIRED." unless ($shortname);
	
	my $req = HTTP::Request->new(POST => 'http://webjay.org/api/by/' .
		$self->username() . '/' . $shortname);
	$req->content_type('application/x-www-form-urlencoded');
	$req->authorization_basic($self->username(), $self->password());
	$req->content('title=' . uri_escape(encode_entities($title)) .
				'&public=' . uri_escape($public).
				'&description=' . uri_escape(encode_entities($description)).
				'&m3u=' . uri_escape($m3u).
				'');
	
	my $res = $self->{UA}->request($req);
	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return $res->code();
}

###########################################################
# To Modify Metadata For A Song
#
# Update metadata related to a playlist entry,
# using the URL of the entry as a key.
# 
# Metadata for an audio URL applies to all instances
# of that URL within your playlists.
# If you do not set a value for the image, description,
# or site parameter, a blank value will be used.
# 
# Args:
# 	song			[URL of an audio resource in one of your playlists] [REQUIRED]
# 	description		text [MAX LENGTH 255] [REQUIRED]
# 	image			URL of a GIF [MAX LENGTH 255] [REQUIRED]
# 	site			URL related to audio resource [MAX LENGTH 255] [REQUIRED]
#
# Returns:
# 	200	on success
# 	4xx on failure
# 	5xx on failure
#
sub modify_metadata	{
	my ($self, %params) = @_;
	my $song = $params{song};
	my $description = $params{description};
	my $image = $params{image};
	my $site = $params{site};

	# Return "bad request" status code on missing params
	confess "The 'song' parameter is REQUIRED." unless ($song);
	confess "The 'description' parameter is REQUIRED." unless ($description);
	confess "The 'image' parameter is REQUIRED." unless ($image);
	confess "The 'site' parameter is REQUIRED." unless ($site);
	
	my $req = HTTP::Request->new(POST => 'http://webjay.org/api/songmetadata/' .
		$self->username() . '/short-name?audio=' . $song);
	$req->content_type('application/x-www-form-urlencoded');
	$req->authorization_basic($self->username(), $self->password());
	$req->content('description=' . uri_escape(encode_entities($description)) .
				'&image=' . uri_escape($image).
				'&site=' . uri_escape(encode_entities($site)).
				'');
	
	my $res = $self->{UA}->request($req);
	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return $res->code();
}

###########################################################
# To Get A Listing Of Your Playlists
#
# Fetch a listing of user playlists.
# 
# Returns a list: playlist1, playlist2, ...
#
sub list_playlists	{
	my $self = shift;
	my $req = HTTP::Request->new(GET => 'http://webjay.org/api/shortname/' . $self->username());
	$req->authorization_basic($self->username(), $self->password());
	my $res = $self->{UA}->request($req);

	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return split /\n/, $res->content;
}

###########################################################
# To Get The Short-Name Of A Playlist
#
# Given a playlist title, fetch the short-name.
# 
# Args:
# 	title			entity-encoded string [MAX LENGTH 255]
#
# Returns shortname
#
sub get_shortname	{
	my ($self, %params) = @_;
	my $title = $params{title};
	
	# Return "bad request" status code on missing params
	confess "The 'title' parameter is REQUIRED." unless ($title);

	my $req = HTTP::Request->new(GET => 'http://webjay.org/api/shortname/' .
		$self->username() . '?title=' . $title);
	$req->authorization_basic($self->username(), $self->password());
	my $res = $self->{UA}->request($req);

	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return $res->content;
}

###########################################################
# To Fetch Playlist Content
#
# Get the actual content of a playlist.
# 
# Args:
# 	shortname		Short-name of the playlist.
# 	
# Returns playlist in xspf
#
sub fetch_playlist	{
	my ($self, %params) = @_;
	my $shortname = $params{shortname};
	
	# Return "bad request" status code on missing params
	confess "The 'shortname' parameter is REQUIRED." unless ($shortname);

	my $req = HTTP::Request->new(GET => 'http://webjay.org/api/xspf/' .
		$self->username() . '/' . $shortname);
	$req->authorization_basic($self->username(), $self->password());
	my $res = $self->{UA}->request($req);

	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return $res->content;
}

###########################################################
# To Delete A Playlist
#
# To delete a playlist, use the HTTP DELETE method on the playlist URI.
# Please be careful.
# You will not be prompted,
# and once a playlist is deleted it is not recoverable.
# 
# Args:
# 	shortname		Short-name of the playlist.
#
# Returns:
# 	200	on success
# 	4xx on failure
# 	5xx on failure
#
sub delete_playlist	{
	my ($self, %params) = @_;
	my $shortname = $params{shortname};

	# Return "bad request" status code on missing params
	confess "The 'shortname' parameter is REQUIRED." unless ($shortname);
	
	my $req = HTTP::Request->new(DELETE => 'http://webjay.org/api/by/' .
		$self->username() . '/' . $shortname);
	$req->content_type('application/x-www-form-urlencoded');
	$req->authorization_basic($self->username(), $self->password());
	
	my $res = $self->{UA}->request($req);
	if (($res->code / 100) == 4 || ($res->code / 100) == 5)	{
		carp "HTTP Error: " . $res->code;
	}
	return $res->code();
}

1;

__END__

=head1 NAME

NET::WebJay - Perl extension for the WebJay API v0.0 (Draft June 2, 2004)

=head1 SYNOPSIS

  use NET::WebJay;
  blah blah blah

=head1 DESCRIPTION

The WebJay module is currently at the stage where one can call the functions to get bypass most of the user agent setup, which was the point.  The module has several methods to mirror the API's declaration:

=head1 METHODS

=head2 create_playlist

If the URI of the playlist is not set, and there is a title in the GET arguments, create a playlist by that title and return the short-name.

=head3 Arguments

title: text [MAX LENGTH 255] [REQUIRED]<br />
public: public OR private [default: public] [REQUIRED]<br />
description: text [MAX LENGTH 255] [OPTIONAL]<br />
m3u: Newline separated list of URLs of playlist entries [MAX LENGTH 40K] [OPTIONAL]<br />

=head3 Returns

201 on success<br />
4xx on failure<br />
5xx on failure<br />

=head2 modify_playlist

POST to the API URL (for example: http://webjay.org/api/by/yourname/short-name) of the playlist that you want to change.<br />

=head3 Arguments

shortname: Short-name of the playlist<br />
title: text [MAX LENGTH 255]<br />
public: public OR private [MAX LENGTH 255]<br />
description: text [MAX LENGTH 255]<br />
m3u: Newline-separated list of URLs of playlist entries [MAX LENGTH 40K]<br />

=head3 Returns

200 on success<br />
4xx on failure<br />
5xx on failure<br />

=head2 delete_playlist

To delete a playlist, use the HTTP DELETE method on the playlist URI.<br />
Please be careful.<br />
You will not be prompted, and once a playlist is deleted it is not recoverable.<br />

=head3 Arguments

shortname: Short-name of the playlist.

=head3 Returns

200 on success<br />
4xx on failure<br />
5xx on failure<br />

=head2 fetch_playlist

Get the actual content of a playlist.

=head2 Arguments

shortname: Short-name of the playlist.

=head2 Returns

A full playlist in XPSF.

=head2 modify_metadata

Update metadata related to a playlist entry, using the URL of the entry as a key.<br />
<br />
Metadata for an audio URL applies to all instances of that URL within your playlists.<br />
If you do not set a value for the image, description, or site parameter, a blank value will be used.<br />

=head3 Arguments

song: [URL of an audio resource in one of your playlists] [REQUIRED]<br />
description: text [MAX LENGTH 255] [REQUIRED]<br />
image: URL of a GIF [MAX LENGTH 255] [REQUIRED]<br />
site: URL related to audio resource [MAX LENGTH 255] [REQUIRED]<br />

=head3 Returns

200 on success<br />
4xx on failure<br />
5xx on failure<br />

=head2 list_playlists

Fetch a listing of user playlists.

=head3 Returns

An array of playlist short-names.

=head2 get_shortname

Given a playlist title, fetch the short-name.

=head3 Arguments

title: entity-encoded string [MAX LENGTH 255]

=head3 Returns

A short-name.

=head2 EXPORT

None by default.

=head1 BUGS AND CAVEATS

This is alpha code.  Lots of things aren't implemented yet.

=head1 SEE ALSO

=for html <a href="http://webjay.org/">WebJay</a>, <a href="http://webjay.org/public/webjay_sample">WebJay Perl Sample</a>, <a href="http://webjay.org/api/help">WebJay API</a>, <a href="http://gonze.com/xspf/xspf-draft-8.html">XPSF Draft 8</a>.

=head1 AUTHOR

Adam P. Blinkinsop E<lt>spaceman@spu.eduE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2004 by Adam P. Blinkinsop

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

=cut