1
0
Fork 0
mirror of https://github.com/Yetangitu/ampache synced 2025-10-05 10:49:37 +02:00

pull from doped

This commit is contained in:
John Moore 2013-11-14 20:11:25 -06:00
commit 83abf55eeb
80 changed files with 6055 additions and 501 deletions

View file

@ -72,6 +72,8 @@ Ampache includes some external modules that carry their own licensing.
* [Prototype](http://www.prototypejs.org/): MIT * [Prototype](http://www.prototypejs.org/): MIT
* [Snoopy](http://snoopy.sourceforge.net/): LGPL v2.1 * [Snoopy](http://snoopy.sourceforge.net/): LGPL v2.1
* [Whatever:hover](http://www.xs4all.nl/~peterned): LGPL v2.1 * [Whatever:hover](http://www.xs4all.nl/~peterned): LGPL v2.1
* [xbmc-php-rpc](https://github.com/karlrixon/xbmc-php-rpc): GPL v3
* [JPlayer](http://jplayer.org/): MIT
Translations Translations
------------ ------------

View file

@ -3,6 +3,12 @@ CHANGELOG
3.6-FUTURE 3.6-FUTURE
---------- ----------
- Fixed issue with long session IDs that affected OS X Mavericks and possibly
other newer PHP installations (reported by yebo29)
- Fixed some sort issues (patch by Afterster)
- Fixed Fresh theme display on large screens (patch by Afterster)
- Fixed bug that allowed guests to add radio stations
- Added support for aacp transcoding
- Improved storage efficiency for large browse results - Improved storage efficiency for large browse results
- Fixed unnecessary growth of the tmp_browse table from API usage (reported - Fixed unnecessary growth of the tmp_browse table from API usage (reported
by Ondalf) by Ondalf)

28
html5_player_embedded.php Normal file
View file

@ -0,0 +1,28 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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.
*
*/
require_once 'lib/init.php';
$iframed = true;
require_once Config::get('prefix') . '/templates/show_html5_player.inc.php';
?>

View file

@ -64,6 +64,11 @@ switch ($_GET['thumb']) {
$size['height'] = '80'; $size['height'] = '80';
$size['width'] = '80'; $size['width'] = '80';
break; break;
case '4':
/* HTML5 Player size */
$size['height'] = 200;
$size['width'] = 200; // 200px width, set via CSS
break;
default: default:
$size['height'] = '275'; $size['height'] = '275';
$size['width'] = '275'; $size['width'] = '275';

BIN
images/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

View file

@ -22,6 +22,12 @@
require_once 'lib/init.php'; require_once 'lib/init.php';
if (Config::get('iframes')) {
if (!isset($_GET['framed'])) {
UI::show_mainframes();
exit;
}
}
UI::show_header(); UI::show_header();
$action = isset($_REQUEST['action']) ? scrub_in($_REQUEST['action']) : null; $action = isset($_REQUEST['action']) ? scrub_in($_REQUEST['action']) : null;

View file

@ -121,6 +121,7 @@ class Album extends database_object {
if ($extra) { if ($extra) {
$sql = "SELECT COUNT(DISTINCT(`song`.`artist`)) AS `artist_count`, " . $sql = "SELECT COUNT(DISTINCT(`song`.`artist`)) AS `artist_count`, " .
"COUNT(`song`.`id`) AS `song_count`, " . "COUNT(`song`.`id`) AS `song_count`, " .
"SUM(`song`.`time`) as `total_duration`," .
"`artist`.`name` AS `artist_name`, " . "`artist`.`name` AS `artist_name`, " .
"`artist`.`prefix` AS `artist_prefix`, " . "`artist`.`prefix` AS `artist_prefix`, " .
"`artist`.`id` AS `artist_id`, `song`.`album`" . "`artist`.`id` AS `artist_id`, `song`.`album`" .
@ -157,14 +158,15 @@ class Album extends database_object {
$sql = "SELECT " . $sql = "SELECT " .
"COUNT(DISTINCT(`song`.`artist`)) AS `artist_count`, " . "COUNT(DISTINCT(`song`.`artist`)) AS `artist_count`, " .
"COUNT(`song`.`id`) AS `song_count`, " . "COUNT(`song`.`id`) AS `song_count`, " .
"SUM(`song`.`time`) as `total_duration`," .
"`artist`.`name` AS `artist_name`, " . "`artist`.`name` AS `artist_name`, " .
"`artist`.`prefix` AS `artist_prefix`, " . "`artist`.`prefix` AS `artist_prefix`, " .
"`artist`.`id` AS `artist_id` " . "`artist`.`id` AS `artist_id` " .
"FROM `song` INNER JOIN `artist` " . "FROM `song` INNER JOIN `artist` " .
"ON `artist`.`id`=`song`.`artist` " . "ON `artist`.`id`=`song`.`artist` " .
"WHERE `song`.`album`='$this->id' " . "WHERE `song`.`album` = ? " .
"GROUP BY `song`.`album`"; "GROUP BY `song`.`album`";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
$results = Dba::fetch_assoc($db_results); $results = Dba::fetch_assoc($db_results);
@ -261,17 +263,17 @@ class Album extends database_object {
$results = array(); $results = array();
$artist = Dba::escape($artist); $sql = "SELECT `id` FROM `song` WHERE `album` = ? ";
$params = array($this->id);
$sql = "SELECT `id` FROM `song` WHERE `album`='$this->id' ";
if ($artist) { if ($artist) {
$sql .= "AND `artist`='$artist'"; $sql .= "AND `artist` = ?";
$params[] = $artist;
} }
$sql .= "ORDER BY `track`, `title`"; $sql .= "ORDER BY `track`, `title`";
if ($limit) { if ($limit) {
$sql .= " LIMIT $limit"; $sql .= " LIMIT " . intval($limit);
} }
$db_results = Dba::read($sql); $db_results = Dba::read($sql, $params);
while ($r = Dba::fetch_assoc($db_results)) { while ($r = Dba::fetch_assoc($db_results)) {
$results[] = $r['id']; $results[] = $r['id'];
@ -287,10 +289,8 @@ class Album extends database_object {
*/ */
public function has_track($title) { public function has_track($title) {
$title = Dba::escape($title); $sql = "SELECT `id` FROM `song` WHERE `album` = ? AND `title` = ?";
$db_results = Dba::read($sql, array($this->id, $title));
$sql = "SELECT `id` FROM `song` WHERE `album`='$this->id' AND `title`='$title'";
$db_results = Dba::read($sql);
$data = Dba::fetch_assoc($db_results); $data = Dba::fetch_assoc($db_results);
@ -354,8 +354,8 @@ class Album extends database_object {
*/ */
function get_random_songs() { function get_random_songs() {
$sql = "SELECT `id` FROM `song` WHERE `album`='$this->id' ORDER BY RAND()"; $sql = "SELECT `id` FROM `song` WHERE `album` = ? ORDER BY RAND()";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
while ($r = Dba::fetch_row($db_results)) { while ($r = Dba::fetch_row($db_results)) {
$results[] = $r['0']; $results[] = $r['0'];

View file

@ -75,7 +75,6 @@ class Catalog extends database_object {
*/ */
private function _create_filecache() { private function _create_filecache() {
if (count($this->_filecache) == 0) { if (count($this->_filecache) == 0) {
$catalog_id = Dba::escape($this->id);
// Get _EVERYTHING_ // Get _EVERYTHING_
$sql = 'SELECT `id`, `file` FROM `song` WHERE `catalog` = ?'; $sql = 'SELECT `id`, `file` FROM `song` WHERE `catalog` = ?';
$db_results = Dba::read($sql, array($this->id)); $db_results = Dba::read($sql, array($this->id));
@ -575,6 +574,29 @@ class Catalog extends database_object {
return $results; return $results;
} }
/**
* get_artist
*
* This returns an array of ids of artists that have songs in the catalogs parameter
*/
public static function get_artists($catalogs = null) {
if(is_array($catalogs) && count($catalogs)) {
$catlist = '(' . implode(',', $catalogs) . ')';
$sql_where = "WHERE `song`.`catalog` IN $catlist";
}
$sql = "SELECT `artist`.id, `artist`.`name` FROM `song` LEFT JOIN `artist` ON `artist`.`id` = `song`.`artist` $sql_where GROUP BY `song`.artist ORDER BY `artist`.`name`";
$results = array();
$db_results = Dba::read($sql);
while ($r = Dba::fetch_assoc($db_results)) {
$results[] = Artist::construct_from_array($r);
}
return $results;
}
/** /**
* gather_art * gather_art
@ -753,8 +775,8 @@ class Catalog extends database_object {
private function update_last_update() { private function update_last_update() {
$date = time(); $date = time();
$sql = "UPDATE `catalog` SET `last_update`='$date' WHERE `id`='$this->id'"; $sql = "UPDATE `catalog` SET `last_update` = ? WHERE `id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($date, $this->id));
} // update_last_update } // update_last_update
@ -765,8 +787,8 @@ class Catalog extends database_object {
public function update_last_add() { public function update_last_add() {
$date = time(); $date = time();
$sql = "UPDATE `catalog` SET `last_add`='$date' WHERE `id`='$this->id'"; $sql = "UPDATE `catalog` SET `last_add` = ? WHERE `id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($date, $this->id));
} // update_last_add } // update_last_add
@ -777,8 +799,8 @@ class Catalog extends database_object {
public function update_last_clean() { public function update_last_clean() {
$date = time(); $date = time();
$sql = "UPDATE `catalog` SET `last_clean`='$date' WHERE `id`='$this->id'"; $sql = "UPDATE `catalog` SET `last_clean` = ? WHERE `id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($date, $this->id));
} // update_last_clean } // update_last_clean
@ -788,16 +810,10 @@ class Catalog extends database_object {
*/ */
public static function update_settings($data) { public static function update_settings($data) {
$id = Dba::escape($data['catalog_id']); $sql = "UPDATE `catalog` SET `name` = ?, `rename_pattern` = ?, " .
$name = Dba::escape($data['name']); "`sort_pattern` = ?, `remote_username` = ?, `remote_password` = ? WHERE `id` = ?";
$rename = Dba::escape($data['rename_pattern']); $params = array($data['name'], $data['rename_pattern'], $data['sort_pattern'], $data['remote_username'], $data['remote_password'], $data['catalog_id']);
$sort = Dba::escape($data['sort_pattern']); $db_results = Dba::write($sql, $params);
$remote_username = Dba::escape($data['remote_username']);
$remote_password = Dba::escape($data['remote_password']);
$sql = "UPDATE `catalog` SET `name`='$name', `rename_pattern`='$rename', " .
"`sort_pattern`='$sort', `remote_username`='$remote_username', `remote_password`='$remote_password' WHERE `id` = '$id'";
$db_results = Dba::write($sql);
return true; return true;
@ -1486,25 +1502,17 @@ class Catalog extends database_object {
$tag_name = vainfo::get_tag_type($vainfo->tags); $tag_name = vainfo::get_tag_type($vainfo->tags);
$results = vainfo::clean_tag_info($vainfo->tags,$tag_name,$file); $results = vainfo::clean_tag_info($vainfo->tags,$tag_name,$file);
$file = Dba::escape($file);
$catalog_id = Dba::escape($this->id);
$title = Dba::escape($results['title']);
$vcodec = $results['video_codec'];
$acodec = $results['audio_codec'];
$rezx = intval($results['resolution_x']); $rezx = intval($results['resolution_x']);
$rezy = intval($results['resolution_y']); $rezy = intval($results['resolution_y']);
$filesize = Dba::escape($filesize);
$time = Dba::escape($results['time']);
$mime = Dba::escape($results['mime']);
// UNUSED CURRENTLY // UNUSED CURRENTLY
$comment = Dba::escape($results['comment']); $comment = $results['comment'];
$year = Dba::escape($results['year']); $year = $results['year'];
$disk = Dba::escape($results['disk']); $disk = $results['disk'];
$sql = "INSERT INTO `video` (`file`,`catalog`,`title`,`video_codec`,`audio_codec`,`resolution_x`,`resolution_y`,`size`,`time`,`mime`) " . $sql = "INSERT INTO `video` (`file`,`catalog`,`title`,`video_codec`,`audio_codec`,`resolution_x`,`resolution_y`,`size`,`time`,`mime`) " .
" VALUES ('$file','$catalog_id','$title','$vcodec','$acodec','$rezx','$rezy','$filesize','$time','$mime')"; " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$db_results = Dba::write($sql); $params = array($file, $this->id, $results['title'], $results['video_codec'], $results['audio_codec'], $rezx, $rezy, $filesize, $results['time'], $results['mime']);
$db_results = Dba::write($sql, $params);
return true; return true;
@ -1541,10 +1549,8 @@ class Catalog extends database_object {
return true; return true;
} }
$full_file = Dba::escape($full_file); $sql = "SELECT `id` FROM `song` WHERE `file` = ?";
$db_results = Dba::read($sql, array($full_file));
$sql = "SELECT `id` FROM `song` WHERE `file` = '$full_file'";
$db_results = Dba::read($sql);
//If it's found then return true //If it's found then return true
if (Dba::fetch_row($db_results)) { if (Dba::fetch_row($db_results)) {
@ -1641,23 +1647,21 @@ class Catalog extends database_object {
*/ */
public static function delete($catalog_id) { public static function delete($catalog_id) {
$catalog_id = Dba::escape($catalog_id);
// First remove the songs in this catalog // First remove the songs in this catalog
$sql = "DELETE FROM `song` WHERE `catalog` = '$catalog_id'"; $sql = "DELETE FROM `song` WHERE `catalog` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($catalog_id));
// Only if the previous one works do we go on // Only if the previous one works do we go on
if (!$db_results) { return false; } if (!$db_results) { return false; }
$sql = "DELETE FROM `video` WHERE `catalog` = '$catalog_id'"; $sql = "DELETE FROM `video` WHERE `catalog` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($catalog_id));
if (!$db_results) { return false; } if (!$db_results) { return false; }
// Next Remove the Catalog Entry it's self // Next Remove the Catalog Entry it's self
$sql = "DELETE FROM `catalog` WHERE `id` = '$catalog_id'"; $sql = "DELETE FROM `catalog` WHERE `id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($catalog_id));
// Run the cleaners... // Run the cleaners...
self::gc(); self::gc();
@ -1671,15 +1675,17 @@ class Catalog extends database_object {
public function export($type) { public function export($type) {
// Select all songs in catalog // Select all songs in catalog
$params = array();
if($this->id) { if($this->id) {
$sql = 'SELECT `id` FROM `song` ' . $sql = 'SELECT `id` FROM `song` ' .
"WHERE `catalog`='$this->id' " . "WHERE `catalog`= ? " .
'ORDER BY `album`, `track`'; 'ORDER BY `album`, `track`';
$params[] = $this->id;
} }
else { else {
$sql = 'SELECT `id` FROM `song` ORDER BY `album`, `track`'; $sql = 'SELECT `id` FROM `song` ORDER BY `album`, `track`';
} }
$db_results = Dba::read($sql); $db_results = Dba::read($sql, $params);
switch ($type) { switch ($type) {
case 'itunes': case 'itunes':

View file

@ -115,11 +115,8 @@ class Playlist extends playlist_object {
*/ */
public function get_track($track_id) { public function get_track($track_id) {
$track_id = Dba::escape($track_id); $sql = "SELECT * FROM `playlist_data` WHERE `id` = ? AND `playlist` = ?";
$playlist_id = Dba::escape($this->id); $db_results = Dba::read($sql, array($track_id, $playlist_id));
$sql = "SELECT * FROM `playlist_data` WHERE `id`='$track_id' AND `playlist`='$playlist_id'";
$db_results = Dba::read($sql);
$row = Dba::fetch_assoc($db_results); $row = Dba::fetch_assoc($db_results);
@ -137,8 +134,8 @@ class Playlist extends playlist_object {
$results = array(); $results = array();
$sql = "SELECT `id`,`object_id`,`object_type`,`track` FROM `playlist_data` WHERE `playlist`='" . Dba::escape($this->id) . "' ORDER BY `track`"; $sql = "SELECT `id`,`object_id`,`object_type`,`track` FROM `playlist_data` WHERE `playlist`= ? ORDER BY `track`";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
$results[] = array( $results[] = array(
@ -164,8 +161,8 @@ class Playlist extends playlist_object {
$limit_sql = $limit ? 'LIMIT ' . intval($limit) : ''; $limit_sql = $limit ? 'LIMIT ' . intval($limit) : '';
$sql = "SELECT `object_id`,`object_type` FROM `playlist_data` " . $sql = "SELECT `object_id`,`object_type` FROM `playlist_data` " .
"WHERE `playlist`='" . Dba::escape($this->id) . "' ORDER BY RAND() $limit_sql"; "WHERE `playlist` = ? ORDER BY RAND() $limit_sql";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
@ -188,8 +185,8 @@ class Playlist extends playlist_object {
$results = array(); $results = array();
$sql = "SELECT * FROM `playlist_data` WHERE `playlist`='" . Dba::escape($this->id) . "' ORDER BY `track`"; $sql = "SELECT * FROM `playlist_data` WHERE `playlist` = ? ORDER BY `track`";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
while ($r = Dba::fetch_assoc($db_results)) { while ($r = Dba::fetch_assoc($db_results)) {
if ($r['dyn_song']) { if ($r['dyn_song']) {
@ -213,14 +210,32 @@ class Playlist extends playlist_object {
*/ */
public function get_song_count() { public function get_song_count() {
$sql = "SELECT COUNT(`id`) FROM `playlist_data` WHERE `playlist`='" . Dba::escape($this->id) . "'"; $sql = "SELECT COUNT(`id`) FROM `playlist_data` WHERE `playlist` = ?";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
$results = Dba::fetch_row($db_results); $results = Dba::fetch_row($db_results);
return $results['0']; return $results['0'];
} // get_song_count } // get_song_count
/**
* get_total_duration
* Get the total duration of all songs.
*/
public function get_total_duration() {
$songs = self::get_songs();
$idlist = '(' . implode(',', $songs) . ')';
$sql = "SELECT SUM(`time`) FROM `song` WHERE `id` IN $idlist";
$db_results = Dba::read($sql);
$results = Dba::fetch_row($db_results);
return $results['0'];
} // get_total_duration
/** /**
* get_users * get_users
@ -229,11 +244,10 @@ class Playlist extends playlist_object {
*/ */
public static function get_users($user_id) { public static function get_users($user_id) {
$user_id = Dba::escape($user_id);
$results = array(); $results = array();
$sql = "SELECT `id` FROM `playlist` WHERE `user`='$user_id' ORDER BY `name`"; $sql = "SELECT `id` FROM `playlist` WHERE `user` = ? ORDER BY `name`";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($user_id));
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
$results[] = $row['id']; $results[] = $row['id'];
@ -292,10 +306,8 @@ class Playlist extends playlist_object {
return false; return false;
} }
$value = Dba::escape($value); $sql = "UPDATE `playlist` SET `$field` = ? WHERE `id` = ?";
$db_results = Dba::write($sql, array($value, $this->id));
$sql = "UPDATE `playlist` SET $field='$value' WHERE `id`='" . Dba::escape($this->id) . "'";
$db_results = Dba::write($sql);
return $db_results; return $db_results;
@ -307,12 +319,8 @@ class Playlist extends playlist_object {
*/ */
public function update_track_number($track_id,$track) { public function update_track_number($track_id,$track) {
$playlist_id = Dba::escape($this->id); $sql = "UPDATE `playlist_data` SET `track` = ? WHERE `id` = ? AND `playlist` = ?";
$track_id = Dba::escape($track_id); $db_results = Dba::write($sql, array($track, $track_id, $this->id));
$track = Dba::escape($track);
$sql = "UPDATE `playlist_data` SET `track`='$track' WHERE `id`='$track_id' AND `playlist`='$playlist_id'";
$db_results = Dba::write($sql);
} // update_track_number } // update_track_number
@ -328,8 +336,8 @@ class Playlist extends playlist_object {
* append, rather then integrate take end track # and add it to * append, rather then integrate take end track # and add it to
* $song->track add one to make sure it really is 'next' * $song->track add one to make sure it really is 'next'
*/ */
$sql = "SELECT `track` FROM `playlist_data` WHERE `playlist`='" . $this->id . "' ORDER BY `track` DESC LIMIT 1"; $sql = "SELECT `track` FROM `playlist_data` WHERE `playlist` = ? ORDER BY `track` DESC LIMIT 1";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
$data = Dba::fetch_assoc($db_results); $data = Dba::fetch_assoc($db_results);
$base_track = $data['track']; $base_track = $data['track'];
debug_event('add_songs', 'Track number: '.$base_track, '5'); debug_event('add_songs', 'Track number: '.$base_track, '5');
@ -340,20 +348,18 @@ class Playlist extends playlist_object {
// Based on the ordered prop we use track + base or just $i++ // Based on the ordered prop we use track + base or just $i++
if (!$ordered) { if (!$ordered) {
$track = Dba::escape($song->track+$base_track); $track = $song->track + $base_track;
} }
else { else {
$i++; $i++;
$track = Dba::escape($base_track+$i); $track = $base_track + $i;
} }
$id = Dba::escape($song->id);
$pl_id = Dba::escape($this->id);
/* Don't insert dead songs */ /* Don't insert dead songs */
if ($id) { if ($id) {
$sql = "INSERT INTO `playlist_data` (`playlist`,`object_id`,`object_type`,`track`) " . $sql = "INSERT INTO `playlist_data` (`playlist`,`object_id`,`object_type`,`track`) " .
" VALUES ('$pl_id','$id','song','$track')"; " VALUES (?, ?, 'song', ?)";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($this->id, $song->id, $track));
} // if valid id } // if valid id
} // end foreach songs } // end foreach songs
@ -367,14 +373,8 @@ class Playlist extends playlist_object {
*/ */
public static function create($name,$type) { public static function create($name,$type) {
$name = Dba::escape($name); $sql = "INSERT INTO `playlist` (`name`,`user`,`type`,`date`) VALUES (?, ?, ?, ?)";
$type = Dba::escape($type); $db_results = Dba::write($sql, array($name, $GLOBALS['user']->id, $type, time()));
$user = Dba::escape($GLOBALS['user']->id);
$date = time();
$sql = "INSERT INTO `playlist` (`name`,`user`,`type`,`date`) " .
" VALUES ('$name','$user','$type','$date')";
$db_results = Dba::write($sql);
$insert_id = Dba::insert_id(); $insert_id = Dba::insert_id();
@ -384,7 +384,7 @@ class Playlist extends playlist_object {
/** /**
* set_items * set_items
* This calles the get_items function and sets it to $this->items which is an array in this object * This calls the get_items function and sets it to $this->items which is an array in this object
*/ */
function set_items() { function set_items() {
@ -396,13 +396,13 @@ class Playlist extends playlist_object {
* normalize_tracks * normalize_tracks
* this takes the crazy out of order tracks * this takes the crazy out of order tracks
* and numbers them in a liner fashion, not allowing for * and numbers them in a liner fashion, not allowing for
* the same track # twice, this is an optional funcition * the same track # twice, this is an optional function
*/ */
public function normalize_tracks() { public function normalize_tracks() {
/* First get all of the songs in order of their tracks */ /* First get all of the songs in order of their tracks */
$sql = "SELECT `id` FROM `playlist_data` WHERE `playlist`='" . Dba::escape($this->id) . "' ORDER BY `track` ASC"; $sql = "SELECT `id` FROM `playlist_data` WHERE `playlist` = ? ORDER BY `track` ASC";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id));
$i = 1; $i = 1;
$results = array(); $results = array();
@ -416,9 +416,8 @@ class Playlist extends playlist_object {
} // end while results } // end while results
foreach($results as $data) { foreach($results as $data) {
$sql = "UPDATE `playlist_data` SET `track`='" . $data['track'] . "' WHERE" . $sql = "UPDATE `playlist_data` SET `track` = ? WHERE `id` = ?";
" `id`='" . $data['id'] . "'"; $db_results = Dba::write($sql, array($data['track'], $data['id']));
$db_results = Dba::write($sql);
} // foreach re-ordered results } // foreach re-ordered results
return true; return true;
@ -431,15 +430,25 @@ class Playlist extends playlist_object {
*/ */
public function delete_track($id) { public function delete_track($id) {
$this_id = Dba::escape($this->id); $sql = "DELETE FROM `playlist_data` WHERE `playlist_data`.`playlist` = ? AND `playlist_data`.`id` = ? LIMIT 1";
$id = Dba::escape($id); $db_results = Dba::write($sql, array($this->id, $id));
$sql = "DELETE FROM `playlist_data` WHERE `playlist_data`.`playlist`='$this_id' AND `playlist_data`.`id`='$id' LIMIT 1";
$db_results = Dba::write($sql);
return true; return true;
} // delete_track } // delete_track
/**
* delete_track_number
* this deletes a single track by it's track #, you specify the playlist_data.track here
*/
public function delete_track_number($track) {
$sql = "DELETE FROM `playlist_data` WHERE `playlist_data`.`playlist` = ? AND `playlist_data`.`track` = ? LIMIT 1";
$db_results = Dba::write($sql, array($this->id, $track));
return true;
} // delete_track_number
/** /**
* delete * delete
@ -447,16 +456,14 @@ class Playlist extends playlist_object {
*/ */
public function delete() { public function delete() {
$id = Dba::escape($this->id); $sql = "DELETE FROM `playlist_data` WHERE `playlist` = ?";
$db_results = Dba::write($sql, array($id));
$sql = "DELETE FROM `playlist_data` WHERE `playlist` = '$id'"; $sql = "DELETE FROM `playlist` WHERE `id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($id));
$sql = "DELETE FROM `playlist` WHERE `id`='$id'"; $sql = "DELETE FROM `object_count` WHERE `object_type`='playlist' AND `object_id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($id));
$sql = "DELETE FROM `object_count` WHERE `object_type`='playlist' AND `object_id`='$id'";
$db_results = Dba::write($sql);
return true; return true;

View file

@ -38,10 +38,8 @@ class Rating extends database_object {
* the id and type of object that we need to pull the rating for * the id and type of object that we need to pull the rating for
*/ */
public function __construct($id, $type) { public function __construct($id, $type) {
$id = intval($id);
$type = Dba::escape($type);
$this->id = $id; $this->id = intval($id);
$this->type = $type; $this->type = $type;
return true; return true;
@ -68,15 +66,14 @@ class Rating extends database_object {
if (!is_array($ids) OR !count($ids)) { return false; } if (!is_array($ids) OR !count($ids)) { return false; }
$user_id = intval($GLOBALS['user']->id);
$ratings = array(); $ratings = array();
$user_ratings = array(); $user_ratings = array();
$idlist = '(' . implode(',', $ids) . ')'; $idlist = '(' . implode(',', $ids) . ')';
$sql = "SELECT `rating`, `object_id` FROM `rating` " . $sql = "SELECT `rating`, `object_id` FROM `rating` " .
"WHERE `user`='$user_id' AND `object_id` IN $idlist " . "WHERE `user` = ? AND `object_id` IN $idlist " .
"AND `object_type`='$type'"; "AND `object_type` = ?";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($GLOBALS['user']->id, $type));
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
$user_ratings[$row['object_id']] = $row['rating']; $user_ratings[$row['object_id']] = $row['rating'];
@ -84,8 +81,8 @@ class Rating extends database_object {
$sql = "SELECT AVG(`rating`) as `rating`, `object_id` FROM " . $sql = "SELECT AVG(`rating`) as `rating`, `object_id` FROM " .
"`rating` WHERE `object_id` IN $idlist AND " . "`rating` WHERE `object_id` IN $idlist AND " .
"`object_type`='$type' GROUP BY `object_id`"; "`object_type` = ? GROUP BY `object_id`";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($type));
while ($row = Dba::fetch_assoc($db_results)) { while ($row = Dba::fetch_assoc($db_results)) {
$ratings[$row['object_id']] = $row['rating']; $ratings[$row['object_id']] = $row['rating'];
@ -99,7 +96,7 @@ class Rating extends database_object {
else { else {
$rating = intval($user_ratings[$id]); $rating = intval($user_ratings[$id]);
} }
parent::add_to_cache('rating_' . $type . '_user' . $user_id, $id, $rating); parent::add_to_cache('rating_' . $type . '_user' . $GLOBALS['user']->id, $id, $rating);
// Then store the average // Then store the average
if (!isset($ratings[$id])) { if (!isset($ratings[$id])) {
@ -122,21 +119,18 @@ class Rating extends database_object {
*/ */
public function get_user_rating($user_id = null) { public function get_user_rating($user_id = null) {
$id = intval($this->id);
$type = Dba::escape($this->type);
if (is_null($user_id)) { if (is_null($user_id)) {
$user_id = $GLOBALS['user']->id; $user_id = $GLOBALS['user']->id;
} }
$user_id = intval($user_id);
$key = 'rating_' . $type . '_user' . $user_id; $key = 'rating_' . $type . '_user' . $user_id;
if (parent::is_cached($key, $id)) { if (parent::is_cached($key, $this->id)) {
return parent::get_from_cache($key, $id); return parent::get_from_cache($key, $this->id);
} }
$sql = "SELECT `rating` FROM `rating` WHERE `user`='$user_id' ". $sql = "SELECT `rating` FROM `rating` WHERE `user` = ? ".
"AND `object_id`='$id' AND `object_type`='$type'"; "AND `object_id` = ? AND `object_type` = ?";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($user_id, $this->id, $type));
$rating = 0; $rating = 0;
@ -144,7 +138,7 @@ class Rating extends database_object {
$rating = $results['rating']; $rating = $results['rating'];
} }
parent::add_to_cache($key, $id, $rating); parent::add_to_cache($key, $this->id, $rating);
return $rating; return $rating;
} // get_user_rating } // get_user_rating
@ -156,16 +150,13 @@ class Rating extends database_object {
*/ */
public function get_average_rating() { public function get_average_rating() {
$id = intval($this->id);
$type = Dba::escape($this->type);
if (parent::is_cached('rating_' . $type . '_all', $id)) { if (parent::is_cached('rating_' . $type . '_all', $id)) {
return parent::get_from_cache('rating_' . $type . '_user', $id); return parent::get_from_cache('rating_' . $type . '_user', $id);
} }
$sql = "SELECT AVG(`rating`) as `rating` FROM `rating` WHERE " . $sql = "SELECT AVG(`rating`) as `rating` FROM `rating` WHERE " .
"`object_id`='$id' AND `object_type`='$type'"; "`object_id` = ? AND `object_type` = ?";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($this->id, $this->type));
$results = Dba::fetch_assoc($db_results); $results = Dba::fetch_assoc($db_results);
@ -173,6 +164,38 @@ class Rating extends database_object {
return $results['rating']; return $results['rating'];
} // get_average_rating } // get_average_rating
/**
* get_highest
* Get objects with the highest average rating.
*/
public static function get_highest($type, $count='', $offset='') {
if (!$count) {
$count = Config::get('popular_threshold');
}
$count = intval($count);
if (!$offset) {
$limit = $count;
} else {
$limit = intval($offset) . "," . $count;
}
/* Select Top objects counting by # of rows */
$sql = "SELECT `object_id`,AVG(`rating`) AS `rating` FROM rating" .
" WHERE object_type = ?" .
" GROUP BY object_id ORDER BY `rating` DESC LIMIT $limit";
$db_results = Dba::read($sql, array($type));
$results = array();
while ($row = Dba::fetch_assoc($db_results)) {
$results[] = $row['object_id'];
}
return $results;
}
/** /**
* set_rating * set_rating
@ -180,9 +203,7 @@ class Rating extends database_object {
* If no userid is passed in, we use the currently logged in user. * If no userid is passed in, we use the currently logged in user.
*/ */
public function set_rating($rating, $user_id = null) { public function set_rating($rating, $user_id = null) {
$id = intval($this->id);
$type = Dba::escape($this->type);
$rating = intval($rating);
if (is_null($user_id)) { if (is_null($user_id)) {
$user_id = $GLOBALS['user']->id; $user_id = $GLOBALS['user']->id;
} }
@ -193,16 +214,18 @@ class Rating extends database_object {
// If score is -1, then remove rating // If score is -1, then remove rating
if ($rating == '-1') { if ($rating == '-1') {
$sql = "DELETE FROM `rating` WHERE " . $sql = "DELETE FROM `rating` WHERE " .
"`object_id`='$this->id' AND " . "`object_id` = ? AND " .
"`object_type`='$this->type' AND " . "`object_type` = ? AND " .
"`user`='$user_id'"; "`user` = ?";
$params = array($this->id, $this->type, $user_id);
} }
else { else {
$sql = "REPLACE INTO `rating` " . $sql = "REPLACE INTO `rating` " .
"(`object_id`, `object_type`, `rating`, `user`) " . "(`object_id`, `object_type`, `rating`, `user`) " .
"VALUES ('$id', '$type', '$rating', '$user_id')"; "VALUES (?, ?, ?, ?)";
$params = array($this->id, $this->type, $rating, $user_id);
} }
$db_results = Dba::write($sql); $db_results = Dba::write($sql, $params);
parent::add_to_cache('rating_' . $type . '_user' . $user_id, $id, $rating); parent::add_to_cache('rating_' . $type . '_user' . $user_id, $id, $rating);

View file

@ -526,6 +526,10 @@ class Search extends playlist_object {
if ($limit > 0) { if ($limit > 0) {
$limit_sql = ' LIMIT ' . $limit; $limit_sql = ' LIMIT ' . $limit;
$offset = intval($data['offset']);
$limit_sql = ' LIMIT ';
if ($offset) $limit_sql .= $offset . ",";
$limit_sql .= $limit;
} }
$search_info = $search->to_sql(); $search_info = $search->to_sql();
@ -550,8 +554,8 @@ class Search extends playlist_object {
*/ */
public function delete() { public function delete() {
$id = Dba::escape($this->id); $id = Dba::escape($this->id);
$sql = "DELETE FROM `search` WHERE `id`='$id'"; $sql = "DELETE FROM `search` WHERE `id` = ?";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($id));
return true; return true;
} }
@ -674,15 +678,8 @@ class Search extends playlist_object {
$this->name .= uniqid('', true); $this->name .= uniqid('', true);
} }
// clean up variables for insert $sql = "INSERT INTO `search` (`name`, `type`, `user`, `rules`, `logic_operator`) VALUES (?, ?, ?, ?, ?)";
$name = Dba::escape($this->name); $db_results = Dba::write($sql, array($this->name, $this->type, $GLOBALS['user']->id, serialize($this->rules), $this->logic_operator));
$user = Dba::escape($GLOBALS['user']->id);
$type = Dba::escape($this->type);
$rules = serialize($this->rules);
$logic_operator = $this->logic_operator;
$sql = "INSERT INTO `search` (`name`, `type`, `user`, `rules`, `logic_operator`) VALUES ('$name', '$type', '$user', '$rules', '$logic_operator')";
$db_results = Dba::write($sql);
$insert_id = Dba::insert_id(); $insert_id = Dba::insert_id();
$this->id = $insert_id; $this->id = $insert_id;
return $insert_id; return $insert_id;
@ -722,14 +719,8 @@ class Search extends playlist_object {
return false; return false;
} }
$name = Dba::escape($this->name); $sql = "UPDATE `search` SET `name` = ?, `type` = ?, `rules` = ?, `logic_operator` = ? WHERE `id` = ?";
$user = Dba::escape($GLOBALS['user']->id); $db_results = Dba::write($sql, array($this->name, $this->type, serialize($this->rules), $this->logic_operator, $this->id));
$type = Dba::escape($this->type);
$rules = serialize($this->rules);
$logic_operator = $this->logic_operator;
$sql = "UPDATE `search` SET `name`='$name', `type`='$type', `rules`='$rules', `logic_operator`='$logic_operator' WHERE `id`='" . Dba::escape($this->id) . "'";
$db_results = Dba::write($sql);
return $db_results; return $db_results;
} }
@ -826,7 +817,7 @@ class Search extends playlist_object {
$table['song'] = "LEFT JOIN `song` ON `song`.`album`=`album`.`id`"; $table['song'] = "LEFT JOIN `song` ON `song`.`album`=`album`.`id`";
} }
if ($join['rating']) { if ($join['rating']) {
$userid = $GLOBALS['user']->id; $userid = intval($GLOBALS['user']->id);
$table['rating'] = "LEFT JOIN `rating` ON " . $table['rating'] = "LEFT JOIN `rating` ON " .
"`rating`.`object_type`='album' " . "`rating`.`object_type`='album' " .
"AND `rating`.`user`='$userid' " . "AND `rating`.`user`='$userid' " .

View file

@ -310,6 +310,9 @@ class Song extends database_object implements media {
case 'm4a': case 'm4a':
return 'audio/mp4'; return 'audio/mp4';
break; break;
case 'aacp':
return 'audio/aacp';
break;
case 'mpc': case 'mpc':
return 'audio/x-musepack'; return 'audio/x-musepack';
break; break;
@ -1022,8 +1025,12 @@ class Song extends database_object implements media {
} // get_recently_played } // get_recently_played
public function get_stream_types() { public function get_stream_types() {
return Song::get_stream_types_for_type($this->type);
} // end stream_types
public static function get_stream_types_for_type($type) {
$types = array(); $types = array();
$transcode = Config::get('transcode_' . $this->type); $transcode = Config::get('transcode_' . $type);
if ($transcode != 'required') { if ($transcode != 'required') {
$types[] = 'native'; $types[] = 'native';

View file

@ -77,13 +77,10 @@ class Stats {
public static function insert($type,$oid,$user) { public static function insert($type,$oid,$user) {
$type = self::validate_type($type); $type = self::validate_type($type);
$oid = Dba::escape($oid);
$user = Dba::escape($user);
$date = time();
$sql = "INSERT INTO `object_count` (`object_type`,`object_id`,`date`,`user`) " . $sql = "INSERT INTO `object_count` (`object_type`,`object_id`,`date`,`user`) " .
" VALUES ('$type','$oid','$date','$user')"; " VALUES (?, ?, ?, ?)";
$db_results = Dba::write($sql); $db_results = Dba::write($sql, array($type, $oid, time(), $user));
if (!$db_results) { if (!$db_results) {
debug_event('statistics','Unabled to insert statistics:' . $sql,'3'); debug_event('statistics','Unabled to insert statistics:' . $sql,'3');
@ -102,10 +99,8 @@ class Stats {
$user_id = $user_id ? $user_id : $GLOBALS['user']->id; $user_id = $user_id ? $user_id : $GLOBALS['user']->id;
$user_id = Dba::escape($user_id); $sql = "SELECT * FROM `object_count` WHERE `user` = ? AND `object_type`='song' ORDER BY `date` DESC LIMIT 1";
$db_results = Dba::read($sql, array($user_id));
$sql = "SELECT * FROM `object_count` WHERE `user`='$user_id' AND `object_type`='song' ORDER BY `date` DESC LIMIT 1";
$db_results = Dba::read($sql);
$results = Dba::fetch_assoc($db_results); $results = Dba::fetch_assoc($db_results);
@ -122,13 +117,9 @@ class Stats {
$user_id = $user_id ? $user_id : $GLOBALS['user']->id; $user_id = $user_id ? $user_id : $GLOBALS['user']->id;
$user_id = Dba::escape($user_id); $sql = "SELECT * FROM `object_count` WHERE `user` = ? AND `object_type`='song' AND `date` >= ? " .
$time = Dba::escape($time);
$sql = "SELECT * FROM `object_count` WHERE `user`='$user_id' AND `object_type`='song' AND `date`>='$time' " .
"ORDER BY `date` DESC"; "ORDER BY `date` DESC";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($user_id, $time));
$results = array(); $results = array();
@ -145,7 +136,7 @@ class Stats {
* This returns the top X for type Y from the * This returns the top X for type Y from the
* last stats_threshold days * last stats_threshold days
*/ */
public static function get_top($type,$count='',$threshold = '') { public static function get_top($type,$count='',$threshold = '',$offset='') {
/* If they don't pass one, then use the preference */ /* If they don't pass one, then use the preference */
if (!$threshold) { if (!$threshold) {
@ -159,12 +150,17 @@ class Stats {
$count = intval($count); $count = intval($count);
$type = self::validate_type($type); $type = self::validate_type($type);
$date = time() - (86400*$threshold); $date = time() - (86400*$threshold);
if (!$offset) {
$limit = $count;
} else {
$limit = intval($offset) . "," . $count;
}
/* Select Top objects counting by # of rows */ /* Select Top objects counting by # of rows */
$sql = "SELECT object_id,COUNT(id) AS `count` FROM object_count" . $sql = "SELECT object_id,COUNT(id) AS `count` FROM object_count" .
" WHERE object_type='$type' AND date >= '$date'" . " WHERE object_type = ? AND date >= ?" .
" GROUP BY object_id ORDER BY `count` DESC LIMIT $count"; " GROUP BY object_id ORDER BY `count` DESC LIMIT $limit";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($type, $date));
$results = array(); $results = array();
@ -175,6 +171,45 @@ class Stats {
return $results; return $results;
} // get_top } // get_top
/**
* get_recent
* This returns the recent X for type Y from the
* last stats_threshold days
*/
public static function get_recent($type,$count='',$threshold = '',$offset='') {
/* If they don't pass one, then use the preference */
if (!$threshold) {
$threshold = Config::get('stats_threshold');
}
if (!$count) {
$count = Config::get('popular_threshold');
}
$count = intval($count);
$type = self::validate_type($type);
if (!$offset) {
$limit = $count;
} else {
$limit = intval($offset) . "," . $count;
}
/* Select Top objects counting by # of rows */
$sql = "SELECT DISTINCT(object_id) FROM object_count" .
" WHERE object_type = ?" .
" GROUP BY object_id ORDER BY `date` DESC LIMIT $limit";
$db_results = Dba::read($sql, array($type));
$results = array();
while ($row = Dba::fetch_assoc($db_results)) {
$results[] = $row['object_id'];
}
return $results;
} // get_recent
/** /**
* get_user * get_user
@ -185,7 +220,6 @@ class Stats {
$count = intval($count); $count = intval($count);
$type = self::validate_type($type); $type = self::validate_type($type);
$user = Dba::escape($user);
/* If full then don't limit on date */ /* If full then don't limit on date */
if ($full) { if ($full) {
@ -198,9 +232,9 @@ class Stats {
/* Select Objects based on user */ /* Select Objects based on user */
//FIXME:: Requires table scan, look at improving //FIXME:: Requires table scan, look at improving
$sql = "SELECT object_id,COUNT(id) AS `count` FROM object_count" . $sql = "SELECT object_id,COUNT(id) AS `count` FROM object_count" .
" WHERE object_type='$type' AND date >= '$date' AND user = '$user'" . " WHERE object_type = ? AND date >= ? AND user = ?" .
" GROUP BY object_id ORDER BY `count` DESC LIMIT $count"; " GROUP BY object_id ORDER BY `count` DESC LIMIT $count";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($type, $date, $user));
$results = array(); $results = array();
@ -238,15 +272,19 @@ class Stats {
* This returns an array of the newest artists/albums/whatever * This returns an array of the newest artists/albums/whatever
* in this ampache instance * in this ampache instance
*/ */
public static function get_newest($type,$limit='') { public static function get_newest($type,$limit='',$offset='') {
if (!$limit) { $limit = Config::get('popular_threshold'); } if (!$count) { $count = Config::get('popular_threshold'); }
if (!$offset) {
$limit = $count;
} else {
$limit = $offset . ',' . $count;
}
$type = self::validate_type($type); $type = self::validate_type($type);
$object_name = ucfirst($type); $object_name = ucfirst($type);
$sql = "SELECT DISTINCT(`$type`), MIN(`addition_time`) AS `real_atime` FROM `song` GROUP BY `$type` ORDER BY `real_atime` DESC " . $sql = "SELECT DISTINCT(`$type`), MIN(`addition_time`) AS `real_atime` FROM `song` GROUP BY `$type` ORDER BY `real_atime` DESC LIMIT $limit";
"LIMIT $limit";
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
$items = array(); $items = array();

View file

@ -39,21 +39,9 @@ class Stream {
public static function set_session($sid) { public static function set_session($sid) {
self::$session=$sid; self::$session=$sid;
} // set_session } // set_session
/** public static function get_allowed_bitrate($song) {
* start_transcode
*
* This is a rather complex function that starts the transcoding or
* resampling of a song and returns the opened file handle.
*/
public static function start_transcode($song, $type = null) {
$transcode_settings = $song->get_transcode_settings($type);
// Bail out early if we're unutterably broken
if ($transcode_settings == false) {
debug_event('stream', 'Transcode requested, but get_transcode_settings failed', 2);
return false;
}
$max_bitrate = Config::get('max_bit_rate'); $max_bitrate = Config::get('max_bit_rate');
$min_bitrate = Config::get('min_bit_rate'); $min_bitrate = Config::get('min_bit_rate');
// FIXME: This should be configurable for each output type // FIXME: This should be configurable for each output type
@ -63,7 +51,7 @@ class Stream {
if ($user_sample_rate < $min_bitrate) { if ($user_sample_rate < $min_bitrate) {
$min_bitrate = $user_sample_rate; $min_bitrate = $user_sample_rate;
} }
// Are there site-wide constraints? (Dynamic downsampling.) // Are there site-wide constraints? (Dynamic downsampling.)
if ($max_bitrate > 1 ) { if ($max_bitrate > 1 ) {
$sql = 'SELECT COUNT(*) FROM `now_playing` ' . $sql = 'SELECT COUNT(*) FROM `now_playing` ' .
@ -102,6 +90,25 @@ class Stream {
else { else {
$sample_rate = $user_sample_rate; $sample_rate = $user_sample_rate;
} }
return $sample_rate;
}
/**
* start_transcode
*
* This is a rather complex function that starts the transcoding or
* resampling of a song and returns the opened file handle.
*/
public static function start_transcode($song, $type = null) {
$transcode_settings = $song->get_transcode_settings($type);
// Bail out early if we're unutterably broken
if ($transcode_settings == false) {
debug_event('stream', 'Transcode requested, but get_transcode_settings failed', 2);
return false;
}
$sample_rate = self::get_allowed_bitrate($song);
debug_event('stream', 'Configured bitrate is ' . $sample_rate, 5); debug_event('stream', 'Configured bitrate is ' . $sample_rate, 5);
@ -135,14 +142,13 @@ class Stream {
debug_event('downsample', "Downsample command: $command", 3); debug_event('downsample', "Downsample command: $command", 3);
$process = proc_open( $descriptors = array(1 => array('pipe', 'w'));
$command, if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
array( // Windows doesn't like to provide stderr as a pipe
1 => array('pipe', 'w'), $descriptors[2] = array('pipe', 'w');
2 => array('pipe', 'w') }
),
$pipes $process = proc_open($command, $descriptors, $pipes);
);
return array( return array(
'process' => $process, 'process' => $process,
'handle' => $pipes[1], 'handle' => $pipes[1],

View file

@ -357,8 +357,14 @@ class Stream_Playlist {
* Creates an html5 player. * Creates an html5 player.
*/ */
public function create_html5_player() { public function create_html5_player() {
require Config::get('prefix') . '/templates/create_html5_player.inc.php';
} if (Config::get("iframes")) {
require Config::get('prefix') . '/templates/create_html5_player_embedded.inc.php';
} else {
require Config::get('prefix') . '/templates/create_html5_player.inc.php';
}
} // create_html5_player
/** /**
* create_localplay * create_localplay

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,407 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* 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; version 2
* of the License.
*
* 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.
*
*/
/**
* XML_Data Class
*
* This class takes care of all of the xml document stuff in Ampache these
* are all static calls
*
*/
class Subsonic_XML_Data {
const API_VERSION = "1.10.0";
const SSERROR_GENERIC = 0;
const SSERROR_MISSINGPARAM = 10;
const SSERROR_APIVERSION_CLIENT = 20;
const SSERROR_APIVERSION_SERVER = 30;
const SSERROR_BADAUTH = 40;
const SSERROR_UNAUTHORIZED = 50;
const SSERROR_TRIAL = 60;
const SSERROR_DATA_NOTFOUND = 70;
// Ampache doesn't have a global unique id but each items are unique per category. We use id pattern to identify item category.
const AMPACHEID_ARTIST = 100000000;
const AMPACHEID_ALBUM = 200000000;
const AMPACHEID_SONG = 300000000;
/**
* constructor
*
* We don't use this, as its really a static class
*/
private function __construct() {
}
public static function getArtistId($id) {
return $id + Subsonic_XML_Data::AMPACHEID_ARTIST;
}
public static function getAlbumId($id) {
return $id + Subsonic_XML_Data::AMPACHEID_ALBUM;
}
public static function getSongId($id) {
return $id + Subsonic_XML_Data::AMPACHEID_SONG;
}
public static function getAmpacheId($id) {
return ($id % Subsonic_XML_Data::AMPACHEID_ARTIST);
}
public static function getAmpacheIds($ids) {
$ampids = array();
foreach ($ids as $id) {
$ampids[] = self::getAmpacheId($id);
}
return $ampids;
}
public static function isArtist($id) {
return ($id >= Subsonic_XML_Data::AMPACHEID_ARTIST && $id < Subsonic_XML_Data::AMPACHEID_ALBUM);
}
public static function isAlbum($id) {
return ($id >= Subsonic_XML_Data::AMPACHEID_ALBUM && $id < Subsonic_XML_Data::AMPACHEID_SONG);
}
public static function isSong($id) {
return ($id >= Subsonic_XML_Data::AMPACHEID_SONG);
}
public static function createFailedResponse($version = "") {
$response = self::createResponse($version);
$response->addAttribute('status', 'failed');
return $response;
}
public static function createSuccessResponse($version = "") {
$response = self::createResponse($version);
$response->addAttribute('status', 'ok');
return $response;
}
public static function createResponse($version = "") {
if (empty($version)) $version = Subsonic_XML_Data::API_VERSION;
$response = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><subsonic-response/>');
$response->addAttribute('xmlns', 'http://subsonic.org/restapi');
$response->addAttribute('version', $version);
return $response;
}
public static function createError($code, $message = "", $version = "") {
if (empty($version)) $version = Subsonic_XML_Data::API_VERSION;
$response = self::createFailedResponse($version);
self::setError($response, $code, $message);
return $response;
}
/**
* Set error information.
*
* @param SimpleXMLElement $xml Parent node
* @param integer $code Error code
* @param string $string Error message
*/
public static function setError($xml, $code, $message = "") {
$xerr = $xml->addChild('error');
$xerr->addAttribute('code', $code);
if (empty($message)) {
switch ($code) {
case Subsonic_XML_Data::SSERROR_GENERIC: $message = "A generic error."; break;
case Subsonic_XML_Data::SSERROR_MISSINGPARAM: $message = "Required parameter is missing."; break;
case Subsonic_XML_Data::SSERROR_APIVERSION_CLIENT: $message = "Incompatible Subsonic REST protocol version. Client must upgrade."; break;
case Subsonic_XML_Data::SSERROR_APIVERSION_SERVER: $message = "Incompatible Subsonic REST protocol version. Server must upgrade."; break;
case Subsonic_XML_Data::SSERROR_BADAUTH: $message = "Wrong username or password."; break;
case Subsonic_XML_Data::SSERROR_UNAUTHORIZED: $message = "User is not authorized for the given operation."; break;
case Subsonic_XML_Data::SSERROR_TRIAL: $message = "The trial period for the Subsonic server is over. Please upgrade to Subsonic Premium. Visit subsonic.org for details."; break;
case Subsonic_XML_Data::SSERROR_DATA_NOTFOUND: $message = "The requested data was not found."; break;
}
}
$xerr->addAttribute("message", $message);
}
public static function addLicense($xml) {
$xlic = $xml->addChild('license');
$xlic->addAttribute('valid', 'true');
$xlic->addAttribute('email', 'webmaster@ampache.org');
$xlic->addAttribute('key', 'ABC123DEF');
$xlic->addAttribute('date', '2009-09-03T14:46:43');
}
public static function addMusicFolders($xml, $catalogs) {
$xfolders = $xml->addChild('musicFolders');
foreach($catalogs as $id) {
$catalog = new Catalog($id);
$xfolder = $xfolders->addChild('musicFolder');
$xfolder->addAttribute('id', $id);
$xfolder->addAttribute('name', $catalog->name);
}
}
public static function addArtistsIndexes($xml, $artists, $lastModified) {
$xindexes = $xml->addChild('indexes');
$xindexes->addAttribute('lastModified', $lastModified);
self::addArtists($xindexes, $artists);
}
public static function addArtistsRoot($xml, $artists) {
$xartists = $xml->addChild('artists');
self::addArtists($xartists, $artists, true);
}
public static function addArtists($xml, $artists, $extra=false) {
$xlastcat = null;
$xlastletter = '';
foreach ($artists as $artist) {
if (strlen($artist->name) > 0) {
$letter = strtoupper($artist->name[0]);
if ($letter == "X" || $letter == "Y" || $letter == "Z") $letter = "X-Z";
else if (!preg_match("/^[A-W]$/", $letter)) $letter = "#";
if ($letter != $xlastletter) {
$xlastletter = $letter;
$xlastcat = $xml->addChild('index');
$xlastcat->addAttribute('name', $xlastletter);
}
}
self::addArtist($xlastcat, $artist, $extra);
}
}
public static function addArtist($xml, $artist, $extra=false, $albums=false) {
$xartist = $xml->addChild('artist');
$xartist->addAttribute('id', self::getArtistId($artist->id));
$xartist->addAttribute('name', $artist->name);
if ($extra) {
//$xartist->addAttribute('coverArt');
$xartist->addAttribute('albumCount', count($artist->get_albums()));
}
if ($albums) {
$allalbums = $artist->get_albums();
foreach ($allalbums as $id) {
$album = new Album($id);
self::addAlbum($xartist, $album);
}
}
}
public static function addAlbumList($xml, $albums, $elementName="albumList") {
$xlist = $xml->addChild($elementName);
foreach($albums as $id) {
$album = new Album($id);
self::addAlbum($xlist, $album);
}
}
public static function addAlbum($xml, $album, $songs=false, $elementName="album") {
$xalbum = $xml->addChild($elementName);
$xalbum->addAttribute('id', self::getAlbumId($album->id));
$xalbum->addAttribute('name', $album->name);
$xalbum->addAttribute('album', $album->name);
$xalbum->addAttribute('title', self::formatAlbum($album));
$xalbum->addAttribute('isDir', 'true');
$album->format();
if ($album->has_art) $xalbum->addAttribute('coverArt', self::getAlbumId($album->id));
$xalbum->addAttribute('songCount', $album->song_count);
$xalbum->addAttribute('duration', $album->total_duration);
$xalbum->addAttribute('artistId', self::getArtistId($album->artist_id));
$xalbum->addAttribute('parent', self::getArtistId($album->artist_id));
$xalbum->addAttribute('artist', $album->artist_name);
$rating = new Rating($album->id, "album");
$rating_value = $rating->get_average_rating();
$xalbum->addAttribute('averageRating', ($rating_value) ? $rating_value : 0);
if ($songs) {
$allsongs = $album->get_songs();
foreach ($allsongs as $id) {
$song = new Song($id);
self::addSong($xalbum, $song);
}
}
}
public static function addSong($xml, $song, $elementName='song') {
self::createSong($xml, $song, $elementName);
}
public static function createSong($xml, $song, $elementName='song') {
$xsong = $xml->addChild($elementName);
$xsong->addAttribute('id', self::getSongId($song->id));
$xsong->addAttribute('parent', self::getAlbumId($song->album));
//$xsong->addAttribute('created', );
$xsong->addAttribute('title', $song->title);
$xsong->addAttribute('isDir', 'false');
$xsong->addAttribute('isVideo', 'false');
$xsong->addAttribute('type', 'music');
$album = new Album($song->album);
$xsong->addAttribute('albumId', self::getAlbumId($album->id));
$xsong->addAttribute('album', $album->name);
$artist = new Artist($song->artist);
$xsong->addAttribute('artistId', self::getArtistId($album->id));
$xsong->addAttribute('artist', $artist->name);
$xsong->addAttribute('coverArt', self::getAlbumId($album->id));
$xsong->addAttribute('duration', $song->time);
$xsong->addAttribute('bitRate', intval($song->bitrate / 1000));
$xsong->addAttribute('track', $song->track);
$xsong->addAttribute('year', $song->year);
$tags = Tag::get_object_tags('song', $song->id);
if (count($tags) > 0) $xsong->addAttribute('genre', $tags[0]['name']);
$xsong->addAttribute('size', $song->size);
if ($album->disk > 0) $xsong->addAttribute('discNumber', $album->disk);
$xsong->addAttribute('suffix', $song->type);
$xsong->addAttribute('contentType', $song->mime);
$xsong->addAttribute('path', $song->file);
//Do we need to support transcodedContentType and transcodedSuffix attributes?
return $xsong;
}
private static function formatAlbum($album) {
return $album->name . " [" . $album->year . "]";
}
public static function addArtistDirectory($xml, $artist) {
$xdir = $xml->addChild('directory');
$xdir->addAttribute('id', self::getArtistId($artist->id));
$xdir->addAttribute('name', $artist->name);
$allalbums = $artist->get_albums();
foreach ($allalbums as $id) {
$album = new Album($id);
self::addAlbum($xdir, $album, false, "child");
}
}
public static function addAlbumDirectory($xml, $album) {
$xdir = $xml->addChild('directory');
$xdir->addAttribute('id', self::getAlbumId($album->id));
$xdir->addAttribute('name', self::formatAlbum($album));
$album->format();
//$xdir->addAttribute('parent', self::getArtistId($album->artist_id));
$allsongs = $album->get_songs();
foreach ($allsongs as $id) {
$song = new Song($id);
self::addSong($xdir, $song, "child");
}
}
public static function addGenres($xml, $tags) {
$xgenres = $xml->addChild('genres');
foreach($tags as $tag) {
$otag = new Tag($tag['id']);
$xgenre = $xgenres->addChild('genre', $otag->name);
}
}
public static function addVideos($xml) {
// Not supported yet
$xvideos = $xml->addChild('videos');
}
public static function addPlaylists($xml, $playlists) {
$xplaylists = $xml->addChild('playlists');
foreach($playlists as $id) {
$playlist = new Playlist($id);
self::addPlaylist($xplaylists, $playlist);
}
}
public static function addPlaylist($xml, $playlist, $songs=false) {
$xplaylist = $xml->addChild('playlist');
$xplaylist->addAttribute('id', $playlist->id);
$xplaylist->addAttribute('name', $playlist->name);
$user = new User($playlist->user);
$xplaylist->addAttribute('owner', $user->username);
$xplaylist->addAttribute('public', ($playlist->type != "private") ? "true" : "false");
$xplaylist->addAttribute('created', date("c", $playlist->date));
$xplaylist->addAttribute('songCount', $playlist->get_song_count());
$xplaylist->addAttribute('duration', $playlist->get_total_duration());
if ($songs) {
$allsongs = $playlist->get_songs();
foreach($allsongs as $id) {
$song = new Song($id);
self::addSong($xplaylist, $song, "entry");
}
}
}
public static function addRandomSongs($xml, $songs) {
$xsongs = $xml->addChild('randomSongs');
foreach ($songs as $id) {
$song = new Song($id);
self::addSong($xsongs, $song);
}
}
public static function addSongsByGenre($xml, $songs) {
$xsongs = $xml->addChild('songsByGenre');
foreach ($songs as $id) {
$song = new Song($id);
self::addSong($xsongs, $song);
}
}
public static function addNowPlaying($xml, $data) {
$xplaynow = $xml->addChild('nowPlaying');
foreach($data as $d) {
$track = self::createSong($xplaynow, $d['media'], "entry");
$track->addAttribute('username', $d['client']->username);
$track->addAttribute('minutesAgo', intval(time() - ($d['expire'] - Config::get('stream_length')) / 1000));
$track->addAttribute('playerId', $d['agent']);
}
}
public static function addSearchResult($xml, $artists, $albums, $songs, $elementName = "searchResult2") {
$xresult = $xml->addChild($elementName);
foreach ($artists as $id) {
$artist = new Artist($id);
self::addArtist($xresult, $artist);
}
foreach ($albums as $id) {
$album = new Album($id);
self::addAlbum($xresult, $album);
}
foreach ($songs as $id) {
$song = new Song($id);
self::addSong($xresult, $song);
}
}
public static function addStarred($xml, $elementName="starred") {
$xstarred = $xml->addChild($elementName);
}
}
?>

View file

@ -412,15 +412,19 @@ class Tag extends database_object {
* get_tag_objects * get_tag_objects
* This gets the objects from a specified tag and returns an array of object ids, nothing more * This gets the objects from a specified tag and returns an array of object ids, nothing more
*/ */
public static function get_tag_objects($type,$tag_id) { public static function get_tag_objects($type,$tag_id,$count='',$offset='') {
if (!self::validate_type($type)) { return array(); } if (!self::validate_type($type)) { return array(); }
$tag_id = Dba::escape($tag_id); if ($count) {
$limit_sql = "LIMIT ";
if ($offset) $limit_sql .= intval($offset) . ',';
$limit_sql .= intval($count);
}
$sql = "SELECT DISTINCT `tag_map`.`object_id` FROM `tag_map` " . $sql = "SELECT DISTINCT `tag_map`.`object_id` FROM `tag_map` " .
"WHERE `tag_map`.`tag_id`='$tag_id' AND `tag_map`.`object_type`='$type'"; "WHERE `tag_map`.`tag_id` = ? AND `tag_map`.`object_type` = ? $limit_sql";
$db_results = Dba::read($sql); $db_results = Dba::read($sql, array($tag_id, $type));
$results = array(); $results = array();
@ -438,13 +442,15 @@ class Tag extends database_object {
* This is a non-object non type depedent function that just returns tags * This is a non-object non type depedent function that just returns tags
* we've got, it can take filters (this is used by the tag cloud) * we've got, it can take filters (this is used by the tag cloud)
*/ */
public static function get_tags($limit,$filters=array()) { public static function get_tags($limit = 0,$filters=array()) {
$sql = "SELECT `tag_map`.`tag_id`,COUNT(`tag_map`.`object_id`) AS `count` " . $sql = "SELECT `tag_map`.`tag_id`,COUNT(`tag_map`.`object_id`) AS `count` " .
"FROM `tag_map` " . "FROM `tag_map` " .
"LEFT JOIN `tag` ON `tag`.`id`=`tag_map`.`tag_id` " . "LEFT JOIN `tag` ON `tag`.`id`=`tag_map`.`tag_id` " .
"GROUP BY `tag`.`name` ORDER BY `count` DESC " . "GROUP BY `tag`.`name` ORDER BY `count` DESC ";
"LIMIT $limit"; if ($limit >0) {
$sql .= " LIMIT $limit";
}
$db_results = Dba::read($sql); $db_results = Dba::read($sql);
$results = array(); $results = array();

View file

@ -244,6 +244,15 @@ class UI {
require_once Config::get('prefix') . '/templates/header.inc.php'; require_once Config::get('prefix') . '/templates/header.inc.php';
} }
/**
* show_mainframes
*
* For now this just shows the mainframes template
*/
public static function show_mainframes() {
require_once Config::get('prefix') . '/templates/mainframes.inc.php';
}
/** /**
* show_footer * show_footer
* *

View file

@ -23,61 +23,34 @@
/** /**
* Update Class * Update Class
* *
* this class handles updating from one version of * This class mainly handles schema updates for the database.
* ampache to the next. Versions are a 6 digit number * Versions are a monotonically increasing integer: First column(s) are the
* <pre> * major version, followed by a single column for the minor version and four
* 220000 * columns for the build number. 3.6 build 1 is 360000; 10.9 build 17 is
* ^ * 1090017.
* Major Revision
*
* 220000
* ^
* Minor Revision
* </pre>
*
* The last 4 digits are a build number...
* If Minor can't go over 9 Major can go as high as we want
*
*/ */
class Update { class Update {
public $key; public $key;
public $value; public $value;
public static $versions; // array containing version information public static $versions; // array containing version information
/** /*
* Update * Constructor
* Constructor, pulls out information about the desired key *
* This should never be called
*/ */
function Update ( $key=0 ) { private function __construct() {
// static class
if (!$key) { return false; } }
$this->key = intval($key);
$info = $this->_get_info();
$this->value = $info['value'];
$this->versions = $this->populate_version();
} // constructor
/**
* _get_info
* gets the information for the zone
*/
private function _get_info() {
$sql = "SELECT * FROM `update_info` WHERE `key`='$this->key'";
$db_results = Dba::read($sql);
return Dba::fetch_assoc($db_results);
} // _get_info
/** /**
* get_version * get_version
* this checks to see what version you are currently running *
* because we may not have the update_info table we have to check * This checks to see what version you are currently running.
* for it's existance first. * Because we may not have the update_info table we have to check
* for its existence first.
*/ */
public static function get_version() { public static function get_version() {
@ -109,69 +82,39 @@ class Update {
/** /**
* format_version * format_version
* make the version number pretty *
* Make the version number pretty.
*/ */
public static function format_version($data) { public static function format_version($data) {
$new_version =
$new_version = substr($data,0,strlen($data) - 5) . "." . substr($data,strlen($data)-5,1) . " Build:" . substr($data, 0, strlen($data) - 5) . '.' .
substr($data,strlen($data)-4,strlen($data)); substr($data, strlen($data) - 5, 1) . ' Build:' .
substr($data, strlen($data) - 4, strlen($data));
return $new_version; return $new_version;
}
} // format_version
/** /**
* need_update * need_update
* checks to see if we need to update *
* ampache at all * Checks to see if we need to update ampache at all.
*/ */
public static function need_update() { public static function need_update() {
$current_version = self::get_version(); $current_version = self::get_version();
if (!is_array(self::$versions)) { if (!is_array(self::$versions)) {
self::$versions = self::populate_version(); self::$versions = self::populate_version();
} }
/* // Iterate through the versions and see if we need to apply any updates
Go through the versions we have and see if
we need to apply any updates
*/
foreach (self::$versions as $update) { foreach (self::$versions as $update) {
if ($update['version'] > $current_version) { if ($update['version'] > $current_version) {
return true; return true;
} }
}
} // end foreach version
return false; return false;
}
} // need_update
/**
* plugins_installed
* This function checks to make sure that there are no plugins
* installed before allowing you to run the update. this is
* to protect the integrity of the database
*/
public static function plugins_installed() {
/* Pull all version info */
$sql = "SELECT * FROM `update_info`";
$db_results = Dba::read($sql);
while ($results = Dba::fetch_assoc($db_results)) {
/* We have only one allowed string */
if ($results['key'] != 'db_version') {
return false;
}
} // while update_info results
return true;
} // plugins_installed
/** /**
* populate_version * populate_version
@ -341,6 +284,12 @@ class Update {
$update_string = '- Update stream_playlist table to address performance issues.<br />'; $update_string = '- Update stream_playlist table to address performance issues.<br />';
$version[] = array('version' => '360013', 'description' => $update_string); $version[] = array('version' => '360013', 'description' => $update_string);
$update_string = '- Increase the length of sessionids again.<br />';
$version[] = array('version' => '360014', 'description' => $update_string);
$update_string = '- Add iframes parameter to preferences.<br />';
$version[] = array('version' => '360015', 'description' => $update_string);
return $version; return $version;
} }
@ -407,13 +356,6 @@ class Update {
// Prevent the script from timing out, which could be bad // Prevent the script from timing out, which could be bad
set_time_limit(0); set_time_limit(0);
/* Verify that there are no plugins installed
//FIXME: provide a link to remove all plugins, otherwise this could turn into a catch 22
if (!$self::plugins_installed()) {
$GLOBALS['error']->add_error('general', T_('Plugins detected, please remove all Plugins and try again'));
return false;
} */
$methods = array(); $methods = array();
$current_version = self::get_version(); $current_version = self::get_version();
@ -1525,5 +1467,39 @@ class Update {
public static function update_360013() { public static function update_360013() {
return Dba::write('ALTER TABLE `stream_playlist` ENGINE=MyISAM'); return Dba::write('ALTER TABLE `stream_playlist` ENGINE=MyISAM');
} }
/**
* update_360014
*
* PHP session IDs are an ever-growing beast.
*/
public static function update_360014() {
$retval = true;
$retval = Dba::write('ALTER TABLE `stream_playlist` CHANGE `sid` `sid` VARCHAR(256)') ? $retval : false;
$retval = Dba::write('ALTER TABLE `tmp_playlist` CHANGE `session` `session` VARCHAR(256)') ? $retval : false;
$retval = Dba::write('ALTER TABLE `session` CHANGE `id` `id` VARCHAR(256) NOT NULL') ? $retval : false;
return $retval;
}
/**
* update_360015
*
* This update inserts the Iframes preference...
*/
public static function update_360015() {
$sql = "INSERT INTO `preference` (`name`,`value`,`description`,`level`,`type`,`catagory`) " .
"VALUES ('iframes','0','Iframes',25,'boolean','interface')";
Dba::write($sql);
$id = Dba::insert_id();
$sql = "INSERT INTO `user_preference` VALUES (-1,?,'0')";
Dba::write($sql, array($id));
return true;
}
} }
?> ?>

View file

@ -79,13 +79,6 @@ function reloadRedirect(target) {
window.location = target; window.location = target;
} // reloadRedirect } // reloadRedirect
// popupWindow
// Loads the specified URL in a new window. Used for art.
function popupWindow(url) {
var newWindow = window.open(url, "ampache_art", "menubar=no,toolbar=no,location=no,directories=no");
if (window.focus) { newWindow.focus(); }
} // popupWindow
// This is kind of ugly. Let's not mess with it too much. // This is kind of ugly. Let's not mess with it too much.
function check_inline_song_edit(type, song) { function check_inline_song_edit(type, song) {
var target = '#' + type + '_select_' + song; var target = '#' + type + '_select_' + song;

View file

@ -166,6 +166,7 @@ function create_preference_input($name,$value) {
case 'rio_track_stats': case 'rio_track_stats':
case 'rio_global_stats': case 'rio_global_stats':
case 'direct_link': case 'direct_link':
case 'iframes':
if ($value == '1') { $is_true = "selected=\"selected\""; } if ($value == '1') { $is_true = "selected=\"selected\""; }
else { $is_false = "selected=\"selected\""; } else { $is_false = "selected=\"selected\""; }
echo "<select name=\"$name\">\n"; echo "<select name=\"$name\">\n";

BIN
modules/jplayer/Jplayer.swf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

34
modules/jplayer/jplayer.playlist.min.js vendored Normal file
View file

@ -0,0 +1,34 @@
/*
* Playlist Object for the jPlayer Plugin
* http://www.jplayer.org
*
* Copyright (c) 2009 - 2013 Happyworm Ltd
* Dual licensed under the MIT and GPL licenses.
* - http://www.opensource.org/licenses/mit-license.php
* - http://www.gnu.org/copyleft/gpl.html
*
* Author: Mark J Panaghiston
* Version: 2.3.0
* Date: 20th April 2013
*
* Requires:
* - jQuery 1.7.0+
* - jPlayer 2.3.0+
*/
(function(b,f){jPlayerPlaylist=function(a,c,d){var e=this;this.current=0;this.removing=this.shuffled=this.loop=!1;this.cssSelector=b.extend({},this._cssSelector,a);this.options=b.extend(!0,{keyBindings:{next:{key:39,fn:function(){e.next()}},previous:{key:37,fn:function(){e.previous()}}}},this._options,d);this.playlist=[];this.original=[];this._initPlaylist(c);this.cssSelector.title=this.cssSelector.cssSelectorAncestor+" .jp-title";this.cssSelector.playlist=this.cssSelector.cssSelectorAncestor+" .jp-playlist";
this.cssSelector.next=this.cssSelector.cssSelectorAncestor+" .jp-next";this.cssSelector.previous=this.cssSelector.cssSelectorAncestor+" .jp-previous";this.cssSelector.shuffle=this.cssSelector.cssSelectorAncestor+" .jp-shuffle";this.cssSelector.shuffleOff=this.cssSelector.cssSelectorAncestor+" .jp-shuffle-off";this.options.cssSelectorAncestor=this.cssSelector.cssSelectorAncestor;this.options.repeat=function(a){e.loop=a.jPlayer.options.loop};b(this.cssSelector.jPlayer).bind(b.jPlayer.event.ready,function(){e._init()});
b(this.cssSelector.jPlayer).bind(b.jPlayer.event.ended,function(){e.next()});b(this.cssSelector.jPlayer).bind(b.jPlayer.event.play,function(){b(this).jPlayer("pauseOthers")});b(this.cssSelector.jPlayer).bind(b.jPlayer.event.resize,function(a){a.jPlayer.options.fullScreen?b(e.cssSelector.title).show():b(e.cssSelector.title).hide()});b(this.cssSelector.previous).click(function(){e.previous();b(this).blur();return!1});b(this.cssSelector.next).click(function(){e.next();b(this).blur();return!1});b(this.cssSelector.shuffle).click(function(){e.shuffle(!0);
return!1});b(this.cssSelector.shuffleOff).click(function(){e.shuffle(!1);return!1}).hide();this.options.fullScreen||b(this.cssSelector.title).hide();b(this.cssSelector.playlist+" ul").empty();this._createItemHandlers();b(this.cssSelector.jPlayer).jPlayer(this.options)};jPlayerPlaylist.prototype={_cssSelector:{jPlayer:"#jquery_jplayer_1",cssSelectorAncestor:"#jp_container_1"},_options:{playlistOptions:{autoPlay:!1,loopOnPrevious:!1,shuffleOnLoop:!0,enableRemoveControls:!1,displayTime:"slow",addTime:"fast",
removeTime:"fast",shuffleTime:"slow",itemClass:"jp-playlist-item",freeGroupClass:"jp-free-media",freeItemClass:"jp-playlist-item-free",removeItemClass:"jp-playlist-item-remove"}},option:function(a,b){if(b===f)return this.options.playlistOptions[a];this.options.playlistOptions[a]=b;switch(a){case "enableRemoveControls":this._updateControls();break;case "itemClass":case "freeGroupClass":case "freeItemClass":case "removeItemClass":this._refresh(!0),this._createItemHandlers()}return this},_init:function(){var a=
this;this._refresh(function(){a.options.playlistOptions.autoPlay?a.play(a.current):a.select(a.current)})},_initPlaylist:function(a){this.current=0;this.removing=this.shuffled=!1;this.original=b.extend(!0,[],a);this._originalPlaylist()},_originalPlaylist:function(){var a=this;this.playlist=[];b.each(this.original,function(b){a.playlist[b]=a.original[b]})},_refresh:function(a){var c=this;if(a&&!b.isFunction(a))b(this.cssSelector.playlist+" ul").empty(),b.each(this.playlist,function(a){b(c.cssSelector.playlist+
" ul").append(c._createListItem(c.playlist[a]))}),this._updateControls();else{var d=b(this.cssSelector.playlist+" ul").children().length?this.options.playlistOptions.displayTime:0;b(this.cssSelector.playlist+" ul").slideUp(d,function(){var d=b(this);b(this).empty();b.each(c.playlist,function(a){d.append(c._createListItem(c.playlist[a]))});c._updateControls();b.isFunction(a)&&a();c.playlist.length?b(this).slideDown(c.options.playlistOptions.displayTime):b(this).show()})}},_createListItem:function(a){var c=
this,d="<li><div>",d=d+("<a href='javascript:;' class='"+this.options.playlistOptions.removeItemClass+"'>&times;</a>");if(a.free){var e=!0,d=d+("<span class='"+this.options.playlistOptions.freeGroupClass+"'>(");b.each(a,function(a,f){b.jPlayer.prototype.format[a]&&(e?e=!1:d+=" | ",d+="<a class='"+c.options.playlistOptions.freeItemClass+"' href='"+f+"' tabindex='1'>"+a+"</a>")});d+=")</span>"}d+="<a href='javascript:;' class='"+this.options.playlistOptions.itemClass+"' tabindex='1'>"+a.title+(a.artist?
" <span class='jp-artist'>by "+a.artist+"</span>":"")+"</a>";return d+="</div></li>"},_createItemHandlers:function(){var a=this;b(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.itemClass).on("click","a."+this.options.playlistOptions.itemClass,function(){var c=b(this).parent().parent().index();a.current!==c?a.play(c):b(a.cssSelector.jPlayer).jPlayer("play");b(this).blur();return!1});b(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.freeItemClass).on("click",
"a."+this.options.playlistOptions.freeItemClass,function(){b(this).parent().parent().find("."+a.options.playlistOptions.itemClass).click();b(this).blur();return!1});b(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.removeItemClass).on("click","a."+this.options.playlistOptions.removeItemClass,function(){var c=b(this).parent().parent().index();a.remove(c);b(this).blur();return!1})},_updateControls:function(){this.options.playlistOptions.enableRemoveControls?b(this.cssSelector.playlist+
" ."+this.options.playlistOptions.removeItemClass).show():b(this.cssSelector.playlist+" ."+this.options.playlistOptions.removeItemClass).hide();this.shuffled?(b(this.cssSelector.shuffleOff).show(),b(this.cssSelector.shuffle).hide()):(b(this.cssSelector.shuffleOff).hide(),b(this.cssSelector.shuffle).show())},_highlight:function(a){this.playlist.length&&a!==f&&(b(this.cssSelector.playlist+" .jp-playlist-current").removeClass("jp-playlist-current"),b(this.cssSelector.playlist+" li:nth-child("+(a+1)+
")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current"),b(this.cssSelector.title+" li").html(this.playlist[a].title+(this.playlist[a].artist?" <span class='jp-artist'>by "+this.playlist[a].artist+"</span>":"")))},setPlaylist:function(a){this._initPlaylist(a);this._init()},add:function(a,c){b(this.cssSelector.playlist+" ul").append(this._createListItem(a)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime);this._updateControls();this.original.push(a);
this.playlist.push(a);c?this.play(this.playlist.length-1):1===this.original.length&&this.select(0)},remove:function(a){var c=this;if(a===f)return this._initPlaylist([]),this._refresh(function(){b(c.cssSelector.jPlayer).jPlayer("clearMedia")}),!0;if(this.removing)return!1;a=0>a?c.original.length+a:a;0<=a&&a<this.playlist.length&&(this.removing=!0,b(this.cssSelector.playlist+" li:nth-child("+(a+1)+")").slideUp(this.options.playlistOptions.removeTime,function(){b(this).remove();if(c.shuffled){var d=
c.playlist[a];b.each(c.original,function(a){if(c.original[a]===d)return c.original.splice(a,1),!1})}else c.original.splice(a,1);c.playlist.splice(a,1);c.original.length?a===c.current?(c.current=a<c.original.length?c.current:c.original.length-1,c.select(c.current)):a<c.current&&c.current--:(b(c.cssSelector.jPlayer).jPlayer("clearMedia"),c.current=0,c.shuffled=!1,c._updateControls());c.removing=!1}));return!0},select:function(a){a=0>a?this.original.length+a:a;0<=a&&a<this.playlist.length?(this.current=
a,this._highlight(a),b(this.cssSelector.jPlayer).jPlayer("setMedia",this.playlist[this.current])):this.current=0},play:function(a){a=0>a?this.original.length+a:a;0<=a&&a<this.playlist.length?this.playlist.length&&(this.select(a),b(this.cssSelector.jPlayer).jPlayer("play")):a===f&&b(this.cssSelector.jPlayer).jPlayer("play")},pause:function(){b(this.cssSelector.jPlayer).jPlayer("pause")},next:function(){var a=this.current+1<this.playlist.length?this.current+1:0;this.loop?0===a&&this.shuffled&&this.options.playlistOptions.shuffleOnLoop&&
1<this.playlist.length?this.shuffle(!0,!0):this.play(a):0<a&&this.play(a)},previous:function(){var a=0<=this.current-1?this.current-1:this.playlist.length-1;(this.loop&&this.options.playlistOptions.loopOnPrevious||a<this.playlist.length-1)&&this.play(a)},shuffle:function(a,c){var d=this;a===f&&(a=!this.shuffled);(a||a!==this.shuffled)&&b(this.cssSelector.playlist+" ul").slideUp(this.options.playlistOptions.shuffleTime,function(){(d.shuffled=a)?d.playlist.sort(function(){return 0.5-Math.random()}):
d._originalPlaylist();d._refresh(!0);c||!b(d.cssSelector.jPlayer).data("jPlayer").status.paused?d.play(0):d.select(0);b(this).slideDown(d.options.playlistOptions.shuffleTime)})}}})(jQuery);

107
modules/jplayer/jquery.jplayer.min.js vendored Normal file
View file

@ -0,0 +1,107 @@
/*
* jPlayer Plugin for jQuery JavaScript Library
* http://www.jplayer.org
*
* Copyright (c) 2009 - 2013 Happyworm Ltd
* Licensed under the MIT license.
* http://opensource.org/licenses/MIT
*
* Author: Mark J Panaghiston
* Version: 2.4.0
* Date: 5th June 2013
*/
(function(b,f){"function"===typeof define&&define.amd?define(["jquery"],f):b.jQuery?f(b.jQuery):f(b.Zepto)})(this,function(b,f){b.fn.jPlayer=function(a){var c="string"===typeof a,d=Array.prototype.slice.call(arguments,1),e=this;a=!c&&d.length?b.extend.apply(null,[!0,a].concat(d)):a;if(c&&"_"===a.charAt(0))return e;c?this.each(function(){var c=b(this).data("jPlayer"),h=c&&b.isFunction(c[a])?c[a].apply(c,d):c;if(h!==c&&h!==f)return e=h,!1}):this.each(function(){var c=b(this).data("jPlayer");c?c.option(a||
{}):b(this).data("jPlayer",new b.jPlayer(a,this))});return e};b.jPlayer=function(a,c){if(arguments.length){this.element=b(c);this.options=b.extend(!0,{},this.options,a);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()});this._init()}};"function"!==typeof b.fn.stop&&(b.fn.stop=function(){});b.jPlayer.emulateMethods="load play pause";b.jPlayer.emulateStatus="src readyState networkState currentTime duration paused ended playbackRate";b.jPlayer.emulateOptions="muted volume";b.jPlayer.reservedEvent=
"ready flashreset resize repeat error warning";b.jPlayer.event={};b.each("ready flashreset resize repeat click error warning loadstart progress suspend abort emptied stalled play pause loadedmetadata loadeddata waiting playing canplay canplaythrough seeking seeked timeupdate ended ratechange durationchange volumechange".split(" "),function(){b.jPlayer.event[this]="jPlayer_"+this});b.jPlayer.htmlEvent="loadstart abort emptied stalled loadedmetadata loadeddata canplay canplaythrough ratechange".split(" ");
b.jPlayer.pause=function(){b.each(b.jPlayer.prototype.instances,function(a,c){c.data("jPlayer").status.srcSet&&c.jPlayer("pause")})};b.jPlayer.timeFormat={showHour:!1,showMin:!0,showSec:!0,padHour:!1,padMin:!0,padSec:!0,sepHour:":",sepMin:":",sepSec:""};var l=function(){this.init()};l.prototype={init:function(){this.options={timeFormat:b.jPlayer.timeFormat}},time:function(a){var c=new Date(1E3*(a&&"number"===typeof a?a:0)),b=c.getUTCHours();a=this.options.timeFormat.showHour?c.getUTCMinutes():c.getUTCMinutes()+
60*b;c=this.options.timeFormat.showMin?c.getUTCSeconds():c.getUTCSeconds()+60*a;b=this.options.timeFormat.padHour&&10>b?"0"+b:b;a=this.options.timeFormat.padMin&&10>a?"0"+a:a;c=this.options.timeFormat.padSec&&10>c?"0"+c:c;b=""+(this.options.timeFormat.showHour?b+this.options.timeFormat.sepHour:"");b+=this.options.timeFormat.showMin?a+this.options.timeFormat.sepMin:"";return b+=this.options.timeFormat.showSec?c+this.options.timeFormat.sepSec:""}};var m=new l;b.jPlayer.convertTime=function(a){return m.time(a)};
b.jPlayer.uaBrowser=function(a){a=a.toLowerCase();var b=/(opera)(?:.*version)?[ \/]([\w.]+)/,d=/(msie) ([\w.]+)/,e=/(mozilla)(?:.*? rv:([\w.]+))?/;a=/(webkit)[ \/]([\w.]+)/.exec(a)||b.exec(a)||d.exec(a)||0>a.indexOf("compatible")&&e.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}};b.jPlayer.uaPlatform=function(a){var b=a.toLowerCase(),d=/(android)/,e=/(mobile)/;a=/(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/.exec(b)||[];b=/(ipad|playbook)/.exec(b)||!e.exec(b)&&d.exec(b)||
[];a[1]&&(a[1]=a[1].replace(/\s/g,"_"));return{platform:a[1]||"",tablet:b[1]||""}};b.jPlayer.browser={};b.jPlayer.platform={};var j=b.jPlayer.uaBrowser(navigator.userAgent);j.browser&&(b.jPlayer.browser[j.browser]=!0,b.jPlayer.browser.version=j.version);j=b.jPlayer.uaPlatform(navigator.userAgent);j.platform&&(b.jPlayer.platform[j.platform]=!0,b.jPlayer.platform.mobile=!j.tablet,b.jPlayer.platform.tablet=!!j.tablet);b.jPlayer.getDocMode=function(){var a;b.jPlayer.browser.msie&&(document.documentMode?
a=document.documentMode:(a=5,document.compatMode&&"CSS1Compat"===document.compatMode&&(a=7)));return a};b.jPlayer.browser.documentMode=b.jPlayer.getDocMode();b.jPlayer.nativeFeatures={init:function(){var a=document,b=a.createElement("video"),d={w3c:"fullscreenEnabled fullscreenElement requestFullscreen exitFullscreen fullscreenchange fullscreenerror".split(" "),moz:"mozFullScreenEnabled mozFullScreenElement mozRequestFullScreen mozCancelFullScreen mozfullscreenchange mozfullscreenerror".split(" "),
webkit:" webkitCurrentFullScreenElement webkitRequestFullScreen webkitCancelFullScreen webkitfullscreenchange ".split(" "),webkitVideo:"webkitSupportsFullscreen webkitDisplayingFullscreen webkitEnterFullscreen webkitExitFullscreen ".split(" ")},e=["w3c","moz","webkit","webkitVideo"],g,h;this.fullscreen=b={support:{w3c:!!a[d.w3c[0]],moz:!!a[d.moz[0]],webkit:"function"===typeof a[d.webkit[3]],webkitVideo:"function"===typeof b[d.webkitVideo[2]]},used:{}};g=0;for(h=e.length;g<h;g++){var f=e[g];if(b.support[f]){b.spec=
f;b.used[f]=!0;break}}if(b.spec){var k=d[b.spec];b.api={fullscreenEnabled:!0,fullscreenElement:function(b){b=b?b:a;return b[k[1]]},requestFullscreen:function(a){return a[k[2]]()},exitFullscreen:function(b){b=b?b:a;return b[k[3]]()}};b.event={fullscreenchange:k[4],fullscreenerror:k[5]}}else b.api={fullscreenEnabled:!1,fullscreenElement:function(){return null},requestFullscreen:function(){},exitFullscreen:function(){}},b.event={}}};b.jPlayer.nativeFeatures.init();b.jPlayer.focus=null;b.jPlayer.keyIgnoreElementNames=
"INPUT TEXTAREA";var n=function(a){var c=b.jPlayer.focus,d;c&&(b.each(b.jPlayer.keyIgnoreElementNames.split(/\s+/g),function(b,c){if(a.target.nodeName.toUpperCase()===c.toUpperCase())return d=!0,!1}),d||b.each(c.options.keyBindings,function(d,g){if(g&&a.which===g.key&&b.isFunction(g.fn))return a.preventDefault(),g.fn(c),!1}))};b.jPlayer.keys=function(a){b(document.documentElement).unbind("keydown.jPlayer");a&&b(document.documentElement).bind("keydown.jPlayer",n)};b.jPlayer.keys(!0);b.jPlayer.prototype=
{count:0,version:{script:"2.4.0",needFlash:"2.4.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",supplied:"mp3",preload:"metadata",volume:0.8,muted:!1,wmode:"opaque",backgroundColor:"#000000",cssSelectorAncestor:"#jp_container_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",volumeMax:".jp-volume-max",
currentTime:".jp-current-time",duration:".jp-duration",fullScreen:".jp-full-screen",restoreScreen:".jp-restore-screen",repeat:".jp-repeat",repeatOff:".jp-repeat-off",gui:".jp-gui",noSolution:".jp-no-solution"},smoothPlayBar:!1,fullScreen:!1,fullWindow:!1,autohide:{restored:!1,full:!0,fadeIn:200,fadeOut:600,hold:1E3},loop:!1,repeat:function(a){a.jPlayer.options.loop?b(this).unbind(".jPlayerRepeat").bind(b.jPlayer.event.ended+".jPlayer.jPlayerRepeat",function(){b(this).jPlayer("play")}):b(this).unbind(".jPlayerRepeat")},
nativeVideoControls:{},noFullWindow:{msie:/msie [0-6]\./,ipad:/ipad.*?os [0-4]\./,iphone:/iphone/,ipod:/ipod/,android_pad:/android [0-3]\.(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/},noVolume:{ipad:/ipad/,iphone:/iphone/,ipod:/ipod/,android_pad:/android(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/,playbook:/playbook/},timeFormat:{},
keyEnabled:!1,audioFullScreen:!1,keyBindings:{play:{key:32,fn:function(a){a.status.paused?a.play():a.pause()}},fullScreen:{key:13,fn:function(a){(a.status.video||a.options.audioFullScreen)&&a._setOption("fullScreen",!a.options.fullScreen)}},muted:{key:8,fn:function(a){a._muted(!a.options.muted)}},volumeUp:{key:38,fn:function(a){a.volume(a.options.volume+0.1)}},volumeDown:{key:40,fn:function(a){a.volume(a.options.volume-0.1)}}},verticalVolume:!1,idPrefix:"jp",noConflict:"jQuery",emulateHtml:!1,errorAlerts:!1,
warningAlerts:!1},optionsAudio:{size:{width:"0px",height:"0px",cssClass:""},sizeFull:{width:"0px",height:"0px",cssClass:""}},optionsVideo:{size:{width:"480px",height:"270px",cssClass:"jp-video-270p"},sizeFull:{width:"100%",height:"100%",cssClass:"jp-video-full"}},instances:{},status:{src:"",media:{},paused:!0,format:{},formatType:"",waitForPlay:!0,waitForLoad:!0,srcSet:!1,video:!1,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0,videoWidth:0,videoHeight:0,readyState:0,
networkState:0,playbackRate:1,ended:0},internal:{ready:!1},solution:{html:!0,flash:!0},format:{mp3:{codec:'audio/mpeg; codecs="mp3"',flashCanPlay:!0,media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:!0,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis"',flashCanPlay:!1,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:!1,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:!1,media:"audio"},fla:{codec:"audio/x-flv",flashCanPlay:!0,media:"audio"},
rtmpa:{codec:'audio/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!0,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',flashCanPlay:!1,media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:!1,media:"video"},flv:{codec:"video/x-flv",flashCanPlay:!0,media:"video"},rtmpv:{codec:'video/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"video"}},_init:function(){var a=this;this.element.empty();this.status=
b.extend({},this.status);this.internal=b.extend({},this.internal);this.options.timeFormat=b.extend({},b.jPlayer.timeFormat,this.options.timeFormat);this.internal.cmdsIgnored=b.jPlayer.platform.ipad||b.jPlayer.platform.iphone||b.jPlayer.platform.ipod;this.internal.domNode=this.element.get(0);this.options.keyEnabled&&!b.jPlayer.focus&&(b.jPlayer.focus=this);this.formats=[];this.solutions=[];this.require={};this.htmlElement={};this.html={};this.html.audio={};this.html.video={};this.flash={};this.css=
{};this.css.cs={};this.css.jq={};this.ancestorJq=[];this.options.volume=this._limitValue(this.options.volume,0,1);b.each(this.options.supplied.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.format[e]){var f=!1;b.each(a.formats,function(a,b){if(e===b)return f=!0,!1});f||a.formats.push(e)}});b.each(this.options.solution.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.solution[e]){var f=!1;b.each(a.solutions,function(a,b){if(e===b)return f=!0,
!1});f||a.solutions.push(e)}});this.internal.instance="jp_"+this.count;this.instances[this.internal.instance]=this.element;this.element.attr("id")||this.element.attr("id",this.options.idPrefix+"_jplayer_"+this.count);this.internal.self=b.extend({},{id:this.element.attr("id"),jq:this.element});this.internal.audio=b.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:f});this.internal.video=b.extend({},{id:this.options.idPrefix+"_video_"+this.count,jq:f});this.internal.flash=b.extend({},{id:this.options.idPrefix+
"_flash_"+this.count,jq:f,swf:this.options.swfPath+(".swf"!==this.options.swfPath.toLowerCase().slice(-4)?(this.options.swfPath&&"/"!==this.options.swfPath.slice(-1)?"/":"")+"Jplayer.swf":"")});this.internal.poster=b.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:f});b.each(b.jPlayer.event,function(b,c){a.options[b]!==f&&(a.element.bind(c+".jPlayer",a.options[b]),a.options[b]=f)});this.require.audio=!1;this.require.video=!1;b.each(this.formats,function(b,c){a.require[a.format[c].media]=
!0});this.options=this.require.video?b.extend(!0,{},this.optionsVideo,this.options):b.extend(!0,{},this.optionsAudio,this.options);this._setSize();this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullWindow=this._uaBlocklist(this.options.noFullWindow);this.status.noVolume=this._uaBlocklist(this.options.noVolume);b.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled&&this._fullscreenAddEventListeners();this._restrictNativeVideoControls();this.htmlElement.poster=
document.createElement("img");this.htmlElement.poster.id=this.internal.poster.id;this.htmlElement.poster.onload=function(){(!a.status.video||a.status.waitForPlay)&&a.internal.poster.jq.show()};this.element.append(this.htmlElement.poster);this.internal.poster.jq=b("#"+this.internal.poster.id);this.internal.poster.jq.css({width:this.status.width,height:this.status.height});this.internal.poster.jq.hide();this.internal.poster.jq.bind("click.jPlayer",function(){a._trigger(b.jPlayer.event.click)});this.html.audio.available=
!1;this.require.audio&&(this.htmlElement.audio=document.createElement("audio"),this.htmlElement.audio.id=this.internal.audio.id,this.html.audio.available=!!this.htmlElement.audio.canPlayType&&this._testCanPlayType(this.htmlElement.audio));this.html.video.available=!1;this.require.video&&(this.htmlElement.video=document.createElement("video"),this.htmlElement.video.id=this.internal.video.id,this.html.video.available=!!this.htmlElement.video.canPlayType&&this._testCanPlayType(this.htmlElement.video));
this.flash.available=this._checkForFlash(10.1);this.html.canPlay={};this.flash.canPlay={};b.each(this.formats,function(b,c){a.html.canPlay[c]=a.html[a.format[c].media].available&&""!==a.htmlElement[a.format[c].media].canPlayType(a.format[c].codec);a.flash.canPlay[c]=a.format[c].flashCanPlay&&a.flash.available});this.html.desired=!1;this.flash.desired=!1;b.each(this.solutions,function(c,d){if(0===c)a[d].desired=!0;else{var e=!1,f=!1;b.each(a.formats,function(b,c){a[a.solutions[0]].canPlay[c]&&("video"===
a.format[c].media?f=!0:e=!0)});a[d].desired=a.require.audio&&!e||a.require.video&&!f}});this.html.support={};this.flash.support={};b.each(this.formats,function(b,c){a.html.support[c]=a.html.canPlay[c]&&a.html.desired;a.flash.support[c]=a.flash.canPlay[c]&&a.flash.desired});this.html.used=!1;this.flash.used=!1;b.each(this.solutions,function(c,d){b.each(a.formats,function(b,c){if(a[d].support[c])return a[d].used=!0,!1})});this._resetActive();this._resetGate();this._cssSelectorAncestor(this.options.cssSelectorAncestor);
!this.html.used&&!this.flash.used?(this._error({type:b.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SOLUTION,hint:b.jPlayer.errorHint.NO_SOLUTION}),this.css.jq.noSolution.length&&this.css.jq.noSolution.show()):this.css.jq.noSolution.length&&this.css.jq.noSolution.hide();if(this.flash.used){var c,d="jQuery="+encodeURI(this.options.noConflict)+"&id="+encodeURI(this.internal.self.id)+"&vol="+this.options.volume+
"&muted="+this.options.muted;if(b.jPlayer.browser.msie&&(9>Number(b.jPlayer.browser.version)||9>b.jPlayer.browser.documentMode)){d=['<param name="movie" value="'+this.internal.flash.swf+'" />','<param name="FlashVars" value="'+d+'" />','<param name="allowScriptAccess" value="always" />','<param name="bgcolor" value="'+this.options.backgroundColor+'" />','<param name="wmode" value="'+this.options.wmode+'" />'];c=document.createElement('<object id="'+this.internal.flash.id+'" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>');
for(var e=0;e<d.length;e++)c.appendChild(document.createElement(d[e]))}else e=function(a,b,c){var d=document.createElement("param");d.setAttribute("name",b);d.setAttribute("value",c);a.appendChild(d)},c=document.createElement("object"),c.setAttribute("id",this.internal.flash.id),c.setAttribute("name",this.internal.flash.id),c.setAttribute("data",this.internal.flash.swf),c.setAttribute("type","application/x-shockwave-flash"),c.setAttribute("width","1"),c.setAttribute("height","1"),c.setAttribute("tabindex",
"-1"),e(c,"flashvars",d),e(c,"allowscriptaccess","always"),e(c,"bgcolor",this.options.backgroundColor),e(c,"wmode",this.options.wmode);this.element.append(c);this.internal.flash.jq=b(c)}this.html.used&&(this.html.audio.available&&(this._addHtmlEventListeners(this.htmlElement.audio,this.html.audio),this.element.append(this.htmlElement.audio),this.internal.audio.jq=b("#"+this.internal.audio.id)),this.html.video.available&&(this._addHtmlEventListeners(this.htmlElement.video,this.html.video),this.element.append(this.htmlElement.video),
this.internal.video.jq=b("#"+this.internal.video.id),this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):this.internal.video.jq.css({width:"0px",height:"0px"}),this.internal.video.jq.bind("click.jPlayer",function(){a._trigger(b.jPlayer.event.click)})));this.options.emulateHtml&&this._emulateHtmlBridge();this.html.used&&!this.flash.used&&setTimeout(function(){a.internal.ready=!0;a.version.flash="n/a";a._trigger(b.jPlayer.event.repeat);a._trigger(b.jPlayer.event.ready)},
100);this._updateNativeVideoControls();this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();b.jPlayer.prototype.count++},destroy:function(){this.clearMedia();this._removeUiClass();this.css.jq.currentTime.length&&this.css.jq.currentTime.text("");this.css.jq.duration.length&&this.css.jq.duration.text("");b.each(this.css.jq,function(a,b){b.length&&b.unbind(".jPlayer")});this.internal.poster.jq.unbind(".jPlayer");this.internal.video.jq&&this.internal.video.jq.unbind(".jPlayer");this._fullscreenRemoveEventListeners();
this===b.jPlayer.focus&&(b.jPlayer.focus=null);this.options.emulateHtml&&this._destroyHtmlBridge();this.element.removeData("jPlayer");this.element.unbind(".jPlayer");this.element.empty();delete this.instances[this.internal.instance]},enable:function(){},disable:function(){},_testCanPlayType:function(a){try{return a.canPlayType(this.format.mp3.codec),!0}catch(b){return!1}},_uaBlocklist:function(a){var c=navigator.userAgent.toLowerCase(),d=!1;b.each(a,function(a,b){if(b&&b.test(c))return d=!0,!1});
return d},_restrictNativeVideoControls:function(){this.require.audio&&this.status.nativeVideoControls&&(this.status.nativeVideoControls=!1,this.status.noFullWindow=!0)},_updateNativeVideoControls:function(){this.html.video.available&&this.html.used&&(this.htmlElement.video.controls=this.status.nativeVideoControls,this._updateAutohide(),this.status.nativeVideoControls&&this.require.video?(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height})):
this.status.waitForPlay&&this.status.video&&(this.internal.poster.jq.show(),this.internal.video.jq.css({width:"0px",height:"0px"})))},_addHtmlEventListeners:function(a,c){var d=this;a.preload=this.options.preload;a.muted=this.options.muted;a.volume=this.options.volume;a.addEventListener("progress",function(){c.gate&&(d.internal.cmdsIgnored&&0<this.readyState&&(d.internal.cmdsIgnored=!1),d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.progress))},!1);a.addEventListener("timeupdate",
function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.timeupdate))},!1);a.addEventListener("durationchange",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.durationchange))},!1);a.addEventListener("play",function(){c.gate&&(d._updateButtons(!0),d._html_checkWaitForPlay(),d._trigger(b.jPlayer.event.play))},!1);a.addEventListener("playing",function(){c.gate&&(d._updateButtons(!0),d._seeked(),d._trigger(b.jPlayer.event.playing))},
!1);a.addEventListener("pause",function(){c.gate&&(d._updateButtons(!1),d._trigger(b.jPlayer.event.pause))},!1);a.addEventListener("waiting",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.waiting))},!1);a.addEventListener("seeking",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.seeking))},!1);a.addEventListener("seeked",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.seeked))},!1);a.addEventListener("volumechange",function(){c.gate&&(d.options.volume=a.volume,
d.options.muted=a.muted,d._updateMute(),d._updateVolume(),d._trigger(b.jPlayer.event.volumechange))},!1);a.addEventListener("suspend",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.suspend))},!1);a.addEventListener("ended",function(){c.gate&&(b.jPlayer.browser.webkit||(d.htmlElement.media.currentTime=0),d.htmlElement.media.pause(),d._updateButtons(!1),d._getHtmlStatus(a,!0),d._updateInterface(),d._trigger(b.jPlayer.event.ended))},!1);a.addEventListener("error",function(){c.gate&&(d._updateButtons(!1),
d._seeked(),d.status.srcSet&&(clearTimeout(d.internal.htmlDlyCmdId),d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:b.jPlayer.error.URL,context:d.status.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL})))},!1);b.each(b.jPlayer.htmlEvent,
function(e,g){a.addEventListener(this,function(){c.gate&&d._trigger(b.jPlayer.event[g])},!1)})},_getHtmlStatus:function(a,b){var d=0,e=0,g=0,f=0;isFinite(a.duration)&&(this.status.duration=a.duration);d=a.currentTime;e=0<this.status.duration?100*d/this.status.duration:0;"object"===typeof a.seekable&&0<a.seekable.length?(g=0<this.status.duration?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100,f=0<this.status.duration?100*a.currentTime/a.seekable.end(a.seekable.length-1):0):(g=100,
f=e);b&&(e=f=d=0);this.status.seekPercent=g;this.status.currentPercentRelative=f;this.status.currentPercentAbsolute=e;this.status.currentTime=d;this.status.videoWidth=a.videoWidth;this.status.videoHeight=a.videoHeight;this.status.readyState=a.readyState;this.status.networkState=a.networkState;this.status.playbackRate=a.playbackRate;this.status.ended=a.ended},_resetStatus:function(){this.status=b.extend({},this.status,b.jPlayer.prototype.status)},_trigger:function(a,c,d){a=b.Event(a);a.jPlayer={};
a.jPlayer.version=b.extend({},this.version);a.jPlayer.options=b.extend(!0,{},this.options);a.jPlayer.status=b.extend(!0,{},this.status);a.jPlayer.html=b.extend(!0,{},this.html);a.jPlayer.flash=b.extend(!0,{},this.flash);c&&(a.jPlayer.error=b.extend({},c));d&&(a.jPlayer.warning=b.extend({},d));this.element.trigger(a)},jPlayerFlashEvent:function(a,c){if(a===b.jPlayer.event.ready)if(this.internal.ready){if(this.flash.gate){if(this.status.srcSet){var d=this.status.currentTime,e=this.status.paused;this.setMedia(this.status.media);
0<d&&(e?this.pause(d):this.play(d))}this._trigger(b.jPlayer.event.flashreset)}}else this.internal.ready=!0,this.internal.flash.jq.css({width:"0px",height:"0px"}),this.version.flash=c.version,this.version.needFlash!==this.version.flash&&this._error({type:b.jPlayer.error.VERSION,context:this.version.flash,message:b.jPlayer.errorMsg.VERSION+this.version.flash,hint:b.jPlayer.errorHint.VERSION}),this._trigger(b.jPlayer.event.repeat),this._trigger(a);if(this.flash.gate)switch(a){case b.jPlayer.event.progress:this._getFlashStatus(c);
this._updateInterface();this._trigger(a);break;case b.jPlayer.event.timeupdate:this._getFlashStatus(c);this._updateInterface();this._trigger(a);break;case b.jPlayer.event.play:this._seeked();this._updateButtons(!0);this._trigger(a);break;case b.jPlayer.event.pause:this._updateButtons(!1);this._trigger(a);break;case b.jPlayer.event.ended:this._updateButtons(!1);this._trigger(a);break;case b.jPlayer.event.click:this._trigger(a);break;case b.jPlayer.event.error:this.status.waitForLoad=!0;this.status.waitForPlay=
!0;this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"});this._validString(this.status.media.poster)&&this.internal.poster.jq.show();this.css.jq.videoPlay.length&&this.status.video&&this.css.jq.videoPlay.show();this.status.video?this._flash_setVideo(this.status.media):this._flash_setAudio(this.status.media);this._updateButtons(!1);this._error({type:b.jPlayer.error.URL,context:c.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL});break;case b.jPlayer.event.seeking:this._seeking();
this._trigger(a);break;case b.jPlayer.event.seeked:this._seeked();this._trigger(a);break;case b.jPlayer.event.ready:break;default:this._trigger(a)}return!1},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent;this.status.currentPercentRelative=a.currentPercentRelative;this.status.currentPercentAbsolute=a.currentPercentAbsolute;this.status.currentTime=a.currentTime;this.status.duration=a.duration;this.status.videoWidth=a.videoWidth;this.status.videoHeight=a.videoHeight;this.status.readyState=
4;this.status.networkState=0;this.status.playbackRate=1;this.status.ended=!1},_updateButtons:function(a){a===f?a=!this.status.paused:this.status.paused=!a;this.css.jq.play.length&&this.css.jq.pause.length&&(a?(this.css.jq.play.hide(),this.css.jq.pause.show()):(this.css.jq.play.show(),this.css.jq.pause.hide()));this.css.jq.restoreScreen.length&&this.css.jq.fullScreen.length&&(this.status.noFullWindow?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.hide()):this.options.fullWindow?(this.css.jq.fullScreen.hide(),
this.css.jq.restoreScreen.show()):(this.css.jq.fullScreen.show(),this.css.jq.restoreScreen.hide()));this.css.jq.repeat.length&&this.css.jq.repeatOff.length&&(this.options.loop?(this.css.jq.repeat.hide(),this.css.jq.repeatOff.show()):(this.css.jq.repeat.show(),this.css.jq.repeatOff.hide()))},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+"%");this.css.jq.playBar.length&&(this.options.smoothPlayBar?this.css.jq.playBar.stop().animate({width:this.status.currentPercentAbsolute+
"%"},250,"linear"):this.css.jq.playBar.width(this.status.currentPercentRelative+"%"));this.css.jq.currentTime.length&&this.css.jq.currentTime.text(this._convertTime(this.status.currentTime));this.css.jq.duration.length&&this.css.jq.duration.text(this._convertTime(this.status.duration))},_convertTime:l.prototype.time,_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg")},
_resetGate:function(){this.html.audio.gate=!1;this.html.video.gate=!1;this.flash.gate=!1},_resetActive:function(){this.html.active=!1;this.flash.active=!1},setMedia:function(a){var c=this,d=!1,e=this.status.media.poster!==a.poster;this._resetMedia();this._resetGate();this._resetActive();b.each(this.formats,function(e,f){var j="video"===c.format[f].media;b.each(c.solutions,function(b,e){if(c[e].support[f]&&c._validString(a[f])){var g="html"===e;j?(g?(c.html.video.gate=!0,c._html_setVideo(a),c.html.active=
!0):(c.flash.gate=!0,c._flash_setVideo(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.show(),c.status.video=!0):(g?(c.html.audio.gate=!0,c._html_setAudio(a),c.html.active=!0):(c.flash.gate=!0,c._flash_setAudio(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.hide(),c.status.video=!1);d=!0;return!1}});if(d)return!1});if(d){if((!this.status.nativeVideoControls||!this.html.video.gate)&&this._validString(a.poster))e?this.htmlElement.poster.src=a.poster:this.internal.poster.jq.show();
this.status.srcSet=!0;this.status.media=b.extend({},a);this._updateButtons(!1);this._updateInterface()}else this._error({type:b.jPlayer.error.NO_SUPPORT,context:"{supplied:'"+this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SUPPORT,hint:b.jPlayer.errorHint.NO_SUPPORT})},_resetMedia:function(){this._resetStatus();this._updateButtons(!1);this._updateInterface();this._seeked();this.internal.poster.jq.hide();clearTimeout(this.internal.htmlDlyCmdId);this.html.active?this._html_resetMedia():this.flash.active&&
this._flash_resetMedia()},clearMedia:function(){this._resetMedia();this.html.active?this._html_clearMedia():this.flash.active&&this._flash_clearMedia();this._resetGate();this._resetActive()},load:function(){this.status.srcSet?this.html.active?this._html_load():this.flash.active&&this._flash_load():this._urlNotSetError("load")},focus:function(){this.options.keyEnabled&&(b.jPlayer.focus=this)},play:function(a){a="number"===typeof a?a:NaN;this.status.srcSet?(this.focus(),this.html.active?this._html_play(a):
this.flash.active&&this._flash_play(a)):this._urlNotSetError("play")},videoPlay:function(){this.play()},pause:function(a){a="number"===typeof a?a:NaN;this.status.srcSet?this.html.active?this._html_pause(a):this.flash.active&&this._flash_pause(a):this._urlNotSetError("pause")},pauseOthers:function(){var a=this;b.each(this.instances,function(b,d){a.element!==d&&d.data("jPlayer").status.srcSet&&d.jPlayer("pause")})},stop:function(){this.status.srcSet?this.html.active?this._html_pause(0):this.flash.active&&
this._flash_pause(0):this._urlNotSetError("stop")},playHead:function(a){a=this._limitValue(a,0,100);this.status.srcSet?this.html.active?this._html_playHead(a):this.flash.active&&this._flash_playHead(a):this._urlNotSetError("playHead")},_muted:function(a){this.options.muted=a;this.html.used&&this._html_mute(a);this.flash.used&&this._flash_mute(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateMute(a),this._updateVolume(this.options.volume),this._trigger(b.jPlayer.event.volumechange))},
mute:function(a){a=a===f?!0:!!a;this._muted(a)},unmute:function(a){a=a===f?!0:!!a;this._muted(!a)},_updateMute:function(a){a===f&&(a=this.options.muted);this.css.jq.mute.length&&this.css.jq.unmute.length&&(this.status.noVolume?(this.css.jq.mute.hide(),this.css.jq.unmute.hide()):a?(this.css.jq.mute.hide(),this.css.jq.unmute.show()):(this.css.jq.mute.show(),this.css.jq.unmute.hide()))},volume:function(a){a=this._limitValue(a,0,1);this.options.volume=a;this.html.used&&this._html_volume(a);this.flash.used&&
this._flash_volume(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateVolume(a),this._trigger(b.jPlayer.event.volumechange))},volumeBar:function(a){if(this.css.jq.volumeBar.length){var c=b(a.currentTarget),d=c.offset(),e=a.pageX-d.left,g=c.width();a=c.height()-a.pageY+d.top;c=c.height();this.options.verticalVolume?this.volume(a/c):this.volume(e/g)}this.options.muted&&this._muted(!1)},volumeBarValue:function(){},_updateVolume:function(a){a===f&&(a=this.options.volume);a=this.options.muted?
0:a;this.status.noVolume?(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.hide(),this.css.jq.volumeBarValue.length&&this.css.jq.volumeBarValue.hide(),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.hide()):(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.show(),this.css.jq.volumeBarValue.length&&(this.css.jq.volumeBarValue.show(),this.css.jq.volumeBarValue[this.options.verticalVolume?"height":"width"](100*a+"%")),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.show())},volumeMax:function(){this.volume(1);
this.options.muted&&this._muted(!1)},_cssSelectorAncestor:function(a){var c=this;this.options.cssSelectorAncestor=a;this._removeUiClass();this.ancestorJq=a?b(a):[];a&&1!==this.ancestorJq.length&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.ancestorJq.length+" found for cssSelectorAncestor.",hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT});this._addUiClass();b.each(this.options.cssSelector,function(a,b){c._cssSelector(a,b)});
this._updateInterface();this._updateButtons();this._updateAutohide();this._updateVolume();this._updateMute()},_cssSelector:function(a,c){var d=this;"string"===typeof c?b.jPlayer.prototype.options.cssSelector[a]?(this.css.jq[a]&&this.css.jq[a].length&&this.css.jq[a].unbind(".jPlayer"),this.options.cssSelector[a]=c,this.css.cs[a]=this.options.cssSelectorAncestor+" "+c,this.css.jq[a]=c?b(this.css.cs[a]):[],this.css.jq[a].length&&this.css.jq[a].bind("click.jPlayer",function(c){c.preventDefault();d[a](c);
b(this).blur()}),c&&1!==this.css.jq[a].length&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:this.css.cs[a],message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.css.jq[a].length+" found for "+a+" method.",hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT})):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_METHOD,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_METHOD,hint:b.jPlayer.warningHint.CSS_SELECTOR_METHOD}):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_STRING,context:c,
message:b.jPlayer.warningMsg.CSS_SELECTOR_STRING,hint:b.jPlayer.warningHint.CSS_SELECTOR_STRING})},seekBar:function(a){if(this.css.jq.seekBar.length){var c=b(a.currentTarget),d=c.offset();a=a.pageX-d.left;c=c.width();this.playHead(100*a/c)}},playBar:function(){},repeat:function(){this._loop(!0)},repeatOff:function(){this._loop(!1)},_loop:function(a){this.options.loop!==a&&(this.options.loop=a,this._updateButtons(),this._trigger(b.jPlayer.event.repeat))},currentTime:function(){},duration:function(){},
gui:function(){},noSolution:function(){},option:function(a,c){var d=a;if(0===arguments.length)return b.extend(!0,{},this.options);if("string"===typeof a){var e=a.split(".");if(c===f){for(var d=b.extend(!0,{},this.options),g=0;g<e.length;g++)if(d[e[g]]!==f)d=d[e[g]];else return this._warning({type:b.jPlayer.warning.OPTION_KEY,context:a,message:b.jPlayer.warningMsg.OPTION_KEY,hint:b.jPlayer.warningHint.OPTION_KEY}),f;return d}for(var g=d={},h=0;h<e.length;h++)h<e.length-1?(g[e[h]]={},g=g[e[h]]):g[e[h]]=
c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,c){var d=this;switch(a){case "volume":this.volume(c);break;case "muted":this._muted(c);break;case "cssSelectorAncestor":this._cssSelectorAncestor(c);break;case "cssSelector":b.each(c,function(a,b){d._cssSelector(a,b)});break;case "fullScreen":if(this.options[a]!==c){var e=b.jPlayer.nativeFeatures.fullscreen.used.webkitVideo;if(!e||e&&!this.status.waitForPlay)e||
(this.options[a]=c),c?this._requestFullscreen():this._exitFullscreen(),e||this._setOption("fullWindow",c)}break;case "fullWindow":this.options[a]!==c&&(this._removeUiClass(),this.options[a]=c,this._refreshSize());break;case "size":!this.options.fullWindow&&this.options[a].cssClass!==c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "sizeFull":this.options.fullWindow&&this.options[a].cssClass!==c.cssClass&&this._removeUiClass();this.options[a]=
b.extend({},this.options[a],c);this._refreshSize();break;case "autohide":this.options[a]=b.extend({},this.options[a],c);this._updateAutohide();break;case "loop":this._loop(c);break;case "nativeVideoControls":this.options[a]=b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this._restrictNativeVideoControls();this._updateNativeVideoControls();break;case "noFullWindow":this.options[a]=b.extend({},this.options[a],c);this.status.nativeVideoControls=
this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullWindow=this._uaBlocklist(this.options.noFullWindow);this._restrictNativeVideoControls();this._updateButtons();break;case "noVolume":this.options[a]=b.extend({},this.options[a],c);this.status.noVolume=this._uaBlocklist(this.options.noVolume);this._updateVolume();this._updateMute();break;case "emulateHtml":this.options[a]!==c&&((this.options[a]=c)?this._emulateHtmlBridge():this._destroyHtmlBridge());break;case "timeFormat":this.options[a]=
b.extend({},this.options[a],c);break;case "keyEnabled":this.options[a]=c;!c&&this===b.jPlayer.focus&&(b.jPlayer.focus=null);break;case "keyBindings":this.options[a]=b.extend(!0,{},this.options[a],c);break;case "audioFullScreen":this.options[a]=c}return this},_refreshSize:function(){this._setSize();this._addUiClass();this._updateSize();this._updateButtons();this._updateAutohide();this._trigger(b.jPlayer.event.resize)},_setSize:function(){this.options.fullWindow?(this.status.width=this.options.sizeFull.width,
this.status.height=this.options.sizeFull.height,this.status.cssClass=this.options.sizeFull.cssClass):(this.status.width=this.options.size.width,this.status.height=this.options.size.height,this.status.cssClass=this.options.size.cssClass);this.element.css({width:this.status.width,height:this.status.height})},_addUiClass:function(){this.ancestorJq.length&&this.ancestorJq.addClass(this.status.cssClass)},_removeUiClass:function(){this.ancestorJq.length&&this.ancestorJq.removeClass(this.status.cssClass)},
_updateSize:function(){this.internal.poster.jq.css({width:this.status.width,height:this.status.height});!this.status.waitForPlay&&this.html.active&&this.status.video||this.html.video.available&&this.html.used&&this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):!this.status.waitForPlay&&(this.flash.active&&this.status.video)&&this.internal.flash.jq.css({width:this.status.width,height:this.status.height})},_updateAutohide:function(){var a=
this,b=function(){a.css.jq.gui.fadeIn(a.options.autohide.fadeIn,function(){clearTimeout(a.internal.autohideId);a.internal.autohideId=setTimeout(function(){a.css.jq.gui.fadeOut(a.options.autohide.fadeOut)},a.options.autohide.hold)})};this.css.jq.gui.length&&(this.css.jq.gui.stop(!0,!0),clearTimeout(this.internal.autohideId),this.element.unbind(".jPlayerAutohide"),this.css.jq.gui.unbind(".jPlayerAutohide"),this.status.nativeVideoControls?this.css.jq.gui.hide():this.options.fullWindow&&this.options.autohide.full||
!this.options.fullWindow&&this.options.autohide.restored?(this.element.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.hide()):this.css.jq.gui.show())},fullScreen:function(){this._setOption("fullScreen",!0)},restoreScreen:function(){this._setOption("fullScreen",!1)},_fullscreenAddEventListeners:function(){var a=this,c=b.jPlayer.nativeFeatures.fullscreen;c.api.fullscreenEnabled&&c.event.fullscreenchange&&("function"!==typeof this.internal.fullscreenchangeHandler&&
(this.internal.fullscreenchangeHandler=function(){a._fullscreenchange()}),document.addEventListener(c.event.fullscreenchange,this.internal.fullscreenchangeHandler,!1))},_fullscreenRemoveEventListeners:function(){var a=b.jPlayer.nativeFeatures.fullscreen;this.internal.fullscreenchangeHandler&&document.addEventListener(a.event.fullscreenchange,this.internal.fullscreenchangeHandler,!1)},_fullscreenchange:function(){this.options.fullScreen&&!b.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()&&
this._setOption("fullScreen",!1)},_requestFullscreen:function(){var a=this.ancestorJq.length?this.ancestorJq[0]:this.element[0],c=b.jPlayer.nativeFeatures.fullscreen;c.used.webkitVideo&&(a=this.htmlElement.video);c.api.fullscreenEnabled&&c.api.requestFullscreen(a)},_exitFullscreen:function(){var a=b.jPlayer.nativeFeatures.fullscreen,c;a.used.webkitVideo&&(c=this.htmlElement.video);a.api.fullscreenEnabled&&a.api.exitFullscreen(c)},_html_initMedia:function(a){var c=b(this.htmlElement.media).empty();
b.each(a.track||[],function(a,b){var g=document.createElement("track");g.setAttribute("kind",b.kind?b.kind:"");g.setAttribute("src",b.src?b.src:"");g.setAttribute("srclang",b.srclang?b.srclang:"");g.setAttribute("label",b.label?b.label:"");b.def&&g.setAttribute("default",b.def);c.append(g)});this.htmlElement.media.src=this.status.src;"none"!==this.options.preload&&this._html_load();this._trigger(b.jPlayer.event.timeupdate)},_html_setFormat:function(a){var c=this;b.each(this.formats,function(b,e){if(c.html.support[e]&&
a[e])return c.status.src=a[e],c.status.format[e]=!0,c.status.formatType=e,!1})},_html_setAudio:function(a){this._html_setFormat(a);this.htmlElement.media=this.htmlElement.audio;this._html_initMedia(a)},_html_setVideo:function(a){this._html_setFormat(a);this.status.nativeVideoControls&&(this.htmlElement.video.poster=this._validString(a.poster)?a.poster:"");this.htmlElement.media=this.htmlElement.video;this._html_initMedia(a)},_html_resetMedia:function(){this.htmlElement.media&&(this.htmlElement.media.id===
this.internal.video.id&&!this.status.nativeVideoControls&&this.internal.video.jq.css({width:"0px",height:"0px"}),this.htmlElement.media.pause())},_html_clearMedia:function(){this.htmlElement.media&&(this.htmlElement.media.src="about:blank",this.htmlElement.media.load())},_html_load:function(){this.status.waitForLoad&&(this.status.waitForLoad=!1,this.htmlElement.media.load());clearTimeout(this.internal.htmlDlyCmdId)},_html_play:function(a){var b=this,d=this.htmlElement.media;this._html_load();if(isNaN(a))d.play();
else{this.internal.cmdsIgnored&&d.play();try{if(!d.seekable||"object"===typeof d.seekable&&0<d.seekable.length)d.currentTime=a,d.play();else throw 1;}catch(e){this.internal.htmlDlyCmdId=setTimeout(function(){b.play(a)},250);return}}this._html_checkWaitForPlay()},_html_pause:function(a){var b=this,d=this.htmlElement.media;0<a?this._html_load():clearTimeout(this.internal.htmlDlyCmdId);d.pause();if(!isNaN(a))try{if(!d.seekable||"object"===typeof d.seekable&&0<d.seekable.length)d.currentTime=a;else throw 1;
}catch(e){this.internal.htmlDlyCmdId=setTimeout(function(){b.pause(a)},250);return}0<a&&this._html_checkWaitForPlay()},_html_playHead:function(a){var b=this,d=this.htmlElement.media;this._html_load();try{if("object"===typeof d.seekable&&0<d.seekable.length)d.currentTime=a*d.seekable.end(d.seekable.length-1)/100;else if(0<d.duration&&!isNaN(d.duration))d.currentTime=a*d.duration/100;else throw"e";}catch(e){this.internal.htmlDlyCmdId=setTimeout(function(){b.playHead(a)},250);return}this.status.waitForLoad||
this._html_checkWaitForPlay()},_html_checkWaitForPlay:function(){this.status.waitForPlay&&(this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height})))},_html_volume:function(a){this.html.audio.available&&(this.htmlElement.audio.volume=a);this.html.video.available&&(this.htmlElement.video.volume=a)},_html_mute:function(a){this.html.audio.available&&
(this.htmlElement.audio.muted=a);this.html.video.available&&(this.htmlElement.video.muted=a)},_flash_setAudio:function(a){var c=this;try{b.each(this.formats,function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4a":case "fla":c._getMovie().fl_setAudio_m4a(a[d]);break;case "mp3":c._getMovie().fl_setAudio_mp3(a[d]);break;case "rtmpa":c._getMovie().fl_setAudio_rtmp(a[d])}c.status.src=a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),"auto"===this.options.preload&&(this._flash_load(),
this.status.waitForLoad=!1)}catch(d){this._flashError(d)}},_flash_setVideo:function(a){var c=this;try{b.each(this.formats,function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4v":case "flv":c._getMovie().fl_setVideo_m4v(a[d]);break;case "rtmpv":c._getMovie().fl_setVideo_rtmp(a[d])}c.status.src=a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),"auto"===this.options.preload&&(this._flash_load(),this.status.waitForLoad=!1)}catch(d){this._flashError(d)}},_flash_resetMedia:function(){this.internal.flash.jq.css({width:"0px",
height:"0px"});this._flash_pause(NaN)},_flash_clearMedia:function(){try{this._getMovie().fl_clearMedia()}catch(a){this._flashError(a)}},_flash_load:function(){try{this._getMovie().fl_load()}catch(a){this._flashError(a)}this.status.waitForLoad=!1},_flash_play:function(a){try{this._getMovie().fl_play(a)}catch(b){this._flashError(b)}this.status.waitForLoad=!1;this._flash_checkWaitForPlay()},_flash_pause:function(a){try{this._getMovie().fl_pause(a)}catch(b){this._flashError(b)}0<a&&(this.status.waitForLoad=
!1,this._flash_checkWaitForPlay())},_flash_playHead:function(a){try{this._getMovie().fl_play_head(a)}catch(b){this._flashError(b)}this.status.waitForLoad||this._flash_checkWaitForPlay()},_flash_checkWaitForPlay:function(){this.status.waitForPlay&&(this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.flash.jq.css({width:this.status.width,height:this.status.height})))},_flash_volume:function(a){try{this._getMovie().fl_volume(a)}catch(b){this._flashError(b)}},
_flash_mute:function(a){try{this._getMovie().fl_mute(a)}catch(b){this._flashError(b)}},_getMovie:function(){return document[this.internal.flash.id]},_getFlashPluginVersion:function(){var a=0,b;if(window.ActiveXObject)try{if(b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")){var d=b.GetVariable("$version");d&&(d=d.split(" ")[1].split(","),a=parseInt(d[0],10)+"."+parseInt(d[1],10))}}catch(e){}else navigator.plugins&&0<navigator.mimeTypes.length&&(b=navigator.plugins["Shockwave Flash"])&&(a=navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/,
"$1"));return 1*a},_checkForFlash:function(a){var b=!1;this._getFlashPluginVersion()>=a&&(b=!0);return b},_validString:function(a){return a&&"string"===typeof a},_limitValue:function(a,b,d){return a<b?b:a>d?d:a},_urlNotSetError:function(a){this._error({type:b.jPlayer.error.URL_NOT_SET,context:a,message:b.jPlayer.errorMsg.URL_NOT_SET,hint:b.jPlayer.errorHint.URL_NOT_SET})},_flashError:function(a){var c;c=this.internal.ready?"FLASH_DISABLED":"FLASH";this._error({type:b.jPlayer.error[c],context:this.internal.flash.swf,
message:b.jPlayer.errorMsg[c]+a.message,hint:b.jPlayer.errorHint[c]});this.internal.flash.jq.css({width:"1px",height:"1px"})},_error:function(a){this._trigger(b.jPlayer.event.error,a);this.options.errorAlerts&&this._alert("Error!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_warning:function(a){this._trigger(b.jPlayer.event.warning,f,a);this.options.warningAlerts&&this._alert("Warning!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+
a.context)},_alert:function(a){alert("jPlayer "+this.version.script+" : id='"+this.internal.self.id+"' : "+a)},_emulateHtmlBridge:function(){var a=this;b.each(b.jPlayer.emulateMethods.split(/\s+/g),function(b,d){a.internal.domNode[d]=function(b){a[d](b)}});b.each(b.jPlayer.event,function(c,d){var e=!0;b.each(b.jPlayer.reservedEvent.split(/\s+/g),function(a,b){if(b===c)return e=!1});e&&a.element.bind(d+".jPlayer.jPlayerHtml",function(){a._emulateHtmlUpdate();var b=document.createEvent("Event");b.initEvent(c,
!1,!0);a.internal.domNode.dispatchEvent(b)})})},_emulateHtmlUpdate:function(){var a=this;b.each(b.jPlayer.emulateStatus.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.status[d]});b.each(b.jPlayer.emulateOptions.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.options[d]})},_destroyHtmlBridge:function(){var a=this;this.element.unbind(".jPlayerHtml");b.each((b.jPlayer.emulateMethods+" "+b.jPlayer.emulateStatus+" "+b.jPlayer.emulateOptions).split(/\s+/g),function(b,d){delete a.internal.domNode[d]})}};
b.jPlayer.error={FLASH:"e_flash",FLASH_DISABLED:"e_flash_disabled",NO_SOLUTION:"e_no_solution",NO_SUPPORT:"e_no_support",URL:"e_url",URL_NOT_SET:"e_url_not_set",VERSION:"e_version"};b.jPlayer.errorMsg={FLASH:"jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ",FLASH_DISABLED:"jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ",NO_SOLUTION:"No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.",
NO_SUPPORT:"It is not possible to play any media format provided in setMedia() on this browser using your current options.",URL:"Media URL could not be loaded.",URL_NOT_SET:"Attempt to issue media playback commands, while no media url is set.",VERSION:"jPlayer "+b.jPlayer.prototype.version.script+" needs Jplayer.swf version "+b.jPlayer.prototype.version.needFlash+" but found "};b.jPlayer.errorHint={FLASH:"Check your swfPath option and that Jplayer.swf is there.",FLASH_DISABLED:"Check that you have not display:none; the jPlayer entity or any ancestor.",
NO_SOLUTION:"Review the jPlayer options: support and supplied.",NO_SUPPORT:"Video or audio formats defined in the supplied option are missing.",URL:"Check media URL is valid.",URL_NOT_SET:"Use setMedia() to set the media URL.",VERSION:"Update jPlayer files."};b.jPlayer.warning={CSS_SELECTOR_COUNT:"e_css_selector_count",CSS_SELECTOR_METHOD:"e_css_selector_method",CSS_SELECTOR_STRING:"e_css_selector_string",OPTION_KEY:"e_option_key"};b.jPlayer.warningMsg={CSS_SELECTOR_COUNT:"The number of css selectors found did not equal one: ",
CSS_SELECTOR_METHOD:"The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",CSS_SELECTOR_STRING:"The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",OPTION_KEY:"The option requested in jPlayer('option') is undefined."};b.jPlayer.warningHint={CSS_SELECTOR_COUNT:"Check your css selector and the ancestor.",CSS_SELECTOR_METHOD:"Check your method name.",CSS_SELECTOR_STRING:"Check your css selector is a string.",OPTION_KEY:"Check your option name."}});

6
modules/jplayer/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -129,27 +129,8 @@ class AmpacheVlc extends localplay_controller {
*/ */
public function add_instance($data) { public function add_instance($data) {
// Foreach and clean up what we need $sql = "INSERT INTO `localplay_vlc` (`name`,`host`,`port`,`password`,`owner`) VALUES (?, ?, ?, ?, ?)";
foreach ($data as $key=>$value) { $db_results = Dba::query($sql, array($data['name'], $data['host'], $data['port'], $data['password'], $GLOBALS['user']->id));
switch ($key) {
case 'name':
case 'host':
case 'port':
case 'password':
${$key} = Dba::escape($value);
break;
default:
// Rien a faire
break;
} // end switch on key
} // end foreach
$user_id = Dba::escape($GLOBALS['user']->id);
$sql = "INSERT INTO `localplay_vlc` (`name`,`host`,`port`,`password`,`owner`) " .
"VALUES ('$name','$host','$port','$password','$user_id')";
$db_results = Dba::query($sql);
return $db_results; return $db_results;
@ -160,11 +141,9 @@ class AmpacheVlc extends localplay_controller {
* This takes a UID and deletes the instance in question * This takes a UID and deletes the instance in question
*/ */
public function delete_instance($uid) { public function delete_instance($uid) {
$uid = Dba::escape($uid);
$sql = "DELETE FROM `localplay_vlc` WHERE `id`='$uid'"; $sql = "DELETE FROM `localplay_vlc` WHERE `id` = ?";
$db_results = Dba::query($sql); $db_results = Dba::query($sql, array($uid));
return true; return true;
@ -195,15 +174,9 @@ class AmpacheVlc extends localplay_controller {
* This takes an ID and an array of data and updates the instance specified * This takes an ID and an array of data and updates the instance specified
*/ */
public function update_instance($uid,$data) { public function update_instance($uid,$data) {
$uid = Dba::escape($uid);
$port = Dba::escape($data['port']);
$host = Dba::escape($data['host']);
$name = Dba::escape($data['name']);
$pass = Dba::escape($data['password']);
$sql = "UPDATE `localplay_vlc` SET `host`='$host', `port`='$port', `name`='$name', `password`='$pass' WHERE `id`='$uid'"; $sql = "UPDATE `localplay_vlc` SET `host` = ?, `port` = ?, `name` = ?, `password` = ? WHERE `id` = ?";
$db_results = Dba::query($sql); $db_results = Dba::query($sql, array($data['host'], $data['port'], $data['name'], $data['password'], $uid));
return true; return true;
@ -232,22 +205,21 @@ class AmpacheVlc extends localplay_controller {
public function get_instance($instance='') { public function get_instance($instance='') {
$instance = $instance ? $instance : Config::get('vlc_active'); $instance = $instance ? $instance : Config::get('vlc_active');
$instance = Dba::escape($instance);
$sql = "SELECT * FROM `localplay_vlc` WHERE `id`='$instance'"; $sql = "SELECT * FROM `localplay_vlc` WHERE `id` = ?";
$db_results = Dba::query($sql); $db_results = Dba::query($sql, array($instance));
$row = Dba::fetch_assoc($db_results); $row = Dba::fetch_assoc($db_results);
return $row; return $row;
} // get_instance } // get_instance
/** /**
* set_active_instance * set_active_instance
* This sets the specified instance as the 'active' one * This sets the specified instance as the 'active' one
*/ */
public function set_active_instance($uid,$user_id='') { public function set_active_instance($uid,$user_id='') {
// Not an admin? bubkiss! // Not an admin? bubkiss!
if (!$GLOBALS['user']->has_access('100')) { if (!$GLOBALS['user']->has_access('100')) {
@ -261,17 +233,17 @@ class AmpacheVlc extends localplay_controller {
return true; return true;
} // set_active_instance } // set_active_instance
/** /**
* get_active_instance * get_active_instance
* This returns the UID of the current active instance * This returns the UID of the current active instance
* false if none are active * false if none are active
*/ */
public function get_active_instance() { public function get_active_instance() {
} // get_active_instance } // get_active_instance
public function add_url(Stream_URL $url) { public function add_url(Stream_URL $url) {
if (is_null($this->_vlc->add($url->title, $url->url))) { if (is_null($this->_vlc->add($url->title, $url->url))) {
@ -322,7 +294,7 @@ class AmpacheVlc extends localplay_controller {
/* A play when it's already playing causes a track restart /* A play when it's already playing causes a track restart
* which we don't want to doublecheck its state * which we don't want to doublecheck its state
*/ */
if ($this->_vlc->state() == 'play') { if ($this->_vlc->state() == 'play') {
return true; return true;
} }
@ -579,11 +551,9 @@ class AmpacheVlc extends localplay_controller {
} }
// if not a known format // if not a known format
else { else {
$array['track_title'] = htmlspecialchars(substr($arrayholder['root']['information']['meta-information']['title']['value'], 0, 25));
$array['track_title'] = htmlspecialchars(substr($arrayholder['root']['information']['meta-information']['title']['value'], 0, 25)); $array['track_artist'] = htmlspecialchars(substr($arrayholder['root']['information']['meta-information']['artist']['value'], 0, 20));
$array['track_artist'] = htmlspecialchars(substr($arrayholder['root']['information']['meta-information']['artist']['value'], 0, 20)); }
}
return $array; return $array;
} // status } // status

View file

@ -0,0 +1,633 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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.
*
*/
/**
* AmpacheXbmc Class
*
* This is the class for the xbmc localplay method to remote control
* a XBMC Instance
*
*/
class AmpacheXbmc extends localplay_controller {
/* Variables */
private $version = '000001';
private $description = 'Controls a XBMC instance';
/* Constructed variables */
private $_xbmc;
// Always use player 0 for now
private $_playerId = 0;
// Always use playlist 0 for now
private $_playlistId = 0;
/**
* Constructor
* This returns the array map for the localplay object
* REQUIRED for Localplay
*/
public function __construct() {
/* Do a Require Once On the needed Libraries */
require_once Config::get('prefix') . '/modules/xbmc-php-rpc/TCPClient.php';
} // Constructor
/**
* get_description
* This returns the description of this localplay method
*/
public function get_description() {
return $this->description;
} // get_description
/**
* get_version
* This returns the current version
*/
public function get_version() {
return $this->version;
} // get_version
/**
* is_installed
* This returns true or false if xbmc controller is installed
*/
public function is_installed() {
$sql = "DESCRIBE `localplay_xbmc`";
$db_results = Dba::query($sql);
return Dba::num_rows($db_results);
} // is_installed
/**
* install
* This function installs the xbmc localplay controller
*/
public function install() {
$sql = "CREATE TABLE `localplay_xbmc` (`id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , ".
"`name` VARCHAR( 128 ) COLLATE utf8_unicode_ci NOT NULL , " .
"`owner` INT( 11 ) NOT NULL, " .
"`host` VARCHAR( 255 ) COLLATE utf8_unicode_ci NOT NULL , " .
"`port` INT( 11 ) UNSIGNED NOT NULL , " .
"`user` VARCHAR( 255 ) COLLATE utf8_unicode_ci NOT NULL , " .
"`pass` VARCHAR( 255 ) COLLATE utf8_unicode_ci NOT NULL" .
") ENGINE = MYISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci";
$db_results = Dba::query($sql);
// Add an internal preference for the users current active instance
Preference::insert('xbmc_active','XBMC Active Instance','0','25','integer','internal');
User::rebuild_all_preferences();
return true;
} // install
/**
* uninstall
* This removes the localplay controller
*/
public function uninstall() {
$sql = "DROP TABLE `localplay_xbmc`";
$db_results = Dba::query($sql);
// Remove the pref we added for this
Preference::delete('xbmc_active');
return true;
} // uninstall
/**
* add_instance
* This takes key'd data and inserts a new xbmc instance
*/
public function add_instance($data) {
$sql = "INSERT INTO `localplay_xbmc` (`name`,`host`,`port`, `user`, `pass`,`owner`) " .
"VALUES (?, ?, ?, ?, ?, ?)";
$db_results = Dba::query($sql, array($data['name'], $data['host'], $data['port'], $data['user'], $data['pass'], $GLOBALS['user']->id));
return $db_results;
} // add_instance
/**
* delete_instance
* This takes a UID and deletes the instance in question
*/
public function delete_instance($uid) {
$sql = "DELETE FROM `localplay_xbmc` WHERE `id` = ?";
$db_results = Dba::query($sql, array($uid));
return true;
} // delete_instance
/**
* get_instances
* This returns a key'd array of the instance information with
* [UID]=>[NAME]
*/
public function get_instances() {
$sql = "SELECT * FROM `localplay_xbmc` ORDER BY `name`";
$db_results = Dba::query($sql);
$results = array();
while ($row = Dba::fetch_assoc($db_results)) {
$results[$row['id']] = $row['name'];
}
return $results;
} // get_instances
/**
* update_instance
* This takes an ID and an array of data and updates the instance specified
*/
public function update_instance($uid,$data) {
$sql = "UPDATE `localplay_xbmc` SET `host` = ?, `port` = ?, `name` = ?, `user` = ?, `pass` = ? WHERE `id` = ?";
$db_results = Dba::query($sql, array($data['host'], $data['port'], $data['name'], $data['user'], $data['pass'], $uid));
return true;
} // update_instance
/**
* instance_fields
* This returns a key'd array of [NAME]=>array([DESCRIPTION]=>VALUE,[TYPE]=>VALUE) for the
* fields so that we can on-the-fly generate a form
*/
public function instance_fields() {
$fields['name'] = array('description' => T_('Instance Name'),'type'=>'textbox');
$fields['host'] = array('description' => T_('Hostname'),'type'=>'textbox');
$fields['port'] = array('description' => T_('Port'),'type'=>'textbox');
$fields['user'] = array('description' => T_('Username'),'type'=>'textbox');
$fields['pass'] = array('description' => T_('Password'),'type'=>'textbox');
return $fields;
} // instance_fields
/**
* get_instance
* This returns a single instance and all it's variables
*/
public function get_instance($instance='') {
$instance = $instance ? $instance : Config::get('xbmc_active');
$sql = "SELECT * FROM `localplay_xbmc` WHERE `id` = ?";
$db_results = Dba::query($sql, array($instance));
$row = Dba::fetch_assoc($db_results);
return $row;
} // get_instance
/**
* set_active_instance
* This sets the specified instance as the 'active' one
*/
public function set_active_instance($uid,$user_id='') {
// Not an admin? bubkiss!
if (!$GLOBALS['user']->has_access('100')) {
$user_id = $GLOBALS['user']->id;
}
$user_id = $user_id ? $user_id : $GLOBALS['user']->id;
Preference::update('xbmc_active', $user_id, intval($uid));
Config::set('xbmc_active', intval($uid), true);
return true;
} // set_active_instance
/**
* get_active_instance
* This returns the UID of the current active instance
* false if none are active
*/
public function get_active_instance() {
} // get_active_instance
public function add_url(Stream_URL $url) {
try {
$this->_xbmc->Playlist->Add(array(
'playlistid' => $this->_playlistId,
'item' => array('file' => $url->url)
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'add_url failed: ' . $ex->getMessage(), 1);
return false;
}
}
/**
* delete_track
* Delete a track from the xbmc playlist
*/
public function delete_track($track) {
try {
$this->_xbmc->Playlist->Remove(array(
'playlistid' => $this->_playlistId,
'position' => $track
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'delete_track failed: ' . $ex->getMessage(), 1);
return false;
}
} // delete_track
/**
* clear_playlist
* This deletes the entire xbmc playlist.
*/
public function clear_playlist() {
try {
$this->_xbmc->Playlist->Clear(array(
'playlistid' => $this->_playlistId
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'clear_playlist failed: ' . $ex->getMessage(), 1);
return false;
}
} // clear_playlist
/**
* play
* This just tells xbmc to start playing, it does not
* take any arguments
*/
public function play() {
try {
// XBMC requires to load a playlist to play. We don't know if this play is after a new playlist or after pause
// So we get current status
$status = $this->status();
if ($status['state'] == 'stop') {
$this->_xbmc->Player->Open(array(
'item' => array('playlistid' => $this->_playlistId))
);
} else {
$this->_xbmc->Player->PlayPause(array(
'playerid' => $this->_playlistId,
'play' => true)
);
}
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'play failed: ' . $ex->getMessage(), 1);
return false;
}
} // play
/**
* pause
* This tells xbmc to pause the current song
*/
public function pause() {
try {
$this->_xbmc->Player->PlayPause(array(
'playerid' => $this->_playerId,
'play' => false)
);
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'pause failed, is the player started? ' . $ex->getMessage(), 1);
return false;
}
} // pause
/**
* stop
* This just tells xbmc to stop playing, it does not take
* any arguments
*/
public function stop() {
try {
$this->_xbmc->Player->Stop(array(
'playerid' => $this->_playerId
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'stop failed, is the player started? ' . $ex->getMessage(), 1);
return false;
}
} // stop
/**
* skip
* This tells xbmc to skip to the specified song
*/
public function skip($song) {
try {
$this->_xbmc->Player->GoTo(array(
'playerid' => $this->_playerId,
'to' => $song
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'skip failed, is the player started?: ' . $ex->getMessage(), 1);
return false;
}
} // skip
/**
* This tells xbmc to increase the volume
*/
public function volume_up() {
try {
$this->_xbmc->Application->SetVolume(array(
'volume' => 'increment'
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'volume_up failed: ' . $ex->getMessage(), 1);
return false;
}
} // volume_up
/**
* This tells xbmc to decrease the volume
*/
public function volume_down() {
try {
$this->_xbmc->Application->SetVolume(array(
'volume' => 'decrement'
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'volume_down failed: ' . $ex->getMessage(), 1);
return false;
}
} // volume_down
/**
* next
* This just tells xbmc to skip to the next song
*/
public function next() {
try {
$this->_xbmc->Player->GoTo(array(
'playerid' => $this->_playerId,
'to' => 'next'
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'next failed, is the player started? ' . $ex->getMessage(), 1);
return false;
}
} // next
/**
* prev
* This just tells xbmc to skip to the prev song
*/
public function prev() {
try {
$this->_xbmc->Player->GoTo(array(
'playerid' => $this->_playerId,
'to' => 'previous'
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'prev failed, is the player started? ' . $ex->getMessage(), 1);
return false;
}
} // prev
/**
* volume
* This tells xbmc to set the volume to the specified amount
*/
public function volume($volume) {
try {
$this->_xbmc->Application->SetVolume(array(
'volume' => $volume
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'volume failed: ' . $ex->getMessage(), 1);
return false;
}
} // volume
/**
* repeat
* This tells xbmc to set the repeating the playlist (i.e. loop) to either on or off
*/
public function repeat($state) {
try {
$this->_xbmc->Player->SetRepeat(array(
'playerid' => $this->_playerId,
'repeat' => ($state ? 'all' : 'off')
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'repeat failed, is the player started? ' . $ex->getMessage(), 1);
return false;
}
} // repeat
/**
* random
* This tells xbmc to turn on or off the playing of songs from the playlist in random order
*/
public function random($onoff) {
try {
$this->_xbmc->Player->SetShuffle(array(
'playerid' => $this->_playerId,
'shuffle' => $onoff
));
return true;
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'random failed, is the player started? ' . $ex->getMessage(), 1);
return false;
}
} // random
/**
* get
* This functions returns an array containing information about
* The songs that xbmc currently has in it's playlist. This must be
* done in a standardized fashion
*/
public function get() {
$results = array();
try {
$playlist = $this->_xbmc->Playlist->GetItems(array(
'playlistid' => $this->_playlistId,
'properties' => array('file')
));
for ($i = $playlist['limits']['start']; $i < $playlist['limits']['end']; ++$i) {
$item = $playlist['items'][$i];
$data = array();
$data['link'] = $item['file'];
$data['id'] = $i;
$data['track'] = $i + 1;
$url_data = $this->parse_url($data['link']);
if ($url_data != null) {
$song = new Song($url_data['oid']);
if ($song != null) {
$data['name'] = $song->get_artist_name() . ' - ' . $song->title;
}
}
if (!$data['name']) {
$data['name'] = $item['label'];
}
$results[] = $data;
}
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'get failed: ' . $ex->getMessage(), 1);
}
return $results;
} // get
/**
* status
* This returns bool/int values for features, loop, repeat and any other features
* that this localplay method supports.
* This works as in requesting the xbmc properties
*/
public function status() {
$array = array();
try {
$appprop = $this->_xbmc->Application->GetProperties(array(
'properties' => array('volume')
));
$array['volume'] = intval($appprop['volume']);
try {
$currentplay = $this->_xbmc->Player->GetItem(array(
'playerid' => $this->_playerId,
'properties' => array('file')
));
// We assume it's playing. No pause detection support.
$array['state'] = 'play';
$playprop = $this->_xbmc->Player->GetProperties(array(
'playerid' => $this->_playerId,
'properties' => array('repeat', 'shuffled')
));
$array['repeat'] = ($playprop['repeat'] != "off");
$array['random'] = (strtolower($playprop['shuffled']) == 1) ;
$array['track'] = $currentplay['file'];
$url_data = $this->parse_url($array['track']);
$song = new Song($url_data['oid']);
if ($song->title || $song->get_artist_name() || $song->get_album_name()) {
$array['track_title'] = $song->title;
$array['track_artist'] = $song->get_artist_name();
$array['track_album'] = $song->get_album_name();
}
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'get current item failed, player probably stopped. ' . $ex->getMessage(), 1);
$array['state'] = 'stop';
}
} catch (XBMC_RPC_Exception $ex) {
debug_event('xbmc', 'status failed: ' . $ex->getMessage(), 1);
}
return $array;
} // status
/**
* connect
* This functions creates the connection to xbmc and returns
* a boolean value for the status, to save time this handle
* is stored in this class
*/
public function connect() {
$options = self::get_instance();
try {
$this->_xbmc = new XBMC_RPC_TCPClient($options);
return true;
} catch (XBMC_RPC_ConnectionException $ex) {
debug_event('xbmc', 'xbmc connection failed: ' . $ex->getMessage(), 1);
return false;
}
} // connect
} //end of AmpacheXbmc
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -0,0 +1,12 @@
.tbox {position:absolute; display:none; padding:14px 17px; z-index:900}
.tinner {padding:15px; -moz-border-radius:5px; border-radius:5px; background:#fff url(images/preload.gif) no-repeat 50% 50%; border-right:1px solid #333; border-bottom:1px solid #333}
.tmask {position:absolute; display:none; top:0px; left:0px; height:100%; width:100%; background:#000; z-index:800}
.tclose {position:absolute; top:0px; right:0px; width:30px; height:30px; cursor:pointer; background:url(images/close.png) no-repeat}
.tclose:hover {background-position:0 -30px}
#error {background:#ff6969; color:#fff; text-shadow:1px 1px #cf5454; border-right:1px solid #000; border-bottom:1px solid #000; padding:0}
#error .tcontent {padding:10px 14px 11px; border:1px solid #ffb8b8; -moz-border-radius:5px; border-radius:5px}
#success {background:#2ea125; color:#fff; text-shadow:1px 1px #1b6116; border-right:1px solid #000; border-bottom:1px solid #000; padding:10; -moz-border-radius:0; border-radius:0}
#bluemask {background:#4195aa}
#frameless {padding:0}
#frameless .tclose {left:6px}

134
modules/tinybox/tinybox.js Normal file
View file

@ -0,0 +1,134 @@
TINY={};
TINY.box=function(){
var j,m,b,g,v,p=0;
return{
show:function(o){
v={opacity:70,close:1,animate:1,fixed:1,mask:1,maskid:'',boxid:'',topsplit:2,url:0,post:0,height:0,width:0,html:0,iframe:0};
for(s in o){v[s]=o[s]}
if(!p){
j=document.createElement('div'); j.className='tbox';
p=document.createElement('div'); p.className='tinner';
b=document.createElement('div'); b.className='tcontent';
m=document.createElement('div'); m.className='tmask';
g=document.createElement('div'); g.className='tclose'; g.v=0;
document.body.appendChild(m); document.body.appendChild(j); j.appendChild(p); p.appendChild(b);
m.onclick=g.onclick=TINY.box.hide; window.onresize=TINY.box.resize
}else{
j.style.display='none'; clearTimeout(p.ah); if(g.v){p.removeChild(g); g.v=0}
}
p.id=v.boxid; m.id=v.maskid; j.style.position=v.fixed?'fixed':'absolute';
if(v.html&&!v.animate){
p.style.backgroundImage='none'; b.innerHTML=v.html; b.style.display='';
p.style.width=v.width?v.width+'px':'auto'; p.style.height=v.height?v.height+'px':'auto'
}else{
b.style.display='none';
if(!v.animate&&v.width&&v.height){
p.style.width=v.width+'px'; p.style.height=v.height+'px'
}else{
p.style.width=p.style.height='100px'
}
}
if(v.mask){this.mask(); this.alpha(m,1,v.opacity)}else{this.alpha(j,1,100)}
if(v.autohide){p.ah=setTimeout(TINY.box.hide,1000*v.autohide)}else{document.onkeyup=TINY.box.esc}
},
fill:function(c,u,k,a,w,h){
if(u){
if(v.image){
var i=new Image(); i.onload=function(){w=w||i.width; h=h||i.height; TINY.box.psh(i,a,w,h)}; i.src=v.image
}else if(v.iframe){
this.psh('<iframe src="'+v.iframe+'" width="'+v.width+'" frameborder="0" height="'+v.height+'"></iframe>',a,w,h)
}else{
var x=window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
x.onreadystatechange=function(){
if(x.readyState==4&&x.status==200){p.style.backgroundImage=''; TINY.box.psh(x.responseText,a,w,h)}
};
if(k){
x.open('POST',c,true); x.setRequestHeader('Content-type','application/x-www-form-urlencoded'); x.send(k)
}else{
x.open('GET',c,true); x.send(null)
}
}
}else{
this.psh(c,a,w,h)
}
},
psh:function(c,a,w,h){
if(typeof c=='object'){b.appendChild(c)}else{b.innerHTML=c}
var x=p.style.width, y=p.style.height;
if(!w||!h){
p.style.width=w?w+'px':''; p.style.height=h?h+'px':''; b.style.display='';
if(!h){h=parseInt(b.offsetHeight)}
if(!w){w=parseInt(b.offsetWidth)}
b.style.display='none'
}
p.style.width=x; p.style.height=y;
this.size(w,h,a)
},
esc:function(e){e=e||window.event; if(e.keyCode==27){TINY.box.hide()}},
hide:function(){TINY.box.alpha(j,-1,0,3); document.onkeypress=null; if(v.closejs){v.closejs()}},
resize:function(){TINY.box.pos(); TINY.box.mask()},
mask:function(){m.style.height=this.total(1)+'px'; m.style.width=this.total(0)+'px'},
pos:function(){
var t;
if(typeof v.top!='undefined'){t=v.top}else{t=(this.height()/v.topsplit)-(j.offsetHeight/2); t=t<20?20:t}
if(!v.fixed&&!v.top){t+=this.top()}
j.style.top=t+'px';
j.style.left=typeof v.left!='undefined'?v.left+'px':(this.width()/2)-(j.offsetWidth/2)+'px'
},
alpha:function(e,d,a){
clearInterval(e.ai);
if(d){e.style.opacity=0; e.style.filter='alpha(opacity=0)'; e.style.display='block'; TINY.box.pos()}
e.ai=setInterval(function(){TINY.box.ta(e,a,d)},20)
},
ta:function(e,a,d){
var o=Math.round(e.style.opacity*100);
if(o==a){
clearInterval(e.ai);
if(d==-1){
e.style.display='none';
e==j?TINY.box.alpha(m,-1,0,2):b.innerHTML=p.style.backgroundImage=''
}else{
if(e==m){
this.alpha(j,1,100)
}else{
j.style.filter='';
TINY.box.fill(v.html||v.url,v.url||v.iframe||v.image,v.post,v.animate,v.width,v.height)
}
}
}else{
var n=a-Math.floor(Math.abs(a-o)*.5)*d;
e.style.opacity=n/100; e.style.filter='alpha(opacity='+n+')'
}
},
size:function(w,h,a){
if(a){
clearInterval(p.si); var wd=parseInt(p.style.width)>w?-1:1, hd=parseInt(p.style.height)>h?-1:1;
p.si=setInterval(function(){TINY.box.ts(w,wd,h,hd)},20)
}else{
p.style.backgroundImage='none'; if(v.close){p.appendChild(g); g.v=1}
p.style.width=w+'px'; p.style.height=h+'px'; b.style.display=''; this.pos();
if(v.openjs){v.openjs()}
}
},
ts:function(w,wd,h,hd){
var cw=parseInt(p.style.width), ch=parseInt(p.style.height);
if(cw==w&&ch==h){
clearInterval(p.si); p.style.backgroundImage='none'; b.style.display='block'; if(v.close){p.appendChild(g); g.v=1}
if(v.openjs){v.openjs()}
}else{
if(cw!=w){p.style.width=(w-Math.floor(Math.abs(w-cw)*.6)*wd)+'px'}
if(ch!=h){p.style.height=(h-Math.floor(Math.abs(h-ch)*.6)*hd)+'px'}
this.pos()
}
},
top:function(){return document.documentElement.scrollTop||document.body.scrollTop},
width:function(){return self.innerWidth||document.documentElement.clientWidth||document.body.clientWidth},
height:function(){return self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight},
total:function(d){
var b=document.body, e=document.documentElement;
return d?Math.max(Math.max(b.scrollHeight,e.scrollHeight),Math.max(b.clientHeight,e.clientHeight)):
Math.max(Math.max(b.scrollWidth,e.scrollWidth),Math.max(b.clientWidth,e.clientWidth))
}
}
}();

View file

@ -337,47 +337,51 @@ class VlcPlayer {
*/ */
private function sendCommand($cmd, $args) { private function sendCommand($cmd, $args) {
$fp = fsockopen($this->host, $this->port, $errno, $errstr); $fp = fsockopen($this->host, $this->port, $errno, $errstr);
if(!$fp) { if(!$fp) {
debug_event('vlc',"VlcPlayer: $errstr ($errno)",'1'); debug_event('vlc',"VlcPlayer: $errstr ($errno)",'1');
return null; return null;
} }
// Define the base message // Define the base message
$msg = "GET /requests/$cmd"; $msg = "GET /requests/$cmd";
// Foreach our arguments // Foreach our arguments
foreach ($args AS $key => $val) { foreach ($args AS $key => $val) {
$msg = $msg . "$key=$val"; $msg .= "$key=$val";
} }
$msg = $msg . " HTTP/1.0\r\n\r\n"; $msg .= " HTTP/1.0\r\n";
// Basic authentication
if (!empty($this->password)) {
$b64pwd = base64_encode(':' . $this->password);
$msg .= "Authorization: Basic " . $b64pwd . "\r\n";
}
$msg .= "\r\n";
fputs($fp, $msg); fputs($fp, $msg);
$data = ''; $data = '';
$header = ""; $header = "";
// here the header is split from the xml to avoid problems // here the header is split from the xml to avoid problems
do // loop until the end of the header do // loop until the end of the header
{ {
$header .= fgets ( $fp ); $header .= fgets ( $fp );
} while ( strpos ( $header, "\r\n\r\n" ) === false );
} while ( strpos ( $header, "\r\n\r\n" ) === false );
// now put the body in variable $data // now put the body in variable $data
while ( ! feof ( $fp ) )
while ( ! feof ( $fp ) ) {
{ $data .= fgets ( $fp );
$data .= fgets ( $fp ); }
}
fclose($fp); fclose($fp);
// send to xml parser and make an array // send to xml parser and make an array
$result = $this->xmltoarray($data); $result = $this->xmltoarray($data);
return $result; return $result;
} // sendCommand } // sendCommand

View file

@ -0,0 +1,327 @@
<?php
require_once 'ClientException.php';
require_once 'ConnectionException.php';
require_once 'RequestException.php';
require_once 'ResponseException.php';
require_once 'Server.php';
require_once 'Namespace.php';
require_once 'Response.php';
abstract class XBMC_RPC_Client {
/**
* @var XBMC_RPC_Server A server object instance representing the server
* to be used for remote procedure calls.
* @access protected
*/
protected $server;
/**
* @var XBMC_RPC_Namespace The root namespace instance.
* @access private
*/
private $rootNamespace;
/**
* @var bool A flag to indicate if the JSON-RPC version is legacy, ie before
* the XBMC Eden updates. This can be used to determine the format of commands
* to be used with this library, allowing client code to support legacy systems.
* @access private
*/
private $isLegacy = false;
/**
* Constructor.
*
* Connects to the server and populates a list of available commands by
* having the server introspect.
*
* @param mixed $parameters An associative array of connection parameters,
* or a valid connection URI as a string. If supplying an array, the following
* paramters are accepted: host, port, user and pass. Any other parameters
* are discarded.
* @exception XBMC_RPC_ConnectionException if it is not possible to connect to
* the server.
* @access public
*/
public function __construct($parameters) {
try {
$server = new XBMC_RPC_Server($parameters);
} catch (XBMC_RPC_ServerException $e) {
throw new XBMC_RPC_ConnectionException($e->getMessage(), $e->getCode(), $e);
}
$this->server = $server;
$this->prepareConnection();
$this->assertCanConnect();
$this->createRootNamespace();
}
/**
* Delegates any direct Command calls to the root namespace.
*
* @param string $name The name of the called command.
* @param mixed $arguments An array of arguments used to call the command.
* @return The result of the command call as returned from the namespace.
* @exception XBMC_RPC_InvalidCommandException if the called command does not
* exist in the root namespace.
* @access public
*/
public function __call($name, array $arguments) {
return call_user_func_array(array($this->rootNamespace, $name), $arguments);
}
/**
* Delegates namespace accesses to the root namespace.
*
* @param string $name The name of the requested namespace.
* @return XBMC_RPC_Namespace The requested namespace.
* @exception XBMC_RPC_InvalidNamespaceException if the namespace does not
* exist in the root namespace.
* @access public
*/
public function __get($name) {
return $this->rootNamespace->$name;
}
/**
* Executes a remote procedure call using the supplied XBMC_RPC_Command
* object.
*
* @param XBMC_RPC_Command The command to execute.
* @return XBMC_RPC_Response The response from the remote procedure call.
* @access public
*/
public function executeCommand(XBMC_RPC_Command $command) {
return $this->sendRpc($command->getFullName(), $command->getArguments());
}
/**
* Determines if the XBMC system to which the client is connected is legacy
* (pre Eden) or not. This is useful because the format of commands/params
* is different in the Eden RPC implementation.
*
* @return bool True if the system is legacy, false if not.
* @access public
*/
public function isLegacy() {
return $this->isLegacy;
}
/**
* Asserts that the server is reachable and a connection can be made.
*
* @return void
* @exception XBMC_RPC_ConnectionException if it is not possible to connect to
* the server.
* @abstract
* @access protected
*/
protected abstract function assertCanConnect();
/**
* Prepares for a connection to XBMC.
*
* Should be used by child classes for any pre-connection logic which is necessary.
*
* @return void
* @exception XBMC_RPC_ClientException if it was not possible to prepare for
* connection successfully.
* @abstract
* @access protected
*/
protected abstract function prepareConnection();
/**
* Sends a JSON-RPC request to XBMC and returns the result.
*
* @param string $json A JSON-encoded string representing the remote procedure call.
* This string should conform to the JSON-RPC 2.0 specification.
* @param string $rpcId The unique ID of the remote procedure call.
* @return string The JSON-encoded response string from the server.
* @exception XBMC_RPC_RequestException if it was not possible to make the request.
* @access protected
* @link http://groups.google.com/group/json-rpc/web/json-rpc-2-0 JSON-RPC 2.0 specification
*/
protected abstract function sendRequest($json, $rpcId);
/**
* Build a JSON-RPC 2.0 compatable json_encoded string representing the
* specified command, parameters and request id.
*
* @param string $command The name of the command to be called.
* @param mixed $params An array of paramters to be passed to the command.
* @param string $rpcId A unique string used for identifying the request.
* @access private
*/
private function buildJson($command, $params, $rpcId) {
$data = array(
'jsonrpc' => '2.0',
'method' => $command,
'params' => $params,
'id' => $rpcId
);
return json_encode($data);
}
/**
* Ensures that the recieved response from a remote procedure call is valid.
*
* $param XBMC_RPC_Response $response A response object encapsulating remote
* procedure call response data as returned from Client::sendRequest().
* @return bool True of the reponse is valid, false if not.
* @access private
*/
private function checkResponse(XBMC_RPC_Response $response, $rpcId) {
return ($response->getId() == $rpcId);
}
/**
* Creates the root namespace instance.
*
* @return void
* @access private
*/
private function createRootNamespace() {
$commands = $this->loadAvailableCommands();
$this->rootNamespace = new XBMC_RPC_Namespace('root', $commands, $this);
}
/**
* Generates a unique string to be used as a remote procedure call ID.
*
* @return string A unique string.
* @access private
*/
private function getRpcId() {
return uniqid();
}
/**
* Retrieves an array of commands by requesting the RPC server to introspect.
*
* @return mixed An array of available commands which may be executed on the server.
* @exception XBMC_RPC_RequestException if it is not possible to retrieve a list of
* available commands.
* @access private
*/
private function loadAvailableCommands() {
try {
$response = $this->sendRpc('JSONRPC.Introspect');
} catch (XBMC_RPC_Exception $e) {
throw new XBMC_RPC_RequestException(
'Unable to retrieve list of available commands: ' . $e->getMessage()
);
}
if (isset($response['commands'])) {
$this->isLegacy = true;
return $this->loadAvailableCommandsLegacy($response);
}
$commands = array();
foreach (array_keys($response['methods']) as $command) {
$array = $this->commandStringToArray($command);
$commands = $this->mergeCommandArrays($commands, $array);
}
return $commands;
}
/**
* Retrieves an array of commands by requesting the RPC server to introspect.
*
* This method supports the legacy implementation of XBMC's RPC.
*
* @return mixed An array of available commands which may be executed on the server.
* @access private
*/
private function loadAvailableCommandsLegacy($response) {
$commands = array();
foreach ($response['commands'] as $command) {
$array = $this->commandStringToArray($command['command']);
$commands = $this->mergeCommandArrays($commands, $array);
}
return $commands;
}
/**
* Converts a dot-delimited command name to a multidimensional array format.
*
* @return mixed An array representing the command.
* @access private
*/
private function commandStringToArray($command) {
$path = explode('.', $command);
if (count($path) === 1) {
$commands[] = $path[0];
continue;
}
$command = array_pop($path);
$array = array();
$reference =& $array;
foreach ($path as $i => $key) {
if (is_numeric($key) && intval($key) > 0 || $key === '0') {
$key = intval($key);
}
if ($i === count($path) - 1) {
$reference[$key] = array($command);
} else {
if (!isset($reference[$key])) {
$reference[$key] = array();
}
$reference =& $reference[$key];
}
}
return $array;
}
/**
* Recursively merges the supplied arrays whilst ensuring that commands are
* not duplicated within a namespace.
*
* Note that array_merge_recursive is not suitable here as it does not ensure
* that values are distinct within an array.
*
* @param mixed $base The base array into which $append will be merged.
* @param mixed $append The array to merge into $base.
* @return mixed The merged array of commands and namespaces.
* @access private
*/
private function mergeCommandArrays(array $base, array $append) {
foreach ($append as $key => $value) {
if (!array_key_exists($key, $base) && !is_numeric($key)) {
$base[$key] = $append[$key];
continue;
}
if (is_array($value) || is_array($base[$key])) {
$base[$key] = $this->mergeCommandArrays($base[$key], $append[$key]);
} elseif (is_numeric($key)) {
if (!in_array($value, $base)) {
$base[] = $value;
}
} else {
$base[$key] = $value;
}
}
return $base;
}
/**
* Executes a remote procedure call using the supplied command name and parameters.
*
* @param string $command The full, dot-delimited name of the command to call.
* @param mixed $params An array of parameters to be passed to the called method.
* @return mixed The data returned from the response.
* @exception XBMC_RPC_RequestException if it was not possible to make the request.
* @exception XBMC_RPC_ResponseException if the response was not being properly received.
* @access private
*/
private function sendRpc($command, $params = array()) {
$rpcId = $this->getRpcId();
$json = $this->buildJson($command, $params, $rpcId);
$response = new XBMC_RPC_Response($this->sendRequest($json, $rpcId));
if (!$this->checkResponse($response, $rpcId)) {
throw new XBMC_RPC_ResponseException('JSON RPC request/response ID mismatch');
}
return $response->getData();
}
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_ClientException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,86 @@
<?php
/**
* A JSON-RPC command.
*/
class XBMC_RPC_Command {
/**
* @var string The name of the command.
* @access private
*/
private $name;
/**
* @var The namespace to which the instance belongs.
* @access private
*/
private $parentNamespace;
/**
* @var The client to be used for executing the command.
* @access private
*/
private $client;
/**
* @var An array of arguments to be passed with the command.
* @access private
*/
private $arguments = array();
/**
* Constructor.
*
* @param string $name The name of the desired command.
* @param XBMC_RPC_Client $client The client instance responsible for operating
* the Command instance.
* @param mixed $parent The parent XBMC_RPC_Command object, or null if there is
* no parent of this instance.
* @access public
*/
public function __construct($name, XBMC_RPC_Client $client, XBMC_RPC_Namespace $parent) {
$this->name = $name;
$this->parentNamespace = $parent;
$this->client = $client;
}
/**
* Executes the remote procedure call command.
*
* @param mixed $arguments An array of arguments to be passed along with the
* command.
* @return mixed The response data as returned from XBMC_RPC_Client::sendRpc().
* @exception XBMC_RPC_Exception if the remote procedure call could be carried
* out successfully.
* @access public
*/
public function execute(array $arguments = array()) {
if (count($arguments) == 1) {
$arguments = array_shift($arguments);
}
$this->arguments = $arguments;
return $this->client->executeCommand($this);
}
/**
* Gets an array of arguments which accompany the command.
*
* @return mixed The array of argument which accompany this command.
* @access public
*/
public function getArguments() {
return $this->arguments;
}
/**
* Gets the full, dot-delimited name of the command including its namespace path.
*
* @return string The command name.
* @access public
*/
public function getFullName() {
return $this->parentNamespace->getFullName() . '.' . $this->name;
}
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_CommandException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_ConnectionException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,5 @@
<?php
class XBMC_RPC_Exception extends Exception {
}

View file

@ -0,0 +1,136 @@
<?php
require_once 'Client.php';
class XBMC_RPC_HTTPClient extends XBMC_RPC_Client {
/**
* @var string The URI of the XBMC server to which requests will be made.
*/
private $uri;
/**
* @var resource The curl resource used for making requests.
*/
private $curlResource;
/**
* @var int The amount of time for which the script will try to connect before giving up.
*/
private $timeout = 15;
/**
* Destructor.
*
* Cleans up the curl resource if necessary.
*/
public function __destruct() {
if (is_resource($this->curlResource)) {
curl_close($this->curlResource);
}
}
/**
* Sets the number of seconds the script will wait while trying to connect
* to the server before giving up.
*
* @param int $seconds The number of seconds to wait.
* @return void
*/
public function setTimeout($seconds) {
$this->timeout = (int) $seconds;
if ($this->timeout < 0) {
$this->timeout = 0;
}
}
/**
* Asserts that the server is reachable and a connection can be made.
*
* @return void
* @exception XBMC_RPC_ConnectionException if it is not possible to connect to
* the server.
*/
protected function assertCanConnect() {
if (extension_loaded('curl')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $this->uri);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
if (!curl_exec($ch) || !in_array(curl_getinfo($ch, CURLINFO_HTTP_CODE), array('200', '401'))) {
throw new XBMC_RPC_ConnectionException('Unable to connect to XBMC server via HTTP');
}
} else {
throw new XBMC_RPC_ConnectionException('Cannot test if XBMC server is reachable via HTTP because cURL is not installed');
}
}
/**
* Prepares for a connection to XBMC via HTTP.
*
* @exception XBMC_RPC_ClientException if it was not possible to prepare for
* connection successfully.
* @access protected
*/
protected function prepareConnection() {
if (!$uri = $this->buildUri()) {
throw new XBMC_RPC_ClientException('Unable to parse server parameters into valid URI string');
}
$this->uri = $uri;
}
/**
* Sends a JSON-RPC request to XBMC and returns the result.
*
* @param string $json A JSON-encoded string representing the remote procedure call.
* This string should conform to the JSON-RPC 2.0 specification.
* @param string $rpcId The unique ID of the remote procedure call.
* @return string The JSON-encoded response string from the server.
* @exception XBMC_RPC_RequestException if it was not possible to make the request.
* @access protected
* @link http://groups.google.com/group/json-rpc/web/json-rpc-2-0 JSON-RPC 2.0 specification
*/
protected function sendRequest($json, $rpcId) {
if (empty($this->curlResource)) {
$this->curlResource = $this->createCurlResource();
}
curl_setopt($this->curlResource, CURLOPT_POSTFIELDS, $json);
curl_setopt($this->curlResource, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
if (!$response = curl_exec($this->curlResource)) {
throw new XBMC_RPC_RequestException('Could not make a request the server');
}
return $response;
}
/**
* Builds the server URI from the supplied parameters.
*
* @return string The server URI.
* @access private
*/
private function buildUri() {
$parameters = $this->server->getParameters();
$credentials = '';
if (!empty($parameters['user'])) {
$credentials = $parameters['user'];
$credentials .= empty($parameters['pass']) ? '@' : ':' . $parameters['pass'] . '@';
}
return sprintf('http://%s%s:%d/jsonrpc', $credentials, $parameters['host'], $parameters['port']);
}
/**
* Creates a curl resource with the correct settings for making JSON-RPC calls
* to XBMC.
*
* @return resource A new curl resource.
* @access private
*/
private function createCurlResource() {
$curlResource = curl_init();
curl_setopt($curlResource, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlResource, CURLOPT_POST, 1);
curl_setopt($curlResource, CURLOPT_URL, $this->uri);
return $curlResource;
}
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_InvalidCommandException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_InvalidNamespaceException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,166 @@
<?php
require_once 'InvalidNamespaceException.php';
require_once 'InvalidCommandException.php';
require_once 'Command.php';
/**
* A collection of commands and namespaces.
*/
class XBMC_RPC_Namespace {
/**
* @var string The name of the namespace.
* @access private
*/
private $name;
/**
* @var XBMC_RPC_Command The parent namespace of the current instance.
* @access private
*/
private $parentNamespace;
/**
* @var The tree of commands and namespaces which are children of the current
* instance.
* @access private
*/
private $children = array();
/**
* @var A cache of child XBMC_RPC_Command and XBMC_RPC_Namespace objects.
* @access private
*/
private $objectCache = array();
/**
* @var An instance of XBMC_RPC_Client to which this XBMC_RPC_Namespace
* instance belongs.
* @access private
*/
private $client;
/**
* Constructor.
*
* @param string $name The name of the namespace.
* @param mixed $children An array of commands and namespaces which are
* children of the current instance.
* @param XBMC_RPC_Client $client The client instance to which this instance
* belongs.
* @param mixed $parent The parent XBMC_RPC_Namespace object, or null if this
* instance is the root namespace.
* @access public
*/
public function __construct($name, array $children, XBMC_RPC_Client $client, XBMC_RPC_Namespace $parent = null) {
$this->name = $name;
$this->children = $children;
$this->client = $client;
$this->parentNamespace = $parent;
}
/**
* Executes the called command.
*
* @param string $name The name of the command to call.
* @arguments mixed An array of arguments to be send with the remote
* procedure call.
* @return XBMC_RPC_Response The response of the remote procedure call.
* @exception XBMC_RPC_InvalidCommandException if the requested command does
* not exist in this namespace.
* @access public
*/
public function __call($name, array $arguments) {
$this->assertHasChildCommand($name);
if (empty($this->objectCache[$name])) {
$this->objectCache[$name] = new XBMC_RPC_Command($name, $this->client, $this);
}
return $this->objectCache[$name]->execute($arguments);
}
/**
* Gets the requested child namespace.
*
* @param string $name The name of the namespace to get.
* @return XBMC_RPC_Namespace The requested child namespace.
* @exception XBMC_RPC_InvalidNamespaceException if the requested namespace does
* not exist in this namespace.
* @access public
*/
public function __get($name) {
$this->assertHasChildNamespace($name);
if (empty($this->objectCache[$name])) {
$this->objectCache[$name] = new XBMC_RPC_Namespace($name, $this->children[$name], $this->client, $this);
}
return $this->objectCache[$name];
}
/**
* Gets the full dot-delimited string representing the path from the root
* namespace to the current namespace.
*
* @return string The dot-delimited string.
* @access public
*/
public function getFullName() {
$name = '';
if (!empty($this->parentNamespace)) {
$name = $this->parentNamespace->getFullName() . '.' . $this->name;
}
return trim($name, '.');
}
/**
* Asserts that the the namespace contains the specified command as a direct
* child.
*
* @param string $name The name of the command to check for.
* @exception XBMC_RPC_InvalidCommandException if the command is not a direct
* child of this namespace.
* @access private
*/
private function assertHasChildCommand($name) {
if (!$this->hasChildCommand($name)) {
throw new XBMC_RPC_InvalidCommandException("Command $name does not exist in namespace $this->name");
}
}
/**
* Asserts that the the namespace contains the specified namespace as a direct
* child.
*
* @param string $name The name of the namespace to check for.
* @exception XBMC_RPC_InvalidNamespaceException if the namespace is not a direct
* child of this namespace.
* @access private
*/
private function assertHasChildNamespace($name) {
if (!$this->hasChildNamespace($name)) {
throw new XBMC_RPC_InvalidNamespaceException("Namespace $name does not exist in namespace $this->name");
}
}
/**
* Checks if the namespace has the specified command as a direct child.
*
* @param string $name The name of the command to check for.
* @return bool True if the command exists in this namespace, false if not.
* @access private
*/
private function hasChildCommand($name) {
return in_array($name, $this->children);
}
/**
* Checks if the namespace has the specified namespace as a direct child.
*
* @param string $name The name of the namespace to check for.
* @return bool True if the namespace exists in this namespace, false if not.
* @access private
*/
private function hasChildNamespace($name) {
return array_key_exists($name, $this->children);
}
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_RequestException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,66 @@
<?php
class XBMC_RPC_Response {
/**
* @var string The id of the response as returned from the server.
* @access private
*/
private $id;
/**
* @var string The data returned from the server if the response was successful.
* @access private
*/
private $data;
/**
* Constructor.
*
* @param string $response The JSON-decoded response string
* as returned from the server
*/
public function __construct($response) {
$response = $this->decodeResponse($response);
$this->id = $response['id'];
if (isset($response['error'])) {
throw new XBMC_RPC_ResponseException($response['error']['message'], $response['error']['code']);
} elseif (!isset($response['result'])) {
throw new XBMC_RPC_ResponseException('Invalid JSON RPC response');
}
$this->data = $response['result'];
}
/**
* Gets the response data.
*
* @return mixed The response data.
*/
public function getData() {
return $this->data;
}
/**
* Gets the response id.
*
* @return string The response id.
*/
public function getId() {
return $this->id;
}
/**
* Takes a JSON string as returned from the server and decodes it into an
* associative array.
*/
private function decodeResponse($json) {
if (extension_loaded('mbstring')) {
$encoding = mb_detect_encoding($json, 'ASCII,UTF-8,ISO-8859-1,windows-1252,iso-8859-15');
if ($encoding && !in_array($encoding, array('UTF-8', 'ASCII'))) {
$json = mb_convert_encoding($json, 'UTF-8', $encoding);
}
}
return json_decode($json, true);
}
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_ResponseException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,88 @@
<?php
require_once 'ServerException.php';
class XBMC_RPC_Server {
/**
* @var mixed An array of parameters used to connect to the server.
* @access private
*/
private $parameters = array();
/**
* Constructor.
*
* @param mixed $parameters An associative array of connection parameters,
* or a valid connection URI as a string. If supplying an array, the following
* paramters are accepted: host, port, user and pass. Any other parameters
* are discarded.
* @exception XBMC_RPC_ServerException if the supplied parameters could not
* be parsed successfully.
* @access public
*/
public function __construct($parameters) {
if (!$parameters = $this->parseParameters($parameters)) {
throw new XBMC_RPC_ServerException('Unable to parse server parameters');
}
$this->parameters = $parameters;
}
/**
* Checks if the server is connected.
*
* @return bool True if the server is connected, false if not.
* @access public
*/
public function isConnected() {
return $this->connected;
}
/**
* Gets the connection parameters/
*
* @return mixed The connection parameters as an associative array.
* @access public
*/
public function getParameters() {
return $this->parameters;
}
/**
* Parses the supplied parameters into a standard associative array format.
*
* @param mixed $parameters An associative array of connection parameters,
* or a valid connection URI as a string. If supplying an array, the following
* paramters are accepted: host, port, user and pass. Any other parameters
* are discarded.
* @return mixed The connection parameters as an associative array, or false
* if the parameters could not be parsed. The array will have the following
* keys: host, port, user and pass.
* @access private
*/
private function parseParameters($parameters) {
if (is_string($parameters)) {
$parameters = preg_replace('#^[a-z]+://#i', '', trim($parameters));
if (!$parameters = parse_url('http://' . $parameters)) {
return false;
}
}
if (!is_array($parameters)) {
// if parameters are not a string or an array, something is wrong
return false;
}
$defaults = array(
'host' => 'localhost',
'port' => 8080,
'user' => null,
'pass' => null
);
$parameters = array_intersect_key(array_merge($defaults, $parameters), $defaults);
return $parameters;
}
}

View file

@ -0,0 +1,7 @@
<?php
require_once 'Exception.php';
class XBMC_RPC_ServerException extends XBMC_RPC_Exception {
}

View file

@ -0,0 +1,139 @@
<?php
require_once 'Client.php';
class XBMC_RPC_TCPClient extends XBMC_RPC_Client {
/**
* @var resource A file pointer resource for reading over the connected socket.
* @access private
*/
private $fp;
/**
* Destructor.
*
* Cleans up the file resource if necessary.
*/
public function __destruct() {
if (is_resource($this->fp)) {
fclose($this->fp);
}
}
/**
* Asserts that the server is reachable and a connection can be made.
*
* @return void
* @exception XBMC_RPC_ConnectionException if it is not possible to connect to
* the server.
* @access protected
*/
protected function assertCanConnect() {
if (!$this->canConnect()) {
throw new XBMC_RPC_ConnectionException('Unable to connect to XBMC server via TCP');
}
}
/**
* Prepares for a connection to XBMC via TCP.
*
* @return void
* @access protected
*/
protected function prepareConnection() {
$parameters = $this->server->getParameters();
$this->fp = @fsockopen($parameters['host'], $parameters['port']);
}
/**
* Sends a JSON-RPC request to XBMC and returns the result.
*
* @param string $json A JSON-encoded string representing the remote procedure call.
* This string should conform to the JSON-RPC 2.0 specification.
* @param string $rpcId The unique ID of the remote procedure call.
* @return string The JSON-encoded response string from the server.
* @exception XBMC_RPC_RequestException if it was not possible to make the request.
* @access protected
* @link http://groups.google.com/group/json-rpc/web/json-rpc-2-0 JSON-RPC 2.0 specification
*/
protected function sendRequest($json, $rpcId) {
$this->prepareConnection();
if (!$this->canConnect()) {
throw new XBMC_RPC_ConnectionException('Lost connection to XBMC server');
}
fwrite($this->fp, $json);
while (true) {
$result = $this->readJsonObject();
if (strpos($result, '"id" : "' . $rpcId . '"') !== false) {
break;
}
if (strpos($result, '"id":"' . $rpcId . '"') !== false) {
break;
}
}
fclose($this->fp);
return $result;
}
/**
* Checks if it is possible to connect to the server.
*
* @return bool True if it is possible to connect, false if not.
* @access private
*/
private function canConnect() {
return is_resource($this->fp);
}
/**
* Reads a single JSON object from the socket and returns it.
*
* @return string The JSON object string from the server.
* @access private
*/
private function readJsonObject() {
$open = $close = 0;
$escaping = false;
$quoteChar = null;
$result = '';
while (false !== ($char = fgetc($this->fp))) {
if (!$escaping) {
switch ($char) {
case "'":
case '"':
if (null === $quoteChar) {
$quoteChar = $char;
} elseif ($quoteChar == $char) {
$quoteChar = null;
}
break;
case '{':
if (null === $quoteChar) {
++$open;
}
break;
case '}':
if (null === $quoteChar) {
++$close;
}
break;
case '\\':
$escaping = true;
break;
}
} else {
$escaping = false;
}
$result .= $char;
if ($open == $close) {
break;
}
}
return $result;
}
}

View file

@ -346,7 +346,6 @@ else if ($transcode_to) {
} }
if ($transcode) { if ($transcode) {
header('Accept-Ranges: none');
$transcoder = Stream::start_transcode($media, $transcode_to); $transcoder = Stream::start_transcode($media, $transcode_to);
$fp = $transcoder['handle']; $fp = $transcoder['handle'];
$media_name = $media->f_artist_full . " - " . $media->title . "." . $transcoder['format']; $media_name = $media->f_artist_full . " - " . $media->title . "." . $transcoder['format'];
@ -356,10 +355,29 @@ else if (!in_array('native', $valid_types)) {
exit(); exit();
} }
else { else {
header('Accept-Ranges: bytes');
$fp = fopen($media->file, 'rb'); $fp = fopen($media->file, 'rb');
} }
if ($transcode) {
// Content-length guessing if required by the player.
// Otherwise it shouldn't be used as we are not really sure about final length when transcoding
// Should also support video, but video implementation as to be reviewed first!
if (get_class($media) == 'Song' && $_REQUEST['content_length'] == 'required') {
$max_bitrate = Stream::get_allowed_bitrate($media);
if ($media->time > 0 && $max_bitrate > 0) {
$stream_size = $media->time * $max_bitrate * 1000;
} else {
debug_event('play', 'Bad media duration / Max bitrate. Content-length calculation skipped.', 5);
$stream_size = null;
}
} else {
$stream_size = null;
}
}
else {
$stream_size = $media->size;
}
if (!is_resource($fp)) { if (!is_resource($fp)) {
debug_event('play', "Failed to open $media->file for streaming", 2); debug_event('play', "Failed to open $media->file for streaming", 2);
exit(); exit();
@ -370,13 +388,6 @@ if (get_class($media) == 'Song') {
Stream::insert_now_playing($media->id,$uid,$media->time,$sid,get_class($media)); Stream::insert_now_playing($media->id,$uid,$media->time,$sid,get_class($media));
} }
if ($transcode) {
$stream_size = null;
}
else {
$stream_size = $media->size;
}
// Handle Content-Range // Handle Content-Range
sscanf($_SERVER['HTTP_RANGE'], "bytes=%d-%d", $start, $end); sscanf($_SERVER['HTTP_RANGE'], "bytes=%d-%d", $start, $end);
@ -391,23 +402,33 @@ if ($start > 0 || $end > 0 ) {
$stream_size = $media->size - $start; $stream_size = $media->size - $start;
} }
if ($transcode) { if ($stream_size == null) {
debug_event('play', 'Bad client behaviour. Content-Range header received, which we cannot fulfill due to transcoding', 2); debug_event('play', 'Content-Range header received, which we cannot fulfill due to unknown final length (transcoding?)', 2);
$stream_size = null;
} }
else { else {
debug_event('play', 'Content-Range header received, skipping ' . $start . ' bytes out of ' . $media->size, 5); if($transcoding) {
fseek($fp, $start); debug_event('play', 'We should transcode only for a calculated frame range, but not yet supported here.', 2);
$stream_size = null;
} else {
debug_event('play', 'Content-Range header received, skipping ' . $start . ' bytes out of ' . $media->size, 5);
fseek($fp, $start);
$range = $start . '-' . $end . '/' . $media->size; $range = $start . '-' . $end . '/' . $media->size;
header('HTTP/1.1 206 Partial Content'); header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $range); header('Content-Range: bytes ' . $range);
}
} }
} }
else { else {
debug_event('play','Starting stream of ' . $media->file . ' with size ' . $media->size, 5); debug_event('play','Starting stream of ' . $media->file . ' with size ' . $media->size, 5);
} }
if ($transcode) {
header('Accept-Ranges: none');
} else {
header('Accept-Ranges: bytes');
}
$mime = $transcode $mime = $transcode
? $media->type_to_mime($transcoder['format']) ? $media->type_to_mime($transcoder['format'])
: $media->mime; : $media->mime;
@ -467,8 +488,10 @@ else {
if ($demo_id) { $democratic->delete_from_oid($oid,'song'); } if ($demo_id) { $democratic->delete_from_oid($oid,'song'); }
if ($transcode) { if ($transcode) {
$stderr = fread($transcoder['stderr'], 8192); if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
fclose($transcoder['stderr']); $stderr = fread($transcoder['stderr'], 8192);
fclose($transcoder['stderr']);
}
fclose($fp); fclose($fp);
proc_close($transcoder['process']); proc_close($transcoder['process']);
debug_event('transcode_cmd', $stderr, 5); debug_event('transcode_cmd', $stderr, 5);

View file

@ -27,7 +27,7 @@ UI::show_header();
// Switch on Action // Switch on Action
switch ($_REQUEST['action']) { switch ($_REQUEST['action']) {
case 'show_create': case 'show_create':
if (!Access::check('interface','25')) { if (!Access::check('interface', 75)) {
UI::access_denied(); UI::access_denied();
exit; exit;
} }
@ -36,7 +36,7 @@ switch ($_REQUEST['action']) {
break; break;
case 'create': case 'create':
if (!Access::check('interface','25') || Config::get('demo_mode')) { if (!Access::check('interface', 75) || Config::get('demo_mode')) {
UI::access_denied(); UI::access_denied();
exit; exit;
} }

6
rest/.htaccess Normal file
View file

@ -0,0 +1,6 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^(.+)\.view$ index.php?action=$1 [QSA]
</IfModule>

141
rest/index.php Normal file
View file

@ -0,0 +1,141 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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.
*
*/
define('NO_SESSION','1');
require_once '../lib/init.php';
$action = strtolower($_GET['action']);
/* Set the correct default headers */
if ($action != "getcoverart" && $action != "hls" && $action != "stream" && $action != "download" && $action != "getavatar") {
header("Content-type: text/xml; charset=" . Config::get('site_charset'));
}
// If we don't even have access control on then we can't use this!
if (!Config::get('access_control')) {
debug_event('Access Control','Error Attempted to use Subsonic API with Access Control turned off','3');
ob_end_clean();
echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_UNAUTHORIZED, T_('Access Control not Enabled'))->asXml();
exit;
}
// Authenticate the user with preemptive HTTP Basic authentication first
$user = $_SERVER['PHP_AUTH_USER'];
if (empty($user)) {
$user = $_GET['u'];
}
$password = $_SERVER['PHP_AUTH_PW'];
if (empty($password)) {
$password = $_GET['p'];
}
$version = $_GET['v'];
$clientapp = $_GET['c'];
if (empty($user) || empty($password) || empty($version) || empty($action) || empty($clientapp)) {
ob_end_clean();
echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_MISSINGPARAM)->asXml();
exit();
}
// Decode hex-encoded password
$encpwd = strpos($password, "enc:");
if ($encpwd !== false) {
$hex = substr($password, 4);
$decpwd = '';
for ($i=0; $i<strlen($hex); $i+=2) $decpwd .= chr(hexdec(substr($hex,$i,2)));
$password = $decpwd;
}
// Check user authentication
$auth = Auth::login($user, $password);
if (!$auth['success']) {
debug_event('Access Denied','Invalid authentication attempt to Subsonic API for user [' . $user . ']','3');
ob_end_clean();
echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_BADAUTH)->asXml();
exit();
}
if (!Access::check_network('init-api', $user, 5)) {
debug_event('Access Denied','Unauthorized access attempt to Subsonic API [' . $_SERVER['REMOTE_ADDR'] . ']', '3');
ob_end_clean();
echo Subsonic_XML_Data::createError(SSERROR_UNAUTHORIZED, 'Unauthorized access attempt to Subsonic API - ACL Error');
exit();
}
$GLOBALS['user'] = User::get_from_username($user);
// Check server version
if (version_compare(Subsonic_XML_Data::API_VERSION, $version) < 0) {
ob_end_clean();
echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_APIVERSION_SERVER)->asXml();
exit();
}
// Get the list of possible methods for the Ampache API
$methods = get_class_methods('subsonic_api');
// Define list of internal functions that should be skipped
$internal_functions = array('check_version', 'check_parameter', 'follow_stream', '_updatePlaylist');
// We do not use $_GET because of multiple parameters with the same name
$query_string = $_SERVER['QUERY_STRING'];
// Trick to avoid $HTTP_RAW_POST_DATA
$postdata = file_get_contents("php://input");
if (!empty($postdata)) {
$query_string .= '&' . $postdata;
}
$query = explode('&', $query_string);
$params = array();
foreach ($query as $param) {
list($name, $value) = explode('=', $param);
$decname = urldecode($name);
$decvalue = urldecode($value);
if (array_key_exists($decname, $params)) {
if (!is_array($params[$decname])) {
$oldvalue = $params[$decname];
$params[$decname] = array();
$params[$decname][] = $oldvalue;
}
$params[$decname][] = $decvalue;
} else {
$params[$decname] = $decvalue;
}
}
//syslog(LOG_INFO, print_r($params, true));
// Recurse through them and see if we're calling one of them
foreach ($methods as $method) {
if (in_array($method,$internal_functions)) { continue; }
// If the method is the same as the action being called
// Then let's call this function!
if ($action == $method) {
call_user_func(array('subsonic_api',$method),$params);
// We only allow a single function to be called, and we assume it's cleaned up!
exit();
}
} // end foreach methods in API
// If we manage to get here, we still need to hand out an XML document
ob_end_clean();
echo Subsonic_XML_Data::createError(Subsonic_XML_Data::SSERROR_DATA_NOTFOUND)->asXml();
?>

View file

@ -27,7 +27,7 @@
<script language="javascript" type="text/javascript"> <script language="javascript" type="text/javascript">
<!-- begin <!-- begin
function PlayerPopUp(URL) { function PlayerPopUp(URL) {
window.open(URL, 'HTML5_player', 'width=700,height=210,scrollbars=0,toolbar=0,location=0,directories=0,status=0,resizable=0'); window.open(URL, 'HTML5_player', 'width=730,height=285,scrollbars=0,toolbar=0,location=0,directories=0,status=0,resizable=0');
window.location = '<?php echo return_referer() ?>'; window.location = '<?php echo return_referer() ?>';
return false; return false;
} }

View file

@ -0,0 +1,44 @@
<?php
/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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.
*
*/
?>
<html>
<head>
<title><?php echo Config::get('site_title'); ?></title>
<script language="javascript" type="text/javascript">
function PlayerFrame(URL) {
var ff = parent.parent.document.getElementById('frame_footer');
var maindiv = parent.parent.document.getElementById('maindiv');
if (ff.getAttribute('className') != 'frame_footer_visible') {
ff.setAttribute('className', 'frame_footer_visible');
ff.setAttribute('class', 'frame_footer_visible');
maindiv.style.height = (parent.parent.innerHeight - 105) + "px";
}
ff.setAttribute('src', URL);
return false;
}
</script>
</head>
<body onLoad="javascript:PlayerFrame('<?php echo Config::get('web_path')?>/html5_player_embedded.php<?php echo '?playlist_id=' . $this->id ?>');">
</body>
</html>

View file

@ -40,11 +40,32 @@ if (Config::get('use_rss')) { ?>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=<?php echo Config::get('site_charset'); ?>" /> <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=<?php echo Config::get('site_charset'); ?>" />
<title><?php echo scrub_out(Config::get('site_title')); ?> - <?php echo $location['title']; ?></title> <title><?php echo scrub_out(Config::get('site_title')); ?> - <?php echo $location['title']; ?></title>
<?php require_once Config::get('prefix') . '/templates/stylesheets.inc.php'; ?> <?php require_once Config::get('prefix') . '/templates/stylesheets.inc.php'; ?>
<<<<<<< HEAD
<link rel="stylesheet" href="<?php echo $web_path; ?>/modules/jquery/jquery-ui-1.10.3.min.css" type="text/css" media="screen" /> <link rel="stylesheet" href="<?php echo $web_path; ?>/modules/jquery/jquery-ui-1.10.3.min.css" type="text/css" media="screen" />
</head> </head>
<body> <body>
<script src="<?php echo $web_path; ?>/modules/jquery/jquery-1.9.1.js" language="javascript" type="text/javascript"></script> <script src="<?php echo $web_path; ?>/modules/jquery/jquery-1.9.1.js" language="javascript" type="text/javascript"></script>
<script src="<?php echo $web_path; ?>/modules/jquery/jquery-ui-1.10.3.min.js" language="javascript" type="text/javascript"></script> <script src="<?php echo $web_path; ?>/modules/jquery/jquery-ui-1.10.3.min.js" language="javascript" type="text/javascript"></script>
=======
<?php
// If iframes, we check in javascript that parent container exist, otherwise we redirect to index. Otherwise HTML5 iframed Player will look broken.
if (Config::get('iframes')) {
?>
<script language="javascript" type="text/javascript">
function forceIframe() {
if (self == top) {
document.location = '<?php echo $web_path; ?>';
}
}
</script>
<?php
}
?>
</head>
<body <?php echo (Config::get('iframes')) ? "onLoad='forceIframe();'" : ""; ?>>
<script src="<?php echo $web_path; ?>/modules/prototype/prototype.js" language="javascript" type="text/javascript"></script>
<script src="<?php echo $web_path; ?>/modules/tinybox/tinybox.js" language="javascript" type="text/javascript"></script>
>>>>>>> 346b25516d711de989bc3877c6c372439dfa58d3
<script src="<?php echo $web_path; ?>/lib/javascript/base.js" language="javascript" type="text/javascript"></script> <script src="<?php echo $web_path; ?>/lib/javascript/base.js" language="javascript" type="text/javascript"></script>
<script src="<?php echo $web_path; ?>/lib/javascript/ajax.js" language="javascript" type="text/javascript"></script> <script src="<?php echo $web_path; ?>/lib/javascript/ajax.js" language="javascript" type="text/javascript"></script>
<!-- rfc3514 implementation --> <!-- rfc3514 implementation -->
@ -53,7 +74,7 @@ if (Config::get('use_rss')) { ?>
<div id="maincontainer"> <div id="maincontainer">
<div id="header"><!-- This is the header --> <div id="header"><!-- This is the header -->
<h1 id="headerlogo"> <h1 id="headerlogo">
<a href="<?php echo Config::get('web_path'); ?>"> <a href="<?php echo Config::get('web_path') . ((Config::get('iframes')) ? '/?framed=1' : ''); ?>">
<img src="<?php echo $web_path; ?><?php echo Config::get('theme_path'); ?>/images/ampache.png" title="<?php echo Config::get('site_title'); ?>" alt="<?php echo Config::get('site_title'); ?>" /> <img src="<?php echo $web_path; ?><?php echo Config::get('theme_path'); ?>/images/ampache.png" title="<?php echo Config::get('site_title'); ?>" alt="<?php echo Config::get('site_title'); ?>" />
</a> </a>
</h1> </h1>
@ -61,7 +82,7 @@ if (Config::get('use_rss')) { ?>
<?php UI::show_box_top('','box box_headerbox'); ?> <?php UI::show_box_top('','box box_headerbox'); ?>
<?php require_once Config::get('prefix') . '/templates/show_search_bar.inc.php'; ?> <?php require_once Config::get('prefix') . '/templates/show_search_bar.inc.php'; ?>
<?php require_once Config::get('prefix') . '/templates/show_playtype_switch.inc.php'; ?> <?php require_once Config::get('prefix') . '/templates/show_playtype_switch.inc.php'; ?>
<span id="loginInfo"><a href="<?php echo Config::get('web_path'); ?>/preferences.php?tab=account"><?php echo $GLOBALS['user']->fullname; ?></a> <a href="<?php echo Config::get('web_path'); ?>/logout.php">[<?php echo T_('Log out'); ?>]</a></span> <span id="loginInfo"><a href="<?php echo Config::get('web_path'); ?>/preferences.php?tab=account"><?php echo $GLOBALS['user']->fullname; ?></a> <a target="_top" href="<?php echo Config::get('web_path'); ?>/logout.php">[<?php echo T_('Log out'); ?>]</a></span>
<?php UI::show_box_bottom(); ?> <?php UI::show_box_bottom(); ?>
</div> <!-- End headerbox --> </div> <!-- End headerbox -->
</div><!-- End header --> </div><!-- End header -->

View file

@ -0,0 +1,750 @@
/*
* Skin for jPlayer Plugin (jQuery JavaScript Library)
* http://www.jplayer.org
*
* Skin Name: Midnight Black
*
* Copyright (c) 2010-2012 Happyworm Ltd
* Dual licensed under the MIT and GPL licenses.
* - http://www.opensource.org/licenses/mit-license.php
* - http://www.gnu.org/copyleft/gpl.html
*
* Author: Per Sandström (https://github.com/persand)
* Maintainer: Kasim Ahmic (https://github.com/TheInfection)
* Skin Version: 2.6.3 (jPlayer 2.1.x, 2.2.x, 2.3.x, 2.4.x)
* Date: October 2nd, 2013
*/
body {
background-color: rgb(25, 25, 25);
}
div.jp-area {
margin-left: auto;
margin-right: auto;
width: 500px;
min-width: 500px;
}
a:active, a:focus {
outline: none; /* To keep Google Chrome from adding that ugly yellow border/outlune on buttons when clicked */
}
div.jp-audio,
div.jp-audio-stream,
div.jp-video {
/* Edit the font-size to counteract inherited font sizing.
* Eg. 1.25em = 1 / 0.8em
*/
font-size: 1.25em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */
font-family: 'Verdana', Arial, sans-serif;
line-height: 1.6;
color: #999;
border:1px solid #191919;
background-color: #eee;
}
div.jp-audio {
width: 480px;
}
div.jp-audio-stream {
width: 150px;
}
div.jp-video-270p {
width: 480px;
}
div.jp-video-360p {
width: 640px;
}
div.jp-video-full {
/* Rules for IE6 (full-screen) */
width: 480px;
height: 270px;
/* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
position: static !important;
position: relative;
}
/* The z-index rule is defined in this manner to enable Popcorn plugins that add overlays to video area. EG. Subtitles. */
div.jp-video-full div div {
z-index: 1000;
}
div.jp-video-full div.jp-jplayer {
top: 0;
left: 0;
position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */
overflow: hidden;
}
div.jp-video-full div.jp-gui {
position: fixed !important; position: static; /* Rules for IE6 (full-screen) */
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1001; /* 1 layer above the others. */
}
div.jp-video-full div.jp-interface {
position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */
bottom: 0;
left: 0;
}
div.jp-interface {
position: relative;
background: #191919 url("../modules/jplayer/jplayer.midnight.black.interface.png") repeat-x;
width: 100%;
z-index: 9999;
}
div.jp-audio div.jp-type-single div.jp-interface {
height: 75px;
}
div.jp-audio div.jp-type-playlist div.jp-interface {
height: 70px;
}
div.jp-audio-stream div.jp-type-single div.jp-interface {
height: 50px;
}
div.jp-video div.jp-interface {
border-top: 1px solid #191919;
}
/* @group CONTROLS */
div.jp-controls-holder {
clear: both;
width: 440px;
margin: 0 auto;
position: relative;
overflow: hidden;
top: -8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */
}
div.jp-interface ul.jp-controls {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
}
div.jp-audio ul.jp-controls {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
padding: 0;
}
div.jp-audio-stream ul.jp-controls {
position: absolute;
top: 5px;
left: 5px;
right: 5px;
}
div.jp-video div.jp-type-single ul.jp-controls {
width: 78px;
margin-left: 200px;
}
div.jp-video div.jp-type-playlist ul.jp-controls {
width: 134px;
margin-left: 172px;
}
div.jp-video ul.jp-controls,
div.jp-interface ul.jp-controls li {
display: inline;
float: left;
}
div.jp-interface ul.jp-controls a {
display: block;
overflow: hidden;
text-indent: -9999px;
}
a.jp-play,
a.jp-pause {
width: 40px;
height: 40px;
}
a.jp-play, a.jp-play:hover, a.jp-pause, a.jp-pause:hover, a.jp-stop, a.jp-stop:hover, a.jp-previous, a.jp-previous:hover, a.jp-next, a.jp-next:hover, div.jp-seek-bar, div.jp-play-bar, a.jp-mute, a.jp-mute:hover, a.jp-unmute, a.jp-unmute:hover, a.jp-volume-max, a.jp-volume-max:hover, div.jp-volume-bar, div.jp-audio, div.jp-volume-bar, div.jp-volume-bar-value, a.jp-full-screen, a.jp-full-screen:hover, a.jp-restore-screen, a.jp-restore-screen:hover, a.jp-repeat, a.jp-repeat:hover, a.jp-repeat-off, a.jp-repeat-off:hover, a.jp-shuffle, a.jp-shuffle:hover, a.jp-shuffle-off, a.jp-shuffle-off:hover {
background: url("../modules/jplayer/jplayer.midnight.black.png") no-repeat;
}
a.jp-play {
background-position: 0 0;
}
a.jp-play:hover {
background-position: -41px 0;
}
a.jp-pause {
background-position: 0 -42px;
display: none;
}
a.jp-pause:hover {
background-position: -41px -42px;
}
a.jp-stop, a.jp-previous, a.jp-next {
width: 28px;
height: 28px;
margin-top: 6px;
}
a.jp-stop {
background-position: 0 -83px;
margin-left: 10px;
}
a.jp-stop:hover {
background-position: -29px -83px;
}
a.jp-previous {
background-position: 0 -112px;
}
a.jp-previous:hover {
background-position: -29px -112px;
}
a.jp-next {
background-position: 0 -141px;
}
a.jp-next:hover {
background-position: -29px -141px;
}
/* @end */
/* @group progress bar */
div.jp-progress {
overflow: hidden;
position: absolute;
background: transparent;
}
div.jp-audio div.jp-progress {
top: 27px;
height: 15px;
}
div.jp-audio div.jp-type-single div.jp-progress {
top: 27px;
left: 110px;
right: 112px;
}
div.jp-audio div.jp-type-playlist div.jp-progress {
left: 166px;
right: 179px;
}
div.jp-video div.jp-progress {
top: 0;
left: 0;
width: 100%;
height: 10px;
}
div.jp-seek-bar {
background-repeat: repeat-x;
background-position: 0 -202px;
width: 0;
height: 100%;
cursor: pointer;
border-radius: 5px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.25);
overflow: hidden;
}
div.jp-play-bar {
background-repeat: repeat-x;
background-position: 0 -218px;
width:0;
height:100%;
border-radius: 4px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.25), 2px 0 5px -2px rgba(0,0,0,0.3);
}
div.jp-video div.jp-seek-bar,
div.jp-video div.jp-play-bar {
border-radius: 0;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2);
}
/* The seeking class is added/removed inside jPlayer */
div.jp-seeking-bg {
background: url("jplayer.midnight.black.seeking.gif");
}
/* @end */
/* @group volume controls */
a.jp-mute,
a.jp-unmute,
a.jp-volume-max {
position: absolute;
width:18px;
height:15px;
}
div.jp-audio div.jp-type-single a.jp-mute,
div.jp-audio div.jp-type-single a.jp-unmute {
top: 12px;
right: 66px;
}
div.jp-audio div.jp-type-playlist a.jp-mute,
div.jp-audio div.jp-type-playlist a.jp-unmute {
top: 12px;
right: 133px;
}
div.jp-audio-stream div.jp-type-single a.jp-mute,
div.jp-audio-stream div.jp-type-single a.jp-unmute {
top: 12px;
right: 67px;
}
div.jp-audio-stream div.jp-type-single a.jp-volume-max,
div.jp-audio div.jp-type-single a.jp-volume-max {
top: 12px;
right: 0;
}
div.jp-audio div.jp-type-playlist a.jp-volume-max {
top: 12px;
right: 66px;
}
div.jp-video a.jp-mute,
div.jp-video a.jp-unmute,
div.jp-video a.jp-volume-max {
position: absolute;
top:12px;
}
div.jp-video a.jp-mute,
div.jp-video a.jp-unmute {
left: 50px;
}
div.jp-video a.jp-volume-max {
left: 130px;
}
a.jp-mute {
background-position: 0 -170px;
}
a.jp-mute:hover {
background-position: -19px -170px;
}
a.jp-unmute {
background-position: -39px -170px;
display: none;
}
a.jp-unmute:hover {
background-position: -60px -170px;
}
a.jp-volume-max {
background-position: 0 -186px;
}
a.jp-volume-max:hover {
background-position: -19px -186px;
}
div.jp-volume-bar {
position: absolute;
overflow: hidden;
background-repeat: repeat-x;
background-position: 0 -250px;
width: 45px;
height: 5px;
cursor: pointer;
border-radius: 5px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2);
}
div.jp-audio div.jp-type-single div.jp-volume-bar {
top: 32px;
right: 38px;
}
div.jp-audio div.jp-type-playlist div.jp-volume-bar {
top: 32px;
right: 104px;
}
div.jp-audio-stream div.jp-volume-bar {
top: 22px;
right: 28px;
}
div.jp-video div.jp-volume-bar {
top: 17px;
left: 72px;
}
div.jp-volume-bar-value {
background-repeat: repeat-x;
background-position: 0 -256px;
width: 0;
height: 5px;
border-radius: 5px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.25);
}
/* @end */
/* @group current time and duration */
div.jp-audio div.jp-time-holder {
position: absolute;
top: 45px;
}
div.jp-audio div.jp-type-single div.jp-time-holder {
left: 110px;
right: 112px;
}
div.jp-audio div.jp-type-playlist div.jp-time-holder {
left: 166px;
right: 179px;
}
div.jp-current-time,
div.jp-duration {
width: auto;
font-size: 10px;
font-style: italic;
padding-right: 2px;
}
div.jp-current-time {
float: left;
display: inline;
text-align: left;
padding-left: 2px;
}
div.jp-duration {
float: right;
display: inline;
text-align: right;
}
div.jp-video div.jp-current-time {
margin-top: 10px;
margin-left: 10px;
}
div.jp-video div.jp-duration {
margin-top: 10px;
margin-right: 10px;
}
/* @end */
/* @group playlist */
div.jp-title {
font-weight: bold;
text-align: center;
color: #FFF;
background: #343433 url("../modules/jplayer/jplayer.midnight.black.playlist.png") repeat-x
}
div.playing_info {
position: absolute;
left: 110px;
top: 10px;
font-size: 1.5em;
font-family: 'Verdana',Arial,sans-serif;
color: rgb(153, 153, 153);
width: 300px;
}
div.playing_artist {
font-size:0.5em;
}
div.playing_title {
font-size:0.7em;
}
div.jp-title,
div.jp-playlist {
position: absolute;
top: 0px;
right: 0px;
width: 25%;
height: 95%;
overflow: auto;
/*background-color: #343433;*/
background-color: #202020;
border-top: 1px solid #191919;
text-shadow: 0 1px 0 rgba(0,0,0,0.3);
z-index: 0;
}
div.jp-type-single div.jp-title,
div.jp-type-playlist div.jp-title,
div.jp-type-single div.jp-playlist {
border-top: none;
}
div.jp-title ul,
div.jp-playlist ul {
list-style-type: none;
margin: 0;
padding: 0;
font-size: .62em;
}
div.jp-title li {
padding: 5px 0;
font-weight: bold;
}
div.jp-playlist li {
padding: 6px 15px;
border-bottom: 1px solid #121212;
/*background: #343433 url("../modules/jplayer/jplayer.midnight.black.playlist.png") repeat-x;*/
text-shadow: 0 1px 0 rgba(0,0,0,0.3);
}
div.jp-playlist li div {
display: inline;
}
/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
div.jp-type-playlist div.jp-playlist li:last-child {
border-bottom: none;
}
div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
padding-left: 20px;
}
div.jp-type-playlist div.jp-playlist a {
color: #BBB;
text-decoration: none;
}
div.jp-type-playlist div.jp-playlist a:hover {
color: #FFF;
}
div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
color: #FFF;
font-weight: bold;
}
div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
float: right;
display: inline;
text-align: right;
margin-right: 10px;
font-weight: bold;
color: #666;
}
div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
color: #FFF;
}
div.jp-type-playlist div.jp-playlist span.jp-free-media {
float: right;
display: inline;
text-align: right;
margin-right: 10px;
}
div.jp-type-playlist div.jp-playlist span.jp-free-media a{
color: #666;
}
div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{
color: #FFF;
}
span.jp-artist {
font-size: .8em;
color: #666;
}
/* @end */
div.jp-video-play {
width: 100%;
overflow: hidden; /* Important for nested negative margins to work in modern browsers */
cursor: pointer;
background-color: rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */
}
div.jp-video-270p div.jp-video-play {
margin-top: -270px;
height: 270px;
}
div.jp-video-360p div.jp-video-play {
margin-top: -360px;
height: 360px;
}
div.jp-video-full div.jp-video-play {
height: 100%;
}
a.jp-video-play-icon {
position:relative;
display:block;
width: 112px;
height: 100px;
margin-left: -56px;
margin-top: -50px;
left: 50%;
top: 50%;
background: url("../modules/jplayer/jplayer.midnight.black.video.play.png") 0 0 no-repeat;
text-indent: -9999px;
}
div.jp-video-play:hover a.jp-video-play-icon {
background: url("../modules/jplayer/jplayer.midnight.black.video.play.png") 0 -100px no-repeat;
}
div.jp-jplayer audio,
div.jp-jplayer {
width: 0;
height: 0;
}
div.jp-jplayer {
background-color: #000000;
position: absolute;
top: 10px;
left: 20px;
}
/* @group TOGGLES */
/* The audio toggles are nested inside jp-time-holder */
ul.jp-toggles {
list-style-type: none;
padding: 0;
margin: 0 auto;
overflow: hidden;
}
div.jp-audio .jp-type-single ul.jp-toggles {
width: auto;
position: absolute;
left: 50%;
margin: 0 0 0 -14px;
}
div.jp-audio .jp-type-playlist ul.jp-toggles {
width: auto;
margin: 0;
position: absolute;
right: 15px;
top: 22px;
}
div.jp-video ul.jp-toggles {
width: auto;
position: absolute;
right: 15px;
top: 6px;
}
ul.jp-toggles li {
display: block;
float: right;
}
ul.jp-toggles li a {
display: block;
width: 28px;
height: 28px;
text-indent: -9999px;
line-height: 100%; /* need this for IE6 */
}
a.jp-full-screen {
background-position: 0 -317px;
margin-left: 20px;
}
a.jp-full-screen:hover {
background-position: -30px -317px;
}
a.jp-restore-screen {
background-position: -60px -317px;
margin-left: 20px;
}
a.jp-restore-screen:hover {
background-position: -90px -317px;
}
a.jp-repeat {
background-position: 0 -289px;
}
a.jp-repeat:hover {
background-position: -30px -289px;
}
a.jp-repeat-off {
background-position: -60px -289px;
}
a.jp-repeat-off:hover {
background-position: -90px -289px;
}
a.jp-shuffle {
background-position: 0 -261px;
margin-left: 5px;
}
a.jp-shuffle:hover {
background-position: -30px -261px;
}
a.jp-shuffle-off {
background-position: -60px -261px;
margin-left: 5px;
}
a.jp-shuffle-off:hover {
background-position: -90px -261px;
}
/* @end */
/* @group NO SOLUTION error feedback */
.jp-no-solution {
padding: 5px;
font-size: .67em;
background: #121112 url("../modules/jplayer/jplayer.midnight.black.interface.png") repeat-x;
border-top: 1px solid #191919;
color: #CCC;
display: none;
text-align: center;
}
.jp-no-solution a {
color: #CCC;
}
.jp-no-solution span {
font-size: 1em;
display: block;
text-align: center;
font-weight: bold;
}
.jp-close {
font-size: 0.67em;
text-align: left;
position: absolute;
top: 0;
left: 0;
}
.jp-close a{
color: #CCC;
}
/* @end */

View file

@ -0,0 +1,726 @@
/*
* Skin for jPlayer Plugin (jQuery JavaScript Library)
* http://www.jplayer.org
*
* Skin Name: Midnight Black
*
* Copyright (c) 2010-2012 Happyworm Ltd
* Dual licensed under the MIT and GPL licenses.
* - http://www.opensource.org/licenses/mit-license.php
* - http://www.gnu.org/copyleft/gpl.html
*
* Author: Per Sandström (https://github.com/persand)
* Maintainer: Kasim Ahmic (https://github.com/TheInfection)
* Skin Version: 2.6.3 (jPlayer 2.1.x, 2.2.x, 2.3.x, 2.4.x)
* Date: October 2nd, 2013
*/
div.jp-area {
margin-left: 230px;
margin-right: auto;
margin-top: 10px;
width: 500px;
min-width: 500px;
}
a:active, a:focus {
outline: none; /* To keep Google Chrome from adding that ugly yellow border/outlune on buttons when clicked */
}
div.jp-audio,
div.jp-audio-stream,
div.jp-video {
/* Edit the font-size to counteract inherited font sizing.
* Eg. 1.25em = 1 / 0.8em
*/
font-size: 1.25em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */
font-family: 'Verdana', Arial, sans-serif;
line-height: 1.6;
color: #999;
border:1px solid #191919;
background-color: #eee;
}
div.jp-audio {
width: 480px;
}
div.jp-audio-stream {
width: 150px;
}
div.jp-video-270p {
width: 480px;
}
div.jp-video-360p {
width: 640px;
}
div.jp-video-full {
/* Rules for IE6 (full-screen) */
width: 480px;
height: 270px;
/* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
position: static !important;
position: relative;
}
/* The z-index rule is defined in this manner to enable Popcorn plugins that add overlays to video area. EG. Subtitles. */
div.jp-video-full div div {
z-index: 1000;
}
div.jp-video-full div.jp-jplayer {
top: 0;
left: 0;
position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */
overflow: hidden;
}
div.jp-video-full div.jp-gui {
position: fixed !important; position: static; /* Rules for IE6 (full-screen) */
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1001; /* 1 layer above the others. */
}
div.jp-video-full div.jp-interface {
position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */
bottom: 0;
left: 0;
}
div.jp-interface {
position: relative;
background: #191919 url("../modules/jplayer/jplayer.midnight.black.interface.png") repeat-x;
width: 100%;
}
div.jp-audio div.jp-type-single div.jp-interface {
height: 75px;
}
div.jp-audio div.jp-type-playlist div.jp-interface {
height: 70px;
}
div.jp-audio-stream div.jp-type-single div.jp-interface {
height: 50px;
}
div.jp-video div.jp-interface {
border-top: 1px solid #191919;
}
/* @group CONTROLS */
div.jp-controls-holder {
clear: both;
width: 440px;
margin: 0 auto;
position: relative;
overflow: hidden;
top: -8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */
}
div.jp-interface ul.jp-controls {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
}
div.jp-audio ul.jp-controls {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
padding: 0;
}
div.jp-audio-stream ul.jp-controls {
position: absolute;
top: 5px;
left: 5px;
right: 5px;
}
div.jp-video div.jp-type-single ul.jp-controls {
width: 78px;
margin-left: 200px;
}
div.jp-video div.jp-type-playlist ul.jp-controls {
width: 134px;
margin-left: 172px;
}
div.jp-video ul.jp-controls,
div.jp-interface ul.jp-controls li {
display: inline;
float: left;
}
div.jp-interface ul.jp-controls a {
display: block;
overflow: hidden;
text-indent: -9999px;
}
a.jp-play,
a.jp-pause {
width: 40px;
height: 40px;
}
a.jp-play, a.jp-play:hover, a.jp-pause, a.jp-pause:hover, a.jp-stop, a.jp-stop:hover, a.jp-previous, a.jp-previous:hover, a.jp-next, a.jp-next:hover, div.jp-seek-bar, div.jp-play-bar, a.jp-mute, a.jp-mute:hover, a.jp-unmute, a.jp-unmute:hover, a.jp-volume-max, a.jp-volume-max:hover, div.jp-volume-bar, div.jp-audio, div.jp-volume-bar, div.jp-volume-bar-value, a.jp-full-screen, a.jp-full-screen:hover, a.jp-restore-screen, a.jp-restore-screen:hover, a.jp-repeat, a.jp-repeat:hover, a.jp-repeat-off, a.jp-repeat-off:hover, a.jp-shuffle, a.jp-shuffle:hover, a.jp-shuffle-off, a.jp-shuffle-off:hover {
background: url("../modules/jplayer/jplayer.midnight.black.png") no-repeat;
}
a.jp-play {
background-position: 0 0;
}
a.jp-play:hover {
background-position: -41px 0;
}
a.jp-pause {
background-position: 0 -42px;
display: none;
}
a.jp-pause:hover {
background-position: -41px -42px;
}
a.jp-stop, a.jp-previous, a.jp-next {
width: 28px;
height: 28px;
margin-top: 6px;
}
a.jp-stop {
background-position: 0 -83px;
margin-left: 10px;
}
a.jp-stop:hover {
background-position: -29px -83px;
}
a.jp-previous {
background-position: 0 -112px;
}
a.jp-previous:hover {
background-position: -29px -112px;
}
a.jp-next {
background-position: 0 -141px;
}
a.jp-next:hover {
background-position: -29px -141px;
}
/* @end */
/* @group progress bar */
div.jp-progress {
overflow: hidden;
position: absolute;
background: transparent;
}
div.jp-audio div.jp-progress {
top: 27px;
height: 15px;
}
div.jp-audio div.jp-type-single div.jp-progress {
top: 27px;
left: 110px;
right: 112px;
}
div.jp-audio div.jp-type-playlist div.jp-progress {
left: 166px;
right: 179px;
}
div.jp-video div.jp-progress {
top: 0;
left: 0;
width: 100%;
height: 10px;
}
div.jp-seek-bar {
background-repeat: repeat-x;
background-position: 0 -202px;
width: 0;
height: 100%;
cursor: pointer;
border-radius: 5px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.25);
overflow: hidden;
}
div.jp-play-bar {
background-repeat: repeat-x;
background-position: 0 -218px;
width:0;
height:100%;
border-radius: 4px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.25), 2px 0 5px -2px rgba(0,0,0,0.3);
}
div.jp-video div.jp-seek-bar,
div.jp-video div.jp-play-bar {
border-radius: 0;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2);
}
/* The seeking class is added/removed inside jPlayer */
div.jp-seeking-bg {
background: url("jplayer.midnight.black.seeking.gif");
}
/* @end */
/* @group volume controls */
a.jp-mute,
a.jp-unmute,
a.jp-volume-max {
position: absolute;
width:18px;
height:15px;
}
div.jp-audio div.jp-type-single a.jp-mute,
div.jp-audio div.jp-type-single a.jp-unmute {
top: 12px;
right: 66px;
}
div.jp-audio div.jp-type-playlist a.jp-mute,
div.jp-audio div.jp-type-playlist a.jp-unmute {
top: 12px;
right: 133px;
}
div.jp-audio-stream div.jp-type-single a.jp-mute,
div.jp-audio-stream div.jp-type-single a.jp-unmute {
top: 12px;
right: 67px;
}
div.jp-audio-stream div.jp-type-single a.jp-volume-max,
div.jp-audio div.jp-type-single a.jp-volume-max {
top: 12px;
right: 0;
}
div.jp-audio div.jp-type-playlist a.jp-volume-max {
top: 12px;
right: 66px;
}
div.jp-video a.jp-mute,
div.jp-video a.jp-unmute,
div.jp-video a.jp-volume-max {
position: absolute;
top:12px;
}
div.jp-video a.jp-mute,
div.jp-video a.jp-unmute {
left: 50px;
}
div.jp-video a.jp-volume-max {
left: 130px;
}
a.jp-mute {
background-position: 0 -170px;
}
a.jp-mute:hover {
background-position: -19px -170px;
}
a.jp-unmute {
background-position: -39px -170px;
display: none;
}
a.jp-unmute:hover {
background-position: -60px -170px;
}
a.jp-volume-max {
background-position: 0 -186px;
}
a.jp-volume-max:hover {
background-position: -19px -186px;
}
div.jp-volume-bar {
position: absolute;
overflow: hidden;
background-repeat: repeat-x;
background-position: 0 -250px;
width: 45px;
height: 5px;
cursor: pointer;
border-radius: 5px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2);
}
div.jp-audio div.jp-type-single div.jp-volume-bar {
top: 32px;
right: 38px;
}
div.jp-audio div.jp-type-playlist div.jp-volume-bar {
top: 32px;
right: 104px;
}
div.jp-audio-stream div.jp-volume-bar {
top: 22px;
right: 28px;
}
div.jp-video div.jp-volume-bar {
top: 17px;
left: 72px;
}
div.jp-volume-bar-value {
background-repeat: repeat-x;
background-position: 0 -256px;
width: 0;
height: 5px;
border-radius: 5px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), inset 0 -1px 0 rgba(0,0,0,0.25);
}
/* @end */
/* @group current time and duration */
div.jp-audio div.jp-time-holder {
position: absolute;
top: 45px;
}
div.jp-audio div.jp-type-single div.jp-time-holder {
left: 110px;
right: 112px;
}
div.jp-audio div.jp-type-playlist div.jp-time-holder {
left: 166px;
right: 179px;
}
div.jp-current-time,
div.jp-duration {
width: auto;
font-size: 10px;
font-style: italic;
}
div.jp-current-time {
float: left;
display: inline;
text-align: left;
}
div.jp-duration {
float: right;
display: inline;
text-align: right;
}
div.jp-video div.jp-current-time {
margin-top: 10px;
margin-left: 10px;
}
div.jp-video div.jp-duration {
margin-top: 10px;
margin-right: 10px;
}
/* @end */
/* @group playlist */
div.jp-title {
font-weight: bold;
text-align: center;
color: #FFF;
background: #343433 url("../modules/jplayer/jplayer.midnight.black.playlist.png") repeat-x
}
div.playing_info {
position: absolute;
left: 10px;
top: 220px;
font-size: 1.5em;
font-family: 'Verdana',Arial,sans-serif;
width: 220px;
}
div.playing_artist {
font-size:0.8em;
}
div.playing_title {
font-size:1.1em;
}
div.jp-title,
div.jp-playlist {
width: 100%;
height: 200px;
background-color: #343433;
border-top: 1px solid #191919;
overflow: auto;
text-shadow: 0 1px 0 rgba(0,0,0,0.3);
z-index: 0;
}
div.jp-type-single div.jp-title,
div.jp-type-playlist div.jp-title,
div.jp-type-single div.jp-playlist {
border-top: none;
}
div.jp-title ul,
div.jp-playlist ul {
list-style-type: none;
margin: 0;
padding: 0;
font-size: .62em;
}
div.jp-title li {
padding: 5px 0;
font-weight: bold;
}
div.jp-playlist li {
padding: 6px 15px;
border-bottom: 1px solid #121212;
background: #343433 url("../modules/jplayer/jplayer.midnight.black.playlist.png") repeat-x;
text-shadow: 0 1px 0 rgba(0,0,0,0.3);
}
div.jp-playlist li div {
display: inline;
}
/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
div.jp-type-playlist div.jp-playlist li:last-child {
border-bottom: none;
}
div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
padding-left: 20px;
}
div.jp-type-playlist div.jp-playlist a {
color: #BBB;
text-decoration: none;
}
div.jp-type-playlist div.jp-playlist a:hover {
color: #FFF;
}
div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
color: #FFF;
font-weight: bold;
}
div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
float: right;
display: inline;
text-align: right;
margin-right: 10px;
font-weight: bold;
color: #666;
}
div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
color: #FFF;
}
div.jp-type-playlist div.jp-playlist span.jp-free-media {
float: right;
display: inline;
text-align: right;
margin-right: 10px;
}
div.jp-type-playlist div.jp-playlist span.jp-free-media a{
color: #666;
}
div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{
color: #FFF;
}
span.jp-artist {
font-size: .8em;
color: #666;
}
/* @end */
div.jp-video-play {
width: 100%;
overflow: hidden; /* Important for nested negative margins to work in modern browsers */
cursor: pointer;
background-color: rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */
}
div.jp-video-270p div.jp-video-play {
margin-top: -270px;
height: 270px;
}
div.jp-video-360p div.jp-video-play {
margin-top: -360px;
height: 360px;
}
div.jp-video-full div.jp-video-play {
height: 100%;
}
a.jp-video-play-icon {
position:relative;
display:block;
width: 112px;
height: 100px;
margin-left: -56px;
margin-top: -50px;
left: 50%;
top: 50%;
background: url("../modules/jplayer/jplayer.midnight.black.video.play.png") 0 0 no-repeat;
text-indent: -9999px;
}
div.jp-video-play:hover a.jp-video-play-icon {
background: url("../modules/jplayer/jplayer.midnight.black.video.play.png") 0 -100px no-repeat;
}
div.jp-jplayer audio,
div.jp-jplayer {
width: 0;
height: 0;
}
div.jp-jplayer {
background-color: #000000;
position: absolute;
top: 10px;
left: 10px;
}
/* @group TOGGLES */
/* The audio toggles are nested inside jp-time-holder */
ul.jp-toggles {
list-style-type: none;
padding: 0;
margin: 0 auto;
overflow: hidden;
}
div.jp-audio .jp-type-single ul.jp-toggles {
width: auto;
position: absolute;
left: 50%;
margin: 0 0 0 -14px;
}
div.jp-audio .jp-type-playlist ul.jp-toggles {
width: auto;
margin: 0;
position: absolute;
right: 15px;
top: 22px;
}
div.jp-video ul.jp-toggles {
width: auto;
position: absolute;
right: 15px;
top: 6px;
}
ul.jp-toggles li {
display: block;
float: right;
}
ul.jp-toggles li a {
display: block;
width: 28px;
height: 28px;
text-indent: -9999px;
line-height: 100%; /* need this for IE6 */
}
a.jp-full-screen {
background-position: 0 -317px;
margin-left: 20px;
}
a.jp-full-screen:hover {
background-position: -30px -317px;
}
a.jp-restore-screen {
background-position: -60px -317px;
margin-left: 20px;
}
a.jp-restore-screen:hover {
background-position: -90px -317px;
}
a.jp-repeat {
background-position: 0 -289px;
}
a.jp-repeat:hover {
background-position: -30px -289px;
}
a.jp-repeat-off {
background-position: -60px -289px;
}
a.jp-repeat-off:hover {
background-position: -90px -289px;
}
a.jp-shuffle {
background-position: 0 -261px;
margin-left: 5px;
}
a.jp-shuffle:hover {
background-position: -30px -261px;
}
a.jp-shuffle-off {
background-position: -60px -261px;
margin-left: 5px;
}
a.jp-shuffle-off:hover {
background-position: -90px -261px;
}
/* @end */
/* @group NO SOLUTION error feedback */
.jp-no-solution {
padding: 5px;
font-size: .67em;
background: #121112 url("../modules/jplayer/jplayer.midnight.black.interface.png") repeat-x;
border-top: 1px solid #191919;
color: #CCC;
display: none;
text-align: center;
}
.jp-no-solution a {
color: #CCC;
}
.jp-no-solution span {
font-size: 1em;
display: block;
text-align: center;
font-weight: bold;
}
/* @end */

View file

@ -0,0 +1,57 @@
<?php
/* vim:set softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 2001 - 2013 Ampache.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* 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.
*
*/
if (INIT_LOADED != '1') { exit; }
$web_path = Config::get('web_path');
$htmllang = str_replace("_","-",Config::get('lang'));
$location = get_location();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $htmllang; ?>" lang="<?php echo $htmllang; ?>" dir="<?php echo is_rtl(Config::get('lang')) ? 'rtl' : 'ltr';?>">
<head>
<link rel="shortcut icon" href="<?php echo $web_path; ?>/favicon.ico" />
<link rel="search" type="application/opensearchdescription+xml" title="<?php echo scrub_out(Config::get('site_title')); ?>" href="<?php echo $web_path; ?>/search.php?action=descriptor" />
<?php
if (Config::get('use_rss')) { ?>
<link rel="alternate" type="application/rss+xml" title="<?php echo T_('Now Playing'); ?>" href="<?php echo $web_path; ?>/rss.php" />
<link rel="alternate" type="application/rss+xml" title="<?php echo T_('Recently Played'); ?>" href="<?php echo $web_path; ?>/rss.php?type=recently_played" />
<?php } ?>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=<?php echo Config::get('site_charset'); ?>" />
<title><?php echo scrub_out(Config::get('site_title')); ?> - <?php echo $location['title']; ?></title>
<style type="text/css">
#wrap { position:fixed; left:0; width:100%; top:0; height:100%; }
.frame_main_full { display: block; width:100%; height: 100%; }
.frame_footer_hide { width:100%; height:0%; border:1px solid black; display:none; }
.frame_footer_visible { width:100%; height:100px; border:1px solid black; display:inline; position:fixed; bottom:0; z-index:999999;}
</style>
</head>
<body style="height: 100%;">
<div id="wrap">
<div id="maindiv" style="width:100%; height: 100%;">
<iframe id="frame_main" class="frame_main_full" src="<?php echo $web_path; ?>/index.php?framed=1"></iframe>
</div>
<iframe id="frame_footer" class="frame_footer_hide" src="" sandbox="allow-top-navigation allow-scripts allow-same-origin"></iframe>
</div>
</body>
</html>

View file

@ -35,8 +35,8 @@ $title .= '&nbsp;-&nbsp;' . $album->f_artist_link;
if ($album->name != T_('Unknown (Orphaned)')) { if ($album->name != T_('Unknown (Orphaned)')) {
$name = '[' . $album->f_artist . '] ' . scrub_out($album->full_name); $name = '[' . $album->f_artist . '] ' . scrub_out($album->full_name);
$aa_url = $web_path . "/image.php?id=" . $album->id . "&amp;type=popup&amp;sid=" . session_id(); $aa_url = $web_path . "/image.php?id=" . $album->id . "&amp;sid=" . session_id();
echo "<a target=\"_blank\" href=\"$aa_url\" onclick=\"popupWindow('$aa_url'); return false;\">"; echo "<a href=\"$aa_url\" onClick=\"TINY.box.show({image:'$aa_url',boxid:'frameless',animate:true}); return false;\">";
echo "<img src=\"" . $web_path . "/image.php?id=" . $album->id . "&amp;thumb=2\" alt=\"".$name."\" title=\"".$name."\" height=\"128\" width=\"128\" />"; echo "<img src=\"" . $web_path . "/image.php?id=" . $album->id . "&amp;thumb=2\" alt=\"".$name."\" title=\"".$name."\" height=\"128\" width=\"128\" />";
echo "</a>\n"; echo "</a>\n";
} }

View file

@ -74,7 +74,7 @@ $web_path = Config::get('web_path');
<th class="cel_cover"><?php echo T_('Cover'); ?></th> <th class="cel_cover"><?php echo T_('Cover'); ?></th>
<?php } ?> <?php } ?>
<th class="cel_album"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=name', T_('Album'),'album_sort_name_bottom'); ?></th> <th class="cel_album"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=name', T_('Album'),'album_sort_name_bottom'); ?></th>
<th class="cel_artist"><?php echo T_('Artist'); ?></th> <th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=artist', T_('Artist'),'album_sort_artist'); ?></th>
<th class="cel_songs"><?php echo T_('Songs'); ?></th> <th class="cel_songs"><?php echo T_('Songs'); ?></th>
<th class="cel_year"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=year', T_('Year'),'album_sort_year_bottom'); ?></th> <th class="cel_year"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=year', T_('Year'),'album_sort_year_bottom'); ?></th>
<th class="cel_tags"><?php echo T_('Tags'); ?></th> <th class="cel_tags"><?php echo T_('Tags'); ?></th>

View file

@ -38,7 +38,7 @@ $web_path = Config::get('web_path');
</colgroup> </colgroup>
<tr class="th-top"> <tr class="th-top">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&type=artist&sort=name', T_('Artist'),'artist_sort_name'); ?></th> <th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=artist&sort=name', T_('Artist'),'artist_sort_name'); ?></th>
<th class="cel_songs"><?php echo T_('Songs'); ?></th> <th class="cel_songs"><?php echo T_('Songs'); ?></th>
<th class="cel_albums"><?php echo T_('Albums'); ?></th> <th class="cel_albums"><?php echo T_('Albums'); ?></th>
<th class="cel_time"><?php echo T_('Time'); ?></th> <th class="cel_time"><?php echo T_('Time'); ?></th>
@ -66,7 +66,7 @@ foreach ($object_ids as $artist_id) {
<?php } ?> <?php } ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&type=artist&sort=name', T_('Artist'),'artist_sort_name_bottom'); ?></th> <th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&type=artist&browse_id=' . $browse->id . '&sort=name', T_('Artist'),'artist_sort_name_bottom'); ?></th>
<th class="cel_songs"> <?php echo T_('Songs'); ?> </th> <th class="cel_songs"> <?php echo T_('Songs'); ?> </th>
<th class="cel_albums"> <?php echo T_('Albums'); ?> </th> <th class="cel_albums"> <?php echo T_('Albums'); ?> </th>
<th class="cel_time"> <?php echo T_('Time'); ?> </th> <th class="cel_time"> <?php echo T_('Time'); ?> </th>

View file

@ -23,42 +23,212 @@
header('Cache-Control: no-cache'); header('Cache-Control: no-cache');
header('Pragma: no-cache'); header('Pragma: no-cache');
header('Expires: ' . gmdate(DATE_RFC1123, time()-1)); header('Expires: ' . gmdate(DATE_RFC1123, time()-1));
function browser_info($agent=null) {
// Declare known browsers to look for
$known = array('msie', 'trident', 'firefox', 'safari', 'webkit', 'opera', 'netscape', 'konqueror', 'gecko');
// Clean up agent and build regex that matches phrases for known browsers
// (e.g. "Firefox/2.0" or "MSIE 6.0" (This only matches the major and minor
// version numbers. E.g. "2.0.0.6" is parsed as simply "2.0"
$agent = strtolower($agent ? $agent : $_SERVER['HTTP_USER_AGENT']);
$pattern = '#(?<browser>' . join('|', $known) . ')[/ ]+(?<version>[0-9]+(?:\.[0-9]+)?)#';
// Find all phrases (or return empty array if none found)
if (!preg_match_all($pattern, $agent, $matches)) return array();
// Since some UAs have more than one phrase (e.g Firefox has a Gecko phrase,
// Opera 7,8 have a MSIE phrase), use the last one found (the right-most one
// in the UA). That's usually the most correct.
$i = count($matches['browser'])-1;
return array($matches['browser'][$i] => $matches['version'][$i]);
}
?> ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html> <html>
<head> <head>
<title><?php echo Config::get('site_title'); ?></title> <title><?php echo Config::get('site_title'); ?></title>
<link rel="stylesheet" href="<?php echo Config::get('web_path'); ?>/templates/html5_player.css" type="text/css" media="screen" /> <?php
if ($iframed) {
?>
<link rel="stylesheet" href="<?php echo Config::get('web_path'); ?>/templates/jplayer.midnight.black-iframed.css" type="text/css" />
<?php
} else {
?>
<link rel="stylesheet" href="<?php echo Config::get('web_path'); ?>/templates/jplayer.midnight.black.css" type="text/css" />
<?php require_once Config::get('prefix') . '/templates/stylesheets.inc.php'; ?> <?php require_once Config::get('prefix') . '/templates/stylesheets.inc.php'; ?>
<<<<<<< HEAD
<script src="<?php echo $web_path; ?>/modules/jquery/jquery-1.9.1.js" language="javascript" type="text/javascript"></script> <script src="<?php echo $web_path; ?>/modules/jquery/jquery-1.9.1.js" language="javascript" type="text/javascript"></script>
=======
<?php
}
?>
<script src="<?php echo Config::get('web_path'); ?>/modules/jplayer/jquery.min.js" language="javascript" type="text/javascript"></script>
<script src="<?php echo Config::get('web_path'); ?>/modules/jplayer/jquery.jplayer.min.js" language="javascript" type="text/javascript"></script>
<script src="<?php echo Config::get('web_path'); ?>/modules/jplayer/jplayer.playlist.min.js" language="javascript" type="text/javascript"></script>
>>>>>>> 346b25516d711de989bc3877c6c372439dfa58d3
<script type="text/javascript"> <script type="text/javascript">
var playlist_items={ $(document).ready(function(){
var myPlaylist = new jPlayerPlaylist({
jPlayer: "#jquery_jplayer_1",
cssSelectorAncestor: "#jp_container_1"
}, [
<?php <?php
$i = 0; $i = 0;
$playlist = new Stream_Playlist(scrub_in($_REQUEST['playlist_id'])); $playlist = new Stream_Playlist(scrub_in($_REQUEST['playlist_id']));
$jtypes = array();
foreach($playlist->urls as $item) foreach($playlist->urls as $item)
{ {
echo ($i++ > 0 ? ',' : '') . $i . ': {'; echo ($i++ > 0 ? ',' : '') . '{' . "\n";
foreach(array('id', 'title', 'type', 'album', 'time', 'author', 'info_url') as $member) foreach(array('title', 'author') as $member)
{ {
echo $member . ': "' . addslashes($item->$member) . '",'; if ($member == "author")
$kmember = "artist";
else
$kmember = $member;
echo $kmember . ': "' . addslashes($item->$member) . '",' . "\n";
} }
echo 'play_url: "' . $item->url . '",';
echo 'albumart_url: "' . $item->image_url . '",'; $url = $item->url;
echo 'media_type: "' . $type . '"}'; $browsers = array_keys(browser_info());
if (count($browsers) > 0 ) {
$browser = $browsers[0];
}
if ($browser == "msie" || $browser == "trident" || $browser == "webkit" || $browser == "safari") {
$type = "mp3";
} else {
$type = "ogg";
}
$ftype = "mp3";
$urlinfo = Stream_URL::parse($url);
if ($urlinfo['id']) {
$song = new Song($urlinfo['id']);
$ftype = $song->type;
}
// Check transcode is required
$transcode = false;
if ($type != $ftype) {
$transcode_cfg = Config::get('transcode');
$valid_types = Song::get_stream_types_for_type($ftype);
if ($transcode_cfg != 'never' && in_array('transcode', $valid_types)) {
$transcode = true;
$url .= '&transcode_to=' . $type; // &content_length=required
}
}
if (!$transcode) {
// Transcode not available for this type, keep real type and hope for flash fallback
$type = $ftype;
}
$jtype = ($type == "ogg") ? "oga" : $type;
if (!in_array($jtype, $jtypes)) {
$jtypes[] = $jtype;
}
echo $jtype.': "' . $url;
echo '",' . "\n";
echo 'poster: "' . $item->image_url . (!$iframed ? '&thumb=4' : '') . '" }' . "\n";
} }
?> ?>
}; ], {
playlistOptions: {
autoPlay: true,
loopOnPrevious: false,
shuffleOnLoop: true,
enableRemoveControls: false,
displayTime: 'slow',
addTime: 'fast',
removeTime: 'fast',
shuffleTime: 'slow'
},
swfPath: "<?php echo Config::get('web_path'); ?>/modules/jplayer/",
supplied: "<?php echo join(",", $jtypes); ?>",
audioFullScreen: true,
size: {
<?php
if ($iframed) {
?>
width: "80px",
height: "80px",
<?php
} else {
?>
width: "200px",
height: "auto",
<?php
}
?>
}
});
$("#jquery_jplayer_1").bind($.jPlayer.event.play, function (event) {
var current = myPlaylist.current,
playlist = myPlaylist.playlist;
$.each(playlist, function (index, obj) {
if (index == current) {
$('.playing_title').text(obj.title);
$('.playing_artist').text(obj.artist);
}
});
});
});
</script>
<script language="javascript" type="text/javascript">
function ExitPlayer() {
var ff = parent.parent.document.getElementById('frame_footer');
var maindiv = parent.parent.document.getElementById('maindiv');
if (ff.getAttribute('className') == 'frame_footer_visible') {
ff.setAttribute('className', 'frame_footer_hide');
ff.setAttribute('class', 'frame_footer_hide');
maindiv.style.height = parent.parent.innerHeight + "px";
}
ff.setAttribute('src', '');
return false;
}
</script> </script>
<script src="<?php echo Config::get('web_path'); ?>/lib/javascript/html5_player.js" language="javascript" type="text/javascript"></script>
</head> </head>
<body id="html5_player"> <body>
<div id="player"> <?php
<div id="albumart"></div> if ($iframed) {
<div id="search"> ?>
<input id="input_search" type="text" value="<?php echo T_('search') ?>" accesskey="<?php echo T_dgettext('html5_player_accesskey', 's') ?>"/> <div class="jp-close">
<button id="clear_search"><?php echo T_('clear') ?></button> <a href="javascript:ExitPlayer();" title="Close Player"><img src="images/close.png" border="0" /></a>
</div>
<?php
}
?>
<div class="playing_info">
<div class="playing_artist"></div>
<div class="playing_title"></div>
</div>
<div class="jp-area">
<div id="jquery_jplayer_1" class="jp-jplayer"></div>
<div id="jp_container_1" class="jp-audio">
<div class="jp-type-playlist">
<div class="jp-gui jp-interface">
<ul class="jp-controls">
<li><a href="javascript:;" class="jp-previous" tabindex="1">previous</a></li>
<li><a href="javascript:;" class="jp-play" tabindex="1">play</a></li>
<li><a href="javascript:;" class="jp-pause" tabindex="1">pause</a></li>
<li><a href="javascript:;" class="jp-next" tabindex="1">next</a></li>
<li><a href="javascript:;" class="jp-stop" tabindex="1">stop</a></li>
<li><a href="javascript:;" class="jp-mute" tabindex="1" title="mute">mute</a></li>
<li><a href="javascript:;" class="jp-unmute" tabindex="1" title="unmute">unmute</a></li>
<li><a href="javascript:;" class="jp-volume-max" tabindex="1" title="max volume">max volume</a></li>
</ul>
<div class="jp-progress">
<div class="jp-seek-bar">
<div class="jp-play-bar"></div>
</div>
</div> </div>
<<<<<<< HEAD
<div id="title"><?php echo T_('Loading...') ?></div> <div id="title"><?php echo T_('Loading...') ?></div>
<div id="album"><?php echo T_('Loading...') ?></div> <div id="album"><?php echo T_('Loading...') ?></div>
<div id="artist"><?php echo T_('Loading...') ?></div> <div id="artist"><?php echo T_('Loading...') ?></div>
@ -71,7 +241,31 @@ foreach($playlist->urls as $item)
</div> </div>
<div> <div>
<ul id="playlist"> <ul id="playlist">
=======
<div class="jp-volume-bar">
<div class="jp-volume-bar-value"></div>
</div>
<div class="jp-current-time"></div>
<div class="jp-duration"></div>
<ul class="jp-toggles">
<li><a href="javascript:;" class="jp-shuffle" tabindex="1" title="shuffle">shuffle</a></li>
<li><a href="javascript:;" class="jp-shuffle-off" tabindex="1" title="shuffle off">shuffle off</a></li>
<li><a href="javascript:;" class="jp-repeat" tabindex="1" title="repeat">repeat</a></li>
<li><a href="javascript:;" class="jp-repeat-off" tabindex="1" title="repeat off">repeat off</a></li>
>>>>>>> 346b25516d711de989bc3877c6c372439dfa58d3
</ul> </ul>
</div>
<div class="jp-playlist">
<ul>
<li></li>
</ul>
</div>
<div class="jp-no-solution">
<span>Unsupported</span>
This media is not supported by the player. Is your browser up to date?
</div>
</div> </div>
</div>
</div>
</body> </body>
</html> </html>

View file

@ -35,9 +35,9 @@ $web_path = Config::get('web_path');
</colgroup> </colgroup>
<tr class="th-top"> <tr class="th-top">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_streamname"><?php echo Ajax::text('?page=browse&action=set_sort&sort=name', T_('Name'),'live_stream_sort_name'); ?></th> <th class="cel_streamname"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=name', T_('Name'),'live_stream_sort_name'); ?></th>
<th class="cel_callsign"><?php echo Ajax::text('?page=browse&action=set_sort&sort=call_sign', T_('Callsign'),'live_stream_call_sign'); ?></th> <th class="cel_callsign"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=call_sign', T_('Callsign'),'live_stream_call_sign'); ?></th>
<th class="cel_frequency"><?php echo Ajax::text('?page=browse&action=set_sort&sort=frequency', T_('Frequency'),'live_stream_frequency'); ?></th> <th class="cel_frequency"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=frequency', T_('Frequency'),'live_stream_frequency'); ?></th>
<th class="cel_genre"><?php echo T_('Tag'); ?></th> <th class="cel_genre"><?php echo T_('Tag'); ?></th>
<th class="cel_action"><?php echo T_('Action'); ?> </th> <th class="cel_action"><?php echo T_('Action'); ?> </th>
</tr> </tr>
@ -57,9 +57,9 @@ foreach ($object_ids as $radio_id) {
<?php } ?> <?php } ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_streamname"><?php echo Ajax::text('?page=browse&action=set_sort&sort=name', T_('Name'),'live_stream_sort_name_bottom'); ?></th> <th class="cel_streamname"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=name', T_('Name'),'live_stream_sort_name_bottom'); ?></th>
<th class="cel_callsign"><?php echo Ajax::text('?page=browse&action=set_sort&sort=call_sign', T_('Callsign'),'live_stream_call_sign_bottom'); ?></th> <th class="cel_callsign"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=call_sign', T_('Callsign'),'live_stream_call_sign_bottom'); ?></th>
<th class="cel_frequency"><?php echo Ajax::text('?page=browse&action=set_sort&sort=frequency', T_('Frequency'),'live_stream_frequency_bottom'); ?></th> <th class="cel_frequency"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&sort=frequency', T_('Frequency'),'live_stream_frequency_bottom'); ?></th>
<th class="cel_genre"><?php echo T_('Tag'); ?></th> <th class="cel_genre"><?php echo T_('Tag'); ?></th>
<th class="cel_action"><?php echo T_('Action'); ?> </th> <th class="cel_action"><?php echo T_('Action'); ?> </th>
</tr> </tr>

View file

@ -30,7 +30,7 @@ $artist = scrub_out(UI::truncate($song->f_artist_full));
<div class="np_group"> <div class="np_group">
<?php if (Config::get('show_album_art')) { ?> <?php if (Config::get('show_album_art')) { ?>
<div class="np_cell cel_albumart"> <div class="np_cell cel_albumart">
<a target="_blank" href="<?php echo $web_path; ?>/image.php?id=<?php echo $song->album; ?>&amp;type=popup&amp;sid=<?php echo session_id(); ?>" onclick="popupWindow('<?php echo $web_path; ?>/image.php?id=<?php echo $song->album; ?>&amp;type=popup&amp;sid=<?php echo session_id(); ?>'); return false;"> <a href="<?php echo $web_path; ?>/image.php?id=<?php echo $song->album; ?>&amp;sid=<?php echo session_id(); ?>" onclick="TINY.box.show({image:'<?php echo $web_path; ?>/image.php?id=<?php echo $song->album; ?>&amp;sid=<?php echo session_id(); ?>',boxid:'frameless',animate:true}); return false;">
<img align="middle" src="<?php echo $web_path; ?>/image.php?id=<?php echo $song->album; ?>&amp;thumb=1&amp;sid=<?php echo session_id(); ?>" alt="<?php echo scrub_out($song->f_album_full); ?>" title="<?php echo scrub_out($song->f_album_full); ?>" height="75" width="75" /> <img align="middle" src="<?php echo $web_path; ?>/image.php?id=<?php echo $song->album; ?>&amp;thumb=1&amp;sid=<?php echo session_id(); ?>" alt="<?php echo scrub_out($song->f_album_full); ?>" title="<?php echo scrub_out($song->f_album_full); ?>" height="75" width="75" />
</a> </a>
</div> </div>

View file

@ -71,7 +71,7 @@
<?php if (Art::is_enabled()) { ?> <?php if (Art::is_enabled()) { ?>
<div class="np_group" id="np_group_3"> <div class="np_group" id="np_group_3">
<div class="np_cell cel_albumart"> <div class="np_cell cel_albumart">
<a target="_blank" href="<?php echo $web_path; ?>/image.php?id=<?php echo $media->album; ?>&amp;type=popup" onclick="popupWindow('<?php echo $web_path; ?>/image.php?id=<?php echo $media->album; ?>&amp;type=popup'); return false;"> <a href="<?php echo $web_path; ?>/image.php?id=<?php echo $media->album; ?>" onclick="TINY.box.show({image:'<?php echo $web_path; ?>/image.php?id=<?php echo $media->album; ?>',boxid:'frameless',animate:true}); return false;">
<img align="middle" src="<?php echo $web_path; ?>/image.php?id=<?php echo $media->album; ?>&amp;thumb=1&amp;sid=<?php echo session_id(); ?>" alt="<?php echo scrub_out($media->f_album_full); ?>" title="<?php echo scrub_out($media->f_album_full); ?>" height="80" width="80" /> <img align="middle" src="<?php echo $web_path; ?>/image.php?id=<?php echo $media->album; ?>&amp;thumb=1&amp;sid=<?php echo session_id(); ?>" alt="<?php echo scrub_out($media->f_album_full); ?>" title="<?php echo scrub_out($media->f_album_full); ?>" height="80" width="80" />
</a> </a>
</div> </div>

View file

@ -32,10 +32,10 @@
</colgroup> </colgroup>
<tr class="th-top"> <tr class="th-top">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=name', T_('Playlist Name'),'playlist_sort_name'); ?></th> <th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=playlist&sort=name', T_('Playlist Name'),'playlist_sort_name'); ?></th>
<th class="cel_type">&nbsp;</th> <th class="cel_type">&nbsp;</th>
<th class="cel_songs"><?php echo T_('# Songs'); ?></th> <th class="cel_songs"><?php echo T_('# Songs'); ?></th>
<th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=user', T_('Owner'),'playlist_sort_owner'); ?></th> <th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=playlist&sort=user', T_('Owner'),'playlist_sort_owner'); ?></th>
<th class="cel_action"><?php echo T_('Actions'); ?></th> <th class="cel_action"><?php echo T_('Actions'); ?></th>
</tr> </tr>
<?php <?php
@ -55,10 +55,10 @@ foreach ($object_ids as $playlist_id) {
<?php } ?> <?php } ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=name', T_('Playlist Name'),'playlist_sort_name_bottom'); ?></th> <th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=playlist&sort=name', T_('Playlist Name'),'playlist_sort_name_bottom'); ?></th>
<th class="cel_type">&nbsp;</th> <th class="cel_type">&nbsp;</th>
<th class="cel_songs"><?php echo T_('# Songs'); ?></th> <th class="cel_songs"><?php echo T_('# Songs'); ?></th>
<th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=user', T_('Owner'),'playlist_sort_owner_bottom'); ?></th> <th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=playlist&sort=user', T_('Owner'),'playlist_sort_owner_bottom'); ?></th>
<th class="cel_action"><?php echo T_('Actions'); ?></th> <th class="cel_action"><?php echo T_('Actions'); ?></th>
</tr> </tr>
</table> </table>

View file

@ -32,9 +32,9 @@
</colgroup> </colgroup>
<tr class="th-top"> <tr class="th-top">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&type=smartplaylist&sort=name', T_('Playlist Name'),'playlist_sort_name'); ?></th> <th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=smartplaylist&sort=name', T_('Playlist Name'),'playlist_sort_name'); ?></th>
<th class="cel_type">&nbsp;</th> <th class="cel_type">&nbsp;</th>
<th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&type=smartplaylist&sort=user', T_('Owner'),'playlist_sort_owner'); ?></th> <th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=smartplaylist&sort=user', T_('Owner'),'playlist_sort_owner'); ?></th>
<th class="cel_action"><?php echo T_('Actions'); ?></th> <th class="cel_action"><?php echo T_('Actions'); ?></th>
</tr> </tr>
<?php <?php
@ -53,9 +53,9 @@ foreach ($object_ids as $playlist_id) {
<?php } ?> <?php } ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=name', T_('Playlist Name'),'playlist_sort_name_bottom'); ?></th> <th class="cel_playlist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=playlist&sort=name', T_('Playlist Name'),'playlist_sort_name_bottom'); ?></th>
<th class="cel_type">&nbsp;</th> <th class="cel_type">&nbsp;</th>
<th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&type=playlist&sort=user', T_('Owner'),'playlist_sort_owner_bottom'); ?></th> <th class="cel_owner"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=playlist&sort=user', T_('Owner'),'playlist_sort_owner_bottom'); ?></th>
<th class="cel_action"><?php echo T_('Actions'); ?></th> <th class="cel_action"><?php echo T_('Actions'); ?></th>
</tr> </tr>
</table> </table>

View file

@ -65,12 +65,12 @@ $web_path = Config::get('web_path');
<?php } ?> <?php } ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_song"><?php echo Ajax::text('?page=browse&action=set_sort&type=song&sort=title', T_('Song Title'),'sort_song_title_bottom'); ?></th> <th class="cel_song"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=song&sort=title', T_('Song Title'),'sort_song_title_bottom'); ?></th>
<th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&type=song&sort=artist', T_('Artist'),'sort_song_artist_bottom'); ?></th> <th class="cel_artist"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=song&sort=artist', T_('Artist'),'sort_song_artist_bottom'); ?></th>
<th class="cel_album"><?php echo Ajax::text('?page=browse&action=set_sort&type=song&sort=album', T_('Album'),'sort_song_album_bottom'); ?></th> <th class="cel_album"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=song&sort=album', T_('Album'),'sort_song_album_bottom'); ?></th>
<th class="cel_tags"><?php echo T_('Tags'); ?></th> <th class="cel_tags"><?php echo T_('Tags'); ?></th>
<th class="cel_track"><?php echo Ajax::text('?page=browse&action=set_sort&type=song&sort=track', T_('Track'),'sort_song_track_bottom'); ?></th> <th class="cel_track"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=song&sort=track', T_('Track'),'sort_song_track_bottom'); ?></th>
<th class="cel_time"><?php echo Ajax::text('?page=browse&action=set_sort&type=song&sort=time', T_('Time'),'sort_song_time_bottom'); ?></th> <th class="cel_time"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=song&sort=time', T_('Time'),'sort_song_time_bottom'); ?></th>
<?php if (Config::get('ratings')) { ?> <?php if (Config::get('ratings')) { ?>
<th class="cel_rating"><?php echo T_('Rating'); ?></th> <th class="cel_rating"><?php echo T_('Rating'); ?></th>
<?php } ?> <?php } ?>

View file

@ -37,9 +37,9 @@ $web_path = Config::get('web_path');
<col id="col_online" /> <col id="col_online" />
</colgroup> </colgroup>
<tr class="th-top"> <tr class="th-top">
<th class="cel_username"><?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=fullname', T_('Fullname'),'users_sort_fullname'); ?>( <?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=username', T_('Username'),'users_sort_username');?>)</th> <th class="cel_username"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=user&sort=fullname', T_('Fullname'),'users_sort_fullname'); ?>( <?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=username', T_('Username'),'users_sort_username');?>)</th>
<th class="cel_lastseen"><?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=last_seen', T_('Last Seen'),'users_sort_lastseen'); ?></th> <th class="cel_lastseen"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=user&sort=last_seen', T_('Last Seen'),'users_sort_lastseen'); ?></th>
<th class="cel_registrationdate"><?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=create_date', T_('Registration Date'),'users_sort_createdate'); ?></th> <th class="cel_registrationdate"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=user&sort=create_date', T_('Registration Date'),'users_sort_createdate'); ?></th>
<th class="cel_activity"><?php echo T_('Activity'); ?></th> <th class="cel_activity"><?php echo T_('Activity'); ?></th>
<?php if (Config::get('track_user_ip')) { ?> <?php if (Config::get('track_user_ip')) { ?>
<th class="cel_lastip"><?php echo T_('Last Ip'); ?></th> <th class="cel_lastip"><?php echo T_('Last Ip'); ?></th>
@ -59,9 +59,9 @@ foreach ($object_ids as $user_id) {
</tr> </tr>
<?php } //end foreach users ?> <?php } //end foreach users ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_username"><?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=fullname', T_('Fullname'),'users_sort_fullname1'); ?>( <?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=username', T_('Username'),'users_sort_username1');?>)</th> <th class="cel_username"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=user&sort=fullname', T_('Fullname'),'users_sort_fullname1'); ?>( <?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=username', T_('Username'),'users_sort_username1');?>)</th>
<th class="cel_lastseen"><?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=last_seen', T_('Last Seen'),'users_sort_lastseen1'); ?></th> <th class="cel_lastseen"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=user&sort=last_seen', T_('Last Seen'),'users_sort_lastseen1'); ?></th>
<th class="cel_registrationdate"><?php echo Ajax::text('?page=browse&action=set_sort&type=user&sort=create_date', T_('Registration Date'),'users_sort_createdate1'); ?></th> <th class="cel_registrationdate"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=user&sort=create_date', T_('Registration Date'),'users_sort_createdate1'); ?></th>
<th class="cel_activity"><?php echo T_('Activity'); ?></th> <th class="cel_activity"><?php echo T_('Activity'); ?></th>
<?php if (Config::get('track_user_ip')) { ?> <?php if (Config::get('track_user_ip')) { ?>
<th class="cel_lastip"><?php echo T_('Last Ip'); ?></th> <th class="cel_lastip"><?php echo T_('Last Ip'); ?></th>

View file

@ -35,10 +35,10 @@ $web_path = Config::get('web_path');
</colgroup> </colgroup>
<tr class="th-top"> <tr class="th-top">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_title"><?php echo Ajax::text('?page=browse&action=set_sort&type=video&sort=title', T_('Title'),'sort_video_title'); ?></th> <th class="cel_title"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=title', T_('Title'),'sort_video_title'); ?></th>
<th class="cel_codec"><?php echo Ajax::text('?page=browse&action=set_sort&type=video&sort=codec', T_('Codec'),'sort_video_codec'); ?></th> <th class="cel_codec"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=codec', T_('Codec'),'sort_video_codec'); ?></th>
<th class="cel_resolution"><?php echo Ajax::text('?page=browse&action=set_sort&type=video&sort=resolution', T_('Resolution'),'sort_video_rez'); ?></th> <th class="cel_resolution"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=resolution', T_('Resolution'),'sort_video_rez'); ?></th>
<th class="cel_length"><?php echo Ajax::text('?page=browse&action=set_sort&type=video&sort=length', T_('Time'),'sort_video_length'); ?></th> <th class="cel_length"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=length', T_('Time'),'sort_video_length'); ?></th>
<th class="cel_tags"><?php echo T_('Tags'); ?></th> <th class="cel_tags"><?php echo T_('Tags'); ?></th>
<th class="cel_action"><?php echo T_('Action'); ?></th> <th class="cel_action"><?php echo T_('Action'); ?></th>
</tr> </tr>
@ -59,10 +59,10 @@ foreach ($object_ids as $video_id) {
<?php } ?> <?php } ?>
<tr class="th-bottom"> <tr class="th-bottom">
<th class="cel_add"><?php echo T_('Add'); ?></th> <th class="cel_add"><?php echo T_('Add'); ?></th>
<th class="cel_title"><?php echo T_('Title'); ?></th> <th class="cel_title"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=title', T_('Title'),'sort_video_title'); ?></th>
<th class="cel_codec"><?php echo T_('Codec'); ?></th> <th class="cel_codec"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=codec', T_('Codec'),'sort_video_codec'); ?></th>
<th class="cel_resolution"><?php echo T_('Resolution'); ?></th> <th class="cel_resolution"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=resolution', T_('Resolution'),'sort_video_rez'); ?></th>
<th class="cel_length"><?php echo Ajax::text('?page=browse&action=set_sort&type=video&sort=length', T_('Time'),'sort_video_length_bottom'); ?></th> <th class="cel_length"><?php echo Ajax::text('?page=browse&action=set_sort&browse_id=' . $browse->id . '&type=video&sort=length', T_('Time'),'sort_video_length'); ?></th>
<th class="cel_tags"><?php echo T_('Tags'); ?></th> <th class="cel_tags"><?php echo T_('Tags'); ?></th>
<th class="cel_action"><?php echo T_('Action'); ?></th> <th class="cel_action"><?php echo T_('Action'); ?></th>
</tr> </tr>

View file

@ -57,7 +57,7 @@ $web_path = Config::get('web_path');
} }
?> ?>
<li id="sb_tab_logout" class="sb1"> <li id="sb_tab_logout" class="sb1">
<a href="<?php echo Config::get('web_path'); ?>/logout.php" id="sidebar_logout" > <a target="_top" href="<?php echo Config::get('web_path'); ?>/logout.php" id="sidebar_logout" >
<?php echo UI::get_icon('logout', T_('Logout')); ?> <?php echo UI::get_icon('logout', T_('Logout')); ?>
</a> </a>
</li> </li>

View file

@ -44,7 +44,7 @@
<?php Ajax::end_container(); ?> <?php Ajax::end_container(); ?>
<li><h4><?php echo T_('Playlist'); ?></h4> <li><h4><?php echo T_('Playlist'); ?></h4>
<ul class="sb3" id="sb_home_info"> <ul class="sb3" id="sb_home_info">
<li id="sb_home_info_CurrentlyPlaying"><a href="<?php echo $web_path; ?>/index.php"><?php echo T_('Currently Playing'); ?></a></li> <li id="sb_home_info_CurrentlyPlaying"><a href="<?php echo Config::get('web_path') . ((Config::get('iframes')) ? '/?framed=1' : ''); ?>"><?php echo T_('Currently Playing'); ?></a></li>
<?php if (Config::get('allow_democratic_playback')) { ?> <?php if (Config::get('allow_democratic_playback')) { ?>
<li id="sb_home_democratic_playlist"><a href="<?php echo $web_path; ?>/democratic.php?action=show_playlist"><?php echo T_('Democratic'); ?></a></li> <li id="sb_home_democratic_playlist"><a href="<?php echo $web_path; ?>/democratic.php?action=show_playlist"><?php echo T_('Democratic'); ?></a></li>
<?php } ?> <?php } ?>

View file

@ -33,4 +33,5 @@ if (is_rtl(Config::get('lang'))
<?php <?php
} }
?> ?>
<link rel="stylesheet" href="<?php echo $web_path; ?>/modules/tinybox/tinybox.css" type="text/css" media="screen" />
<link rel="stylesheet" href="<?php echo $web_path; ?>/templates/print.css" type="text/css" media="print" /> <link rel="stylesheet" href="<?php echo $web_path; ?>/templates/print.css" type="text/css" media="print" />

View file

@ -97,7 +97,7 @@ hr {
***********************************************/ ***********************************************/
#maincontainer #maincontainer
{ {
width:1315px; width:100%;
} }
#sidebar #sidebar
@ -109,7 +109,8 @@ hr {
{ {
margin-top:32px; margin-top:32px;
margin-left:160px; margin-left:160px;
width:945px; margin-right:230px;
width:auto;
} }
.box .box
@ -121,16 +122,19 @@ hr {
{ {
width:180px; width:180px;
margin-top:32px; margin-top:32px;
margin-left:1120px; right:10px;
position:absolute; /* Set position to fixed to 'pin' the playlist */
/*position:fixed;*/
position: absolute;
clear:both; clear:both;
} }
#footer #footer
{ {
width: 1100px; width: auto;
margin-top: 20px; margin-top: 20px;
margin-bottom: 120px; margin-bottom: 120px;
margin-right: 230px;
} }
/*********************************************** /***********************************************
@ -141,7 +145,14 @@ hr {
background:#222; background:#222;
line-height:30px; line-height:30px;
height:50px; height:50px;
padding:7px; padding-top:7px;
padding-bottom:7px;
width: 100%;
}
#headerbox
{
margin-right: 7px;
} }
#header .box-inside #header .box-inside
@ -274,6 +285,16 @@ hr {
width: 115px; width: 115px;
} }
#sidebar-tabs #catalog_select
{
width:130px;
}
/* Localplay */
.active_instance {
border: 1px inset #99ccff;
}
/*********************************************** /***********************************************
Rightbar Rightbar
***********************************************/ ***********************************************/
@ -1027,6 +1048,7 @@ ins,#rightbar a
#header #headerlogo #header #headerlogo
{ {
float:left; float:left;
margin-left: 7px;
} }
#header .box-inside div,#header .box-inside form,#rightbar #rb_action li,.star-rating li #header .box-inside div,#header .box-inside form,#rightbar #rb_action li,.star-rating li