Several fixes

- User playlists should now list correctly (fixed a race condition)
  - Livestream types can autoplay (no longer stuck at currentTime = -3)
  - Playlist items with NaN duration do not break user playlist saving
  - ffmpeg support can handle live media (e.g. icecast)
  - Invalid volume is sanitized and an error message is added
  - JWPlayer displays correctly for both HTML5 and Flash
  - JWPlayer volume synchronization is fixed
  - <audio> and <video> tags are scaled correctly with .embed-responsive-item
This commit is contained in:
calzoneman 2014-12-02 22:21:52 -06:00
parent b09346392e
commit b587da6701
7 changed files with 33 additions and 14 deletions

View file

@ -219,6 +219,9 @@ PlaylistModule.prototype.onUserPostJoin = function (user) {
user.socket.on("shufflePlaylist", this.handleShuffle.bind(this, user)); user.socket.on("shufflePlaylist", this.handleShuffle.bind(this, user));
/* User playlists */ /* User playlists */
user.socket.on("listPlaylists", this.handleListPlaylists.bind(this, user)); user.socket.on("listPlaylists", this.handleListPlaylists.bind(this, user));
if (user.is(Flags.U_REGISTERED)) {
this.handleListPlaylists(user);
}
user.socket.typecheckedOn("clonePlaylist", TYPE_CLONE_PLAYLIST, this.handleClonePlaylist.bind(this, user)); user.socket.typecheckedOn("clonePlaylist", TYPE_CLONE_PLAYLIST, this.handleClonePlaylist.bind(this, user));
user.socket.typecheckedOn("deletePlaylist", TYPE_CLONE_PLAYLIST, this.handleDeletePlaylist.bind(this, user)); user.socket.typecheckedOn("deletePlaylist", TYPE_CLONE_PLAYLIST, this.handleDeletePlaylist.bind(this, user));
user.socket.typecheckedOn("queuePlaylist", TYPE_QUEUE_PLAYLIST, this.handleQueuePlaylist.bind(this, user)); user.socket.typecheckedOn("queuePlaylist", TYPE_QUEUE_PLAYLIST, this.handleQueuePlaylist.bind(this, user));
@ -1018,7 +1021,7 @@ PlaylistModule.prototype.startPlayback = function (time) {
} }
/* Lead-in time of 3 seconds to allow clients to buffer */ /* Lead-in time of 3 seconds to allow clients to buffer */
time = time || -3; time = time || (media.seconds > 0 ? -3 : 0);
media.paused = time < 0; media.paused = time < 0;
media.currentTime = time; media.currentTime = time;

View file

@ -404,14 +404,14 @@ module.exports.saveUserPlaylist = function (pl, username, plname, callback) {
var e = { var e = {
id: pl[i].media.id, id: pl[i].media.id,
title: pl[i].media.title, title: pl[i].media.title,
seconds: pl[i].media.seconds, seconds: pl[i].media.seconds || 0,
type: pl[i].media.type, type: pl[i].media.type,
meta: { meta: {
codec: pl[i].media.meta.codec, codec: pl[i].media.meta.codec,
bitrate: pl[i].media.meta.bitrate bitrate: pl[i].media.meta.bitrate
} }
}; };
time += pl[i].media.seconds; time += pl[i].media.seconds || 0;
tmp.push(e); tmp.push(e);
} }
var count = tmp.length; var count = tmp.length;

View file

