Files
html5-music-player/index.html

673 lines
15 KiB
HTML

<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<title>dtam music playlist - HTML5 Player</title>
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.min.js"></script>
<script>
var g_playlist = null;
var g_previous = [];
var g_previous_idx = 0;
var g_current = -1;
var g_looping = false;
var g_shuffle = true;
var MAX_HISTORY = 10;
var scrubp = 0;
var is_dragging_scrubber = false;
var PLAYLISTS = {
'weeb': '//dtam.pw/music/main_parsed.xml',
'VIP': '//vip.aersia.net/roster.xml',
};
var DEFAULT_PLAYLIST = 'weeb';
function formatTimecode (seconds) {
seconds = Math.floor (seconds);
minutes = Math.floor (seconds / 60);
seconds = seconds - (minutes * 60);
minutes = "" + minutes;
seconds = "" + seconds;
if (minutes.length == 1)
minutes = "0" + minutes;
if (seconds.length == 1)
seconds = "0" + seconds;
return minutes + ":" + seconds;
}
// Creates an id for a track used in the location hash
function createTrackId (track) {
var playlist = $('#select-playlist').val ();
var track = track.creator + ' - ' + track.title;
track = track.replace(/[^a-zA-Z0-9-]/g, '_');
return encodeURIComponent (playlist) + ':' + track;
}
function parseTrackId (trackId) {
var pieces = trackId.split (':');
var playlist = '';
var track = '';
if (pieces.length < 2) {
playlist = decodeURIComponent (trackId);
track = '';
} else {
pieces.pop ();
playlist = decodeURIComponent (pieces.join (':'));
track = trackId;
}
if (!(playlist in PLAYLISTS))
return null;
return {
playlist: playlist,
track: track
};
}
function parsePlaylist (playlistXML) {
result = [];
$(playlistXML).find ('playlist trackList > track').each (function () {
track = {
creator: $(this).find ('creator').text (),
title: $(this).find ('title').text (),
location: $(this).find ('location').text ()
};
result.push (track);
});
return result;
}
function playPreviousTrack () {
if (g_playlist === null)
return;
if (g_previous_idx <= 0)
g_previous_idx = 0;
else
g_previous_idx -= 1;
playTrack (g_previous[g_previous_idx]);
}
function playNextTrack () {
if (g_playlist === null)
return;
if (g_previous_idx >= (g_previous.length - 1)) {
if (g_shuffle) {
g_current = Math.floor (Math.random () * g_playlist.length);
}
else {
g_current += 1;
}
g_previous.push (g_current);
g_previous_idx = g_previous.length - 1;
}
else {
g_previous_idx += 1;
}
while (g_previous.length > MAX_HISTORY) {
g_previous.shift ();
g_previous_idx -= 1;
}
playTrack (g_previous[g_previous_idx]);
}
function playTrack (trackid) {
var track = g_playlist[trackid];
$('#tracks-table .selected').removeClass ('selected');
var trackelem = $('#tracks-table div').eq (trackid);
trackelem.addClass ('selected');
window.location.hash = createTrackId (track);
$('audio').attr ('src', track.location);
$('audio').trigger ('play');
$('html, body').stop ().animate ({
scrollTop: trackelem.offset ().top - $('.control-bar').height ()
}, 1000);
g_current = trackid;
localStorage['current'] = g_current;
}
function loadNewPlaylist (playlist, track) {
var playlistURL = PLAYLISTS[playlist];
var selected_track = track;
localStorage['playlist'] = playlist;
$('#select-playlist').val (playlist);
// Clear
$('#tracks-table div').remove ();
g_previous = [];
g_previous_idx = 0;
g_playlist = null;
$.ajax({
url: playlistURL,
success: function (data) {
// Parse track list
g_playlist = parsePlaylist (data);
// Build HTML table for track listing
for (var i = 0; i < g_playlist.length; ++i) {
var track = g_playlist[i];
var row = $('<div>');
row.text (track.creator + ' - ' + track.title);
row.attr ('id', createTrackId (track));
row.appendTo ('#tracks-table');
(function (i) {
row.click (function () {
playTrack (i);
});
}) (i);
}
// Select specified track if possible, or play random track if not.
var elements = $('#tracks-table div').filter (function (idx, elem) {
return elem.id == selected_track;
});
if (elements.length > 0) {
elements[0].click ();
} else {
if (g_current === -1) {
g_current = Math.floor (Math.random () * g_playlist.length);
}
playNextTrack ();
}
}
});
};
function playpause () {
if ($('audio').get (0).paused)
$('audio').trigger ('play');
else
$('audio').trigger ('pause');
}
function toggleLooping () {
g_looping = !g_looping;
$('audio').attr ('loop', g_looping);
$('#btn-loop i').toggleClass('fa-times', g_looping);
$('#btn-loop i').toggleClass('fa-repeat', !g_looping);
}
function toggleShuffle () {
g_shuffle = !g_shuffle;
toggleShuffleColor();
localStorage['shuffle'] = g_shuffle;
}
function toggleShuffleColor() {
if (g_shuffle) {
$('#btn-shuffle').css('color', '#FF9148');
$('#btn-shuffle').hover(function(e) {
$(this).css("color",e.type === "mouseenter"?"#4e91ff":"#FF9148")
});
}
else {
$('#btn-shuffle').css('color', '#808080');
$('#btn-shuffle').hover(function(e) {
$(this).css("color",e.type === "mouseenter"?"#4e91ff":"#808080")
});
}
}
function populatePlaylistOptions () {
for (var name in PLAYLISTS) {
var option = $("<option>");
option.val (name);
option.text (name);
$('#select-playlist').append (option);
}
}
$(function () {
// Register Events
$('audio').on ('pause', function () {
$('#btn-play i').removeClass ('fa-pause');
$('#btn-play i').addClass ('fa-play');
});
$('audio').on ('play', function () {
$('#btn-play i').removeClass ('fa-play');
$('#btn-play i').addClass ('fa-pause');
});
$('audio').on ('error', function () {
playNextTrack ();
});
$('audio').on ('timeupdate', function () {
if (isNaN (this.duration))
return;
if (!is_dragging_scrubber)
$('#scrubber-progress').css('width', (this.currentTime / this.duration) * 100+'%');
$('#time-current').text (formatTimecode (this.currentTime));
$('#time-remaining').text (formatTimecode (this.duration - this.currentTime));
});
$('#time-bar').on('mousedown mouseup', function(e) {
if (e.which == 1) {
is_dragging_scrubber = true;
var sc_w = $('#scrubber-track').outerWidth();
var p = ((e.pageX - $('#scrubber-track').offset().left) / sc_w) * 100;
$('#scrubber-progress').css('width', p+'%');
scrubp = p;
$(document).on('mousemove.scrubber-track', function(e) {
sc_w = $('#scrubber-track').outerWidth();
p = ((e.pageX - $('#scrubber-track').offset().left) / sc_w) * 100;
$('#scrubber-progress').css('width', p+'%');
scrubp = p;
});
}
});
$(document).on('mouseup.scrubber-track', function(e) {
if (is_dragging_scrubber) {
$('audio').get(0).currentTime = (scrubp / 100) * $('audio').get(0).duration;
$(this).off('mousemove.scrubber-track');
is_dragging_scrubber = false;
}
});
$('audio').on ('ended', function () {
if (!g_looping)
playNextTrack ();
});
$('#btn-play').click (playpause);
$(document).keypress (function (e) {
if (e.which == 32) {
e.preventDefault ();
playpause ();
}
});
$('#btn-next').click (function () {
playNextTrack (true);
});
$('#btn-previous').click (function () {
playPreviousTrack ();
});
$('#btn-loop').click (function () {
toggleLooping ();
});
$('#btn-shuffle').click (function () {
toggleShuffle ();
});
$('#select-playlist').on ('change', function () {
var playlist = $('#select-playlist').val ();
g_current = -1;
loadNewPlaylist (playlist, '');
});
$('#volume-slider').slider({
orientation: "vertical",
range: "min",
min: 0,
max: 100,
value: $('audio').get (0).volume * 100,
slide: function(event, ui) {
//change volume here
$('audio').get(0).volume = (ui.value / 100);
if (ui.value > 50) {
$('#btn-volume i').removeClass($('#btn-volume i').attr('class').split(' ')[1]).addClass('fa-volume-up');
}
else if (ui.value > 0) {
$('#btn-volume i').removeClass($('#btn-volume i').attr('class').split(' ')[1]).addClass('fa-volume-down');
}
else {
$('#btn-volume i').removeClass($('#btn-volume i').attr('class').split(' ')[1]).addClass('fa-volume-off');
}
localStorage['volume'] = $('audio').get (0).volume;
}
});
$('#btn-volume').on('click', function() {
$('#volume-slider').slideToggle(200);
});
populatePlaylistOptions ();
// Default playlist, random track
var playlist = DEFAULT_PLAYLIST;
var track = '';
/* Load settings */
if (localStorage.getItem ('volume') !== null) {
$('audio').get (0).volume = localStorage.getItem('volume');
$('#volume-slider').slider({
value: $('audio').get (0).volume * 100
});
}
if (localStorage.getItem ('playlist') !== null) {
if (localStorage.getItem ('playlist') in PLAYLISTS)
playlist = localStorage.getItem ('playlist');
}
if (localStorage.getItem ('shuffle') !== null) {
let shuffle = localStorage.getItem('shuffle');
if (shuffle === 'false') {
g_shuffle = false;
if (localStorage.getItem ('current') !== null) {
g_current = parseInt(localStorage.getItem ('current'))-1;
}
}
else {
g_shuffle = true;
}
toggleShuffleColor();
}
// If hash is set, override playlist and track
var url_track = parseTrackId (window.location.hash.substr (1));
if (url_track !== null) {
playlist = url_track.playlist;
track = url_track.track;
}
// Load playlist and track
loadNewPlaylist (playlist, track);
});
</script>
<style>
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
body {
background-color: #183c63;
}
#tracks-table {
width: 100%;
margin-top: 18px;
}
#tracks-table div {
background-color: #183c63;
border: 1px solid #003366;
color: #FF9148;
padding: 5px;
font-family: Helvetica, Arial, sans-serif;
font-size: 8pt;
cursor: pointer;
}
#tracks-table div.selected {
background-color: #e5874a;
color: #183c63;
}
#tracks-table div:hover {
background-color: #4e91ff;
color: #183c63;
}
.control-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 18px;
background: linear-gradient(to bottom, rgba(192,204,217,1) 0%, rgba(0,12,25,1) 100%);
}
.control-buttons {
width: 100%;
height: 100%;
border-spacing: 1px;
border-collapse: separate;
}
.control-buttons td {
font-family: Helvetica, Arial, sans-serif;
font-size: 7pt;
color: #FF9148;
border-width: 0px;
background: linear-gradient(to bottom, rgba(61,99,137,1) 0%, rgba(3,41,79,1) 100%);
text-align: center;
cursor: pointer;
vertical-align: middle;
}
.control-buttons td:hover {
color: #4e91ff;
}
.control-button {
width: 20px;
}
.control-volume {
width: 60px;
font-size: 9pt;
}
.control-playlist {
width: 80px;
}
.control-playlist select {
height: 16px;
font-family: Helvetica, Arial, sans-serif;
font-size: 7pt;
padding: 0;
color: #FF9148;
border: 0;
background: transparent;
}
.credits {
position: fixed;
bottom: 0;
right: 0;
width: 100px;
background-color: #000;
background-color: rgba(0,0,0,0.5);
color: #FF9148;
padding: 5px;
font-family: Helvetica, Arial, sans-serif;
font-size: 8pt;
text-align: center;
}
.credits a {
color: #a96030;
font-family: Helvetica, Arial, sans-serif;
font-size: 8pt;
text-decoration: none;
}
#time-current, #time-remaining {
width: 60px;
}
#time-bar:hover #scrubber {
background: rgb(78,145,255);
}
#scrubber-track {
width: 100%;
height: 5px;
background: #7f6157;
}
#scrubber-progress {
background: #FF9148;
height: 100%;
position: relative;
}
#scrubber {
position: absolute;
right: 0;
height: 8px;
width: 3px;
display: inline-block;
border: 1px solid #7f6157;
background: #FF9148;
-ms-transform: translateY(-25%);
-webkit-transform: translateY(-25%);
transform: translateY(-25%);
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background-color: #7f6157;
}
::-webkit-scrollbar-thumb {
background-color: #FF9148;
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgb(78,145,255);
}
#volume-slider {
width: 10px;
height: 65px;
position: absolute;
background: linear-gradient(to bottom, rgba(61,99,137,1) 0%, rgba(3,41,79,1) 100%);
border: 1px solid gray;
top: 19px;
margin-left: -1px;
display: none;
padding: 0 5px;
}
.ui-slider-range-min {
background-color: #FF9148;
position: absolute;
width: 8px;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
@media(max-device-width: 700px) {
.control-bar {
height: 70px;
}
.control-buttons {
height: 50px;
}
.control-button {
width: 30px;
}
#time-bar {
position: absolute;
bottom: 10px;
left: 0;
width: 100%;
}
#tracks-table {
margin-top: 70px;
}
#tracks-table div {
font-size: 11pt;
}
}
</style>
</head>
<body>
<div class='control-bar'>
<table class='control-buttons' cellpadding="0" cellspacing="0">
<tr>
<td id='btn-play' class='control-button'><i class="fa fa-play"></i></td>
<td id='btn-previous' class='control-button'><i class="fa fa-step-backward"></i></td>
<td id='btn-next' class='control-button'><i class="fa fa-step-forward"></i></td>
<td id='btn-loop' class='control-button'><i class="fa fa-repeat"></i></td>
<td id='btn-shuffle' class='control-button'><i class="fa fa-random"></i></td>
<td id='time-current'></td>
<td id='time-bar'><div id="scrubber-track"><div id="scrubber-progress"><div id="scrubber"></div></div></div></td>
<td id='time-remaining'></td>
<td id='btn-volume' class='control-button'><i class="fa fa-volume-up"></i><div id="volume-slider"></div></td>
<td class='control-playlist'>
<select id='select-playlist'></select>
</td>
</tr>
</table>
</div>
<audio></audio>
<div id='tracks-table'></div>
</body>
</html>