diff --git a/channel.js b/channel.js index 0511eafc..3aba97ef 100644 --- a/channel.js +++ b/channel.js @@ -796,6 +796,9 @@ Channel.prototype.broadcastNewUser = function(user) { // Someone"s rank changed, or their leadership status changed Channel.prototype.broadcastRankUpdate = function(user) { + user.socket.emit("rank", { + rank: user.rank + }); this.sendAll("updateUser", { name: user.name, rank: user.rank, diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 9a41e7c6..953ec79c 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -36,29 +36,8 @@ function initCallbacks() { }); socket.on("rank", function(data) { - if(data.rank >= Rank.Moderator) { - $("#playlist_controls").css("display", "block"); - $("#playlist_controls button").each(function() { - $(this).attr("disabled", false); - }); - $("#qlockbtn").css("display", "block"); - var poll = $("#pollcontainer .active"); - if(poll.length > 0) { - $("").addClass("btn btn-danger pull-right").text("Close Poll") - .insertAfter(poll.find(".close")) - .click(function() { - socket.emit("closePoll") - }); - } - var users = $("#userlist").children(); - for(var i = 0; i < users.length; i++) { - addUserDropdown(users[i], users[i].children[1].innerHTML); - } - - $("#modnav").show(); - $("#chancontrols").show(); - } RANK = data.rank; + handleRankChange(); }); socket.on("login", function(data) { @@ -132,7 +111,7 @@ function initCallbacks() { } for(var i = 0; i < data.pl.length; i++) { var li = makeQueueEntry(data.pl[i]); - if(RANK >= Rank.Moderator || OPENQUEUE) + if(RANK >= Rank.Moderator || OPENQUEUE || LEADER) addQueueButtons(li); $(li).appendTo(ul); } @@ -140,7 +119,7 @@ function initCallbacks() { socket.on("queue", function(data) { var li = makeQueueEntry(data.media); - if(RANK >= Rank.Moderator || OPENQUEUE) + if(RANK >= Rank.Moderator || OPENQUEUE || LEADER) addQueueButtons(li); $(li).css("display", "none"); var idx = data.pos; @@ -203,6 +182,8 @@ function initCallbacks() { socket.on("mediaUpdate", function(data) { $("#currenttitle").text("Currently Playing: " + data.title); + if(data.type != "sc" && MEDIATYPE == "sc") + fixSoundcloudShit(); if(data.type == "yt") updateYT(data); else if(data.type == "tw") @@ -230,8 +211,9 @@ function initCallbacks() { socket.on("updateUser", function(data) { if(data.name == uname) { LEADER = data.leader; + handleRankChange(); if(LEADER) { - // I"m a leader! Set up sync function + // I'm a leader! Set up sync function sendVideoUpdate = function() { if(MEDIATYPE == "yt") { socket.emit("mediaUpdate", { @@ -271,14 +253,11 @@ function initCallbacks() { } }; } - // I"m not a leader. Don"t send syncs to the server + // I'm not a leader. Don"t send syncs to the server else { sendVideoUpdate = function() { } } - RANK = data.rank; - if(data.rank >= Rank.Moderator) - $("#playlist_controls").css("display", "block"); } var users = $("#userlist").children(); for(var i = 0; i < users.length; i++) { @@ -308,7 +287,7 @@ function initCallbacks() { var ul = $("#library")[0]; for(var i = 0; i < data.results.length; i++) { var li = makeQueueEntry(data.results[i]); - if(RANK >= Rank.Moderator || OPENQUEUE) + if(RANK >= Rank.Moderator || OPENQUEUE || LEADER) addLibraryButtons(li, data.results[i].id); $(li).appendTo(ul); } diff --git a/www/assets/js/functions.js b/www/assets/js/functions.js index baea6e9c..c778570d 100644 --- a/www/assets/js/functions.js +++ b/www/assets/js/functions.js @@ -319,6 +319,7 @@ function updateYT(data) { // Soundcloud synchronization function updateSC(data) { if(MEDIATYPE != "sc") { + unfixSoundcloudShit(); var currentEmbed = $("#ytapiplayer"); var iframe = $("").insertBefore(currentEmbed); currentEmbed.remove(); @@ -350,7 +351,6 @@ function updateSC(data) { // Dailymotion synchronization function updateDM(data) { if(MEDIATYPE != "dm") { - console.log("updateDM: MEDIATYPE=", MEDIATYPE); removeCurrentPlayer(); PLAYER = DM.player("ytapiplayer", { video: data.id, @@ -370,6 +370,9 @@ function updateDM(data) { if(Math.abs(data.currentTime - PLAYER.currentTime) > SYNC_THRESHOLD) { PLAYER.api("seek", data.currentTime); } + else if(PLAYER.currentTime > data.seconds || PLAYER.currentTime+"" == "NaN") { + PLAYER.api("load", data.id); + } } } @@ -582,7 +585,7 @@ function showChannelRegistration() { $("").addClass("close pull-right").text("×") .appendTo(div) .click(function() { div.remove(); }); - $("
").text("This channel isn"t registered").appendTo(div); + $("").text("This channel isn't registered").appendTo(div); $("").addClass("btn btn-primary").text("Register it") .appendTo(div) .click(function() { @@ -622,3 +625,46 @@ function updateBanlist(entries) { remove.click(callback); } } + +function handleRankChange() { + rebuildPlaylist(); + if(RANK >= Rank.Moderator || LEADER) { + $("#playlist_controls").css("display", "block"); + $("#playlist_controls button").each(function() { + $(this).attr("disabled", false); + }); + } + if(RANK >= Rank.Moderator) { + $("#qlockbtn").css("display", "block"); + var poll = $("#pollcontainer .active"); + if(poll.length > 0) { + $("").addClass("btn btn-danger pull-right").text("Close Poll") + .insertAfter(poll.find(".close")) + .click(function() { + socket.emit("closePoll") + }); + } + var users = $("#userlist").children(); + for(var i = 0; i < users.length; i++) { + addUserDropdown(users[i], users[i].children[1].innerHTML); + } + + $("#modnav").show(); + $("#chancontrols").show(); + } + else { + if(OPENQUEUE) { + if(CHANNELOPTS.qopen_allow_qnext || LEADER) + $("#queue_next").attr("disabled", false); + else + $("#queue_next").attr("disabled", true); + if(CHANNELOPTS.qopen_allow_playnext || LEADER) + $("#play_next").attr("disabled", false); + else + $("#play_next").attr("disabled", true); + } + else { + $("#playlist_controls").css("display", "none"); + } + } +} diff --git a/www/assets/js/sc.js b/www/assets/js/sc.js new file mode 100644 index 00000000..3a7c3c08 --- /dev/null +++ b/www/assets/js/sc.js @@ -0,0 +1,330 @@ +(function () { + var requirejs, require, define, __inflate; + (function (e) { + function a(e, t) { + var n = t && t.split("/"), + i = r.map, + s = i && i["*"] || {}, o, u, a, f, l, c, h; + if (e && e.charAt(0) === "." && t) { + n = n.slice(0, n.length - 1), e = n.concat(e.split("/")); + for (l = 0; h = e[l]; l++) if (h === ".") e.splice(l, 1), l -= 1; + else if (h === "..") { + if (l === 1 && (e[2] === ".." || e[0] === "..")) return !0; + l > 0 && (e.splice(l - 1, 2), l -= 2) + } + e = e.join("/") + } + if ((n || s) && i) { + o = e.split("/"); + for (l = o.length; l > 0; l -= 1) { + u = o.slice(0, l).join("/"); + if (n) for (c = n.length; c > 0; c -= 1) { + a = i[n.slice(0, c).join("/")]; + if (a) { + a = a[u]; + if (a) { + f = a; + break + } + } + } + f = f || s[u]; + if (f) { + o.splice(0, l, f), e = o.join("/"); + break + } + } + } + return e + } + function f(t, n) { + return function () { + return u.apply(e, s.call(arguments, 0).concat([t, n])) + } + } + function l(e) { + return function (t) { + return a(t, e) + } + } + function c(e) { + return function (n) { + t[e] = n + } + } + function h(r) { + if (n.hasOwnProperty(r)) { + var s = n[r]; + delete n[r], i[r] = !0, o.apply(e, s) + } + if (!t.hasOwnProperty(r)) throw new Error("No " + r); + return t[r] + } + function p(e, t) { + var n, r, i = e.indexOf("!"); + return i !== -1 ? (n = a(e.slice(0, i), t), e = e.slice(i + 1), r = h(n), r && r.normalize ? e = r.normalize(e, l(t)) : e = a(e, t)) : e = a(e, t), { + f: n ? n + "!" + e : e, + n: e, + p: r + } + } + function d(e) { + return function () { + return r && r.config && r.config[e] || {} + } + } + var t = {}, n = {}, r = {}, i = {}, s = [].slice, + o, u; + o = function (r, s, o, u) { + var a = [], + l, v, m, g, y, b; + u = u || r, typeof o == "string" && (o = __inflate(r, o)); + if (typeof o == "function") { + s = !s.length && o.length ? ["require", "exports", "module"] : s; + for (b = 0; b < s.length; b++) { + y = p(s[b], u), m = y.f; + if (m === "require") a[b] = f(r); + else if (m === "exports") a[b] = t[r] = {}, l = !0; + else if (m === "module") v = a[b] = { + id: r, + uri: "", + exports: t[r], + config: d(r) + }; + else if (t.hasOwnProperty(m) || n.hasOwnProperty(m)) a[b] = h(m); + else if (y.p) y.p.load(y.n, f(u, !0), c(m), {}), a[b] = t[m]; + else if (!i[m]) throw new Error(r + " missing " + m) + } + g = o.apply(t[r], a); + if (r) if (v && v.exports !== e && v.exports !== t[r]) t[r] = v.exports; + else if (g !== e || !l) t[r] = g + } else r && (t[r] = o) + }, requirejs = require = u = function (t, n, i, s) { + return typeof t == "string" ? h(p(t, n).f) : (t.splice || (r = t, n.splice ? (t = n, n = i, i = null) : t = e), n = n || function () {}, s ? o(e, t, n, i) : setTimeout(function () { + o(e, t, n, i) + }, 15), u) + }, u.config = function (e) { + return r = e, u + }, define = function (e, t, r) { + t.splice || (r = t, t = []), n[e] = [e, t, r] + }, define.amd = { + jQuery: !0 + } + })(), __inflate = function (name, src) { + var r; + return eval(["r = function(a,b,c){", "\n};\n//@ sourceURL=" + name + "\n"].join(src)), r + }, define("lib/api/events", ["require", "exports", "module"], function (e, t, n) { + t.api = { + LOAD_PROGRESS: "loadProgres", + PLAY_PROGRESS: "playProgress", + PLAY: "play", + PAUSE: "pause", + FINISH: "finish", + SEEK: "seek", + READY: "ready", + OPEN_SHARE_PANEL: "sharePanelOpened", + SHARE: "share", + CLICK_DOWNLOAD: "downloadClicked", + CLICK_BUY: "buyClicked" + }, t.bridge = { + REMOVE_LISTENER: "removeEventListener", + ADD_LISTENER: "addEventListener" + } + }), define("lib/api/getters", ["require", "exports", "module"], function (e, t, n) { + n.exports = { + GET_VOLUME: "getVolume", + GET_DURATION: "getDuration", + GET_POSITION: "getPosition", + GET_SOUNDS: "getSounds", + GET_CURRENT_SOUND: "getCurrentSound", + GET_CURRENT_SOUND_INDEX: "getCurrentSoundIndex", + IS_PAUSED: "isPaused" + } + }), define("lib/api/setters", ["require", "exports", "module"], function (e, t, n) { + n.exports = { + PLAY: "play", + PAUSE: "pause", + TOGGLE: "toggle", + SEEK_TO: "seekTo", + SET_VOLUME: "setVolume", + NEXT: "next", + PREV: "prev", + SKIP: "skip" + } + }), define("lib/api/api", ["require", "exports", "module", "lib/api/events", "lib/api/getters", "lib/api/setters"], function (e, t, n) { + function m(e) { + return !!(e === "" || e && e.charCodeAt && e.substr) + } + function g(e) { + return !!(e && e.constructor && e.call && e.apply) + } + function y(e) { + return !!e && e.nodeType === 1 && e.nodeName.toUpperCase() === "IFRAME" + } + function b(e) { + var t = !1, + n; + for (n in i) if (i.hasOwnProperty(n) && i[n] === e) { + t = !0; + break + } + return t + } + function w(e) { + var t, n, r; + for (t = 0, n = f.length; t < n; t++) { + r = e(f[t]); + if (r === !1) break + } + } + function E(e) { + var t = "", + n, r, i; + e.substr(0, 2) === "//" && (e = window.location.protocol + e), i = e.split("/"); + for (n = 0, r = i.length; n < r; n++) { + if (!(n < 3)) break; + t += i[n], n < 2 && (t += "/") + } + return t + } + function S(e) { + return e.contentWindow ? e.contentWindow : e.contentDocument && "parentWindow" in e.contentDocument ? e.contentDocument.parentWindow : null + } + function x(e) { + var t = [], + n; + for (n in e) e.hasOwnProperty(n) && t.push(e[n]); + return t + } + function T(e, t, n) { + n.callbacks[e] = n.callbacks[e] || [], n.callbacks[e].push(t) + } + function N(e, t) { + var n = !0, + r; + return t.callbacks[e] = [], w(function (t) { + r = t.callbacks[e] || []; + if (r.length) return n = !1, !1 + }), n + } + function C(e, t, n) { + var r = S(n), + i, s; + if (!r.postMessage) return !1; + i = n.getAttribute("src").split("?")[0], s = JSON.stringify({ + method: e, + value: t + }), i.substr(0, 2) === "//" && (i = window.location.protocol + i), i = i.replace(/http:\/\/(w|wt).soundcloud.com/, "https://$1.soundcloud.com"), r.postMessage(s, i) + } + function k(e) { + var t; + return w(function (n) { + if (n.instance === e) return t = n, !1 + }), t + } + function L(e) { + var t; + return w(function (n) { + if (S(n.element) === e) return t = n, !1 + }), t + } + function A(e, t) { + return function (n) { + var r = g(n), + i = k(this), + s = !r && t ? n : null, + o = r && !t ? n : null; + return o && T(e, o, i), C(e, s, i.element), this + } + } + function O(e, t, n) { + var r, i, s; + for (r = 0, i = t.length; r < i; r++) s = t[r], e[s] = A(s, n) + } + function M(e, t, n) { + return e + "?url=" + t + "&" + _(n) + } + function _(e) { + var t, n, r = []; + for (t in e) e.hasOwnProperty(t) && (n = e[t], r.push(t + "=" + (t === "start_track" ? parseInt(n, 10) : n ? "true" : "false"))); + return r.join("&") + } + function D(e, t, n) { + var r = e.callbacks[t] || [], + i, s; + for (i = 0, s = r.length; i < s; i++) r[i].apply(e.instance, n); + if (b(t) || t === o.READY) e.callbacks[t] = [] + } + function P(e) { + var t, n, r, i, s; + try { + n = JSON.parse(e.data) + } catch (u) {} + t = L(e.source), r = n.method, i = n.value, r === o.READY && (t ? (t.isReady = !0, D(t, l), N(l, t)) : a.push(e.source)), r === o.PLAY && !t.playEventFired && (t.playEventFired = !0), r === o.PLAY_PROGRESS && !t.playEventFired && (t.playEventFired = !0, D(t, o.PLAY, [i])); + if (!t || H(e.origin) !== H(t.domain)) return !1; + s = [], i !== undefined && s.push(i), D(t, r, s) + } + // Hack + function H(e) { + return e.replace(h, "") + } + var r = e("lib/api/events"), + i = e("lib/api/getters"), + s = e("lib/api/setters"), + o = r.api, + u = r.bridge, + a = [], + f = [], + l = "__LATE_BINDING__", + c = "http://wt.soundcloud.dev:9200/", + h = /^http(?:s?)/, + p, d, v; + window.scwtf = P; + window.fixSoundcloudShit = function() { + window.removeEventListener ? window.removeEventListener("message", window.scwtf, !1) : window.detachEvent("onmessage", window.scwtf); + } + window.unfixSoundcloudShit = function() { + window.addEventListener ? window.addEventListener("message", scwtf, !1) : window.attachEvent("onmessage", scwtf); + } + n.exports = v = function (e, t, n) { + m(e) && (e = document.getElementById(e)); + if (!y(e)) throw new Error("SC.Widget function should be given either iframe element or a string specifying id attribute of iframe element."); + t && (n = n || {}, e.src = M(c, t, n)); + var r = L(S(e)), + i, s; + return r && r.instance ? r.instance : (i = a.indexOf(S(e)) > -1, s = new p(e), f.push(new d(s, e, i)), s) + }, v.Events = o, window.SC = window.SC || {}, window.SC.Widget = v, d = function (e, t, n) { + this.instance = e, this.element = t, this.domain = E(t.getAttribute("src")), this.isReady = !! n, this.callbacks = {} + }, p = function () {}, p.prototype = { + constructor: p, + load: function (e, t) { + if (!e) return; + t = t || {}; + var n = this, + r = k(this), + i = r.element, + s = i.src, + a = s.substr(0, s.indexOf("?")); + r.isReady = !1, r.playEventFired = !1, i.onload = function () { + n.bind(o.READY, function () { + var e, n = r.callbacks; + for (e in n) n.hasOwnProperty(e) && e !== o.READY && C(u.ADD_LISTENER, e, r.element); + t.callback && t.callback() + }) + }, i.src = M(a, e, t) + }, + bind: function (e, t) { + var n = this, + r = k(this); + return r && r.element && (e === o.READY && r.isReady ? setTimeout(t, 1) : r.isReady ? (T(e, t, r), C(u.ADD_LISTENER, e, r.element)) : T(l, function () { + n.bind(e, t) + }, r)), this + }, + unbind: function (e) { + var t = k(this), + n; + t && t.element && (n = N(e, t), e !== o.READY && n && C(u.REMOVE_LISTENER, e, t.element)) + } + }, O(p.prototype, x(i)), O(p.prototype, x(s), !0) + }), window.SC = window.SC || {}, window.SC.Widget = require("lib/api/api") +})() diff --git a/www/index.html b/www/index.html index 9ae8ee2b..89110a4c 100644 --- a/www/index.html +++ b/www/index.html @@ -160,8 +160,8 @@ - +