1
0
Fork 0
mirror of https://github.com/Yetangitu/ampache synced 2025-10-03 17:59:21 +02:00

Add an HTML5 player

Merge request #20.  Basic, not very pretty, but works and, unlike the
Flash player, is maintainable.
This commit is contained in:
Holger Brunn 2013-01-24 16:13:17 -05:00 committed by Paul Arthur
parent 499aef7414
commit 959aebe07f
13 changed files with 509 additions and 8 deletions

View file

@ -4,6 +4,7 @@
--------------------------------------------------------------------------
v.3.6-FUTURE
- Added an HTML5 player (patch by Holger Brunn)
- Changed the way themes handle RTL languages
- Fixed a display problem with the Penguin theme by adding a new CSS class
(patch by Fred Thomsen)

33
html5_player.php Normal file
View file

@ -0,0 +1,33 @@
<?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.
*
*/
require_once 'lib/init.php';
// Switch on actions
switch ($_REQUEST['action']) {
default:
require_once Config::get('prefix') . '/templates/show_html5_player.inc.php';
break;
} // end switch
?>

View file

@ -144,8 +144,8 @@ class Stream {
* 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) {
$transcode_settings = $song->get_transcode_settings();
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);

View file

@ -160,6 +160,7 @@ class Stream_Playlist {
case 'democratic':
case 'localplay':
case 'xspf_player':
case 'html5_player':
// These are valid, but witchy
$redirect = false;
unset($ext);
@ -395,6 +396,15 @@ class Stream_Playlist {
}
} // create_xspf_player
/**
* create_html5_player
*
* Creates an html5 player.
*/
public function create_html5_player() {
require Config::get('prefix') . '/templates/create_html5_player.inc.php';
}
/**
* create_localplay
* This calls the Localplay API to add the URLs and then start playback
@ -450,7 +460,5 @@ class Stream_Playlist {
echo $url->url . "\n";
}
} // create_ram
}
?>

View file

@ -0,0 +1,204 @@
/* vim:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 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.
*
*/
var current_playlist_item = null;
function play_item(event)
{
stop();
current_playlist_item = event.findElement().getStorage().get('playlist_item');
play();
}
function adjust_buttons()
{
if(!current_playlist_item.player.paused)
{
$('play').addClassName('inactive');
$('pause').removeClassName('inactive');
$('stop').removeClassName('inactive');
}
else
{
$('play').removeClassName('inactive');
$('pause').addClassName('inactive');
$('stop').addClassName('inactive');
}
}
function stop(event)
{
if(current_playlist_item)
{
current_playlist_item.player.pause();
current_playlist_item.player.currentTime = 0;
if(current_playlist_item.player.currentTime)
{
var src=current_playlist_item.player.src;
current_playlist_item.player.src=null;
current_playlist_item.player.src=src;
}
current_playlist_item.element.removeClassName('playing');
adjust_buttons();
}
}
function pause(event)
{
if(current_playlist_item)
{
current_playlist_item.player.pause();
adjust_buttons();
}
}
function play(event)
{
if(current_playlist_item)
{
$('title').update(current_playlist_item.info_url);
$('title').select('a')[0].writeAttribute('target', '_new');
$('album').update(current_playlist_item.f_album_link);
//$('album').select('a')[0].writeAttribute('target', '_new');
$('artist').update(current_playlist_item.author);
//$('artist').select('a')[0].writeAttribute('target', '_new');
$('albumart').update(new Element('img', {src: current_playlist_item.albumart_url}));
current_playlist_item.player.writeAttribute('preload', 'auto');
current_playlist_item.player.play();
if(current_playlist_item.element.offsetTop - $('playlist').offsetTop - $('playlist').scrollTop > $('playlist').measure('height') || current_playlist_item.element.offsetTop - $('playlist').offsetTop - $('playlist').scrollTop < 0)
{
$('playlist').scrollTop = current_playlist_item.element.offsetTop - $('playlist').offsetTop;
}
current_playlist_item.element.addClassName('playing');
adjust_buttons();
}
}
function next(event)
{
if(current_playlist_item && current_playlist_item.next)
{
stop();
current_playlist_item = current_playlist_item.next;
play();
}
}
function previous(event)
{
if(current_playlist_item && current_playlist_item.previous)
{
stop();
current_playlist_item = current_playlist_item.previous;
play();
}
}
function seconds_to_string(seconds)
{
return Math.floor(seconds / 60) + ":" + (Math.floor(seconds % 60) < 10 ? '0' : '') + Math.floor(seconds % 60);
}
function timeupdate(event)
{
if(current_playlist_item)
{
$('progress_text').update(seconds_to_string(current_playlist_item.player.currentTime) + "/" + seconds_to_string(current_playlist_item.time));
if(current_playlist_item.player.currentTime > current_playlist_item.time / 2)
{
if(current_playlist_item.next)
{
current_playlist_item.next.player.writeAttribute('preload', 'auto');
}
}
//fix for chrome where ended is not thrown properly
if(current_playlist_item.player.currentTime >= current_playlist_item.time)
{
ended(event);
}
}
}
function ended(event)
{
if(current_playlist_item && current_playlist_item.next)
{
stop();
current_playlist_item = current_playlist_item.next;
play();
}
}
function search(event)
{
var search = new RegExp(".*" + event.findElement().value + ".*", "i");
for(var item = $('playlist').firstDescendant(); item; item = item.next())
{
if(!search.test(item.textContent != undefined ? item.textContent : item.innerText))
{
item.hide();
}
else
{
item.show();
}
}
}
function clear_search(event)
{
event.findElement().value = "";
search(event);
}
document.observe("dom:loaded", function()
{
var last_item = null, first_item = null;
for(id in playlist_items)
{
var li = new Element('li');
$('playlist').insert(li);
playlist_items[id].play_url += '&transcode_to=' + (Prototype.Browser.IE || Prototype.Browser.WebKit || Prototype.Browser.MobileSafari ? 'mp3' : 'ogg');
li.update(playlist_items[id].title);
playlist_items[id].player = new Element("audio", {preload: Prototype.Browser.IE ? 'auto' : 'none', src : playlist_items[id].play_url});
li.insert(playlist_items[id].player);
li.getStorage().set('playlist_item', playlist_items[id]);
li.observe('click', play_item);
playlist_items[id].player.observe('ended', ended);
playlist_items[id].player.observe('timeupdate', timeupdate);
playlist_items[id].element = li;
if(last_item)
{
last_item.next = playlist_items[id];
}
if(first_item == null)
{
first_item = playlist_items[id];
}
playlist_items[id].previous = last_item;
last_item = playlist_items[id];
}
if(first_item)
{
first_item.previous = last_item;
last_item.next = first_item;
current_playlist_item = first_item;
play();
}
$('stop').observe('click', stop);
$('play').observe('click', play);
$('pause').observe('click', pause);
$('next').observe('click', next);
$('previous').observe('click', previous);
$('input_search').observe('keyup', search);
$('input_search').observe('html5_player:clear_search', clear_search);
$('input_search').observe('focus', clear_search);
$('clear_search').observe('click', function() {
$('input_search').fire('html5_player:clear_search')
});
});

