diff options
author | Holger Brunn <opensource@holgerbrunn.net> | 2013-01-24 16:13:17 -0500 |
---|---|---|
committer | Paul Arthur <paul.arthur@flowerysong.com> | 2013-01-28 13:26:11 -0500 |
commit | 959aebe07fffe334bf3dc3f2bfcf9c5e77fad92a (patch) | |
tree | e38e598eb859fdb906d8055c4d2724a62e854c0e | |
parent | 499aef74145a32db8c73aeacb9c5d2dd5da40771 (diff) | |
download | ampache-959aebe07fffe334bf3dc3f2bfcf9c5e77fad92a.tar.gz ampache-959aebe07fffe334bf3dc3f2bfcf9c5e77fad92a.tar.bz2 ampache-959aebe07fffe334bf3dc3f2bfcf9c5e77fad92a.zip |
Add an HTML5 player
Merge request #20. Basic, not very pretty, but works and, unlike the
Flash player, is maintainable.
-rwxr-xr-x | docs/CHANGELOG | 1 | ||||
-rw-r--r-- | html5_player.php | 33 | ||||
-rw-r--r-- | lib/class/stream.class.php | 4 | ||||
-rw-r--r-- | lib/class/stream_playlist.class.php | 12 | ||||
-rw-r--r-- | lib/javascript/html5_player.js | 204 | ||||
-rw-r--r-- | lib/preferences.php | 3 | ||||
-rw-r--r-- | play/index.php | 11 | ||||
-rw-r--r-- | server/stream.ajax.php | 1 | ||||
-rw-r--r-- | templates/create_html5_player.inc.php | 39 | ||||
-rw-r--r-- | templates/show_html5_player.inc.php | 76 | ||||
-rw-r--r-- | templates/show_playtype_switch.inc.php | 1 | ||||
-rw-r--r-- | themes/classic/templates/default.css | 66 | ||||
-rw-r--r-- | themes/fresh/templates/default.css | 66 |
13 files changed, 509 insertions, 8 deletions
diff --git a/docs/CHANGELOG b/docs/CHANGELOG index 684edf8d..aedf7c9d 100755 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -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) diff --git a/html5_player.php b/html5_player.php new file mode 100644 index 00000000..d740f15a --- /dev/null +++ b/html5_player.php @@ -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 + + +?> diff --git a/lib/class/stream.class.php b/lib/class/stream.class.php index 338898a2..7304891c 100644 --- a/lib/class/stream.class.php +++ b/lib/class/stream.class.php @@ -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); diff --git a/lib/class/stream_playlist.class.php b/lib/class/stream_playlist.class.php index 6d85f8f0..1f8b4b88 100644 --- a/lib/class/stream_playlist.class.php +++ b/lib/class/stream_playlist.class.php @@ -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); @@ -396,6 +397,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 - } - ?> diff --git a/lib/javascript/html5_player.js b/lib/javascript/html5_player.js new file mode 100644 index 00000000..4bed561c --- /dev/null +++ b/lib/javascript/html5_player.js @@ -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') + }); +}); diff --git a/lib/preferences.php b/lib/preferences.php index 6fe5c178..eeef5646 100644 --- a/lib/preferences.php +++ b/lib/preferences.php @@ -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"; diff --git a/play/index.php b/play/index.php index 498b7a2d..9c22f909 100644 --- a/play/index.php +++ b/play/index.php @@ -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']; } diff --git a/server/stream.ajax.php b/server/stream.ajax.php index c08d6cb3..1ad0b237 100644 --- a/server/stream.ajax.php +++ b/server/stream.ajax.php @@ -45,6 +45,7 @@ switch ($_REQUEST['action']) { $new = $_POST['type']; break; case 'xspf_player': + case 'html5_player': $new = $_POST['type']; // Rien a faire break; diff --git a/templates/create_html5_player.inc.php b/templates/create_html5_player.inc.php new file mode 100644 index 00000000..de3e036c --- /dev/null +++ b/templates/create_html5_player.inc.php @@ -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> diff --git a/templates/show_html5_player.inc.php b/templates/show_html5_player.inc.php new file mode 100644 index 00000000..505909b2 --- /dev/null +++ b/templates/show_html5_player.inc.php @@ -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> diff --git a/templates/show_playtype_switch.inc.php b/templates/show_playtype_switch.inc.php index e2bf8f11..ce30bac2 100644 --- a/templates/show_playtype_switch.inc.php +++ b/templates/show_playtype_switch.inc.php @@ -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> diff --git a/themes/classic/templates/default.css b/themes/classic/templates/default.css index f65e984c..c9e7592c 100644 --- a/themes/classic/templates/default.css +++ b/themes/classic/templates/default.css @@ -696,6 +696,71 @@ td.lp_current a { }
/************************************************/
+/* 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 */
/************************************************/
#loginPage #maincontainer{
@@ -863,3 +928,4 @@ textarea:focus{ color: #c0c0c0;
}
+
diff --git a/themes/fresh/templates/default.css b/themes/fresh/templates/default.css index 89ef4cb5..4ab2b2b2 100644 --- a/themes/fresh/templates/default.css +++ b/themes/fresh/templates/default.css @@ -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
***********************************************/
|