281 lines
12 KiB
PHTML
281 lines
12 KiB
PHTML
<!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">
|
|
|
|
<head>
|
|
<link rel="stylesheet" href="<?php echo $this->css ?>" type="text/css">
|
|
<script src="<?php echo $this->playerhtml5_js ?>" type="text/javascript"></script>
|
|
<script src="<?php echo $this->jquery ?>" type="text/javascript"></script>
|
|
|
|
<script src="<?php echo $this->jquery_i18n ?>" type="text/javascript"></script>
|
|
<script src="/locale/general-translation-table" type="text/javascript"></script>
|
|
<link href='https://fonts.googleapis.com/css?family=Roboto:400,100,300,700' rel='stylesheet' type='text/css'>
|
|
<script type="text/javascript">
|
|
$.i18n.setDictionary(general_dict);
|
|
|
|
var MAX_MOBILE_SCREEN_WIDTH = 760;
|
|
|
|
var Html5Player = function() {
|
|
var id_element = getRandomIdPlayer(3000);
|
|
this.mobileDetect = this.mobileDetect();
|
|
this.playerMode = "<?php echo $this->playerMode ?>";
|
|
this.settings = {
|
|
'elementId': id_element, // leave alone
|
|
'autoplay': false, // or true (only works on some browsers)
|
|
'forceHTTPS': false, // or true if the stream is in SSL (beware of the listening port, usually 8000)
|
|
'replacePort': false, // false for disabled or '8000' as the usual start port, forces to specify replacePortTo.
|
|
'replacePortTo': '' // either '' to use the default port of the browser (80/http, 443/https) or '8443' to force the port of the stream.
|
|
};
|
|
|
|
if (this.playerMode == "manual") {
|
|
this.settings.url = <?php echo $this->streamURL ?>;
|
|
this.settings.codec = "<?php echo $this->codec ?>";
|
|
} else if (this.playerMode == "file") {
|
|
this.settings.url = <?php echo $this->streamURL ?>;
|
|
this.settings.codec = "<?php echo $this->codec ?>";
|
|
} else if (this.playerMode == "auto") {
|
|
this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams ?>;
|
|
this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams ?>;
|
|
var stream = this.getNextAvailableStream();
|
|
this.settings.url = stream["url"];
|
|
this.settings.codec = stream["codec"];
|
|
}
|
|
|
|
// Create the Muses player object
|
|
playerhtml5_insert(this.settings);
|
|
playerhtml5_audio = document.getElementById(id_element);
|
|
if (playerhtml5_audio.played == true) togglePlayStopButton();
|
|
|
|
// Configure player title
|
|
var player_title = <?php echo $this->player_title ?>;
|
|
if (player_title === null) {
|
|
$(".airtime_header").hide();
|
|
$(".airtime_player").css('height', '150px');
|
|
} else {
|
|
$("p.station_name").html(player_title);
|
|
}
|
|
|
|
attachStreamMetadataToPlayer();
|
|
|
|
// detects events in HTML5 mode
|
|
|
|
};
|
|
Html5Player.prototype.mobileDetect = function() {
|
|
return (screen.width <= MAX_MOBILE_SCREEN_WIDTH);
|
|
}
|
|
|
|
// This function is called if an error occurs while a client is
|
|
// attempting to connect to a stream (An error would occur if
|
|
// the streams listener count has been maxed out or if the stream is down).
|
|
// It checks if the client is a mobile device or not and returns the next
|
|
// best available stream.
|
|
Html5Player.prototype.getNextAvailableStream = function() {
|
|
if (this.mobileDetect && this.availableMobileStreamQueue.length > 0) {
|
|
return this.getNextAvailableMobileStream();
|
|
}
|
|
|
|
if (!this.mobileDetect && this.availableDesktopStreamQueue.length > 0) {
|
|
return this.getNextAvailableDesktopStream();
|
|
}
|
|
|
|
// If we get to this point there are no available streams for the
|
|
// type of device the client has connected with so just return
|
|
// the next available stream - first we'll try the desktop streams
|
|
var desktopStream = this.getNextAvailableDesktopStream();
|
|
if (desktopStream) {
|
|
return desktopStream;
|
|
} else {
|
|
return this.getNextAvailableMobileStream();
|
|
}
|
|
|
|
}
|
|
|
|
// Gets and returns the next available mobile stream from the queue,
|
|
// but adds it back to the end of the queue to be recycled.
|
|
Html5Player.prototype.getNextAvailableMobileStream = function() {
|
|
var stream = this.availableMobileStreamQueue.shift();
|
|
//add to end of queue
|
|
this.availableMobileStreamQueue.push(stream);
|
|
return stream;
|
|
}
|
|
|
|
// Gets and returns the next available desktop stream from the queue,
|
|
// but adds it back to the end of the queue to be recycled.
|
|
Html5Player.prototype.getNextAvailableDesktopStream = function() {
|
|
var stream = this.availableDesktopStreamQueue.shift();
|
|
//add to end of queue
|
|
this.availableDesktopStreamQueue.push(stream);
|
|
return stream;
|
|
}
|
|
|
|
Html5Player.prototype.play = function() {
|
|
console.log('play');
|
|
playerhtml5_audio.src = this.settings.url;
|
|
playerhtml5_audio.play();
|
|
togglePlayStopButton();
|
|
};
|
|
|
|
Html5Player.prototype.stop = function() {
|
|
console.log('stop');
|
|
playerhtml5_audio.pause();
|
|
togglePlayStopButton();
|
|
};
|
|
|
|
function togglePlayStopButton() {
|
|
document.getElementById("play_button").classList.toggle("hide_button");
|
|
document.getElementById("stop_button").classList.toggle("hide_button");
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
$(".play").click(function() {
|
|
if ($(this).hasClass("pause")) {
|
|
html5Player.stop();
|
|
} else {
|
|
html5Player.play();
|
|
}
|
|
|
|
$(this).toggleClass("pause");
|
|
});
|
|
});
|
|
|
|
// variables for updating the player's metadata
|
|
var time_to_next_track_starts = 0;
|
|
var metadataTimer = null;
|
|
|
|
// Fetches the streams metadata from the Airtime live-info API
|
|
// and attaches it to the player UI.
|
|
//
|
|
// The metadata is fetched when the current track is about to end.
|
|
function attachStreamMetadataToPlayer() {
|
|
$.ajax({
|
|
url: "<?php echo $this->metadata_api_url ?>",
|
|
data: {
|
|
type: "interval",
|
|
limit: "5"
|
|
},
|
|
dataType: "jsonp",
|
|
success: function(data) {
|
|
|
|
if (data.current === null) {
|
|
if (data.currentShow != null && data.currentShow.length > 0) {
|
|
//Master/show source have no current track but they do have a current show.
|
|
$("p.now_playing").html($.i18n._("On Air") + "<span>" + data.currentShow[0].name + "</span>");
|
|
} else {
|
|
$("p.now_playing").html($.i18n._("Off Air") + "<span>" + $.i18n._("Offline") + "</span>");
|
|
}
|
|
time_to_next_track_starts = 20000;
|
|
} else {
|
|
var artist = data.current.name.split(" - ")[0];
|
|
var track = data.current.name.split(" - ")[1];
|
|
var nowPlayingHtml = "";
|
|
if (artist) {
|
|
nowPlayingHtml += artist;
|
|
}
|
|
if (track) {
|
|
nowPlayingHtml += "<span>" + track + "</span>";
|
|
}
|
|
$("p.now_playing").html(nowPlayingHtml);
|
|
|
|
var current_track_end_time = new Date(data.current.ends);
|
|
if (current_track_end_time == "Invalid Date" || isNaN(current_track_end_time)) {
|
|
// If the conversion didn't work (since the String is not in ISO format)
|
|
// then change it to be ISO-compliant. This is somewhat hacky and may break
|
|
// if the date string format in live-info changes!
|
|
current_track_end_time = new Date((data.current.ends).replace(" ", "T"));
|
|
}
|
|
var current_time = new Date();
|
|
//convert current_time to UTC to match the timezone of time_to_next_track_starts
|
|
current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset() * 60 * 1000);
|
|
time_to_next_track_starts = current_track_end_time - current_time;
|
|
}
|
|
|
|
if (data.next === null) {
|
|
$("ul.schedule_list").find("li").html($.i18n._("Nothing scheduled"));
|
|
} else {
|
|
$("ul.schedule_list").find("li").html(data.next.name);
|
|
}
|
|
}
|
|
});
|
|
|
|
//Preventative code if the local and remote clocks are out of sync.
|
|
if (isNaN(time_to_next_track_starts) || time_to_next_track_starts < 0) {
|
|
time_to_next_track_starts = 0;
|
|
}
|
|
|
|
// Add 3 seconds to the timeout so Airtime has time to update the metadata before we fetch it
|
|
metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts + 3000);
|
|
|
|
|
|
}
|
|
</script>
|
|
|
|
<style type="text/css">
|
|
/*
|
|
We have to have the default Muses skin displayed on the page or else
|
|
the player will not work. Setting the display to none and hidden does
|
|
not work. It has to be "visible" on the page. As a hacky work around we
|
|
set the height and width to 1px so users will not see it.
|
|
*/
|
|
#html5player_skin {
|
|
width: 0;
|
|
height: 0;
|
|
overflow: hidden;
|
|
}
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="player" <?php if ($this->player_style == "basic") echo "style='display:block;'";
|
|
else echo "style='display:none'"; ?>>
|
|
<div class="airtime_player">
|
|
|
|
<div class="airtime_header">
|
|
<p class="station_name">fff</p>
|
|
</div>
|
|
|
|
<div class="airtime_box">
|
|
|
|
<div class="airtime_button">
|
|
<span id="play_button" class="play_button" onclick="html5Player.play()"></span>
|
|
<span id="stop_button" class="stop_button hide_button" onclick="html5Player.stop()"></span>
|
|
</div>
|
|
<p class="now_playing"></p>
|
|
|
|
</div>
|
|
|
|
<div style="clear:both"></div>
|
|
|
|
<div class="airtime_schedule">
|
|
<p class="airtime_next"><?php echo _("Next") ?></p>
|
|
<ul class="schedule_list">
|
|
<li></li>
|
|
</ul>
|
|
</div>
|
|
<a class="airtime_pro" target="_blank" href="<?php echo PRODUCT_SITE_URL; ?>"><?php printf(_('Powered by %s'), PRODUCT_NAME); ?></a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div id="premium_player" <?php if ($this->player_style == "premium") echo "style='display:block;'";
|
|
else echo "style='display:none'"; ?>>
|
|
<div class="bottom_bar">
|
|
<div class="play cont_btn"></div>
|
|
|
|
<div class="on_air">
|
|
<p class="now_playing"></p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div id="html5player_skin">
|
|
<script type="text/javascript">
|
|
var html5Player = new Html5Player();
|
|
</script>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|