initial clone

This commit is contained in:
2020-08-29 04:11:22 -05:00
commit 0a80f0664c
3 changed files with 677 additions and 0 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 fpgaminer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

39
README.md Normal file
View File

@@ -0,0 +1,39 @@
"Vidya Intarweb Playlist" HTML5 Player
======================================
["Vidya Intarweb Playlist"](http://www.aersia.net/threads/vip-and-wap-faqs.8/) is a fantastic video game playlist maintained by Cats777 over at [Aersia.net](http://www.aersia.net). The VIP has been one of my main sources of background music while working.
This is an HTML5-based replacement player for the VIP. I created it because the original player for the VIP is Flash-based. Since Flash is outdated and insecure, I decided to hack together a new player. Now the "Vidya Intarweb Playlist" is accessible on all my devices.
[Listen Here](http://fpgaminer.github.io/vip-html5-player)
----------------------------------------------------------
[Original Player Here](http://vip.aersia.net/vip.swf)
What's Different
================
I cloned the aesthetic of the original VIP player, so everything looks and feels the same. There are a few differences and improvements.
**Differences**
* The context menu has been replaced by a small credits box in the lower right corner, to properly credit Cats777 and link back to Aersia.
**Missing**
* Optimizing style and behavior of volume controls
**New**
* Next Track button goes to a random track, instead of next in the playlist.
* Previous Track button goes to the track previously played, instead of the previous in the playlist.
* Playlist Selection dropdown. Easily switch between the different VIP playlists (VIP, Mellow, Source, Exiled, WAP, CPP).
Compatibility
=============
This player should be compatible with all modern devices and browsers that support HTML5 and M4A (AAC) audio files. If you run into any bugs, let me know!
I have tested the current version on Firefox (Ubuntu), iPhone 5, and iPad 3. On the latter two, the playlist doesn't play automatically the first time; just tap a track to begin. Also, on the iPhone the player controls are incredibly tiny. Both bugs will be fixed.

617
index.html Normal file
View File

@@ -0,0 +1,617 @@
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<title>Vidya Intarweb 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_looping = false;
var MAX_HISTORY = 10;
var scrubp = 0;
var is_dragging_scrubber = false;
var PLAYLISTS = {
'VIP': '//vip.aersia.net/roster.xml',
'Mellow': '//vip.aersia.net/roster-mellow.xml',
'Source': '//vip.aersia.net/roster-source.xml',
'Exiled': '//vip.aersia.net/roster-exiled.xml',
'WAP': '//wap.aersia.net/roster.xml',
'CPP': '//cpp.aersia.net/roster.xml',
};
var DEFAULT_PLAYLIST = 'VIP';
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)) {
g_previous.push (Math.floor (Math.random () * g_playlist.length));
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);
}
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 {
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 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 ();
});
$('#select-playlist').on ('change', function () {
var playlist = $('#select-playlist').val ();
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');
if (localStorage.getItem ('playlist') !== null) {
if (localStorage.getItem ('playlist') in PLAYLISTS)
playlist = localStorage.getItem ('playlist');
}
// 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='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>
<div class='credits'>
<a href="//aersia.net" target="_blank">playlist by Cats777</a>
</div>
</body>
</html>