@ -52,7 +52,7 @@ exports.query = function (filename, cb) {
var data = { var data = {
title: meta.title || "Raw Video", title: meta.title || "Raw Video",
duration: Math.ceil(meta.seconds), duration: Math.ceil(meta.seconds) || "--:--",
bitrate: meta.bitrate, bitrate: meta.bitrate,
codec: codec codec: codec
}; };
@ -67,7 +67,7 @@ exports.query = function (filename, cb) {
var data = { var data = {
title: meta.title || "Raw Audio", title: meta.title || "Raw Audio",
duration: Math.ceil(meta.seconds), duration: Math.ceil(meta.seconds) || "--:--",
bitrate: meta.bitrate, bitrate: meta.bitrate,
codec: codec codec: codec
}; };

View file

@ -52,6 +52,7 @@ var urlRetrieve = function (transport, options, callback) {
Logger.errlog.log(err.stack); Logger.errlog.log(err.stack);
Logger.errlog.log("urlRetrieve failed: " + err); Logger.errlog.log("urlRetrieve failed: " + err);
Logger.errlog.log("Request was: " + options.host + options.path); Logger.errlog.log("Request was: " + options.host + options.path);
callback(503, "");
}); });
d.run(function () { d.run(function () {
var req = transport.request(options, function (res) { var req = transport.request(options, function (res) {

View file

@ -418,9 +418,6 @@ Callbacks = {
/* REGION Rank Stuff */ /* REGION Rank Stuff */
rank: function(r) { rank: function(r) {
if (r >= 1) {
socket.emit("listPlaylists");
}
if(r >= 255) if(r >= 255)
SUPERADMIN = true; SUPERADMIN = true;
CLIENT.rank = r; CLIENT.rank = r;
@ -840,7 +837,7 @@ Callbacks = {
} }
/* Failsafe */ /* Failsafe */
if (isNaN(VOLUME)) { if (isNaN(VOLUME) || VOLUME > 1 || VOLUME < 0) {
VOLUME = 1; VOLUME = 1;
} }
@ -849,8 +846,14 @@ Callbacks = {
if (PLAYER && typeof PLAYER.getVolume === "function") { if (PLAYER && typeof PLAYER.getVolume === "function") {
PLAYER.getVolume(function (v) { PLAYER.getVolume(function (v) {
if (typeof v === "number") { if (typeof v === "number") {
VOLUME = v; if (v < 0 || v > 1) {
setOpt("volume", VOLUME); alert("Something went wrong with retrieving the volume. " +
"Please tell calzoneman the following: " +
JSON.stringify({ v: v, t: PLAYER.type, i: PLAYER.videoId }));
} else {
VOLUME = v;
setOpt("volume", VOLUME);
}
} }
}); });
} }

View file

@ -706,11 +706,19 @@ var JWPlayer = function (data) {
jwplayer().onReady(function() { jwplayer().onReady(function() {
$("#ytapiplayer").addClass("embed-responsive-item"); $("#ytapiplayer").addClass("embed-responsive-item");
$("#ytapiplayer").parent().css("position", "absolute"); if ($("#ytapiplayer")[0].tagName === "OBJECT") {
$("#ytapiplayer").parent().css("position", "absolute");
}
handleVideoResize(); handleVideoResize();
}); });
jwplayer().onPlay(function() { jwplayer().onPlay(function() {
/* Somehow JWPlayer manages to have THE SAME PROBLEM AS SOUNDCLOUD.
* It seems to be impossible to set the volume before the video has
* started playing. How this is so damn difficult to get right I will
* never understand.
*/
self.setVolume(VOLUME);
self.paused = false; self.paused = false;
if(CLIENT.leader) if(CLIENT.leader)
sendVideoUpdate(); sendVideoUpdate();
@ -723,8 +731,6 @@ var JWPlayer = function (data) {
jwplayer().onComplete(function() { jwplayer().onComplete(function() {
socket.emit("playNext"); socket.emit("playNext");
}); });
self.setVolume(VOLUME);
}; };
self.load = function (data) { self.load = function (data) {
@ -898,15 +904,18 @@ function FilePlayer(data) {
video = $("<video/>") video = $("<video/>")
} }
video video
.addClass("embed-responsive-item")
.attr("src", self.videoURL) .attr("src", self.videoURL)
.attr("controls", "controls") .attr("controls", "controls")
.attr("id", "#ytapiplayer") .attr("id", "#ytapiplayer")
.attr("width", VWIDTH) .attr("width", VWIDTH)
.attr("height", VHEIGHT) .attr("height", VHEIGHT)
.attr("autoplay", true)
.html("Your browser does not support HTML5 <code>&lt;video&gt;</code> tags :("); .html("Your browser does not support HTML5 <code>&lt;video&gt;</code> tags :(");
video.error(function (err) { video.error(function (err) {
setTimeout(function () { setTimeout(function () {
console.log("<video> tag failed, falling back to Flash"); console.log("<video> tag failed, falling back to Flash");
console.log(err);
PLAYER = new JWPlayer(data); PLAYER = new JWPlayer(data);
PLAYER.type = "jw"; PLAYER.type = "jw";
}, 100); }, 100);

View file

@ -2569,6 +2569,9 @@ function fallbackRaw(data) {
$("video").each(function () { $("video").each(function () {
killVideoUntilItIsDead($(this)); killVideoUntilItIsDead($(this));
}); });
$("audio").each(function () {
killVideoUntilItIsDead($(this));
});
data.type = "fl"; data.type = "fl";
data.url = data.direct.sd.url; data.url = data.direct.sd.url;
PLAYER.player = undefined; PLAYER.player = undefined;