View file

@ -178,6 +178,7 @@ function create_preference_input($name,$value) {
if ($value == 'localplay') { $is_local = 'selected="selected"'; }
elseif ($value == 'democratic') { $is_vote = 'selected="selected"'; }
elseif ($value == 'xspf_player') { $is_xspf_player = 'selected="selected"'; }
elseif ($value == 'html5_player') { $is_html5_player = 'selected="selected"'; }
else { $is_stream = "selected=\"selected\""; }
echo "<select name=\"$name\">\n";
echo "\t<option value=\"\">" . T_('None') . "</option>\n";
@ -191,6 +192,7 @@ function create_preference_input($name,$value) {
echo "\t<option value=\"localplay\" $is_local>" . T_('Localplay') . "</option>\n";
}
echo "\t<option value=\"xspf_player\" $is_xspf_player>" . T_('Flash Player') . "</option>\n";
echo "\t<option value=\"html5_player\" $is_html5_player>" . _('HTML5 Player') . "</option>\n";
echo "</select>\n";
break;
case 'playlist_type':
@ -210,7 +212,6 @@ function create_preference_input($name,$value) {
echo '<select name="' . $name . '">' . "\n";
foreach ($languages as $lang=>$name) {
$selected = ($lang == $value) ? 'selected="selected"' : '';
echo "\t<option value=\"$lang\" " . $selected . ">$name</option>\n";
} // end foreach
echo "</select>\n";

View file

@ -41,6 +41,7 @@ $sid = scrub_in($_REQUEST['ssid']);
$xml_rpc = scrub_in($_REQUEST['xml_rpc']);
$video = make_bool($_REQUEST['video']);
$type = scrub_in($_REQUEST['type']);
$transcode_to = scrub_in($_REQUEST['transcode_to']);
if ($type == 'playlist') {
$playlist_type = scrub_in($_REQUEST['playlist_type']);
@ -314,9 +315,15 @@ if (Config::get('downsample_remote')) {
// Determine whether to transcode
$transcode = false;
$transcode_cfg = Config::get('transcode');
// transcode_to should only have an effect if the song is the wrong format
$transcode_to = $transcode_to == $media->type ? null : $transcode_to;
$valid_types = $media->get_stream_types();
if ($transcode_cfg != 'never' && in_array('transcode', $valid_types)) {
if ($transcode_cfg == 'always') {
if ($transcode_to) {
$transcode = true;
debug_event('play', 'Transcoding due to explicit request for ' . $transcode_to, 5);
}
else if ($transcode_cfg == 'always') {
$transcode = true;
debug_event('play', 'Transcoding due to always', 5);
}
@ -335,7 +342,7 @@ if ($transcode_cfg != 'never' && in_array('transcode', $valid_types)) {
if ($transcode) {
header('Accept-Ranges: none');
$transcoder = Stream::start_transcode($media);
$transcoder = Stream::start_transcode($media, $transcode_to);
$fp = $transcoder['handle'];
$media_name = $media->f_artist_full . " - " . $media->title . "." . $transcoder['format'];
}

View file

@ -45,6 +45,7 @@ switch ($_REQUEST['action']) {
$new = $_POST['type'];
break;
case 'xspf_player':
case 'html5_player':
$new = $_POST['type'];
// Rien a faire
break;

View file

@ -0,0 +1,39 @@
<?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">
<!-- begin
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.location = '<?php echo return_referer() ?>';
return false;
}
// end -->
</script>
</head>
<body onLoad="javascript:PlayerPopUp('<?php echo Config::get('web_path')?>/html5_player.php<?php echo '?playlist_id=' . $this->id ?>')">
</body>
</html>

View file

@ -0,0 +1,76 @@
<?php
/* vim:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */
/**
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright 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.
*
*/
header('Cache-Control: no-cache');
header('Pragma: no-cache');
header('Expires: ' . gmdate(DATE_RFC1123, time()-1));
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<title><?php echo Config::get('site_title'); ?></title>
<link rel="stylesheet" href="<?php echo Config::get('web_path').Config::get('theme_path').'/templates/'.'default.css'; ?>" type="text/css" media="screen" />
<script src="<?php echo Config::get('web_path'); ?>/modules/prototype/prototype.js" language="javascript" type="text/javascript"></script>
<script type="text/javascript">
var playlist_items={
<?php
$i = 0;
$playlist = new Stream_Playlist(scrub_in($_REQUEST['playlist_id']));
foreach($playlist->urls as $item)
{
echo ($i++ > 0 ? ',' : '') . $i . ': {';
foreach(array('id', 'title', 'type', 'album', 'time', 'author', 'info_url') as $member)
{
echo $member . ': "' . addslashes($item->$member) . '",';
}
echo 'play_url: "' . $item->url . '",';
echo 'albumart_url: "' . $item->image_url . '",';
echo 'media_type: "' . $type . '"}';
}
?>
};
</script>
<script src="<?php echo Config::get('web_path'); ?>/lib/javascript/html5_player.js" language="javascript" type="text/javascript"></script>
</head>
<body id="html5_player">
<div id="player">
<div id="albumart"></div>
<div id="search">
<input id="input_search" type="text" value="<?php echo T_('search') ?>"/>
<div id="clear_search"><?php echo T_('clear') ?></div>
</div>
<div id="title"><?php echo T_('Loading...') ?></div>
<div id="album"><?php echo T_('Loading...') ?></div>
<div id="artist"><?php echo T_('Loading...') ?></div>
<div id="progress_text"><?php echo T_('Loading...') ?></div>
<div id="stop"><?php echo T_('Stop') ?></div>
<div id="play"><?php echo T_('Play') ?></div>
<div id="pause"><?php echo T_('Pause') ?></div>
<div id="previous"><?php echo T_('Previous') ?></div>
<div id="next"><?php echo T_('Next') ?></div>
</div>
<div>
<ul id="playlist">
</ul>
</div>
</body>
</html>

View file

@ -37,6 +37,7 @@ if (Preference::has_access('play_type')) {
<option value="democratic" <?php echo $is_democratic; ?>><?php echo T_('Democratic'); ?></option>
<?php } ?>
<option value="xspf_player" <?php echo $is_xspf_player; ?>><?php echo T_('Flash Player'); ?></option>
<option value="html5_player" <?php echo $is_html5_player; ?>><?php echo _('HTML5 Player'); ?></option>
</select>
<?php echo Ajax::observe('play_type_select','change',Ajax::action('?page=stream&action=set_play_type','play_type_select','play_type_form'),'1'); ?>
</form>

View file

@ -695,6 +695,71 @@ td.lp_current a {
text-decoration:none;
}
/************************************************/
/* HTML5 Player */
/************************************************/
#html5_player #albumart img
{
width: 200px;
float: left;
margin: 5px;
}
#html5_player #title
{
padding-top: 5px;
}
#html5_player #artist, #html5_player #album
{
display: inline;
}
#html5_player #artist:before
{
content: ' by ';
}
#html5_player #progress_text
{
margin: 10px 0px 10px 0px;
}
#html5_player #stop, #html5_player #play,#html5_player #pause,#html5_player #next,#html5_player #previous,#html5_player #clear_search
{
display: inline;
border: thin solid black;
cursor: pointer;
padding: 2px;
margin-right: 5px;
}
#html5_player #playlist
{
overflow-x: hidden;
overflow-y: scroll;
position: absolute;
top: 105px;
left: 210px;
right: 5px;
bottom: 5px;
}
#html5_player #playlist li
{
cursor: pointer;
}
#html5_player #playlist li.playing
{
font-weight: bold;
}
#html5_player #stop.inactive, #html5_player #pause.inactive, #html5_player #play.inactive
{
display: none;
}
#html5_player #search
{
top: 54px;
right: 5px;
position: absolute;
}
#html5_player #search input
{
background: transparent;
}
/************************************************/
/* Styles for Login template */
/************************************************/
@ -863,3 +928,4 @@ textarea:focus{
color: #c0c0c0;
}

View file

@ -993,7 +993,71 @@ table.tabledata .cel_php_setting, table.tabledata .cel_configuration, .cel_prefe
width: 200px;
}
/************************************************/
/* HTML5 Player */
/************************************************/
#html5_player #albumart img
{
width: 200px;
float: left;
margin: 5px;
}
#html5_player #title
{
padding-top: 5px;
}
#html5_player #artist, #html5_player #album
{
display: inline;
}
#html5_player #artist:before
{
content: ' by ';
}
#html5_player #progress_text
{
margin: 10px 0px 10px 0px;
}
#html5_player #stop, #html5_player #play,#html5_player #pause,#html5_player #next,#html5_player #previous,#html5_player #clear_search
{
display: inline;
border: thin solid black;
cursor: pointer;
padding: 2px;
margin-right: 5px;
}
#html5_player #playlist
{
overflow-x: hidden;
overflow-y: scroll;
position: absolute;
top: 85px;
left: 210px;
right: 5px;
bottom: 5px;
}
#html5_player #playlist li
{
cursor: pointer;
}
#html5_player #playlist li.playing
{
font-weight: bold;
}
#html5_player #stop.inactive, #html5_player #pause.inactive, #html5_player #play.inactive
{
display: none;
}
#html5_player #search
{
top: 56px;
right: 5px;
position: absolute;
}
#html5_player #search input
{
background: transparent;
}
/***********************************************
Other
***********************************************/