Advertisement
Guest User

Untitled

a guest
Apr 5th, 2016
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 206.57 KB | None | 0 0
  1. /*global API config angular YT CryptoJS Tour lightbox grecaptcha*/
  2. (function(){
  3.  
  4. if (!config){
  5. throw new Error('Config not loaded!');
  6. }
  7.  
  8. // Initialization
  9. var MP = {
  10.  
  11. applyModels: function(specific){
  12. if (!window.angular) return;
  13.  
  14. var updates = {
  15. roomInfo: MP.session.roomInfo,
  16. playlists: (MP.user ? MP.user.playlists : {}),
  17. viewedPlContents: (MP.user && MP.session.viewedPl && MP.user.playlists[MP.session.viewedPl] ? MP.user.playlists[MP.session.viewedPl].content : []),
  18. user: (MP.user ? MP.user : {}),
  19. username: (MP.user ? MP.user.un : 'Not Logged In'),
  20. isLoggedIn: (typeof MP.user !== 'undefined'),
  21. activepl: (MP.user ? MP.user.activepl : 0),
  22. viewedPl: MP.session.viewedPl,
  23. songSearch: MP.session.songSearch,
  24. searchResults: MP.session.searchResults,
  25. playlistResults: MP.session.playlistResults,
  26. nextSong: ( (MP.user && MP.user.activepl && MP.user.playlists[ MP.user.activepl ] && MP.user.playlists[ MP.user.activepl ].content.length) ?
  27. MP.user.playlists[ MP.user.activepl ].content[0] : 'No song selected'),
  28. userlist: (function(){ var out = []; for (var i in MP.userList.users){out.push(MP.seenUsers[MP.userList.users[i]]);} return out; })(),
  29. historyList: MP.historyList,
  30. stafflist: (function(){ var out = []; for (var i in MP.session.roomStaff){out.push(MP.seenUsers[MP.session.roomStaff[i].uid]);} return out; })(),
  31. bannedlist: (function(){ var out = []; for (var i in MP.session.bannedUsers){out.push(MP.seenUsers[MP.session.bannedUsers[i].uid]);} return out; })(),
  32. numUsers: MP.userList.users.length + MP.userList.guests,
  33. currentDJ: MP.session.queue.currentdj,
  34. currentSong: (MP.session.queue.currentsong ? MP.session.queue.currentsong.title : 'Nobody is playing'),
  35. queue: MP.session.queue,
  36. canSkip: (MP.checkPerm('djqueue.skip.other') || (MP.user && MP.findPosInWaitlist() == 0 && MP.checkPerm('djqueue.skip.self'))),
  37. canLock: (MP.checkPerm('djqueue.lock')),
  38. canCycle: (MP.checkPerm('djqueue.cycle')),
  39. canMove: (MP.checkPerm('djqueue.move')),
  40. secondsLeftInSong: MP.media.timeRemaining,
  41. songDuration: MP.getDuration(),
  42. songProgress: (MP.getDuration() ? MP.getTimeElapsed() / MP.getDuration() : 0),
  43. queueList: (function(){ var out = []; var j = 1; for (var i in MP.session.queue.users){out.push({num: j++, user: MP.findUser(MP.session.queue.users[i]) });} return out; })(),
  44. queueLength: (MP.session.queue.users ? MP.session.queue.users.length + (MP.session.queue.currentdj ? 1 : 0) : 0),
  45. snooze: MP.session.snooze,
  46. vote: $('.btn-upvote.active').length ? '#A7CA00' : ($('.btn-downvote.active').length ? '#C8303E' : '#925AFF'),
  47. allowemojis: MP.session.allowemojis,
  48. lastdj: MP.session.lastdj,
  49. description: MP.session.description,
  50. };
  51.  
  52. var $scope = angular.element( $("body") ).scope();
  53.  
  54. if (MP.models.viewedPl != MP.session.viewedPl) try{ $('.lib-sng').draggable('destroy'); } catch (e){}
  55.  
  56. for (var i in updates){
  57. if (updates[i] != MP.models[i])
  58. MP.models[i] = updates[i];
  59. }
  60.  
  61. $scope.$apply(function(){
  62. for (var i in MP.models){
  63. $scope[i] = MP.models[i];
  64. }
  65. if ($scope.user && $scope.user.badge &&
  66. $scope.userSettings && $scope.userSettings.newBadgeTop == '' &&
  67. $scope.userSettings.newBadgeBottom == '') {
  68. $scope.userSettings.newBadgeTop = $scope.user.badge.top;
  69. $scope.userSettings.newBadgeBottom = $scope.user.badge.bottom;
  70. }
  71. });
  72.  
  73. if (MP.session.viewedPl && MP.models.viewedPlContents.length){
  74. var $song = $('.lib-sng');
  75.  
  76. $song.draggable({
  77. appendTo: 'div.library',
  78. helper: function(){
  79. return $(this).clone().css({'width': $(this).css('width'), 'font-weight': 'bold'});
  80. },
  81. opacity: 0.7,
  82. zIndex: 100000000,
  83. cancel: '.nav',
  84. scroll: true,
  85. scrollSensitivity: 100,
  86. cursorAt: { top: 10, left: 10 },
  87. refreshPositions: true,
  88. start: function(){
  89. $('.lib-fdr:not([data-pid=' + MP.session.viewedPl + '])').droppable({
  90. accept: '.lib-sng',
  91. hoverClass: 'draghover',
  92. tolerance: 'pointer',
  93. drop: function(e, ui){
  94. var pid = $(this).attr('data-pid');
  95. var cid = $(ui.draggable).attr('data-cid');
  96. MP.playlistAdd(pid, cid, 'top', function(err, data){
  97. if(err == "SongAlreadyInPlaylist"){
  98. MP.makeConfirmModal({
  99. content: "Song is already in your playlist, would like to move it to the top?",
  100. callback: function(res){
  101. if(res) MP.api.playlist.moveSong(pid, cid, 'top');
  102. }
  103. });
  104. }
  105. });
  106. }
  107. });
  108.  
  109. $('div.lib-song-list').append('<div class="lib-sng-drop"></div>');
  110. },
  111. drag: function(e, ui){
  112. var $firstSong = $('.lib-sng:eq(0)');
  113. var $songDrop = $('.lib-sng-drop');
  114. var $songList = $('.lib-song-list');
  115.  
  116. var offset = $firstSong.offset();
  117. var height = $firstSong.height() + 1;
  118. var innerPos = ui.offset.top - offset.top + 5;
  119.  
  120.  
  121. if (ui.offset.left < offset.left || ui.offset.left > (offset.left + $firstSong.width())){
  122. $songDrop.css('display', 'none');
  123. return;
  124. }else{
  125. $songDrop.css('display', 'block');
  126.  
  127. if ( (ui.offset.top - offset.top - $songList.scrollTop()) < 30 ){
  128. $songList.autoscroll({
  129. direction: 'up',
  130. step: 400,
  131. scroll: true
  132. });
  133. }else if (( $songList.height() + $songList.offset().top - ui.offset.top) < 30 ){
  134. $songList.autoscroll({
  135. direction: 'down',
  136. step: 400,
  137. scroll: true
  138. });
  139. }else {
  140. if ($songList.autoscroll('get'))
  141. $songList.autoscroll('destroy');
  142. }
  143. }
  144.  
  145. var snapMult = Math.floor( innerPos / height );
  146. var snapFinal = null;
  147.  
  148. if ( (innerPos % height) <= (height/2)){
  149. snapFinal = 0;
  150. }else{
  151. snapFinal = 1;
  152. }
  153.  
  154. var newPos = Math.max( 0, Math.min((snapFinal + snapMult), MP.models.viewedPlContents.length) );
  155.  
  156. $songDrop
  157. .css('top', newPos * height + offset.top - $('.lib-songs').offset().top + $('.lib-songs').scrollTop() - 1 + 'px')
  158. .attr('data-pos', newPos);
  159. },
  160. stop: function(e, ui){
  161. $('.ui-draggable-dragging').remove();
  162.  
  163. var $songList = $('.lib-song-list');
  164.  
  165. if ($songList.autoscroll('get'))
  166. $songList.autoscroll('destroy');
  167.  
  168. var $songDrop = $('.lib-sng-drop');
  169.  
  170. if (!$songDrop.is(':hidden')){
  171. MP.playlistMove(MP.session.viewedPl, ui.helper.attr('data-cid'), $('.lib-sng-drop').attr('data-pos'));
  172. }
  173. $('.lib-fdr:not([data-pid=' + MP.session.viewedPl + '])').droppable('destroy');
  174. $('.lib-sng-drop').remove();
  175. }
  176.  
  177. });
  178.  
  179. }
  180.  
  181. var playerSettings = JSON.parse(localStorage.settings).player;
  182. if (!MP.session.queue.currentsong){
  183. $('#player').hide();
  184. $('.btn-skip:visible').hide();
  185. $('.btn-refresh:visible').hide();
  186. } else {
  187. if (playerSettings.stream && !MP.session.snooze){
  188. $('#player').show();
  189. $('.btn-skip:hidden').show();
  190. $('.btn-refresh:hidden').show();
  191. } else {
  192. $('#player').hide();
  193. }
  194. }
  195. $('.btn-stream div').removeClass('mdi-video-off').removeClass('mdi-video');
  196. if (!playerSettings.stream){
  197. $('#player').hide();
  198. $('.btn-refresh:visible').hide();
  199. $('.btn-stream div').addClass('mdi-video-off');
  200. }else{
  201. $('.btn-stream div').addClass('mdi-video');
  202. }
  203. },
  204. models: {
  205. playlists: {},
  206. viewedPlContents: [],
  207. user: {},
  208. username: '',
  209. activepl: 0,
  210. viewedPl: null,
  211. songSearch: false,
  212. searchResults: [],
  213. nextSong: '',
  214. userlist: [],
  215. historyList: {},
  216. stafflist: [],
  217. numUsers: 0,
  218. currentSong: '',
  219. currentDJ: '',
  220. queueList: [],
  221. queueLength: 0,
  222. queue: {},
  223. secondsLeftInSong: 0,
  224. songDuration: 0,
  225. songProgress: 0
  226. },
  227. session: { // Used for temp variables specific to current session
  228. roomInfo: {},
  229. viewedPl: null,
  230. songSearch: false,
  231. searchResults: [],
  232. playlistResults: [],
  233. queue: {},
  234. roles: {},
  235. roleOrder: [],
  236. staffRoles: [],
  237. roomStaff: [],
  238. bannedUsers: [],
  239. mediaPreview : {
  240. fadeInterval: 0,
  241. player: null,
  242. mainVolume: 100,
  243. previewVolume: 0,
  244. },
  245. serverDateDiff: 0,
  246. snooze: false,
  247. lastMessage: null,
  248. lastPMUid: null,
  249. imgc: 0,
  250. allowemojis: true,
  251. captchakey: '',
  252. historylimit: 50,
  253. lastdj: false,
  254. description: '',
  255. },
  256. isOnWaitlist: function(uid){
  257. if (MP.session.queue.currentdj && MP.session.queue.currentdj.uid == uid) return true;
  258.  
  259. for (var i = 0; i < MP.session.queue.users.length; i++){
  260. if (MP.session.queue.users[i] == uid) return true;
  261. }
  262.  
  263. return false;
  264. },
  265. isStaffMember: function(uid){
  266. var user = uid ? MP.findUser(uid) : MP.user;
  267.  
  268. if ( user && MP.session.staffRoles && MP.session.staffRoles.indexOf(user.role) > -1) {
  269. return true;
  270. }
  271. return false;
  272. },
  273. userList: {
  274. guests: 0,
  275. users: []
  276. },
  277. historyList: {
  278. historyInitialized: false,
  279. filter: "",
  280. history: []
  281. },
  282. seenUsers: {},
  283. media : {
  284. media : null,
  285. timeRemaining: 0,
  286. start: null
  287. },
  288. intervals : {
  289. timeRemaining : null
  290. },
  291. onConnect: null,
  292. emotes: { Basic: {}, TastyCat: {}, Twitch: {}, BetterTTV: {} },
  293. emotes_ascii: {},
  294. cbId: 1,
  295. callbacks: {},
  296. addCallback: function(event, func, timeout){
  297. var that = MP;
  298. if (!func) return;
  299. if ( typeof MP.callbacks[event] === 'undefined') MP.callbacks[event] = {};
  300.  
  301. var id = MP.cbId++;
  302. MP.callbacks[event][id] = {
  303. cb: func,
  304. timeoutId: setTimeout(function(){
  305. console.log(event + ' REQUEST TIMED OUT');
  306. MP.callbacks[event][id].cb('RequestTimedOut');
  307. that.removeCallback(event, id);
  308. }, timeout || 5000)
  309. };
  310. return id;
  311. },
  312. removeCallback: function(event, id){
  313. if ( typeof MP.callbacks[event] === 'undefined' ) return;
  314. if ( typeof MP.callbacks[event][id] === 'undefined' ){ console.log('Invalid callback id'); return; }
  315.  
  316. clearTimeout(MP.callbacks[event][id].timeoutId);
  317. delete MP.callbacks[event][id];
  318. },
  319. callCallback: function(data){
  320. if ( !data.requestType || typeof MP.callbacks[data.requestType] === 'undefined' ){ return; }
  321.  
  322. var callback = MP.callbacks[data.requestType][data.id];
  323. if (typeof callback === 'undefined') return;
  324.  
  325. MP.removeCallback(data.requestType, data.id);
  326. callback.cb.call(window, (data.data ? data.data.error : null), data.data, data);
  327. },
  328. listenerId: 1,
  329. listeners: {},
  330. extListeners: {},
  331. on: function(event, func, ext){
  332. var lists = (ext ? MP.extListeners : MP.listeners);
  333.  
  334. if ( typeof func !== 'function') return;
  335. if ( typeof lists[event] === 'undefined') lists[event] = {};
  336.  
  337. var id = MP.listenerId++;
  338. lists[event][id] = {
  339. cb: func
  340. };
  341. return id;
  342. },
  343. off: function(event, id, ext){
  344. var lists = (ext ? MP.extListeners : MP.listeners);
  345. id = typeof id === "string" ? parseInt(id) : id;
  346.  
  347. if (typeof lists[event] === 'undefined') return;
  348.  
  349. if (typeof id === 'number'){
  350. if ( typeof lists[event][id] === 'undefined' ){ console.log('Invalid callback id'); return false; }
  351. delete lists[event][id];
  352. return true;
  353. } else if (typeof id === 'function'){
  354. for (var i in lists[event]){
  355. if (lists[event][i].cb === id){
  356. delete lists[event][i];
  357. return true;
  358. }
  359. }
  360. }
  361.  
  362. return false;
  363. },
  364. once: function(event, func, ext){
  365. var lists = (ext ? MP.extListeners : MP.listeners);
  366.  
  367. if ( typeof func !== 'function') return;
  368. if ( typeof lists[event] === 'undefined') lists[event] = {};
  369.  
  370. var id = MP.listenerId++;
  371. lists[event][id] = {
  372. cb: func,
  373. once: true,
  374. };
  375. return id;
  376. },
  377. callListeners: function(data){
  378. if ( typeof MP.listeners[data.type] === 'undefined' && typeof MP.extListeners[data.type] === 'undefined'){ return; }
  379.  
  380. var callbacks = $.extend({}, (MP.listeners[data.type] || {}), (MP.extListeners[data.type] || {}));
  381.  
  382. for (var i in callbacks){
  383. if (callbacks[i].cb.length == 1) {
  384. callbacks[i].cb.call(window, data.data, data);
  385. }
  386. else {
  387. callbacks[i].cb.call(window, (data.data || {}).error, data.data, data);
  388. }
  389. if(callbacks[i].once){
  390. MP.off(data.type, i, true);
  391. }
  392. }
  393. },
  394. cookie: {
  395. setCookie: function(cname, cvalue, exdays) {
  396. var d = new Date();
  397. d.setTime(d.getTime() + (exdays*24*60*60*1000));
  398. var expires = "expires="+d.toUTCString();
  399. document.cookie = cname + "=" + cvalue + "; " + expires + '; path=/';
  400. },
  401. getCookie: function(cname) {
  402. var name = cname + "=";
  403. var ca = document.cookie.split(';');
  404. for(var i=0; i<ca.length; i++) {
  405. var c = ca[i];
  406. while (c.charAt(0)==' ') c = c.substring(1);
  407. if (c.indexOf(name) == 0) return c.substring(name.length,c.length);
  408. }
  409. return "";
  410. }
  411. },
  412. timeConvert: function(d1, d2){
  413. var parsed = {
  414. years: 0,
  415. months: 0,
  416. days: 0,
  417. hours: 0,
  418. minutes: 0,
  419. seconds: 0,
  420. milisseconds: 0
  421. };
  422. var times = {
  423. year: 31536000e3,
  424. month: 2628000e3,
  425. day: 86400e3,
  426. hour: 3600e3,
  427. min: 60e3,
  428. sec: 1e3
  429. };
  430. var diff = d1 - (d2||0);
  431.  
  432. if (diff >= times.year){
  433. parsed.years = Math.floor(diff/times.year);
  434. diff -= parsed.years*times.year;
  435. }
  436.  
  437. if (diff >= times.month){
  438. parsed.months = Math.floor(diff/times.month);
  439. diff -= parsed.months*times.month;
  440. }
  441.  
  442. if (diff >= times.day){
  443. parsed.days = Math.floor(diff/times.day);
  444. diff -= parsed.days*times.day;
  445. }
  446.  
  447. if (diff >= times.hour){
  448. parsed.hours = Math.floor(diff/times.hour);
  449. diff -= parsed.hours*times.hour;
  450. }
  451.  
  452. if (diff >= times.min){
  453. parsed.minutes = Math.floor(diff/times.min);
  454. diff -= parsed.minutes*times.min;
  455. }
  456.  
  457. if (diff >= times.sec){
  458. parsed.seconds = Math.floor(diff/times.sec);
  459. diff -= parsed.seconds*times.sec;
  460. }
  461.  
  462. parsed.milisseconds = diff;
  463.  
  464. return parsed;
  465. },
  466.  
  467. url: {
  468. //useful regex from http://stackoverflow.com/a/3809435, this works much better than the old regex
  469. regex: /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g,
  470. serverUrl: 'https://mp-caipira.rhcloud.com/',
  471. getURLData: function(url, data, body, callback){
  472. //note: images have the content-type starting with image/*
  473. //others types: http://webdesign.about.com/od/multimedia/a/mime-types-by-content-type.htm
  474. //useful to show image loading: http://stackoverflow.com/questions/76976/how-to-get-progress-from-xmlhttprequest
  475. //ps: CORS, CORS!!!
  476. //can solve using this tool: https://cors-anywhere.herokuapp.com/[full_request_url_here]
  477. //example: https://robwu.nl/cors-anywhere.html
  478.  
  479. if (typeof data != 'string' && !Array.isArray(data)) return console.log('Invalid headers field');
  480. if (typeof callback != 'function') return console.log('Callback must be required');
  481.  
  482. if (typeof data == 'string') data = [data];
  483. var xhttp = new XMLHttpRequest();
  484.  
  485. xhttp.onreadystatechange = function() {
  486. if (xhttp.readyState == 4) {
  487. if (xhttp.status == 200){
  488. var fields = {};
  489.  
  490. for (var i in data){
  491. fields[data[i]] = xhttp.getResponseHeader(data[i]);
  492. }
  493. callback(fields, url, xhttp.responseText);
  494. }else{
  495. callback(null, url);
  496. }
  497. }
  498. };
  499. xhttp.open((body ? "GET" : "HEAD"), MP.url.serverUrl+url, true);
  500. xhttp.send();
  501. },
  502. parse: function(txt, keep_protocol_js_url){
  503. return txt.replace(this.regex,function(a){
  504. return '<a target="_blank" href="'+a+'">'+(keep_protocol_js_url && /.js$/i.test(a) ? a : a.replace(/^https?:\/\//i, ''))+'</a>';
  505. });
  506. },
  507.  
  508. match: function(txt){
  509. return txt.match(this.regex) || [];
  510. }
  511. },
  512.  
  513. chatImage: {
  514. knownSites: [
  515. 'prntscr.com/',
  516. 'giphy.com/gifs/',
  517. '500px.com/photo/',
  518. 'pixabay.com/',
  519. 'flickr.com/photos/'
  520. ],
  521. append: function(element, url, imgClickUrl){
  522. imgClickUrl = imgClickUrl ? imgClickUrl : url;
  523. var settings = JSON.parse(localStorage.getItem("settings"));
  524. element.append('<span class="image-content" style="color: #79BE6C; cursor: pointer;"><span class="image-toggle" onclick="API.util.toggle_images(\''+escape(url)+'\',\''+escape(imgClickUrl)+'\',this);" style="cursor: pointer;">[Show Image]</span></span> ');
  525.  
  526. if (settings && settings.roomSettings && settings.roomSettings.showImages)
  527. element.find('.image-toggle').last().click();
  528. },
  529. parse: function(msg, cid){
  530. if (!msg || !cid) return;
  531.  
  532. var urls = MP.url.match(msg);
  533.  
  534. if (urls.length > 0){
  535. var msgdom = $('#cm-' + cid + ' .umsg');
  536. if (!msgdom.length) return;
  537.  
  538. msgdom.append('<br>');
  539.  
  540. var settings = JSON.parse(localStorage.getItem("settings"));
  541.  
  542. for (var i in urls){
  543. if (urls[i].match(/\.(png|jpe?g|gif)/i) != null){
  544. MP.chatImage.append(msgdom, urls[i]);
  545. }else{
  546. var reg = new RegExp('('+MP.chatImage.knownSites.join('|').replace(/\./g,'\\\.').replace(/\//g,'\\\/')+')','i');
  547. if (urls[i].match(reg) != null){
  548. MP.chatImage.getImageFromMeta(urls[i], false, function(imgurl){
  549. if (imgurl){
  550. MP.chatImage.append(msgdom, imgurl);
  551. }
  552. });
  553. }
  554. if (urls[i].match(/facebook.com\/(.*?)\/?photo(s\/)?/) != null){
  555. MP.url.getURLData(urls[i], [], true, function(fields, pageurl, body){
  556. if (!body) return;
  557.  
  558. var imgurl = (body.match(/<img(.*?)class="fbPhotoImage img"(.*?)src="(.*?)"(.*?)alt="/)||[])[3];
  559.  
  560. if (!imgurl) return;
  561. imgurl = imgurl.replace(/&amp;/g,'&');
  562. MP.chatImage.append(msgdom, imgurl);
  563. });
  564. }
  565. var ytmatch = urls[i].match(/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/);
  566. var ytid = ((ytmatch&&ytmatch[7].length==11)? ytmatch[7] : false);
  567. if (ytid != false){
  568. MP.chatImage.append(msgdom, "https://img.youtube.com/vi/" + ytid + "/mqdefault.jpg", urls[i]);
  569. }
  570. }
  571. }
  572. }
  573. },
  574.  
  575. getImageFromMeta: function(url, imgLength, callback){
  576. MP.url.getURLData(url, ['x-final-url'], true, function(fields, _url, body){
  577. if (!body) return callback(null);
  578.  
  579. var imgurl = (body.match(/<meta.*property=['"]og:image['"].*>/)||[])[0];
  580.  
  581. if (!imgurl) return callback(null);
  582.  
  583. imgurl = imgurl.match(MP.url.regex)[0];
  584.  
  585. if (imgLength){
  586. MP.url.getURLData(imgurl, ['Content-length'], false, function(_fields, _imgurl, _body){
  587. callback(imgurl, _fields['Content-length']);
  588. });
  589. }else{
  590. callback(imgurl);
  591. }
  592. });
  593. },
  594. showModal: function(url){
  595. API.util.makeCustomModal({
  596. content: '<div class="image-modal"><div id="image-preview"></div>',
  597. buttons: [
  598. {
  599. icon: 'mdi-arrow-left-bold',
  600. handler: function(){
  601. // $('.modal-bg').remove();
  602. },
  603. classes: 'modal-yes'
  604. },
  605. {
  606. icon: 'mdi-close',
  607. handler: function(){
  608. $('.modal-bg').remove();
  609. },
  610. classes: 'modal-no'
  611. },
  612. {
  613. icon: 'mdi-arrow-right-bold',
  614. handler: function(){
  615. // $('.modal-bg').remove();
  616. },
  617. classes: 'modal-yes'
  618. }
  619. ],
  620. style: {
  621. width:'auto',
  622. height:'auto',
  623. 'min-width':'35%',
  624. 'min-height':'35%',
  625. 'max-width':'80%',
  626. 'max-height':'80%',
  627. display:'table'
  628. },
  629. dismissable: true,
  630. appendTo: '#app-left',
  631. callback: function(){
  632. $('.modal-box').css({display: 'table-cell'});
  633. var img = new Image();
  634. img.src = url;
  635. img.style = 'width: 100%; height: 100%;';
  636.  
  637. $('#image-preview').append(img);
  638. }
  639. });
  640. }
  641. },
  642.  
  643. api: {
  644. queue: {
  645. join: function(callback){
  646. if (typeof callback != 'function') callback = function(){};
  647.  
  648. var user = MP.user;
  649. if (!user){
  650. callback('notLoggedIn');
  651. return false;
  652. }
  653. if (!MP.checkPerm('djqueue.join')){
  654. callback('InsufficientPermissions');
  655. return false;
  656. }
  657. if (MP.findPosInWaitlist() >= 0){
  658. callback('alreadyInQueue');
  659. return false;
  660. }
  661. if (MP.session.queue.lock && !MP.checkPerm('djqueue.joinlocked')){
  662. callback('queueLocked');
  663. return false;
  664. }
  665. MP.djQueueJoin(callback);
  666. return true;
  667. },
  668. leave: function(callback){
  669. if (typeof callback != 'function') callback = function(){};
  670.  
  671. var user = MP.user;
  672. if (!user){
  673. callback('notLoggedIn');
  674. return false;
  675. }
  676. if (!MP.checkPerm('djqueue.leave')){
  677. callback('InsufficientPermissions');
  678. return false;
  679. }
  680. if (MP.findPosInWaitlist() == -1){
  681. callback('notInQueue');
  682. return false;
  683. }
  684. MP.djQueueLeave(callback);
  685. return true;
  686. },
  687. modAddDJ: function(uid, position, callback){
  688. if (typeof position == 'function'){
  689. callback = position;
  690. position = undefined;
  691. }
  692. if (typeof callback != 'function') callback = function(){};
  693.  
  694. if (!MP.user){
  695. callback('notLoggedIn');
  696. return false;
  697. }
  698.  
  699. if (typeof position == 'number'){
  700. position--;
  701. }
  702.  
  703. var user = MP.findUser(uid);
  704. if (!user){
  705. callback('userNotFound');
  706. return false;
  707. }
  708. if (MP.findPosInWaitlist(uid) >= 0){
  709. callback('alreadyInQueue');
  710. return false;
  711. }
  712. if (MP.session.queue.lock && !MP.checkPerm('djqueue.move')){
  713. callback('InsufficientPermissions');
  714. return false;
  715. }
  716. MP.djQueueModAdd(user.uid, position, callback);
  717. return true;
  718. },
  719. modRemoveDJ: function(uid, callback){
  720. if (typeof callback != 'function') callback = function(){};
  721.  
  722. if (!MP.user){
  723. callback('notLoggedIn');
  724. return false;
  725. }
  726.  
  727. var user = MP.findUser(uid);
  728. if (!user){
  729. callback('userNotFound');
  730. return false;
  731. }
  732. if (MP.findPosInWaitlist(user.uid) == -1){
  733. callback('notInQueue');
  734. return false;
  735. }
  736. if (MP.session.queue.lock && !MP.checkPerm('djqueue.move')){
  737. callback('InsufficientPermissions');
  738. return false;
  739. }
  740. MP.djQueueModRemove(user.uid, callback);
  741. return true;
  742. },
  743. modSwapDJ: function(uid1, uid2, callback){
  744. if (typeof callback != 'function') callback = function(){};
  745.  
  746. if (!MP.user){
  747. callback('notLoggedIn');
  748. return false;
  749. }
  750.  
  751. if (MP.session.queue.lock && !MP.checkPerm('djqueue.move')){
  752. callback('InsufficientPermissions');
  753. return false;
  754. }
  755.  
  756. var user1 = MP.findUser(uid1);
  757. var user2 = MP.findUser(uid2);
  758. if (!user1 || !user2){
  759. callback('userNotFound');
  760. return false;
  761. }
  762. if (user1.uid == user2.uid){
  763. callback('sameUser');
  764. return false;
  765. }
  766. if (MP.findPosInWaitlist(user1.uid) == -1 || MP.findPosInWaitlist(user2.uid) == -1){
  767. callback('notInQueue');
  768. return false;
  769. }
  770. MP.djQueueModSwap(user1.uid, user2.uid, callback);
  771. return true;
  772. },
  773. modMoveDJ: function(uid, position, callback){
  774. if (typeof callback != 'function') callback = function(){};
  775.  
  776. if (!MP.user){
  777. callback('notLoggedIn');
  778. return false;
  779. }
  780.  
  781. if (MP.session.queue.lock && !MP.checkPerm('djqueue.move')){
  782. callback('InsufficientPermissions');
  783. return false;
  784. }
  785.  
  786. var user = MP.findUser(uid);
  787. if (!user){
  788. callback('userNotFound');
  789. return false;
  790. }
  791. if (MP.findPosInWaitlist(user.uid) == -1){
  792. callback('notInQueue');
  793. return false;
  794. }
  795. MP.djQueueModMove(user.uid, position, callback);
  796. return true;
  797. },
  798. skip: function(lockSkipPosition, callback){
  799. if (typeof lockSkipPosition == 'function'){
  800. callback = lockSkipPosition;
  801. lockSkipPosition = undefined;
  802. }
  803. if (typeof callback != 'function') callback = function(){};
  804.  
  805. if (!MP.checkPerm('djqueue.skip.self') && !MP.checkPerm('djqueue.skip.other')){
  806. callback('InsufficientPermissions');
  807. return false;
  808. }
  809. MP.djQueueSkip(lockSkipPosition, callback);
  810. },
  811. setLock: function(status, callback){
  812. if (typeof status == 'function'){
  813. callback = status;
  814. status = !MP.session.queue.lock;
  815. }
  816. if (typeof status == 'undefined') status = !MP.session.queue.lock;
  817. if (typeof callback != 'function') callback = function(){};
  818.  
  819. if (!MP.user){
  820. callback('notLoggedIn');
  821. return false;
  822. }
  823.  
  824. if (MP.checkPerm('djqueue.lock')){
  825. callback('InsufficientPermissions');
  826. return false;
  827. }
  828.  
  829. if (status == MP.session.queue.lock){
  830. callback('noChange');
  831. return false;
  832. }
  833.  
  834. MP.djQueueLock(callback);
  835. return true;
  836. },
  837. setCycle: function(status, callback){
  838. if (typeof status == 'function'){
  839. callback = status;
  840. status = !MP.session.queue.cycle;
  841. }
  842. if (typeof status == 'undefined') status = !MP.session.queue.cycle;
  843. if (typeof callback != 'function') callback = function(){};
  844.  
  845. if (!MP.user){
  846. callback('notLoggedIn');
  847. return false;
  848. }
  849.  
  850. if (MP.checkPerm('djqueue.cycle')){
  851. callback('InsufficientPermissions');
  852. return false;
  853. }
  854.  
  855. if (status == MP.session.queue.cycle){
  856. callback('noChange');
  857. return false;
  858. }
  859.  
  860. MP.djQueueCycle(callback);
  861. return true;
  862. },
  863. setLimit: function(limit, callback){
  864. if (typeof callback != 'function') callback = function(){};
  865.  
  866. if (!MP.user){
  867. callback('notLoggedIn');
  868. return false;
  869. }
  870.  
  871. if (MP.checkPerm('djqueue.limit')){
  872. callback('InsufficientPermissions');
  873. return false;
  874. }
  875.  
  876. if (typeof limit != 'number' || limit < 1){
  877. callback('invalidValue');
  878. return false;
  879. }
  880. MP.djQueueLimit(limit, callback);
  881. return true;
  882. },
  883. getDJ: function(){
  884. return MP.session.queue.currentdj;
  885. },
  886. getDJs: function(arr){
  887. if (typeof arr == 'undefined') arr = true;
  888.  
  889. if (arr){
  890. var queue = [];
  891.  
  892. for (var i in MP.session.queue.users){
  893. queue.push(MP.seenUsers[MP.session.queue.users[i]]);
  894. }
  895. return queue;
  896. }else{
  897. var queue = {};
  898.  
  899. for (var i in MP.session.queue.users){
  900. var user = MP.seenUsers[MP.session.queue.users[i]];
  901. queue[user.uid] = user;
  902. }
  903. return queue;
  904. }
  905. },
  906. getPosition: function(uid){
  907. return MP.findPosInWaitlist(uid);
  908. },
  909. getInfo: function(){
  910. return {
  911. lock: MP.session.queue.lock,
  912. cycle: MP.session.queue.cycle,
  913. length: this.getDJs(true).length,
  914. dj: this.getDJ()
  915. };
  916. }
  917. },
  918. room: {
  919. getInfo: function(callback){
  920. if (typeof callback == 'function') return MP.getRoomInfo(callback);
  921. return MP.session.roomInfo;
  922. },
  923. isLoggedIn: function(){
  924. return MP.isLoggedIn();
  925. },
  926. getUser: function(uid){
  927. if (!uid) return MP.user;
  928. return MP.findUser(uid);
  929. },
  930. getUsers: function(arr){
  931. if (typeof arr == 'undefined') arr = false;
  932.  
  933. var users = MP.getUsersInRoom();
  934. if (arr){
  935. return MP.api.util.objectToArray(users);
  936. }
  937. return users;
  938. },
  939. getRoles: function(arr){
  940. if (typeof arr == 'undefined') arr = false;
  941.  
  942. var roles = MP.session.roles;
  943. if (arr){
  944. return MP.api.util.objectToArray(roles);
  945. }
  946. return roles;
  947. },
  948. getHistory: function(callback){
  949. if (typeof callback == 'undefined'){
  950. return MP.historyList.history;
  951. }
  952. MP.getHistory(callback);
  953. },
  954. getMedia: function(){
  955. return MP.media.media;
  956. },
  957. getTimeElapsed: function(){
  958. return MP.getTimeElapsed();
  959. },
  960. getTimeRemaining: function(){
  961. return MP.getTimeRemaining();
  962. },
  963. setRole: function(uid, role, callback){
  964. if (typeof callback != 'function') callback = function(){};
  965.  
  966. if (!MP.user){
  967. callback('notLoggedIn');
  968. return false;
  969. }
  970.  
  971. if (!MP.checkPerm('room.grantroles')){
  972. callback('InsufficientPermissions');
  973. return false;
  974. }
  975.  
  976. if (!role){
  977. callback('invalidRole');
  978. return false;
  979. }
  980. role = role.toLowerCase();
  981.  
  982. var roles = this.getRoles(false);
  983. if (!roles || roles[role].canGrantRoles.indexOf(role) == -1){
  984. callback('invalidRole');
  985. return false;
  986. }
  987.  
  988. var user = MP.findUser(uid);
  989. if (!user){
  990. callback('userNotFound');
  991. return false;
  992. }
  993.  
  994. MP.setRole(uid, role, callback);
  995. return true;
  996. },
  997. getStaff: function(callback){
  998. if (typeof callback != 'function') return MP.session.roomStaff;
  999. MP.getRoomStaff(callback);
  1000. },
  1001. getBannedUsers: function(callback){
  1002. if (typeof callback != 'function') return MP.session.bannedUsers;
  1003. MP.getBannedUsers(callback);
  1004. },
  1005. banUser: function(uid, duration, reason, callback){
  1006. if (typeof reason == 'function'){
  1007. callback = reason;
  1008. reason = '';
  1009. }
  1010. if (!reason) reason = '';
  1011.  
  1012. if (typeof callback != 'function') callback = function(){};
  1013.  
  1014. if (!MP.user){
  1015. callback('notLoggedIn');
  1016. return false;
  1017. }
  1018.  
  1019. if (!MP.checkPerm('room.banUser')){
  1020. callback('InsufficientPermissions');
  1021. return false;
  1022. }
  1023.  
  1024. if (!duration){
  1025. callback('missingDuration');
  1026. return false;
  1027. }
  1028.  
  1029. var user = MP.findUser(uid);
  1030. if (!user){
  1031. callback('userNotFound');
  1032. return false;
  1033. }
  1034. MP.banUser(uid, duration, reason, callback);
  1035. return true;
  1036. },
  1037. unbanUser: function(uid, callback){
  1038. if (typeof callback != 'function') callback = function(){};
  1039.  
  1040. if (!MP.user){
  1041. callback('notLoggedIn');
  1042. return false;
  1043. }
  1044.  
  1045. if (!MP.checkPerm('room.banUser')){
  1046. callback('InsufficientPermissions');
  1047. return false;
  1048. }
  1049. if (!uid){
  1050. callback('invalidUid');
  1051. return false;
  1052. }
  1053.  
  1054. MP.unbanUser(uid, callback);
  1055. return true;
  1056. }
  1057. },
  1058. chat: {
  1059. log: function(a,b){
  1060. MP.addMessage({msg:a,user:{un:b}}, 'log');
  1061. },
  1062. system: function(msg){
  1063. MP.addMessage(msg, 'system');
  1064. },
  1065. broadcast: function(msg){
  1066. if (!MP.user || !MP.checkPerm('chat.broadcast')) return false;
  1067.  
  1068. MP.sendBroadcast(msg);
  1069. return true;
  1070. },
  1071. send: function(msg){
  1072. if (!MP.user || !msg || !MP.checkPerm('chat.send')) return false;
  1073.  
  1074. MP.sendMessage(msg);
  1075. return true;
  1076. },
  1077. sendPrivate: function(uid, message, callback){
  1078. MP.privateMessage(uid, message, callback);
  1079. },
  1080. delete: function(cid, callback){
  1081. if (!MP.user || !cid || !MP.checkPerm('chat.delete')) return false;
  1082.  
  1083. MP.deleteChat(cid, callback);
  1084. return true;
  1085. },
  1086. getPos: function(){
  1087. var $chat = $("#chat");
  1088. return $chat[0].scrollTop + $chat.height() - $chat[0].scrollHeight + 20;
  1089. },
  1090. setPos: function(pos){
  1091. var $chat = $("#chat");
  1092. $chat.scrollTop(pos);
  1093. },
  1094. scrollBottom: function(){
  1095. var $chat = $("#chat");
  1096. $chat.scrollTop($chat[0].scrollHeight);
  1097. }
  1098. },
  1099. playlist: {
  1100. get: function(pid, arr){
  1101. if (typeof pid == 'boolean'){
  1102. arr = pid;
  1103. pid = null;
  1104. }
  1105. if (typeof arr == 'undefined') arr = true;
  1106.  
  1107. if (pid) return MP.user.playlists[pid];
  1108.  
  1109. var playlists = MP.user.playlists;
  1110.  
  1111. if (arr) playlists = MP.api.util.objectToArray(playlists);
  1112. return playlists;
  1113. },
  1114. getActive: function(){
  1115. if (!MP.user || !MP.user.activepl || !MP.user.playlists || !MP.user.playlists[MP.user.activepl]) return null;
  1116. return MP.user.playlists[MP.user.activepl];
  1117. },
  1118. active: function(pid, callback){
  1119. if (!MP.user || !MP.user.activepl || !MP.user.playlists || !MP.user.playlists[MP.user.activepl]) return null;
  1120.  
  1121. return MP.user.playlists[MP.user.activepl];
  1122. },
  1123. getNextSong: function(){
  1124. if (!MP.user || !MP.user.activepl || !MP.user.playlists || !MP.user.playlists[MP.user.activepl]) return null;
  1125. return MP.user.playlists[MP.user.activepl].content[0] || null;
  1126. },
  1127. create: function(name, callback){
  1128. if (typeof callback != 'function') callback = function(){};
  1129.  
  1130. if (!MP.user){
  1131. callback('notLoggedIn');
  1132. return false;
  1133. }
  1134.  
  1135. if (!MP.checkPerm('playlist.create')){
  1136. callback('InsufficientPermissions');
  1137. return false;
  1138. }
  1139. if (!name){
  1140. callback('emptyName');
  1141. return false;
  1142. }
  1143.  
  1144. MP.playlistCreate(name, callback);
  1145. return true;
  1146. },
  1147. delete: function(pid, callback){
  1148. if (typeof callback != 'function') callback = function(){};
  1149.  
  1150. if (!MP.user){
  1151. callback('notLoggedIn');
  1152. return false;
  1153. }
  1154.  
  1155. if (!MP.checkPerm('playlist.delete')){
  1156. callback('InsufficientPermissions');
  1157. return false;
  1158. }
  1159. if (!MP.user.playlists[pid]){
  1160. callback('playlistNotFound');
  1161. return false;
  1162. }
  1163. MP.playlistDelete(pid, callback);
  1164. return true;
  1165. },
  1166. addSong: function(pid, cid, pos, callback){
  1167. if (typeof pos == 'function'){
  1168. callback = pos;
  1169. pos = 0;
  1170. }
  1171. if (typeof pos != 'number') pos = 0;
  1172. if (typeof callback != 'function') callback = function(){};
  1173.  
  1174. if (!pid || !cid){
  1175. callback('invalidPidOrCid');
  1176. return false;
  1177. }
  1178. /*
  1179. if (typeof pid == 'string'){
  1180. var pl = this.get().filter(function(a){return a.name == pid;})[0];
  1181.  
  1182. if (pl == undefined){
  1183. callback('playlistNotFound');
  1184. return false;
  1185. }
  1186. pid = pl.id;
  1187. }
  1188. */
  1189. if (!MP.user.playlists[pid]){
  1190. callback('playlistNotFound');
  1191. return false;
  1192. }
  1193. if (MP.user.playlists[pid].content && MP.user.playlists[pid].content.filter(function(a){return a.cid == cid;}).length>0){
  1194. callback('SongAlreadyInPlaylist');
  1195. return false;
  1196. }
  1197.  
  1198. MP.playlistAdd(pid, cid, pos, callback);
  1199. return true;
  1200. },
  1201. removeSong: function(pid, cid, callback){
  1202. if (typeof callback != 'function') callback = function(){};
  1203.  
  1204. if (!pid || !cid){
  1205. callback('invalidPidOrCid');
  1206. return false;
  1207. }
  1208. if (!MP.user.playlists[pid]){
  1209. callback('playlistNotFound');
  1210. return false;
  1211. }
  1212.  
  1213. MP.playlistRemove(pid, cid, callback);
  1214. return true;
  1215. },
  1216. moveSong: function(pid, cid, pos, callback){
  1217. if (typeof pos == 'function'){
  1218. callback = pos;
  1219. pos = 0;
  1220. }
  1221. if (typeof pos != 'number') pos = 0;
  1222. if (typeof callback != 'function') callback = function(){};
  1223.  
  1224. if (!pid || !cid){
  1225. callback('invalidPidOrCid');
  1226. return false;
  1227. }
  1228. if (!MP.user.playlists[pid]){
  1229. callback('playlistNotFound');
  1230. return false;
  1231. }
  1232. MP.playlistMove(pid, cid, pos, callback);
  1233. return true;
  1234. },
  1235. getContents: function(pid, arr, callback){
  1236. if (!pid){
  1237. callback('invalidPid');
  1238. return false;
  1239. }
  1240. if (!MP.user.playlists[pid]){
  1241. callback('playlistNotFound');
  1242. return false;
  1243. }
  1244.  
  1245. if (typeof callback == 'undefined') return MP.user.playlists[pid].content;
  1246. MP.getPlaylistContents(pid, callback);
  1247. return true;
  1248. },
  1249. shuffle: function(pid, callback){
  1250. if (!MP.checkPerm('playlist.shuffle')){
  1251. if (callback) callback('InsufficientPermissions');
  1252. return false;
  1253. }
  1254.  
  1255. if(!(pid = pid || MP.session.viewedPl)){
  1256. if (callback) callback('NoPlaylistSelected');
  1257. return false;
  1258. }
  1259. var obj = {
  1260. type: 'playlistShuffle',
  1261. data: {
  1262. pid: pid,
  1263. }
  1264. };
  1265. obj.id = MP.addCallback(obj.type, function(err, data){
  1266. if(err) return;
  1267. if("function" === typeof callback) callback(null, MP.copyObject(data));
  1268. MP.user.playlists[pid].content = data.content;
  1269. MP.applyModels();
  1270. });
  1271. socket.sendJSON(obj);
  1272. return true;
  1273. },
  1274. import: function(pid, expand, callback){
  1275. if (!MP.checkPerm('playlist.import')){
  1276. if (callback) callback('InsufficientPermissions');
  1277. return false;
  1278. }
  1279. MP.playlistImport(pid, expand, callback);
  1280. }
  1281. },
  1282. util: {
  1283. makeAlertModal: function(opts){MP.makeAlertModal(opts);},
  1284. makeCustomModal: function(opts){MP.makeCustomModal(opts);},
  1285. showBanModal: function(uid){MP.showBanModal(uid);},
  1286. showRoleModal: function(uid){MP.showRoleModal(uid);},
  1287. objectToArray: function(obj){
  1288. if (typeof obj != 'object' || obj == null) return [];
  1289. var arr = [];
  1290.  
  1291. for (var i in obj) arr.push(obj[i]);
  1292. return arr;
  1293. },
  1294. timeConvert: function(d1,d2){return MP.timeConvert(d1,d2);},
  1295. youtube_parser: function(url){
  1296. var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
  1297. var match = url.match(regExp);
  1298. return (match && match[7].length == 11) ? match[7] : false;
  1299. }, // Useful function from http://stackoverflow.com/a/8260383
  1300. colourNameToHex: function(colour){ // Useful function from http://stackoverflow.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes
  1301. var colours = {"aliceblue":"#f0f8ff","antiquewhite":"#faebd7","aqua":"#00ffff","aquamarine":"#7fffd4","azure":"#f0ffff",
  1302. "beige":"#f5f5dc","bisque":"#ffe4c4","black":"#000000","blanchedalmond":"#ffebcd","blue":"#0000ff","blueviolet":"#8a2be2",
  1303. "brown":"#a52a2a","burlywood":"#deb887","cadetblue":"#5f9ea0","chartreuse":"#7fff00","chocolate":"#d2691e","coral":"#ff7f50",
  1304. "cornflowerblue":"#6495ed","cornsilk":"#fff8dc","crimson":"#dc143c","cyan":"#00ffff","darkblue":"#00008b","darkcyan":"#008b8b",
  1305. "darkgoldenrod":"#b8860b","darkgray":"#a9a9a9","darkgreen":"#006400","darkkhaki":"#bdb76b","darkmagenta":"#8b008b",
  1306. "darkolivegreen":"#556b2f","darkorange":"#ff8c00","darkorchid":"#9932cc","darkred":"#8b0000","darksalmon":"#e9967a",
  1307. "darkseagreen":"#8fbc8f","darkslateblue":"#483d8b","darkslategray":"#2f4f4f","darkturquoise":"#00ced1","darkviolet":"#9400d3",
  1308. "deeppink":"#ff1493","deepskyblue":"#00bfff","dimgray":"#696969","dodgerblue":"#1e90ff","firebrick":"#b22222",
  1309. "floralwhite":"#fffaf0","forestgreen":"#228b22","fuchsia":"#ff00ff","gainsboro":"#dcdcdc","ghostwhite":"#f8f8ff","gold":"#ffd700",
  1310. "goldenrod":"#daa520","gray":"#808080","green":"#008000","greenyellow":"#adff2f","honeydew":"#f0fff0","hotpink":"#ff69b4",
  1311. "indianred ":"#cd5c5c","indigo":"#4b0082","ivory":"#fffff0","khaki":"#f0e68c","lavender":"#e6e6fa","lavenderblush":"#fff0f5",
  1312. "lawngreen":"#7cfc00","lemonchiffon":"#fffacd","lightblue":"#add8e6","lightcoral":"#f08080","lightcyan":"#e0ffff",
  1313. "lightgoldenrodyellow":"#fafad2","lightgrey":"#d3d3d3","lightgreen":"#90ee90","lightpink":"#ffb6c1","lightsalmon":"#ffa07a",
  1314. "lightseagreen":"#20b2aa","lightskyblue":"#87cefa","lightslategray":"#778899","lightsteelblue":"#b0c4de","lightyellow":"#ffffe0",
  1315. "lime":"#00ff00","limegreen":"#32cd32","linen":"#faf0e6","magenta":"#ff00ff","maroon":"#800000","mediumaquamarine":"#66cdaa",
  1316. "mediumblue":"#0000cd","mediumorchid":"#ba55d3","mediumpurple":"#9370d8","mediumseagreen":"#3cb371","mediumslateblue":"#7b68ee",
  1317. "mediumspringgreen":"#00fa9a","mediumturquoise":"#48d1cc","mediumvioletred":"#c71585","midnightblue":"#191970",
  1318. "mintcream":"#f5fffa","mistyrose":"#ffe4e1","moccasin":"#ffe4b5","navajowhite":"#ffdead","navy":"#000080","oldlace":"#fdf5e6",
  1319. "olive":"#808000","olivedrab":"#6b8e23","orange":"#ffa500","orangered":"#ff4500","orchid":"#da70d6","palegoldenrod":"#eee8aa",
  1320. "palegreen":"#98fb98","paleturquoise":"#afeeee","palevioletred":"#d87093","papayawhip":"#ffefd5","peachpuff":"#ffdab9",
  1321. "peru":"#cd853f","pink":"#ffc0cb","plum":"#dda0dd","powderblue":"#b0e0e6","purple":"#800080","red":"#ff0000",
  1322. "rosybrown":"#bc8f8f","royalblue":"#4169e1","saddlebrown":"#8b4513","salmon":"#fa8072","sandybrown":"#f4a460",
  1323. "seagreen":"#2e8b57","seashell":"#fff5ee","sienna":"#a0522d","silver":"#c0c0c0","skyblue":"#87ceeb","slateblue":"#6a5acd",
  1324. "slategray":"#708090","snow":"#fffafa","springgreen":"#00ff7f","steelblue":"#4682b4","tan":"#d2b48c","teal":"#008080",
  1325. "thistle":"#d8bfd8","tomato":"#ff6347","turquoise":"#40e0d0","violet":"#ee82ee","wheat":"#f5deb3","white":"#ffffff",
  1326. "whitesmoke":"#f5f5f5","yellow":"#ffff00","yellowgreen":"#9acd32"};
  1327.  
  1328. if (typeof colours[colour.toLowerCase()] != 'undefined')
  1329. return colours[colour.toLowerCase()];
  1330.  
  1331. return false;
  1332. },
  1333. makeStyleString: function(obj){
  1334. var style = '';
  1335.  
  1336. for (var i in obj){
  1337. style += (i + ': ' + obj[i] + '; ');
  1338. }
  1339.  
  1340. return style;
  1341. },
  1342. toggle_images: function(url,clickUrl,ctx){
  1343. if (!url || !clickUrl || !ctx)
  1344. return;
  1345. ctx = $(ctx).parent();
  1346. var img_cont = ctx.find('.image-content');
  1347.  
  1348. if (!img_cont.length){
  1349. ctx.find('.image-toggle').text('[Hide Image]');
  1350. var el = $('<span class="image-content"></span>'),
  1351. img_link = document.createElement('a'),
  1352. img_el = document.createElement('img');
  1353.  
  1354. el.append('<br>');
  1355. img_link.setAttribute('class','chat-image');
  1356. img_link.setAttribute('href', unescape(clickUrl ? clickUrl : url));
  1357. img_link.setAttribute('target','_blank');
  1358. img_link.setAttribute('data-lightbox', MP.session.imgc++);
  1359. img_el.setAttribute('src', unescape(url));
  1360. img_el.setAttribute('style','max-width: 100%;');
  1361. img_el.onload = function(){
  1362. var $chat = $("#chat");
  1363. $chat.scrollTop($chat[0].scrollHeight);
  1364. };
  1365.  
  1366. img_link = $(img_link);
  1367. img_link.append(img_el);
  1368. el.append(img_link);
  1369. el.append('<br>');
  1370. ctx.append(el);
  1371. }else{
  1372. img_cont.remove();
  1373. ctx.find('.image-toggle').text('[Show Image]');
  1374. }
  1375. },
  1376. changefavicon: function(src) {
  1377. var link = document.createElement('link'),
  1378. oldLink = document.getElementById('dynamic-favicon');
  1379. link.id = 'dynamic-favicon';
  1380. link.rel = 'shortcut icon';
  1381. link.href = src;
  1382. if (oldLink) {
  1383. document.head.removeChild(oldLink);
  1384. }
  1385. document.head.appendChild(link);
  1386. },
  1387. },
  1388. showLogin: function(){
  1389. $('#creds-back').css('display','table');
  1390. $('.dash, #app-left, #app-right').hide();
  1391. $('#l-email').focus();
  1392. grecaptcha.reset();
  1393. },
  1394. hideLogin: function(){
  1395. $('#creds-back').hide();
  1396. $('.dash, #app-left, #app-right').show();
  1397. },
  1398. },
  1399. mediaPreview : {
  1400. isOpened: function(){return MP.session.mediaPreview.player != null;},
  1401. open: function(cid){
  1402. var settings = JSON.parse(localStorage.getItem("settings"));
  1403.  
  1404. MP.makeCustomModal({
  1405. content: '<div class="modal-preview"><div id="player-preview" style="width:100%;"></div></div>',
  1406. buttons: [
  1407. {
  1408. icon: 'mdi-close',
  1409. handler: function(){
  1410. $('.modal-bg').remove();
  1411. MP.mediaPreview.close();
  1412. },
  1413. classes: 'modal-no'
  1414. }
  1415. ],
  1416. style: {
  1417. width: '50%'
  1418. },
  1419. dismissable: true,
  1420. appendTo: '.logo-menu',
  1421. callback: function(){
  1422. clearInterval(MP.session.mediaPreview.fadeInterval);
  1423. MP.session.mediaPreview.mainVolume = (settings.player.mute ? 0 : settings.player.volume);
  1424. MP.session.mediaPreview.previewVolume = MP.session.mediaPreview.mainVolume;
  1425.  
  1426. MP.session.mediaPreview.player = new YT.Player('player-preview', {
  1427. height: '390',
  1428. width: '640',
  1429. videoId: cid,
  1430. playerVars: {
  1431. controls: 1, //Enable controls
  1432. iv_load_policy: 3, //Disable annotations
  1433. showinfo: 1, //Enable video info
  1434. autoplay: 1, //Enable autoplay
  1435. fs: 0, //Disable fullscreen
  1436. modestbranding: 1, //Disable YT logo - YT API doesn't allow it anymore with showinfo: 0
  1437. rel: 0, //Disable showing related videos
  1438. disablekb: 1, //Disable keyboard
  1439. }
  1440. });
  1441. MP.session.mediaPreview.fadeInterval = setInterval(MP.mediaPreview.fadeOut,100);
  1442. }
  1443. });
  1444. },
  1445. close: function(){
  1446. if (!MP.session.mediaPreview.player){
  1447. return;
  1448. }
  1449. MP.session.mediaPreview.player.destroy();
  1450. MP.session.mediaPreview.player=null;
  1451.  
  1452. clearInterval(MP.session.mediaPreview.fadeInterval);
  1453.  
  1454. var settings = JSON.parse(localStorage.getItem("settings"));
  1455. MP.session.mediaPreview.mainVolume = (settings.player.mute ? 0 : settings.player.volume);
  1456. MP.session.mediaPreview.fadeInterval = setInterval(MP.mediaPreview.fadeIn,100);
  1457. },
  1458. fadeIn: function(){
  1459. MP.session.mediaPreview.previewVolume += 10;
  1460. if (MP.session.mediaPreview.previewVolume > MP.session.mediaPreview.mainVolume){
  1461. MP.session.mediaPreview.previewVolume = MP.session.mediaPreview.mainVolume;
  1462. }
  1463. API.player.getPlayer().setVolume(MP.session.mediaPreview.previewVolume);
  1464.  
  1465. if (MP.session.mediaPreview.previewVolume == MP.session.mediaPreview.mainVolume){
  1466. clearInterval(MP.session.mediaPreview.fadeInterval);
  1467. }
  1468. },
  1469. fadeOut: function(){
  1470. MP.session.mediaPreview.previewVolume -= 10;
  1471. if (MP.session.mediaPreview.previewVolume<0){
  1472. MP.session.mediaPreview.previewVolume=0;
  1473. }
  1474. API.player.getPlayer().setVolume(MP.session.mediaPreview.previewVolume);
  1475.  
  1476. if (MP.session.mediaPreview.previewVolume == 0){
  1477. clearInterval(MP.session.mediaPreview.fadeInterval);
  1478. }
  1479. }
  1480. },
  1481. clearTimeRemaining: function(){
  1482. clearInterval(MP.intervals.timeRemaining);
  1483. },
  1484. startTimeRemaining: function(){
  1485. MP.clearTimeRemaining();
  1486. MP.intervals.timeRemaining = setInterval(MP.updateTimeRemaining,1000);
  1487. },
  1488. updateTimeRemaining: function(){
  1489. if (MP.media.timeRemaining == 0){
  1490. return MP.clearTimeRemaining();
  1491. }
  1492. MP.media.timeRemaining--;
  1493.  
  1494. MP.applyModels();
  1495. },
  1496. getMedia: function(){
  1497. return MP.media.media;
  1498. },
  1499. getDuration: function(){
  1500. if (!MP.media.media){
  1501. return 0;
  1502. }
  1503. return MP.media.media.duration;
  1504. },
  1505. getTimeElapsed: function(){
  1506. if (!MP.media.media){
  1507. return 0;
  1508. }
  1509. return MP.media.media.duration - MP.media.timeRemaining;
  1510. },
  1511. getTimeRemaining: function(){
  1512. return MP.media.timeRemaining;
  1513. },
  1514. getWaitList: function(){
  1515. return MP.session.queue.users;
  1516. },
  1517. getUsersInRoom: function(){
  1518. var out = {};
  1519.  
  1520. for (var i in MP.userList.users){
  1521. out[ MP.userList.users[i] ] = MP.seenUsers[MP.userList.users[i]];
  1522. }
  1523.  
  1524. return out;
  1525. },
  1526. getRoomStaff: function(callback) {
  1527. var obj = {
  1528. type: 'getStaff'
  1529. };
  1530.  
  1531. obj.id = MP.addCallback(obj.type, function(err, data){
  1532. MP.session.roomStaff = data;
  1533.  
  1534. for (var i in data){
  1535. MP.seenUsers[data[i].uid] = data[i];
  1536. }
  1537.  
  1538. MP.applyModels();
  1539. if (typeof callback == 'function') callback(err, data);
  1540. });
  1541.  
  1542. socket.sendJSON(obj);
  1543. },
  1544. getBannedUsers: function(callback) {
  1545. var obj = {
  1546. type: 'getBannedUsers'
  1547. };
  1548.  
  1549. obj.id = MP.addCallback(obj.type, function(err, data){
  1550. MP.session.bannedUsers = data;
  1551.  
  1552. for (var i in data){
  1553. MP.seenUsers[data[i].uid] = data[i];
  1554. }
  1555.  
  1556. MP.applyModels();
  1557. if (typeof callback == 'function') callback(err, data);
  1558. });
  1559.  
  1560. socket.sendJSON(obj);
  1561. },
  1562. makeBadgeStyle: function(opts){
  1563. /*
  1564. {
  1565. user: {
  1566. badge: {
  1567. top,
  1568. bottom,
  1569. },
  1570. role,
  1571. },
  1572. type,
  1573. mdi,
  1574. class,
  1575. style,
  1576. }
  1577. */
  1578.  
  1579. opts.user = opts.user || {};
  1580. var badge = $.extend(MP.copyObject(opts.user.badge || {}), { outline: ((MP.getRole(opts.user.role) || {}).style || {}).color || 'white'});
  1581.  
  1582. if(!opts.mdi && badge.top && badge.bottom && badge.outline){
  1583. if(opts.user.banned){
  1584. var icon = 'account-remove';
  1585. opts.style = { color: '#C8303E', };
  1586. } else {
  1587. var icon = (MP.getRole(opts.user.role) || {}).badge;
  1588. }
  1589. if(icon){
  1590. return '<div class="mdi mdi-' + icon + ' bdg-icon ' + (opts.class || '') + '" style="color: ' + badge.outline + '"></div>';
  1591. } else {
  1592. var gradclass = ['badgegrad', badge.top, badge.bottom, opts.type].join(';');
  1593. return '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" version="1.1" class="bdg">\
  1594. <defs>\
  1595. <linearGradient id="' + gradclass + '">\
  1596. <stop stop-color="' + badge.top + '" offset="49%"></stop>\
  1597. <stop stop-color="' + badge.bottom + '" offset="51%"></stop>\
  1598. </linearGradient>\
  1599. </defs>\
  1600. <g>\
  1601. <circle id="circle" r="7.25" cy="8" cx="8" transform="rotate(45, 8, 8)" stroke-linecap="null" stroke-linejoin="null" stroke="' + badge.outline + '" fill="url(#' + gradclass + ')" stroke-width="1.5"></circle>\
  1602. </g>\
  1603. </svg>';
  1604. }
  1605. } else if (opts.mdi){
  1606. return '<div class="mdi mdi-' + opts.mdi + ' bdg-icon ' + opts.class + '" style="color: ' + ((opts.style || {}).color || 'white') + ';"></div>';
  1607. } else {
  1608. return '';
  1609. }
  1610.  
  1611. //Three colors | no outline
  1612. /*
  1613. return '<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" class="bdg">\
  1614. <defs>\
  1615. <linearGradient id="gradient" x1="0" y1="0" x2="1" y2="1">\
  1616. <stop offset="45%" stop-color="' + hexTop + '"/>\
  1617. <stop offset="45.1%" stop-color="' + nameCol + '"/>\
  1618. <stop offset="54.9%" stop-color="' + nameCol + '"/>\
  1619. <stop offset="55%" stop-color="' + hexBot + '"/>\
  1620. </linearGradient>\
  1621. </defs>\
  1622. <g>\
  1623. <circle stroke-width="0" fill="url(#gradient)" cx="8" cy="8" r="8"/>\
  1624. </g>\
  1625. </svg>';
  1626. */
  1627.  
  1628. //Original
  1629. /*
  1630. return 'background-image: linear-gradient(45deg, ' + hexBot + ' 45%, ' + hexTop + ' 45%); background-image: -moz-linear-gradient(45deg, ' + hexBot + ' 45%, ' + hexTop + ' 45%); background-image: -webkit-linear-gradient(45deg, ' + hexBot + ' 45%, ' + hexTop + ' 45%);';
  1631. */
  1632. },
  1633. makeUsernameStyle: function(role){
  1634. if (MP.getRole(role)){
  1635. var style = MP.getRole(role).style;
  1636. var out = '';
  1637.  
  1638. for (var i in style){
  1639. out += (i + ': ' + style[i] + '; ');
  1640. }
  1641.  
  1642. return out;
  1643. }else{
  1644. return '';
  1645. }
  1646. },
  1647. emojiReplace: function(text){
  1648. var settings = JSON.parse(localStorage.settings).roomSettings;
  1649.  
  1650. //Check if emojis are disabled
  1651. if(!settings.enableEmojis) return text;
  1652.  
  1653. //Parse all ASCII emojis
  1654. if(settings.emojis['basic'])
  1655. for(var key in MP.emotes_ascii){
  1656. text = text.replace(new RegExp("(^|\\s)(" + key.replace("<", "&lt;").replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + ")(?=\\s|$)", "g"), "$1:" + MP.emotes_ascii[key] + ":");
  1657. }
  1658.  
  1659. //Check for all emojis to replace
  1660. var toReplace = text.match(/:[\+a-zA-Z0-9_-]+:/g);
  1661.  
  1662. if(toReplace){
  1663. toReplace = toReplace.map(function(x){ return x.slice(1, -1).toLowerCase(); }).filter(function(e, i, a){ return a.indexOf(e) === i; });
  1664. for(var i in toReplace){
  1665. for(var emoset in MP.emotes)
  1666. if(MP.emotes[emoset][toReplace[i]] && JSON.parse(localStorage.settings).roomSettings.emojis[emoset.toLowerCase()]){
  1667. text = text.replace(new RegExp(':' + toReplace[i].replace('+', '\\+') + ':', 'gi'), '<img align="absmiddle" alt=":' + toReplace[i] + ':" class="emoji" src="' + MP.emotes[emoset][toReplace[i]].url + '" title=":' + toReplace[i] + ':"' + (MP.emotes[emoset][toReplace[i]].style ? 'style="' + MP.emotes[emoset][toReplace[i]].style + '"' : '') + ' />');
  1668. break;
  1669. }
  1670. }
  1671. return text;
  1672. } else return text;
  1673. },
  1674. loadEmoji: function(reload, callback){
  1675. if(reload) MP.emotes = { Basic: {}, TastyCat: {}, Twitch: {}, BetterTTV: {} };
  1676. if(!MP.session.allowemojis) return;
  1677.  
  1678. //Basic
  1679. $.getJSON("https://raw.githubusercontent.com/Ranks/emojione/master/emoji.json", function(data) {
  1680. for(var e in data){
  1681. //MP.emotes[e] = MP.emotes[e] || "https://raw.githubusercontent.com/Ranks/emojify.js/master/dist/images/basic/" + e + ".png";
  1682. MP.emotes["Basic"][e] = MP.emotes["Basic"][e] || { url: "https://raw.githubusercontent.com/Ranks/emojione/master/assets/png/" + data[e].unicode + ".png" };
  1683.  
  1684. //Regular aliases
  1685. if(data[e].aliases)
  1686. for(var ee in data[e].aliases){
  1687. ee = data[e].aliases[ee].slice(1, -1);
  1688. //MP.emotes[ee] = MP.emotes[ee] || "https://raw.githubusercontent.com/Ranks/emojify.js/master/dist/images/basic/" + e + ".png";
  1689. MP.emotes["Basic"][ee] = MP.emotes["Basic"][ee] || { url: "https://raw.githubusercontent.com/Ranks/emojione/master/assets/png/" + data[e].unicode + ".png", style: 'max-width: 24px; max-height: 24px;', };
  1690. }
  1691.  
  1692. //ASCII aliases
  1693. if(data[e].aliases_ascii)
  1694. for(var ee in data[e].aliases_ascii)
  1695. MP.emotes_ascii[data[e].aliases_ascii[ee]] = MP.emotes_ascii[data[e].aliases_ascii[ee]] || e;
  1696. }
  1697. //Trollface emote
  1698. var e = 'trollface';
  1699. MP.emotes['Basic'][e] = MP.emotes['Basic'][e] || { url: 'https://raw.githubusercontent.com/Ranks/emojify.js/master/dist/images/basic/' + e + '.png', };
  1700. }).done(function(){
  1701. //TastyCat
  1702. $.getJSON("https://emotes.tastycat.org/emotes-full.json", function(data) {
  1703. for(var e in data.emotes)
  1704. MP.emotes["TastyCat"][e.toLowerCase().replace('&', 'n')] = MP.emotes["TastyCat"][e.toLowerCase().replace('&', 'n')] || { url: data.emotes[e].url, style: 'max-width: ' + data.emotes[e].width + 'px ;max-height: ' + data.emotes[e].height + 'px;'};
  1705. }).done(function(){
  1706. //Twitch.tv
  1707. $.getJSON("https://twitchemotes.com/api_cache/v2/images.json", function(data) {
  1708. for(var e in data.images)
  1709. MP.emotes["Twitch"][data.images[e].code.toLowerCase()] = MP.emotes["Twitch"][data.images[e].code.toLowerCase()] || { url: "https://static-cdn.jtvnw.net/emoticons/v1/" + e + "/1.0", style: 'max-width: 24px; max-height: 24px;', };
  1710. }).done(function(){
  1711. //BetterTTV
  1712. $.getJSON("https://api.betterttv.net/emotes", function(data){
  1713. for(var e in data.emotes)
  1714. if((e = data.emotes[e]).regex.indexOf(':') == -1) MP.emotes["BetterTTV"][e.regex.toLowerCase().replace('&', 'n')] = MP.emotes["BetterTTV"][e.regex.toLowerCase().replace('&', 'n')] || { url: e.url, style: 'max-width: 24px; max-height: 24px;', };
  1715. }).done(callback || (function(){}));
  1716. });
  1717. });
  1718. });
  1719. },
  1720. escape: function(txt){
  1721. return txt.replace(/</g,'&lt;').replace(/>/g,'&gt;');
  1722. },
  1723. leaveConfirmation: function(){
  1724. return 'Are you sure you want to leave Vaporwave.io?';
  1725. },
  1726. addMessage: function(data, type){
  1727. var $chat = $("#chat");
  1728. var $messages = $("#chat > #messages");
  1729. var time = new Date(data.time);
  1730. var scrolledFromTop = MP.api.chat.getPos();
  1731. var settings = JSON.parse(localStorage.getItem("settings"));
  1732.  
  1733. type = type || 'chat';
  1734.  
  1735. if (type == 'chat'){
  1736. var msg = data.message;
  1737.  
  1738. if (!msg){
  1739. return;
  1740. }
  1741. var user = data.user || MP.findUser(data.uid);
  1742.  
  1743. var queue_pos = MP.findPosInWaitlist();
  1744. var mention = '';
  1745.  
  1746. var arr_mention = [];
  1747.  
  1748. if (MP.user){
  1749. arr_mention.push('@' + MP.user.un);
  1750. if(MP.getRole(MP.user.role).mention && MP.getRole(user.role).permissions.indexOf('chat.specialMention')) arr_mention.push('@' + MP.getRole(MP.user.role).mention);
  1751. }
  1752. if (MP.isStaffMember(data.uid) && MP.isStaffMember()) {
  1753. arr_mention.push('@staff');
  1754. }
  1755. if (MP.checkPerm('chat.specialMention',user)){
  1756. arr_mention.push('@everyone');
  1757.  
  1758. if (queue_pos >= 0){
  1759. arr_mention.push('@djs');
  1760. }
  1761. if (!MP.user){
  1762. arr_mention.push('@guest');
  1763. }
  1764. }
  1765.  
  1766. if (arr_mention.length != 0){
  1767. var regmention = new RegExp('('+arr_mention.join('|') + ')( |$)','g');
  1768. var emreg = /^\/(me|em)(\s|$)/i;
  1769. mention = (msg.match(regmention) != null ? 'mention' : '');
  1770. var emote = '';
  1771.  
  1772. if (mention){
  1773. msg = msg.replace(regmention,function(a){
  1774. return '<span style="'+ MP.makeUsernameStyle(MP.user ? MP.user.role : null) +' font-weight: bold;">'+a+'</span>';
  1775. });
  1776. }
  1777. }
  1778.  
  1779. if (/^\/(me|em) /i.test(msg)){
  1780. emote = 'emote';
  1781. msg = msg.slice(4);
  1782. if (msg.length==0){
  1783. return;
  1784. }
  1785. }
  1786.  
  1787. msg = MP.url.parse(msg,true);
  1788.  
  1789. // parse bold tags
  1790. msg = msg.replace(/\*(.*?)\*/g, function(a){
  1791. return '<b>'+a.slice(1,-1)+'</b>';
  1792. });
  1793.  
  1794. //parse strike tags
  1795. msg = msg.replace(/~(.*?)~/g, function(a){
  1796. return '<s>'+a.slice(1,-1)+'</s>';
  1797. });
  1798.  
  1799. if (mention && !MP.session.hasfocus) {
  1800. document.title = '* ' + document.title;
  1801. }
  1802.  
  1803. if (mention && settings && settings.roomSettings && settings.roomSettings.soundMention){
  1804. mentionSound.play();
  1805. }
  1806.  
  1807. var badge = $(MP.makeBadgeStyle({ user: user }));
  1808. var isTheDj = (MP.session.queue.currentdj || {}).uid == user.uid;
  1809.  
  1810. $messages.append(
  1811. '<div ' + (data.cid ? 'id="cm-' + data.cid + '"' : '') + ' class="cm message ' + [mention, emote, data.special, (MP.checkPerm('chat.delete') ? 'msg-del' : ''), (MP.user && user.uid == MP.user.uid ? 'self' : '')].join(' ') + '">' + (MP.checkPerm('chat.delete') ? '<div class="mdi mdi-close msg-del-btn"></div>' : '') + '<span class="time">' + MP.makeTime(time) + '</span>' +
  1812. // TODO: Make user object to lookup UID
  1813. badge.attr('class', (badge.prop('tagName').toLowerCase() == 'svg' ? 'bdg ' : badge.attr('class')) + (isTheDj ? ' hidden' : '')).prop('outerHTML') +
  1814. /*(
  1815. MP.getRole(user.role).badge
  1816. ?
  1817. $('<div class="mdi mdi-' + MP.getRole(user.role).badge + ' bdg-icon bdg-icon-role" style="color: ' + ((MP.getRole(user.role).style || { color: 'white', }).color || 'white') + ';"></div>').addClass((MP.session.queue.currentdj || {}).uid == user.uid ? 'hidden' : '').prop('outerHTML')
  1818. :
  1819. $(MP.makeBadgeStyle(user.badge.top, user.badge.bottom, MP.getRole(user.role).style.color, "c" + data.cid)).attr('class', (MP.session.queue.currentdj || {}).uid == user.uid ? 'bdg hidden' : 'bdg').prop("outerHTML")
  1820. ) +*/
  1821. (isTheDj ? MP.makeBadgeStyle({ mdi: 'headphones', class: 'bdg-icon-dj', style: MP.getRole(user.role).style }) : '') +
  1822. '<div class="text"><span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>' +
  1823. '<span class="umsg">' + MP.emojiReplace(msg) + '</span></div></div>'
  1824. );
  1825. MP.chatImage.parse(msg, data.cid);
  1826. } else if (type == 'log'){
  1827. var user = data.user || {};
  1828. var un = user.un || '';
  1829. var unclass = (user.un == undefined) ? '' : 'uname';
  1830. var msg = data.msg;
  1831.  
  1832. $messages.append(
  1833. '<div class="cm log"><span class="time">' + MP.makeTime(new Date()) + '</span>' +
  1834. '<div class="text">' +
  1835. '<span data-uid="'+ user.uid +'" style="'+ MP.makeUsernameStyle(user.role) +'" class="'+ unclass +'">' + un + '</span>' +
  1836. '<span class="umsg">' + msg + '</span></div></div>'
  1837. );
  1838. } else if (type == 'system'){
  1839. var msg = data;
  1840.  
  1841. $messages.append(
  1842. '<div class="cm system"><span class="time">' + MP.makeTime(new Date()) + '</span>' +
  1843. '<div class="mdi mdi-map-marker msg"></div>' +
  1844. '<div class="text">' +
  1845. '<span class="umsg">' + msg + '</span></div></div></div>'
  1846. );
  1847. } else if (type == 'broadcast'){
  1848. var msg = data;
  1849.  
  1850. $messages.append(
  1851. '<div class="cm broadcast"><span class="time">' + MP.makeTime(new Date()) + '</span>' +
  1852. '<div class="mdi mdi-alert msg"></div>' +
  1853. '<div class="text">' +
  1854. // MP.emojiReplace($('<span class="umsg"></span>').text(msg).prop('outerHTML')) + '</div></div></div>'
  1855. MP.emojiReplace(MP.escape(msg)) + '</div></div></div>'
  1856. );
  1857. if (settings && settings.roomSettings && settings.roomSettings.soundMention){
  1858. mentionSound.play();
  1859. }
  1860. }
  1861.  
  1862. while($messages.children().length > (Number(JSON.parse(localStorage.settings).roomSettings.chatlimit) || $messages.children().length)){
  1863. $messages.children().first().remove();
  1864. }
  1865.  
  1866. if ( scrolledFromTop >= 0)
  1867. MP.api.chat.scrollBottom();
  1868. },
  1869. sendBroadcast: function(msg) {
  1870. if (!MP.checkPerm('chat.broadcast')) return;
  1871.  
  1872. var obj = {
  1873. type: 'broadcastMessage',
  1874. data: {
  1875. message: msg
  1876. }
  1877. };
  1878.  
  1879. socket.sendJSON(obj);
  1880. },
  1881. findUser: function(uid){
  1882. if (typeof MP.seenUsers[uid] == undefined) return null;
  1883.  
  1884. return MP.seenUsers[uid];
  1885. },
  1886. findPosInWaitlist: function(uid){
  1887. var user = uid ? MP.findUser(uid) : MP.user;
  1888.  
  1889. if (!user || !MP.session.queue.users) return -1;
  1890.  
  1891. var pos = MP.session.queue.users.indexOf(user.uid);
  1892.  
  1893. if (MP.session.queue.currentdj && MP.session.queue.currentdj.uid == user.uid) return 0;
  1894. if (pos == -1) return pos;
  1895.  
  1896. return (pos+1);
  1897. },
  1898. chatCommands : {
  1899. cmds: {
  1900. description: 'Show available chat commands',
  1901. aliases: ['commands', 'cmd', 'help'],
  1902. exec: function(arr){
  1903. var cmds = '<span style="color: #ffffff; font-weight: bold;">User commands</span><br>';
  1904. var staffcmds = '<span style="color: #ffffff; font-weight: bold;">Staff commands</span><br>';
  1905.  
  1906. //Loop through all commands
  1907. for(var key in MP.chatCommands){
  1908. var cmd = MP.chatCommands[key];
  1909.  
  1910. var cmdstr = '/' + key + ' - ' + cmd.description + (cmd.aliases ? ' [ ' + cmd.aliases.join(', ') + ' ]' : '') + '<br>';
  1911.  
  1912. if(cmd.staff)
  1913. staffcmds += cmdstr;
  1914. else
  1915. cmds += cmdstr;
  1916. }
  1917.  
  1918. API.chat.log(cmds + (MP.isStaffMember(MP.user.uid) ? '<br>' + staffcmds : ''));
  1919. },
  1920. },
  1921.  
  1922. log: {
  1923. description: 'Shows a message in chat client-side',
  1924. exec: function(arr){
  1925. MP.api.chat.log(arr.shift());
  1926. },
  1927. },
  1928.  
  1929. join: {
  1930. description: 'Join the DJ queue',
  1931. aliases: ['j'],
  1932. exec: function(arr){
  1933. MP.djQueueJoin();
  1934. },
  1935. },
  1936.  
  1937. leave: {
  1938. description: 'Leave the DJ queue',
  1939. aliases: ['l'],
  1940. exec: function(arr){
  1941. MP.djQueueLeave();
  1942. },
  1943. },
  1944.  
  1945. cycle: {
  1946. description: 'Toggle DJ queue cycling',
  1947. exec: function(){
  1948. MP.djQueueCycle();
  1949. },
  1950. },
  1951.  
  1952. lock: {
  1953. description: 'Toggle DJ queue lock',
  1954. exec: function(){
  1955. MP.djQueueLock();
  1956. },
  1957. },
  1958.  
  1959. skip: {
  1960. description: 'Skip the current DJ',
  1961. exec: function(arr){
  1962. arr.shift();
  1963.  
  1964. var lockSkipPosition = parseInt(arr[0]);
  1965. MP.djQueueSkip(!isNaN(lockSkipPosition) ? lockSkipPosition : undefined);
  1966. },
  1967. },
  1968.  
  1969. vol: {
  1970. description: 'Change or show the current volume',
  1971. aliases: ['volume'],
  1972. exec: function(arr){
  1973. if (arr.length==1){
  1974. return API.chat.log('<br>Current volume: '+API.player.getPlayer().getVolume(),'Volume');
  1975. }
  1976. var vol_val = Math.round(Math.max(0, Math.min(arr[1], 100)));
  1977.  
  1978. if (isNaN(vol_val)){
  1979. return API.chat.log('<br>Volume should be an integer (0 ~ 100)','Volume');
  1980. }
  1981. API.player.setVolume(vol_val);
  1982. API.chat.log('<br>Current volume: '+vol_val,'Volume');
  1983. },
  1984. },
  1985.  
  1986. clear: {
  1987. description: 'Clear the chat (client-side only)',
  1988. aliases: ['c'],
  1989. exec: function(){
  1990. $('#messages').html('');
  1991. },
  1992. },
  1993.  
  1994. stream: {
  1995. description: 'Toggle video stream',
  1996. exec: function(){
  1997. API.chat.log('<br>Video stream '+(MP.toggleVideoStream()?'enabled':'disabled'),'Video stream');
  1998. },
  1999. },
  2000.  
  2001. shrug: {
  2002. description: 'Appends ¯\\_(ツ)_/¯ to your message',
  2003. exec: function(arr){
  2004. arr.shift();
  2005. MP.sendMessage((arr.join(" ")+" ¯\\_(ツ)_/¯").trim());
  2006. },
  2007. },
  2008.  
  2009. flip: {
  2010. description: 'Appends (ノಠ益ಠ)ノ彡┻━┻ to your message',
  2011. exec: function(arr){
  2012. arr.shift();
  2013. MP.sendMessage((arr.join(" ")+" (ノಠ益ಠ)ノ彡┻━┻").trim());
  2014. },
  2015. },
  2016.  
  2017. unflip: {
  2018. description: 'Appends ┬──┬ ノ( ゜-゜ノ) to your message',
  2019. exec: function(arr){
  2020. arr.shift();
  2021. MP.sendMessage((arr.join(" ")+" ┬──┬ ノ( ゜-゜ノ)").trim());
  2022. },
  2023. },
  2024.  
  2025. lenny: {
  2026. description: 'Appends ( ͡° ͜ʖ ͡°) to your message',
  2027. exec: function(arr){
  2028. arr.shift();
  2029. MP.sendMessage((arr.join(" ")+" ( ͡° ͜ʖ ͡°)").trim());
  2030. },
  2031. },
  2032.  
  2033. confirm: {
  2034. description: 'Confirms your email address',
  2035. exec: function(arr){
  2036. arr.shift();
  2037. var obj = {
  2038. type: 'confirmation',
  2039. data: {
  2040. code: arr[0],
  2041. },
  2042. };
  2043. obj.id = MP.addCallback(obj.type, function(err, data){
  2044. if(data.success){
  2045. MP.addMessage('Email confirmed, welcome to Vaporwave.io! :)', 'system');
  2046. } else {
  2047. MP.addMessage('Wrong confirmation code or email already confirmed', 'system');
  2048. }
  2049. });
  2050. socket.sendJSON(obj);
  2051. },
  2052. },
  2053.  
  2054. s: {
  2055. description: 'Sends a message to all staff members',
  2056. exec: function(arr){
  2057. arr.shift();
  2058. MP.sendMessage(arr.join(" "), true);
  2059. },
  2060. },
  2061.  
  2062. gib: {
  2063. description: 'Prepends ༼ つ ◕_◕ ༽つ to your message',
  2064. exec: function(arr){
  2065. arr.shift();
  2066. MP.sendMessage(("༼ つ ◕_◕ ༽つ " + arr.join(" ")).trim());
  2067. },
  2068. },
  2069.  
  2070. whisper: {
  2071. description: 'Sends a private message',
  2072. aliases: ['w', 'pm'],
  2073. exec: function(arr){
  2074. if (!MP.checkPerm('chat.private')) {
  2075. return API.chat.log('<br>You do not have permission to perform this command', 'Insufficient Permissions');
  2076. }
  2077.  
  2078. if (arr.length<=2){
  2079. return API.chat.log('<br>Try /pm username message','Private Message');
  2080. }
  2081.  
  2082. arr.shift();
  2083. var usernick = arr.shift().replace(/[@:]/g,'');
  2084.  
  2085. var users = MP.api.util.objectToArray(MP.getUsersInRoom());
  2086. var user = users.filter(function(a){ return a.un == usernick; })[0];
  2087.  
  2088. if (!user) return;
  2089.  
  2090. MP.privateMessage(user.uid, arr.join(" "), function(err, data){
  2091. if (err) return API.chat.log('<br>Failed to send private message to @' + user.un, 'Private Chat');
  2092.  
  2093. API.chat.log('<br>' + MP.escape(data.message), '<span onclick="$(\'#msg-in\').val(\'/pm '+ user.un + ' \').focus();">Private Message sent to </span><span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>');
  2094. });
  2095. },
  2096. },
  2097.  
  2098. ban: {
  2099. descriptions: 'Ban a user',
  2100. staff: true,
  2101. exec: function(arr){
  2102. arr.shift();
  2103.  
  2104. if (arr.length == 0 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@'){
  2105. return API.chat.log('<br>Try /ban @username', 'Ban user');
  2106. }
  2107.  
  2108. var users = MP.api.room.getUsers(true);
  2109. var user = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2110.  
  2111. if (!user) return;
  2112.  
  2113. MP.showBanModal(user.uid);
  2114. },
  2115. },
  2116.  
  2117. role: {
  2118. description: 'Sets user role',
  2119. staff: true,
  2120. exec: function(arr){
  2121. arr.shift();
  2122.  
  2123. if (arr.length == 0 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@'){
  2124. return API.chat.log('<br>Try /role @username', 'Set user role');
  2125. }
  2126.  
  2127. var users = MP.api.room.getUsers(true);
  2128. var user = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2129.  
  2130. if (!user) return;
  2131.  
  2132. MP.showRoleModal(user.uid);
  2133. },
  2134. },
  2135.  
  2136. mute: {
  2137. description: 'Mute a user',
  2138. staff: true,
  2139. exec: function(arr){
  2140. arr.shift();
  2141.  
  2142. if (arr.length == 0 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@'){
  2143. return API.chat.log('<br>Try /mute @username', 'Ignore user');
  2144. }
  2145.  
  2146. var users = MP.api.room.getUsers(true);
  2147. var user = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2148.  
  2149. if (!user) return;
  2150.  
  2151. MP.showMuteModal(user.uid);
  2152. },
  2153. },
  2154.  
  2155. add: {
  2156. description: 'Add a user to the DJ queue',
  2157. staff: true,
  2158. exec: function(arr){
  2159. arr.shift();
  2160.  
  2161. if (arr.length == 0 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@'){
  2162. return API.chat.log('<br>Try /add @username', 'Add user to queue');
  2163. }
  2164.  
  2165. var users = MP.api.room.getUsers(true);
  2166. var user = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2167.  
  2168. if (!user) return;
  2169. var position = parseInt(arr[1]);
  2170. if (typeof position == 'number') position--;
  2171. MP.djQueueModAdd(user.uid, position);
  2172. },
  2173. },
  2174.  
  2175. rem: {
  2176. description: 'Remove a user from the DJ queue',
  2177. aliases: ['remove'],
  2178. staff: true,
  2179. exec: function(arr){
  2180. arr.shift();
  2181.  
  2182. if (arr.length == 0 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@'){
  2183. return API.chat.log('<br>Try /rem @username', 'Remove user from queue');
  2184. }
  2185.  
  2186. var users = MP.api.room.getUsers(true);
  2187. var user = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2188.  
  2189. if (!user) return;
  2190. MP.djQueueModRemove(user.uid);
  2191. },
  2192. },
  2193.  
  2194. move: {
  2195. description: 'Move a user in the DJ queue',
  2196. staff: true,
  2197. exec: function(arr){
  2198. arr.shift();
  2199.  
  2200. if (arr.length < 2 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@' || isNaN(parseInt(arr[1]))){
  2201. return API.chat.log('<br>Try /move @username 1', 'Move user in queue');
  2202. }
  2203.  
  2204. var users = MP.api.room.getUsers(true);
  2205. var user = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2206.  
  2207. if (!user) return;
  2208. var pos = parseInt(arr[1]);
  2209. MP.djQueueModMove(user.uid,pos);
  2210. },
  2211. },
  2212.  
  2213. swap: {
  2214. description: 'Swaps two users in the DJ queue',
  2215. staff: true,
  2216. exec: function(arr){
  2217. arr.shift();
  2218.  
  2219. if (arr.length < 2 || typeof arr[0] != 'string' || arr[0].charAt(0)!='@' || typeof arr[1] != 'string' || arr[1].charAt(0)!='@'){
  2220. return API.chat.log('<br>Try /swap @username1 @username2', 'Swap users in queue');
  2221. }
  2222.  
  2223. var users = MP.api.room.getUsers(true);
  2224. var user1 = users.filter(function(a){return a.un == arr[0].substring(1);})[0];
  2225. var user2 = users.filter(function(a){return a.un == arr[1].substring(1);})[0];
  2226.  
  2227. if (!user1 || !user2 || user1.uid == user2.uid) return;
  2228. MP.djQueueModSwap(user1.uid,user2.uid);
  2229. },
  2230. },
  2231.  
  2232. broadcast: {
  2233. description: 'Broadcasts a message to all users',
  2234. staff: true,
  2235. exec: function(arr){
  2236. arr.shift();
  2237. if (!MP.checkPerm('chat.broadcast')) {
  2238. return API.chat.log('<br>You do not have permission to perform this command', 'Insufficient Permissions');
  2239. }
  2240. if (arr.length < 1){
  2241. return API.chat.log('<br>Try /broadcst message', 'Broadcasts a message to the room');
  2242. }
  2243. MP.sendBroadcast(arr.join(' '));
  2244. },
  2245. },
  2246.  
  2247. badge: {
  2248. description: 'Changes your badge',
  2249. exec: function(arr){
  2250. if (arr.length == 1){
  2251. return API.chat.log('<br>At least one color is required. Example: /badge #00FFFF red','Badge');
  2252. }
  2253. var hextop = arr[1];
  2254. var hexbottom = arr[2] || hextop;
  2255.  
  2256. var colorValidator = /^#([0-9a-f]{6}|[0-9a-f]{3})$/gi;
  2257.  
  2258. if ((hextop.search(colorValidator)) == -1 && !MP.api.util.colourNameToHex(hextop)){
  2259. return API.chat.log('<br>Invalid color: '+hextop, 'Badge');
  2260. }
  2261.  
  2262. if ((hexbottom.search(colorValidator)) == -1 && !MP.api.util.colourNameToHex(hexbottom)){
  2263. return API.chat.log('<br>Invalid color: '+hexbottom, 'Badge');
  2264. }
  2265.  
  2266. hextop = MP.api.util.colourNameToHex(hextop) || hextop;
  2267. hexbottom = MP.api.util.colourNameToHex(hexbottom) || hexbottom;
  2268.  
  2269. MP.updateBadge({top: hextop.toUpperCase(), bottom: hexbottom.toUpperCase()});
  2270. },
  2271. },
  2272. },
  2273. sendMessage: function(message, staff){
  2274. staff = staff || false;
  2275. if (!MP.isLoggedIn()){
  2276. console.log('Must be logged in to send chat messages');
  2277. return;
  2278. }
  2279. if (typeof message != 'string'){
  2280. console.log('Message should be a string');
  2281. return;
  2282. }
  2283. if (!message){
  2284. console.log('Message can\'t be empty');
  2285. return;
  2286. }
  2287.  
  2288. if (message.charAt(0)=='/'){
  2289. var arr = message.trim().substring(1).replace(/\s{2,}/g, ' ').split(' ');
  2290.  
  2291. var cmdkey = '';
  2292.  
  2293. for(var key in MP.chatCommands){
  2294. var cmd = MP.chatCommands[key];
  2295.  
  2296. if(key == arr[0]) {
  2297. cmdkey = key;
  2298. break;
  2299. }
  2300.  
  2301. for(var al in (cmd.aliases || [])){
  2302. if(cmd.aliases[al] == arr[0]) {
  2303. cmdkey = key;
  2304. break;
  2305. }
  2306. }
  2307.  
  2308. if(cmdkey) break;
  2309. }
  2310.  
  2311. if(cmdkey) return MP.chatCommands[cmdkey].exec(arr);
  2312.  
  2313. if (arr[0].match(/^(me|em)/i) == null){
  2314. MP.callListeners({type: API.DATA.EVENTS.CHAT_COMMAND, data:message});
  2315. return;
  2316. }
  2317. }
  2318.  
  2319. socket.sendJSON({
  2320. type: (staff ? 'staff' : '') + 'chat',
  2321. data: {
  2322. message: message.substring(0,255)
  2323. }
  2324. });
  2325. },
  2326. deleteChat: function(cid, callback){
  2327. if (!MP.checkPerm('chat.delete')) return;
  2328.  
  2329. cid = parseInt(cid);
  2330.  
  2331. if (isNaN(cid) || cid < 1){
  2332. return;
  2333. }
  2334. var obj = {
  2335. type: 'deleteChat',
  2336. data: {
  2337. cid: cid
  2338. }
  2339. };
  2340.  
  2341. obj.id = MP.addCallback(obj.type, callback);
  2342. socket.sendJSON(obj);
  2343. },
  2344. signup: function(inEmail, inUser, inPass, inCaptcha, callback){
  2345. if (MP.isLoggedIn()){
  2346. console.log('Can\'t signup, already logged in');
  2347. return;
  2348. }
  2349.  
  2350. var obj = {
  2351. type: 'signup',
  2352. data: {
  2353. email: inEmail,
  2354. un: inUser,
  2355. pw: CryptoJS.SHA256( inPass ).toString(),
  2356. captcha: inCaptcha,
  2357. }
  2358. };
  2359.  
  2360. grecaptcha.reset();
  2361.  
  2362. obj.id = MP.addCallback(obj.type, function(err, data){
  2363. //if (err) alert('There was a problem signing up: ' + err);
  2364.  
  2365. onLogin(err, data, callback);
  2366.  
  2367. if (callback) callback(err, data);
  2368. });
  2369.  
  2370. socket.sendJSON(obj);
  2371. },
  2372. rawLogin: function(inEmail, inPass, token, callback){
  2373. if (MP.isLoggedIn()){
  2374. console.log('Can\'t login, already logged in');
  2375. if (callback) callback('AlreadyLoggedIn');
  2376. return;
  2377. }
  2378.  
  2379. var obj = {
  2380. type: 'login',
  2381. data: {
  2382. email: inEmail,
  2383. pw: CryptoJS.SHA256( inPass ).toString(),
  2384. token: token
  2385. }
  2386. };
  2387.  
  2388. obj.id = MP.addCallback(obj.type, function(err, data){
  2389. //if (err){ alert('There was a problem logging in: ' + err); }
  2390. if (onLogin){
  2391. onLogin(err, data, callback);
  2392. }
  2393.  
  2394. if (callback) callback(err, data);
  2395. });
  2396.  
  2397.  
  2398. socket.sendJSON(obj);
  2399. },
  2400. login: function(inEmail, inPass, callback){
  2401. MP.rawLogin(inEmail, inPass, null, callback);
  2402. },
  2403. loginWithTok: function(token, callback){
  2404. if (!token){ callback('Token argument not set'); return; }
  2405.  
  2406. MP.rawLogin(null, null, token, callback);
  2407. },
  2408. logout: function(callback){
  2409. if (!MP.isLoggedIn()){
  2410. console.log('Can\'t logout, not logged in');
  2411. return;
  2412. }
  2413.  
  2414. var obj = {
  2415. type: 'logout',
  2416. data: {}
  2417. };
  2418.  
  2419. if (callback) obj.id = MP.addCallback(obj.type, callback);
  2420.  
  2421. var ind = MP.userList.users.indexOf(MP.user.uid);
  2422. if (ind != -1){
  2423. MP.userList.users.splice( ind, 1);
  2424. MP.userList.guests++;
  2425. }
  2426.  
  2427. delete MP.user;
  2428. MP.session.viewedPl;
  2429. MP.applyModels();
  2430.  
  2431. MP.cookie.setCookie(MP.getTokenName());
  2432. socket.sendJSON(obj);
  2433. },
  2434. joinRoom: function(callback){
  2435. var obj = {
  2436. type: 'joinRoom',
  2437. data: {}
  2438. };
  2439.  
  2440. obj.id = MP.addCallback(obj.type, function(err, data){
  2441. if (err){
  2442. console.log('Could not join room: ' + err);
  2443. if (callback) callback(err, data);
  2444. return;
  2445. }
  2446. MP.getUsers(function(){
  2447. MP.session.roomInfo = data.room;
  2448. MP.session.queue = data.queue;
  2449. MP.session.roles = data.roles;
  2450. MP.session.roleOrder = data.roleOrder;
  2451. MP.session.staffRoles = data.staffRoles;
  2452. MP.session.queue.currentdj = (data.queue.currentdj ? MP.findUser(data.queue.currentdj) : null);
  2453. MP.session.allowemojis = data.allowemojis;
  2454. MP.session.captchakey = data.captchakey;
  2455. MP.session.historylimit = data.historylimit;
  2456. MP.media.start = data.queue.songStart;
  2457. MP.session.description = data.description;
  2458.  
  2459. var client = new Date().getTime();
  2460. var server = data.time || client;
  2461.  
  2462. MP.session.serverDateDiff = (server < client ? server - client : client - server);
  2463. try{
  2464. grecaptcha.render('recaptcha', { sitekey: MP.session.captchakey, 'theme': 'dark',});
  2465. }catch(e){}
  2466. MP.addCurrentToHistory();
  2467.  
  2468. $('.btn-grab.active, .btn-upvote.active, .btn-downvote.active').removeClass('active');
  2469.  
  2470. var buttonClasses = {
  2471. like: 'btn-upvote',
  2472. dislike: 'btn-downvote',
  2473. grab: 'btn-grab'
  2474. };
  2475.  
  2476. for(var i in data.queue.vote){
  2477. var $button = $('.' + buttonClasses[data.queue.vote[i]]);
  2478. $button.addClass('active');
  2479. }
  2480.  
  2481. MP.applyModels();
  2482.  
  2483. if (callback) callback(err, data);
  2484. });
  2485.  
  2486. MP.media.media = data.queue.currentsong;
  2487.  
  2488. if (data.queue.currentsong){
  2489. MP.media.timeRemaining = Math.round(data.queue.currentsong.duration - data.queue.time);
  2490. MP.startTimeRemaining();
  2491. }else{
  2492. MP.media.timeRemaining = 0;
  2493. MP.clearTimeRemaining();
  2494. }
  2495. });
  2496.  
  2497.  
  2498. socket.sendJSON(obj);
  2499.  
  2500.  
  2501. },
  2502. leaveRoom: function(callback){
  2503. var obj = {
  2504. type: 'leaveRoom',
  2505. data: {}
  2506. };
  2507.  
  2508. obj.id = MP.addCallback(obj.type, function(err, data){
  2509. MP.user.role = null;
  2510.  
  2511. if (callback) callback(err, data);
  2512. });
  2513.  
  2514. socket.sendJSON(obj);
  2515. },
  2516. getRole: function(role){
  2517. if (role && MP.session.roles[role]){
  2518. return MP.session.roles[role];
  2519. }
  2520.  
  2521. return MP.session.roles.default;
  2522. },
  2523. getRoleIndex: function(role){
  2524. if (typeof role != 'string') return -1;
  2525.  
  2526. var roles = [];
  2527. for (var i in MP.session.roles){
  2528. roles.push(i);
  2529. }
  2530. roles = roles.reverse();
  2531. return roles.indexOf(role.toLowerCase());
  2532. },
  2533. checkPerm: function(perm, user){
  2534. user = user || MP.user;
  2535.  
  2536. if (!user) return false;
  2537.  
  2538. return (user.role && MP.getRole(user.role) && MP.getRole(user.role).permissions.indexOf(perm) == -1 ? false : true);
  2539. },
  2540. canGrantRole: function(role, user){
  2541. user = user || MP.user;
  2542.  
  2543. if (!user || !user.role) return false;
  2544.  
  2545. if ( !MP.checkPerm('room.grantroles') || MP.getRole(user.role).canGrantRoles.indexOf(role) == -1)
  2546. return false;
  2547.  
  2548. return true;
  2549. },
  2550. getRoomInfo: function(callback){
  2551. var obj = {
  2552. type: 'getRoomInfo',
  2553. data: {}
  2554. };
  2555. obj.id = MP.addCallback(obj.type, function(err,data){
  2556. if (err){
  2557. console.log('Getting Room Info failed!');
  2558. if (callback) callback(err);
  2559. return;
  2560. }
  2561. MP.session.roomInfo = data;
  2562.  
  2563. MP.applyModels();
  2564.  
  2565. if (callback) callback(err, data);
  2566. });
  2567. socket.sendJSON(obj);
  2568. },
  2569. getUsers: function(callback){
  2570. var obj = {
  2571. type: 'getUsers',
  2572. data: {}
  2573. };
  2574.  
  2575. obj.id = MP.addCallback(obj.type, function(err,data){
  2576. if (err){
  2577. console.log('Getting users failed! : ' + err);
  2578. if (callback) callback(err);
  2579. }
  2580.  
  2581. for (var i in data.users){
  2582. var uid = parseInt(i);
  2583.  
  2584. MP.seenUsers[uid] = data.users[i];
  2585.  
  2586. if (MP.user && data.users[i].uid == MP.user.uid) MP.user.role = data.users[i].role;
  2587.  
  2588. MP.userList.guests = data.guests;
  2589.  
  2590. if (MP.userList.users.indexOf(uid) == -1){
  2591. MP.userList.users.push(uid);
  2592. }
  2593. }
  2594.  
  2595. MP.applyModels();
  2596.  
  2597. if (callback) callback(err, data);
  2598. });
  2599. socket.sendJSON(obj);
  2600. },
  2601. getHistory: function(callback){
  2602. var obj = {
  2603. type: 'getHistory',
  2604. data: {}
  2605. };
  2606.  
  2607. obj.id = MP.addCallback(obj.type, function(err,data){
  2608. if (err){
  2609. console.log('Getting history failed!');
  2610. if (callback) callback(err);
  2611. return;
  2612. }
  2613.  
  2614. /*
  2615. data: {
  2616. type: 'getHistory',
  2617. data: [
  2618. {
  2619. votes: {
  2620. likes: 0,
  2621. grabs: 0,
  2622. dislikes: 0
  2623. },
  2624. song: {
  2625. defaultSongObject Properties
  2626. },
  2627. user: {
  2628. defaultUserObject Properties
  2629. }
  2630. }
  2631. ]
  2632. }
  2633. */
  2634.  
  2635. MP.historyList.history = data;
  2636. MP.historyList.historyInitialized = true;
  2637. MP.historyList.filter = "";
  2638.  
  2639. MP.addCurrentToHistory();
  2640.  
  2641. MP.applyModels();
  2642.  
  2643. if (callback) callback(err, data);
  2644. });
  2645. socket.sendJSON(obj);
  2646. },
  2647. updateBadge: function(badge, callback){
  2648. var obj = {
  2649. type: 'badgeUpdate',
  2650. data: {
  2651. badge: badge
  2652. }
  2653. };
  2654.  
  2655. obj.id = MP.addCallback(obj.type, function(err, data){
  2656. if (err){
  2657. console.log('Updating badge failed!', err);
  2658. // Handle error
  2659. return;
  2660. }else{
  2661. console.log('Badge Updated Successfully.');
  2662.  
  2663. $('#badge-top-color-input').minicolors('value',badge.top);
  2664. $('#badge-bottom-color-input').minicolors('value',badge.bottom);
  2665.  
  2666. // Save success notif
  2667. }
  2668. if (typeof callback == 'function') callback(err, data);
  2669. });
  2670. socket.sendJSON(obj);
  2671. },
  2672. addCurrentToHistory: function(){
  2673. if (MP.historyList.historyInitialized && MP.session.queue.currentsong != null) {
  2674. if(MP.session.historylimit)
  2675. while(MP.historyList.history.length >= MP.session.historylimit) {
  2676. MP.historyList.history.pop();
  2677. }
  2678. MP.historyList.history.unshift({
  2679. votes: MP.session.queue.votes,
  2680. song: MP.session.queue.currentsong,
  2681. user: MP.session.queue.currentdj,
  2682. start: MP.media.start || new Date().getTime()-(MP.getTimeElapsed()*1e3)
  2683. });
  2684. }
  2685. },
  2686. isLoggedIn: function(){
  2687. if (MP.user) return true;
  2688.  
  2689. return false;
  2690. },
  2691. getPlaylistContents: function(pid, callback){
  2692. var obj = {
  2693. type: 'getPlaylistContents',
  2694. data: {
  2695. pid: pid
  2696. }
  2697. };
  2698.  
  2699. MP.togglePlaylistLoading(true);
  2700.  
  2701. obj.id = MP.addCallback(obj.type, function(err, data){
  2702. MP.togglePlaylistLoading(false);
  2703.  
  2704. if (err){ if (callback) callback(err); return;}
  2705.  
  2706. MP.user.playlists[pid].num = data.content.length;
  2707. MP.user.playlists[pid].content = data.content;
  2708. MP.applyModels();
  2709.  
  2710. if (callback) callback(err, data);
  2711. }, 10000);
  2712.  
  2713. socket.sendJSON(obj);
  2714. },
  2715. playlistCreate: function(name, callback){
  2716. if (!MP.checkPerm('playlist.create')) return;
  2717.  
  2718. var obj = {
  2719. type: 'playlistCreate',
  2720. data: {name: name}
  2721. };
  2722.  
  2723. obj.id = MP.addCallback(obj.type, function(err, data){
  2724. MP.togglePlaylistLoading(false);
  2725.  
  2726. if (err){console.log('Could not add playlist: ' + err); if (callback) callback(err, data); return;}
  2727. MP.user.playlists[data.id] = data.playlist;
  2728. var onlyPlaylist = true;
  2729.  
  2730. for (var i in MP.user.playlists)
  2731. if (i != data.id) onlyPlaylist = false;
  2732.  
  2733. if (onlyPlaylist) MP.user.activepl = data.id;
  2734. MP.applyModels();
  2735.  
  2736. if (callback) callback(err, data);
  2737. });
  2738.  
  2739. socket.sendJSON(obj);
  2740. MP.togglePlaylistLoading(true);
  2741. },
  2742.  
  2743. playlistRename: function(pid, name, callback){
  2744. //if (!MP.checkPerm('playlist.delete')) return;
  2745.  
  2746. var obj = {
  2747. type: 'playlistRename',
  2748. data: {
  2749. pid: pid,
  2750. name: name
  2751. }
  2752. };
  2753.  
  2754. if (!pid || !name){
  2755. if (callback) callback('MissingProps');
  2756. return;
  2757. }
  2758.  
  2759. obj.id = MP.addCallback(obj.type, function(err, data){
  2760. MP.togglePlaylistLoading(false);
  2761. if (err){
  2762. if (callback) callback(err);
  2763. return;
  2764. }
  2765.  
  2766. MP.user.playlists[pid].name = data.name;
  2767. MP.applyModels();
  2768. callback(null, data);
  2769. });
  2770.  
  2771. socket.sendJSON(obj);
  2772. MP.togglePlaylistLoading(true);
  2773. },
  2774.  
  2775. playlistDelete: function(pid, callback){
  2776. if (!MP.checkPerm('playlist.delete')) return;
  2777.  
  2778. var obj = {
  2779. type: 'playlistDelete',
  2780. data: {
  2781. pid: pid
  2782. }
  2783. };
  2784.  
  2785. obj.id = MP.addCallback(obj.type, function(err, data){
  2786. MP.togglePlaylistLoading(false);
  2787.  
  2788. if (err) {console.log('Could not delete playlist: ' + err); if (callback) callback(err); return;}
  2789.  
  2790. delete MP.user.playlists[pid];
  2791.  
  2792. if (MP.session.viewedPl == pid){
  2793. MP.session.viewedPl = null;
  2794. }
  2795.  
  2796. if (data.active){
  2797. MP.user.activepl = data.active;
  2798. MP.session.viewedPl = data.active;
  2799. }
  2800.  
  2801. MP.applyModels();
  2802.  
  2803. if (callback) callback(err, data);
  2804. });
  2805.  
  2806. socket.sendJSON(obj);
  2807. MP.togglePlaylistLoading(true);
  2808. },
  2809. playlistActivate: function(pid, callback){
  2810. if (MP.user && MP.user.activepl == pid){ if (callback) callback('Playlist already active'); return; }
  2811. var obj = {
  2812. type: 'playlistActivate',
  2813. data: {
  2814. pid: pid
  2815. }
  2816. };
  2817.  
  2818. obj.id = MP.addCallback(obj.type, function(err, data){
  2819. MP.togglePlaylistLoading(false);
  2820.  
  2821. if (err) {console.log('Could not activate playlist: ' + err); if (callback) callback(err); return;}
  2822.  
  2823. MP.user.activepl = pid;
  2824. MP.applyModels();
  2825.  
  2826. if (callback) callback(err, data);
  2827. });
  2828.  
  2829. socket.sendJSON(obj);
  2830. MP.togglePlaylistLoading(true);
  2831. },
  2832. playlistAdd: function(pid, cid, pos, callback){
  2833. var obj = {
  2834. type: 'playlistAddSong',
  2835. data: {
  2836. pid: pid,
  2837. cid: cid,
  2838. pos: pos
  2839. }
  2840. };
  2841.  
  2842. obj.id = MP.addCallback(obj.type, function(err, data){
  2843. MP.togglePlaylistLoading(false);
  2844.  
  2845. if (err){ if (callback) callback(err); console.log('Could not add to playlist: ' + err); return;}
  2846.  
  2847. if (data.pos == 'top'){
  2848. if (Array.isArray(data.video)) {
  2849. for (var i = 0, len = data.video.length; i < len; i++) {
  2850. MP.user.playlists[data.plid].content.unshift(data.video[i]);
  2851. }
  2852. }
  2853. else {
  2854. MP.user.playlists[data.plid].content.unshift(data.video);
  2855. }
  2856. }else if (data.pos == 'bottom'){
  2857. if (Array.isArray(data.video)) {
  2858. for (var i = 0, len = data.video.length; i < len; i++) {
  2859. MP.user.playlists[data.plid].content.push(data.video[i]);
  2860. }
  2861. }
  2862. else {
  2863. MP.user.playlists[data.plid].content.push(data.video);
  2864. }
  2865. }
  2866.  
  2867. if (Array.isArray(data.video)) {
  2868. MP.user.playlists[data.plid].num += data.video.length;
  2869. }
  2870. else {
  2871. MP.user.playlists[data.plid].num++;
  2872. }
  2873. MP.applyModels();
  2874.  
  2875. if (callback) callback(err, data);
  2876. }, 20000);
  2877.  
  2878. socket.sendJSON(obj);
  2879. MP.togglePlaylistLoading(true);
  2880. },
  2881. playlistRemove: function(pid, cid, callback){
  2882. var obj = {
  2883. type: 'playlistRemoveSong',
  2884. data: {
  2885. pid: pid,
  2886. cid: cid
  2887. }
  2888. };
  2889.  
  2890. var content = MP.user.playlists[pid].content;
  2891. var ind = null;
  2892.  
  2893. for (var i = 0; i < content.length; i++){
  2894. if (content[i].cid == cid){
  2895. ind = i;
  2896. break;
  2897. }
  2898. }
  2899.  
  2900. if (ind == null){
  2901. console.log('Cannot find CID in playlist specified');
  2902. if (callback) callback('SongNotInPlaylist');
  2903. return;
  2904. }
  2905.  
  2906. obj.id = MP.addCallback(obj.type, function(err, data){
  2907. MP.togglePlaylistLoading(false);
  2908.  
  2909. if (err){ if (callback) callback(err); console.log('Could not remove from playlist: ' + err); return;}
  2910.  
  2911. MP.user.playlists[pid].content.splice( ind, 1 );
  2912. MP.user.playlists[pid].num--;
  2913. MP.applyModels();
  2914.  
  2915. if (callback) callback(err, data);
  2916. });
  2917.  
  2918. socket.sendJSON(obj);
  2919.  
  2920. MP.togglePlaylistLoading(true);
  2921. },
  2922. playlistMove: function(pid, cid, index, callback){
  2923. var obj = {
  2924. type: 'playlistMoveSong',
  2925. data: {
  2926. pid: pid,
  2927. cid: cid,
  2928. index: index
  2929. }
  2930. };
  2931.  
  2932. var content = MP.user.playlists[pid].content;
  2933. var ind = null;
  2934.  
  2935. for (var i = 0; i < content.length; i++){
  2936. if (content[i].cid == cid){
  2937. ind = i;
  2938. break;
  2939. }
  2940. }
  2941.  
  2942. if (ind === null){
  2943. console.log('Cannot find CID in playlist specified');
  2944. if (callback) callback('SongNotInPlaylist');
  2945. return;
  2946. }
  2947.  
  2948. if (ind == index || (ind+1) == index) return;
  2949.  
  2950. obj.id = MP.addCallback(obj.type, function(err, data){
  2951. MP.togglePlaylistLoading(false);
  2952.  
  2953. if (err){ if (callback) callback(err); console.log('Could not move song: ' + err); return;}
  2954.  
  2955. var content = MP.user.playlists[pid].content.splice(ind, 1);
  2956. MP.user.playlists[pid].content.splice(( ind > index ? index : index-1), 0, content[0]);
  2957. MP.applyModels();
  2958.  
  2959. if (callback) callback(err, data);
  2960. });
  2961.  
  2962. socket.sendJSON(obj);
  2963.  
  2964. MP.togglePlaylistLoading(true);
  2965. },
  2966. playlistImport: function(pid, expand, callback){
  2967. callback = callback || function(){};
  2968. if(!pid) { callback("MissingProps"); return false; }
  2969. var obj = {
  2970. type: 'importPlaylist',
  2971. data: {
  2972. playlistId: pid,
  2973. expanded: expand || false,
  2974. }
  2975. };
  2976.  
  2977. obj.id = MP.addCallback(obj.type, function(err, data){
  2978. if(err) { callback(err); return; }
  2979.  
  2980. for(var e in data.content){
  2981. MP.user.playlists[data.content[e].id] = {
  2982. id: data.content[e].id,
  2983. name: data.content[e].name,
  2984. content: expand ? data.content[e].content : [],
  2985. num: expand ? data.content[e].content.length : data.content[e].num,
  2986. };
  2987. }
  2988.  
  2989. MP.applyModels();
  2990. callback(null, data);
  2991. }, 25000);
  2992.  
  2993. socket.sendJSON(obj);
  2994. return true;
  2995. },
  2996. youtubeSearch: function(query, callback){
  2997. var obj = {
  2998. type: 'youtubeSearch',
  2999. data: {
  3000. query: query
  3001. }
  3002. };
  3003.  
  3004. obj.id = MP.addCallback(obj.type, function(err, data){
  3005. MP.togglePlaylistLoading(false);
  3006. if (err){ if (callback) callback(err); console.log('Youtube search error: ' + err); return;}
  3007.  
  3008. if (callback) callback(err, data.results);
  3009. });
  3010.  
  3011. socket.sendJSON(obj);
  3012. MP.togglePlaylistLoading(true);
  3013. },
  3014. findInPlaylist: function(playlist, cid){
  3015. for (var i = 0; i < playlist.length; i++){
  3016. if (playlist[i].cid == cid) return i;
  3017. }
  3018.  
  3019. return null;
  3020. },
  3021. makeTime: function(dateObj){
  3022. var settings = JSON.parse(localStorage.settings);
  3023. if(settings.roomSettings && settings.roomSettings.chatTimestampFormat == API.DATA.CHAT.TSFORMAT.HR12)
  3024. return ((dateObj.getHours()) % 12 || 12) + ':' + ('0' + dateObj.getMinutes()).slice(-2);
  3025. else
  3026. return (dateObj.getHours() + ':' + ('0' + dateObj.getMinutes()).slice(-2));
  3027. },
  3028. djQueueJoin: function(callback){
  3029. if (!MP.checkPerm('djqueue.join')) return;
  3030.  
  3031. if (MP.session.queue.lock && !MP.checkPerm('djqueue.joinlocked')){
  3032. return;
  3033. }
  3034.  
  3035. var obj = {
  3036. type: 'djQueueJoin'
  3037. };
  3038.  
  3039. obj.id = MP.addCallback(obj.type, function(err, data){
  3040. if (err){ if (callback) callback(err); console.log('Could not join waitlist: ' + err); return;}
  3041.  
  3042. if (callback) callback(err, data);
  3043. });
  3044.  
  3045. socket.sendJSON(obj);
  3046. },
  3047. djQueueLeave: function(callback){
  3048. if (!MP.checkPerm('djqueue.leave')) return;
  3049.  
  3050. var obj = {
  3051. type: 'djQueueLeave'
  3052. };
  3053.  
  3054. obj.id = MP.addCallback(obj.type, function(err, data){
  3055. if (err){ if (callback) callback(err); console.log('Could not leave waitlist: ' + err); return;}
  3056.  
  3057. if (callback) callback(err, data);
  3058. });
  3059.  
  3060. socket.sendJSON(obj);
  3061. },
  3062. djQueueSkip: function(lockSkipPosition, callback){
  3063. if (typeof lockSkipPosition === 'function'){
  3064. callback = lockSkipPosition;
  3065. lockSkipPosition = undefined;
  3066. }
  3067. if (!MP.checkPerm('djqueue.skip.self') && !MP.checkPerm('djqueue.skip.other')){
  3068. if (callback) callback('InsufficientPermissions');
  3069. return;
  3070. }
  3071.  
  3072. if (!MP.session.queue.currentdj || !MP.user){
  3073. if (callback) callback('InvalidDJ');
  3074. return;
  3075. }
  3076.  
  3077. var mod = typeof lockSkipPosition === 'number' || MP.session.queue.currentdj.uid != MP.user.uid;
  3078.  
  3079. if ( (mod && !MP.checkPerm('djqueue.skip.other')) || (!mod && !MP.checkPerm('djqueue.skip.self')) ){
  3080. if (callback) callback('InsufficientPermissions');
  3081. return;
  3082. }
  3083.  
  3084. var obj = {
  3085. type: (mod ? 'djQueueModSkip' : 'djQueueSkip')
  3086. };
  3087.  
  3088. if (typeof lockSkipPosition === 'number'){
  3089. obj.data = {
  3090. lockSkipPosition: lockSkipPosition
  3091. };
  3092. }
  3093.  
  3094. if (callback) obj.id = MP.addCallback(obj.type, callback);
  3095.  
  3096. socket.sendJSON(obj);
  3097. },
  3098. toggleLastDj: function(callback){
  3099. callback = callback || function(){};
  3100. if(!MP.session.queue.cycle){
  3101. callback("DjQueueCycleNotEnabled");
  3102. return false;
  3103. }
  3104.  
  3105. var obj = {
  3106. type: 'toggleLastDj',
  3107. };
  3108.  
  3109. obj.id = MP.addCallback(obj.type, function(err, data){
  3110. if(!err){
  3111. MP.session.lastdj = data.newval;
  3112. MP.applyModels();
  3113. }
  3114. callback(err, data);
  3115. });
  3116.  
  3117. socket.sendJSON(obj);
  3118. },
  3119. djQueueCycle: function(callback){
  3120. if (!MP.checkPerm('djqueue.cycle')){
  3121. if (callback) callback('InsufficientPermissions');
  3122. return;
  3123. }
  3124. var obj = {
  3125. type: 'djQueueCycle'
  3126. };
  3127.  
  3128. if (callback) obj.id = MP.addCallback(obj.type, callback);
  3129.  
  3130. socket.sendJSON(obj);
  3131. },
  3132. djQueueLock: function(callback){
  3133. if (!MP.checkPerm('djqueue.lock')){
  3134. if (callback) callback('InsufficientPermissions');
  3135. return;
  3136. }
  3137.  
  3138. var obj = {
  3139. type: 'djQueueLock'
  3140. };
  3141.  
  3142. if (callback) obj.id = MP.addCallback(obj.type, callback);
  3143.  
  3144. socket.sendJSON(obj);
  3145. },
  3146. djQueueModAdd: function(uid, position, callback) {
  3147. if (typeof position == 'function'){
  3148. callback = position;
  3149. position = undefined;
  3150. }
  3151. if (!MP.checkPerm('djqueue.move')){
  3152. if (callback) callback('InsufficientPermissions');
  3153. return;
  3154. }
  3155.  
  3156. var obj = {
  3157. type: 'djQueueModAdd',
  3158. data: {
  3159. uid: uid,
  3160. position: position
  3161. }
  3162. };
  3163.  
  3164. obj.id = MP.addCallback(obj.type, function(err, data){
  3165. if (err){ if (callback) callback(err); console.log('Could not add user to dj queue: ' + err); return;}
  3166.  
  3167. if (callback) callback(err, data);
  3168. });
  3169.  
  3170. socket.sendJSON(obj);
  3171. },
  3172. djQueueModRemove: function(uid, callback) {
  3173. if (!MP.checkPerm('djqueue.move')){
  3174. if (callback) callback('InsufficientPermissions');
  3175. return;
  3176. }
  3177.  
  3178. var obj = {
  3179. type: 'djQueueModRemove',
  3180. data: {
  3181. uid: uid
  3182. }
  3183. };
  3184.  
  3185. obj.id = MP.addCallback(obj.type, function(err, data){
  3186. if (err){ if (callback) callback(err); console.log('Could not remove user to dj queue: ' + err); return;}
  3187.  
  3188. if (callback) callback(err, data);
  3189. });
  3190.  
  3191. socket.sendJSON(obj);
  3192. },
  3193. djQueueModMove: function(uid, position, callback) {
  3194. if (!MP.checkPerm('djqueue.move')){
  3195. if (callback) callback('InsufficientPermissions');
  3196. return;
  3197. }
  3198.  
  3199. var obj = {
  3200. type: 'djQueueModMove',
  3201. data: {
  3202. uid: uid,
  3203. position: position - 1
  3204. }
  3205. };
  3206.  
  3207. obj.id = MP.addCallback(obj.type, function(err, data){
  3208. if (err){ if (callback) callback(err); console.log('Could not move user in dj queue: ' + err); return;}
  3209.  
  3210. if (callback) callback(err, data);
  3211. });
  3212.  
  3213. socket.sendJSON(obj);
  3214. },
  3215. djQueueModSwap: function(uid1, uid2, callback) {
  3216. if (!MP.checkPerm('djqueue.move')){
  3217. if (callback) callback('InsufficientPermissions');
  3218. return;
  3219. }
  3220.  
  3221. var obj = {
  3222. type: 'djQueueModSwap',
  3223. data: {
  3224. uid1: uid1,
  3225. uid2: uid2
  3226. }
  3227. };
  3228.  
  3229. obj.id = MP.addCallback(obj.type, function(err, data){
  3230. if (err){ if (callback) callback(err); console.log('Could not swap users in dj queue: ' + err); return;}
  3231.  
  3232. if (callback) callback(err, data);
  3233. });
  3234.  
  3235. socket.sendJSON(obj);
  3236. },
  3237. djQueueLimit: function(limit, callback){
  3238. if (!MP.checkPerm('djqueue.limit')){
  3239. if (callback) callback('InsufficientPermissions');
  3240. return;
  3241. }
  3242.  
  3243. var obj = {
  3244. type: 'djQueueLimit',
  3245. data: {
  3246. limit: limmit
  3247. }
  3248. };
  3249.  
  3250. obj.id = MP.addCallback(obj.type, function(err, data){
  3251. if (err){ if (callback) callback(err); console.log('Could not change the queue limit: ' + err); return;}
  3252.  
  3253. if (callback) callback(err, data);
  3254. });
  3255.  
  3256. socket.sendJSON(obj);
  3257. },
  3258. privateMessage: function(uid, message, callback){
  3259. if (!MP.checkPerm('chat.send')){
  3260. if (callback) callback('InsufficientPermissions');
  3261. return;
  3262. }
  3263. if (typeof message != 'string' || !message){
  3264. if (callback) callback('emptyMessage');
  3265. return;
  3266. }
  3267.  
  3268. if (!MP.findUser(uid)){
  3269. if (callback) callback('userNotFound');
  3270. return;
  3271. }
  3272.  
  3273. var obj = {
  3274. type: 'privateMessage',
  3275. data: {
  3276. uid: uid,
  3277. message: message
  3278. }
  3279. };
  3280.  
  3281. obj.id = MP.addCallback(obj.type, function(err, data){
  3282. if (err){ if (callback) callback(err); console.log('Could not send private message: ' + err); return;}
  3283.  
  3284. if (callback) callback(err, data);
  3285. });
  3286.  
  3287. socket.sendJSON(obj);
  3288. },
  3289. getCurrentVideoTime: function(callback){
  3290. var obj = {
  3291. type: 'getCurrentSongTime'
  3292. };
  3293.  
  3294. obj.id = MP.addCallback(obj.type, function(err, data){
  3295. if (data.success && MP.media.media){
  3296. MP.media.timeRemaining = Math.round(MP.media.media.duration - data.time);
  3297. }
  3298. if (callback) callback(err, data);
  3299. });
  3300.  
  3301. socket.sendJSON(obj);
  3302. },
  3303. togglePlaylistLoading: function(bool){
  3304. $('.lib-sng-search .load-spin').toggle(bool);
  3305. $('.lib-sng-search .btn-search').toggle(!bool);
  3306. },
  3307. toggleVideoStream: function(bool){
  3308. var settings = JSON.parse(localStorage.settings);
  3309.  
  3310. if (bool === null || bool === undefined || typeof bool != 'boolean'){
  3311. bool = !settings.player.stream;
  3312. }
  3313.  
  3314. if (bool == settings.player.stream){
  3315. return bool;
  3316. }
  3317.  
  3318. settings.player.stream = bool;
  3319. localStorage.setItem("settings", JSON.stringify(settings));
  3320.  
  3321. var player = API.player.getPlayer();
  3322.  
  3323. if (settings.player.stream){
  3324. var media = MP.media.media;
  3325.  
  3326. if (media){
  3327. player.loadVideoById(media.cid);
  3328. if (settings.player.hd){
  3329. player.setPlaybackQuality('hd720');
  3330. }
  3331.  
  3332. var curTime = Date.now();
  3333. MP.getCurrentVideoTime(function(err, data){
  3334. player.seekTo(((Date.now() - curTime) / 1000) + data.time);
  3335. });
  3336.  
  3337. }
  3338. }else{
  3339. API.player.getPlayer().loadVideoById(null);
  3340. }
  3341. MP.applyModels();
  3342. return bool;
  3343. },
  3344. toggleHighDefinitionQuality: function(bool){
  3345. var settings = JSON.parse(localStorage.settings);
  3346.  
  3347. if (bool === null || bool === undefined || typeof bool != 'boolean'){
  3348. bool = !settings.player.hd;
  3349. }
  3350.  
  3351. if (bool == settings.player.hd){
  3352. return bool;
  3353. }
  3354.  
  3355. settings.player.hd = bool;
  3356. localStorage.setItem("settings", JSON.stringify(settings));
  3357.  
  3358. if (settings.player.stream) {
  3359. var player = API.player.getPlayer();
  3360.  
  3361. if (settings.player.hd){
  3362. player.setPlaybackQuality('hd720');
  3363. $('.btn-hd').addClass('active');
  3364. }
  3365. else {
  3366. player.setPlaybackQuality('default');
  3367. $('.btn-hd').removeClass('active');
  3368. }
  3369. }
  3370. },
  3371. vote: function(voteType, callback){
  3372. var obj = {
  3373. type: 'vote'
  3374. };
  3375.  
  3376. voteType = voteType.toLowerCase();
  3377. if (['like', 'dislike', 'grab'].indexOf(voteType) == -1) return false;
  3378. if (!MP.session.queue.currentdj || !MP.user || MP.session.queue.currentdj && MP.session.queue.currentdj.uid == MP.user.uid) return false;
  3379.  
  3380. obj.data = {
  3381. voteType: voteType
  3382. };
  3383.  
  3384. obj.id = MP.addCallback(obj.type, function(err, data){
  3385. if (err){ if (callback) callback(err); console.log('Cannot vote: ' + err); return;}
  3386.  
  3387. var buttonClasses = {
  3388. like: 'btn-upvote',
  3389. dislike: 'btn-downvote',
  3390. grab: 'btn-grab'
  3391. };
  3392.  
  3393. if (!data.success) return;
  3394.  
  3395. var $button = $('.' + buttonClasses[voteType]);
  3396.  
  3397. MP.models
  3398.  
  3399. if (voteType == 'like'){
  3400. var $dislikeButton = $('.' + buttonClasses.dislike);
  3401. if ($dislikeButton.hasClass('active')) $dislikeButton.removeClass('active');
  3402. }else if (voteType == 'dislike'){
  3403. var $likeButton = $('.' + buttonClasses.like);
  3404. if ($likeButton.hasClass('active')) $likeButton.removeClass('active');
  3405. }
  3406.  
  3407. if ($button.hasClass('active'))
  3408. $button.removeClass('active');
  3409. else
  3410. $button.addClass('active');
  3411.  
  3412. if (callback) callback(err, data);
  3413. MP.applyModels();
  3414. });
  3415.  
  3416. socket.sendJSON(obj);
  3417.  
  3418. return true;
  3419. },
  3420. banUser: function(uid, duration, reason, callback){
  3421. if (!MP.checkPerm('room.banUser')) return;
  3422.  
  3423. var obj = {
  3424. type: 'banUser',
  3425. data: {
  3426. uid: uid,
  3427. duration: duration,
  3428. reason: reason.substr(0,50)
  3429. }
  3430. };
  3431.  
  3432. obj.id = MP.addCallback(obj.type, function(err, data){
  3433. if (err){ if (callback) callback(err); console.log('Could not ban user: ' + err); return;}
  3434.  
  3435. if (callback) callback(err, data);
  3436. });
  3437.  
  3438. socket.sendJSON(obj);
  3439. },
  3440. unbanUser: function(uid, callback){
  3441. if (!MP.checkPerm('room.banUser')) return;
  3442.  
  3443. var obj = {
  3444. type: 'unbanUser',
  3445. data: {
  3446. uid: uid
  3447. }
  3448. };
  3449.  
  3450. obj.id = MP.addCallback(obj.type, function(err, data){
  3451. if (err){ if (callback) callback(err); console.log('Could not unban user: ' + err); return;}
  3452.  
  3453. if (callback) callback(err, data);
  3454. });
  3455.  
  3456. socket.sendJSON(obj);
  3457. },
  3458. showBanModal: function(uid){
  3459. if (!MP.checkPerm('room.banUser') || !MP.seenUsers[uid]) return;
  3460. MP.makeCustomModal({
  3461. content: '<div>\
  3462. <h3>You are about to BAN <span id="BanUserModalUser" style="'+ MP.makeUsernameStyle(MP.seenUsers[uid].role) +'" data-uid="' + uid + '">' + MP.seenUsers[uid].un + '</span> for </h3>\
  3463. <div id="BanUserModalDuration" class="modal-options">\
  3464. <div class="ban-opt" data-val="PT15M">Quarter</div>\
  3465. <div class="ban-opt" data-val="PT1H">Hour</div>\
  3466. <div class="ban-opt" data-val="P1DT">Day</div>\
  3467. <div class="ban-opt" data-val="P100YT">Perma</div>\
  3468. <input class="ban-opt" placeholder="(Days?)"></input>\
  3469. </div>\
  3470. <input class="ban-reason" type="text" placeholder="Reason for punishment..." id="BanUserModalReason" />\
  3471. </div>',
  3472. dismissable: false,
  3473. buttons: [
  3474. {
  3475. icon: 'mdi-close',
  3476. classes: 'modal-no',
  3477. handler: function(e){
  3478. $('.modal-bg').remove();
  3479. }
  3480. },
  3481. {
  3482. icon: 'mdi-check',
  3483. classes: 'modal-yes',
  3484. handler: function(e){
  3485. var duration = $('#BanUserModalDuration .ban-opt.active');
  3486. var uid = $('#BanUserModalUser').attr('data-uid');
  3487.  
  3488. if (!duration.length) return;
  3489.  
  3490. if (duration.is('input')){
  3491. duration = parseFloat(duration.val());
  3492. var remaining = null;
  3493. var durs = {
  3494. H: 60*60,
  3495. M: 60,
  3496. S: 1
  3497. };
  3498.  
  3499. if (isNaN(duration)) return;
  3500.  
  3501. var out = 'P' + Math.floor(duration) + 'DT';
  3502. remaining = (duration % 1) * 24 * 60 * 60;
  3503.  
  3504. for (var i in durs){
  3505. var result = Math.floor(remaining / durs[i]);
  3506.  
  3507. out += (result + i);
  3508.  
  3509. remaining = remaining - (durs[i]*result);
  3510. }
  3511.  
  3512. duration = out;
  3513. } else if (duration.is('div')){
  3514. duration = duration.attr('data-val');
  3515. }
  3516. MP.banUser(uid, duration, $('#BanUserModalReason').val(), function(err, data){
  3517. if (err){
  3518. alert(err);
  3519. return;
  3520. }
  3521.  
  3522. $('.modal-bg').remove();
  3523. });
  3524. }
  3525. }
  3526. ],
  3527. callback: function(){
  3528. var $banOpts = $('#BanUserModalDuration .ban-opt');
  3529.  
  3530. $banOpts.on('click', function(){
  3531. if ($(this).hasClass('active')) return;
  3532.  
  3533. $banOpts.removeClass('active');
  3534.  
  3535. $(this).addClass('active');
  3536. });
  3537. }
  3538. });
  3539. },
  3540. showRoleModal: function(uid){
  3541. if (!MP.checkPerm('room.grantroles') || !MP.seenUsers[uid] || !MP.getRole(MP.user.role).canGrantRoles) return;
  3542. MP.makeCustomModal({
  3543. content: '<div>\
  3544. <h3>You are about to set \
  3545. <span id="RoleModalUser" style="'+ MP.makeUsernameStyle(MP.seenUsers[uid].role) +'" data-uid="' + uid + '">' + MP.seenUsers[uid].un + '</span> as\
  3546. <select id="RoleModalSelect">' +
  3547. (function(){
  3548. var out = '';
  3549.  
  3550. for(var key in MP.session.roleOrder) {
  3551. var prop = MP.session.roleOrder[key];
  3552.  
  3553. if (!MP.session.roles[prop]) continue;
  3554. if (MP.getRole(MP.user.role).canGrantRoles.indexOf(prop) == -1) continue;
  3555.  
  3556. out += '<option ' + (MP.seenUsers[uid].role == prop ? 'selected' : '') +' value="' + prop + '">' + (MP.session.roles[prop].title || (prop.substr(0,1).toUpperCase() + prop.substr(1)) ) + '</option>';
  3557. }
  3558.  
  3559. return out;
  3560. })()
  3561.  
  3562.  
  3563. + '</select>\
  3564. </h3></div>',
  3565. dismissable: false,
  3566. buttons: [
  3567. {
  3568. icon: 'mdi-close',
  3569. classes: 'modal-no',
  3570. handler: function(e){
  3571. $('.modal-bg').remove();
  3572. }
  3573. },
  3574. {
  3575. icon: 'mdi-check',
  3576. classes: 'modal-yes',
  3577. handler: function(e){
  3578. var select = $('#RoleModalSelect').val();
  3579. var uid = $('#RoleModalUser').attr('data-uid');
  3580.  
  3581. if (select == MP.seenUsers[uid].role){
  3582. $('.modal-bg').remove();
  3583. return;
  3584. }
  3585.  
  3586. MP.setRole(uid, select, function(err, data){
  3587. if (err){
  3588. alert(err);
  3589. return;
  3590. }
  3591.  
  3592. $('.modal-bg').remove();
  3593. });
  3594.  
  3595.  
  3596. }
  3597. }
  3598. ],
  3599. callback: function(){
  3600. $('.modal select').selectmenu({
  3601. width: 300,
  3602. appendTo: '.modal-box'
  3603. });
  3604. }
  3605. });
  3606. },
  3607. showEditPlaylistModal: function(pid,cid){
  3608. if (!MP.models.playlists[pid]) return;
  3609.  
  3610. var playlist = MP.models.playlists[pid];
  3611. var title = playlist.name;
  3612.  
  3613. if (cid){
  3614. var media = playlist.content.filter(function(a){return a.cid==cid;})[0];
  3615.  
  3616. if (!media) return;
  3617. title = media.title;
  3618. }
  3619.  
  3620. MP.makeCustomModal({
  3621. content: '<div>\
  3622. <h3>Edit '+(cid ? 'song' : 'playlist')+' name</h3> \
  3623. <input type="text" class="edit-playlist-name" id="edit-playlist" value="' + title + '"/>\
  3624. </div>',
  3625. dismissable: true,
  3626. buttons: [
  3627. {
  3628. icon: 'mdi-close',
  3629. classes: 'modal-no',
  3630. handler: function(e){
  3631. $('.modal-bg').remove();
  3632. }
  3633. },
  3634. {
  3635. icon: 'mdi-check',
  3636. classes: 'modal-yes',
  3637. handler: function(e){
  3638. var newtitle = $('#edit-playlist').val();
  3639.  
  3640. if (newtitle == title || newtitle.match(/^.{1,100}$/) == null) return;
  3641.  
  3642. if (cid){
  3643. var obj = {
  3644. type: 'playlistEditMedia',
  3645. data: {
  3646. pid: pid,
  3647. cid: cid,
  3648. name: newtitle
  3649. }
  3650. };
  3651.  
  3652. socket.sendJSON(obj);
  3653. }else{
  3654. MP.playlistRename(pid, newtitle, function(err, data){
  3655. if (err){
  3656. alert('Could not rename playlist: ' + err);
  3657. return;
  3658. }
  3659.  
  3660. $('.modal-bg').remove();
  3661. });
  3662. }
  3663. }
  3664. }
  3665. ]
  3666. });
  3667. },
  3668. setRole: function(uid, role, callback){
  3669. var obj = {
  3670. type: 'setRole',
  3671. data: {
  3672. uid: uid,
  3673. role: role
  3674. }
  3675. };
  3676.  
  3677. if (!uid || !role) return;
  3678.  
  3679. obj.id = MP.addCallback(obj.type, function(err, data){
  3680. if (err){ if (callback) callback(err); console.log('Cannot set role: ' + err); return;}
  3681.  
  3682. if (callback) callback(err, data);
  3683. });
  3684.  
  3685. socket.sendJSON(obj);
  3686. },
  3687. userAutocomplete: function(input){
  3688. var inputReg = new RegExp('^' + input, "i");
  3689. var out = [];
  3690.  
  3691. for (var i in MP.userList.users){
  3692. var user = MP.seenUsers[ MP.userList.users[i] ];
  3693. if (inputReg.test(user.un)) out.push(user);
  3694. }
  3695.  
  3696. out.sort(function (a, b) {
  3697. return (a['un'].localeCompare(b['un']));
  3698. });
  3699.  
  3700. return out;
  3701. },
  3702. emojiAutocomplete: function(input){
  3703. var inputReg = new RegExp('^' + input.replace('+', '\\+'), 'i');
  3704. var out = {};
  3705. var num = 0;
  3706.  
  3707. for (var emoset in MP.emotes)
  3708. if(JSON.parse(localStorage.settings).roomSettings.emojis[emoset.toLowerCase()])
  3709. for (var i in MP.emotes[emoset]){
  3710. if (inputReg.test(i)){
  3711. if(!out[i]){
  3712. num++;
  3713. out[i] = MP.emotes[emoset][i].url;
  3714. }
  3715. }
  3716. if (num == 10) return out;
  3717. }
  3718. return out;
  3719. },
  3720. commandAutocomplete: function(input){
  3721. var inputReg = new RegExp('^' + input, 'i');
  3722. var out = [];
  3723.  
  3724. //Check for commands
  3725. for (var cmd in MP.chatCommands){
  3726. if(inputReg.test(cmd)) out.push(cmd);
  3727.  
  3728. //Check for aliases
  3729. for(var alias in MP.chatCommands[cmd].aliases){
  3730. alias = MP.chatCommands[cmd].aliases[alias];
  3731. if(inputReg.test(alias)) out.push(alias);
  3732. }
  3733. }
  3734.  
  3735. return out;
  3736. },
  3737. showUserMenu: function(user, $this){
  3738. $('.user-menu').remove();
  3739.  
  3740. if (!user) return;
  3741. var $appendElem = $('\
  3742. <div class="user-menu" style="visibility: hidden;">\
  3743. <div class="arrow"></div>\
  3744. <div class="user-menu-content">'+
  3745. '<div>' + MP.makeBadgeStyle({ user: user }) + '</div>' +
  3746. '<span class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span><span class="people-info">' + MP.getRole(user.role).title + '</span>\
  3747. </div>\
  3748. <div class="user-menu-content">'+
  3749. '<span class="people-info left">User ID: '+ user.uid +'</span>'+
  3750. (MP.findPosInWaitlist(user.uid) != -1 ? '<span class="people-info">Position: ' + ((MP.findPosInWaitlist(user.uid) != 0) ? MP.findPosInWaitlist(user.uid) : 'DJ') + '</span>' : '') +
  3751. '</div>\
  3752. <div class="modal-controls" data-uid="'+ user.uid +'">' +
  3753. (!MP.user || MP.user.uid == user.uid ? '':
  3754. ( (MP.checkPerm('room.banUser') && !MP.canGrantRole(MP.user.role, user)) ? ( !user.banned ? '<div class="modal-ctrl ban" title="Ban user"><i class="mdi mdi-account-remove"></i></div>' :
  3755. '<div class="modal-ctrl unban" title="Unban user"><i class="mdi mdi-account-check"></i></div>') : '' )+
  3756. '<div class="modal-ctrl mute" title="Mute user"><i class="mdi mdi-account-alert"></i></div>' +
  3757. ( MP.canGrantRole(user.role) ? '<div class="modal-ctrl set-role" title="Set role"><i class="mdi mdi-account-key"></i></div>' : '')
  3758. ) +
  3759. (MP.checkPerm('djqueue.move') ? (MP.isOnWaitlist(user.uid) ? '<div class="modal-ctrl remove-dj" title="Remove DJ"><i class="mdi mdi-account-minus"></i></div>' :
  3760. '<div class="modal-ctrl add-dj" title="Add DJ"><i class="mdi mdi-account-plus"></i></div>') : '') +
  3761. '<div class="modal-ctrl menu-mention" title="Mention user"><i class="mdi mdi-at"></i></div>' +
  3762. '</div>\
  3763. </div>\
  3764. ');
  3765. $('body').append($appendElem);
  3766.  
  3767. var Y = $this.offset().top - ($this.height()/2) - 44;
  3768.  
  3769. if (Y < 0) Y = 0;
  3770. if ( (Y + $appendElem.height()) > $(window).height()) Y = $(window).height() - $appendElem.height();
  3771.  
  3772. var X = $this.offset().left - $appendElem.width() - 53;
  3773.  
  3774. if (X < 0) X = 0;
  3775.  
  3776. var aY = 50;
  3777. $appendElem.css({
  3778. top: Y + 'px',
  3779. left: X + 'px'
  3780. });
  3781. $appendElem.find('.arrow').css('top', aY + 'px');
  3782. $appendElem.css('visibility', '');
  3783. },
  3784. makeConfirmModal: function(inOpts){
  3785. /* opts available:
  3786. content: content in the modal,
  3787. callback: function(result (bool)),
  3788. */
  3789.  
  3790. var opts = inOpts || {};
  3791.  
  3792. MP.makeCustomModal({
  3793. content: opts.content || '',
  3794. buttons: [
  3795. {
  3796. icon: 'mdi-close',
  3797. handler: function(){
  3798. $('.modal-bg').remove();
  3799. if (opts.callback) opts.callback(false);
  3800. },
  3801. classes: 'modal-no'
  3802. },
  3803. {
  3804. icon: 'mdi-check',
  3805. handler: function(){
  3806. $('.modal-bg').remove();
  3807. if (opts.callback) opts.callback(true);
  3808. },
  3809. classes: 'modal-yes'
  3810. }
  3811. ],
  3812. dismissable: opts.dismissable || false
  3813. });
  3814. },
  3815. makeAlertModal: function(inOpts){
  3816. /* opts available:
  3817. content: content in the modal,
  3818. dismissable: bool,
  3819. onDismiss: function() (run on dismiss)
  3820. */
  3821.  
  3822. var opts = inOpts || {};
  3823.  
  3824. MP.makeCustomModal({
  3825. content: opts.content || '',
  3826. buttons: [
  3827. {
  3828. icon: 'mdi-check',
  3829. handler: function(){
  3830. $('.modal-bg').remove();
  3831. },
  3832. classes: 'modal-yes'
  3833. }
  3834. ],
  3835. dismissable: ('undefined' !== typeof opts.dismissable ? opts.dismissable : true),
  3836. onDismiss: opts.onDismiss || function(){}
  3837. });
  3838. },
  3839. makeCustomModal: function(inOpts){
  3840. /* opts available:
  3841. content: content in the modal,
  3842. buttons: [
  3843. {
  3844. icon: MDI class string
  3845. style: {prop: 'value'},
  3846. hoverStyle: {prop: 'value'},
  3847. handler: function,
  3848. classes: classes prop string
  3849. }
  3850. ]
  3851. style: object of {prop: 'value'}
  3852. appendTo: selector to append modal to
  3853. dismissable: bool
  3854. onDismiss: function() (run on dismiss)
  3855. callback: function() (run after modal is made)
  3856. */
  3857.  
  3858. var opts = inOpts || {};
  3859. $('.modal').remove();
  3860. $(opts.appendTo || 'body').append('\
  3861. <div class="modal-bg"><div class="modal-container"><div class="modal" style="' +
  3862. (function(){
  3863. var out = '';
  3864.  
  3865. out += API.util.makeStyleString(opts.style);
  3866.  
  3867. return out;
  3868. })()
  3869.  
  3870. + '">\
  3871. <div class="modal-box">\
  3872. <div class="modal-text">' + (opts.content || '') + '</div>\
  3873. </div>\
  3874. <div class="modal-controls">' +
  3875. (function(){
  3876. var out = '';
  3877. for (var j in opts.buttons){
  3878. out += ('<div class="modal-ctrl ' + opts.buttons[j].classes + '" style="width: ' + (100 / opts.buttons.length) + '%; ' + API.util.makeStyleString(opts.buttons[j].style) + '" id="CustomModalButton-'+j+'"><div class="mdi ' + opts.buttons[j].icon + '"></div></div>');
  3879. }
  3880.  
  3881. return out;
  3882.  
  3883. })()
  3884. + '</div>\
  3885. </div></div></div>\
  3886. ');
  3887.  
  3888. for (var j in opts.buttons){
  3889.  
  3890. $('#CustomModalButton-'+j).on('click', {bid: j}, function(e){
  3891. var len = $('.modal-bg').length;
  3892.  
  3893. if (opts.buttons[ e.data.bid ].handler) opts.buttons[ e.data.bid ].handler(e);
  3894.  
  3895. if ($('.modal-bg').length < len && opts.onDismiss) opts.onDismiss();
  3896. });
  3897.  
  3898. if (opts.buttons[j].hoverStyle){
  3899. $('#CustomModalButton-'+j)
  3900. .on('mouseenter', {bid: j}, function(e){
  3901. $(this).css(opts.buttons[e.data.bid].hoverStyle);
  3902. })
  3903. .on('mouseleave', {bid: j}, function(e){
  3904. var obj = {};
  3905. for (var i in opts.buttons[e.data.bid].hoverStyle){
  3906. if (opts.buttons[e.data.bid].style[i])
  3907. obj[i] = opts.buttons[e.data.bid].style[i];
  3908. else
  3909. obj[i] = '';
  3910. }
  3911.  
  3912. $(this).css(obj);
  3913. });
  3914. }
  3915. }
  3916.  
  3917. if ( typeof opts.dismissable === 'undefined' || opts.dismissable){
  3918. $('.modal-bg').on('click', function(e){
  3919. e.originalEvent.dismissable = true;
  3920.  
  3921. if (!$(e.target).closest('.modal').length){
  3922. if (opts.onDismiss) opts.onDismiss();
  3923. }
  3924. });
  3925. }else{
  3926. $('.modal-bg').on('click', function(e){
  3927. e.originalEvent.dismissable = false;
  3928. });
  3929. }
  3930.  
  3931. if ( opts.callback ) opts.callback();
  3932. },
  3933. copyObject: function(obj){
  3934. if (!obj || "object" != typeof obj) return obj;
  3935. return $.extend(true, Array.isArray(obj) ? [] : {}, obj);
  3936. },
  3937. };
  3938.  
  3939. // Exposing internal functions to the global scope
  3940. // TODO: Extend any data output so you can't change internal objects
  3941. window.API = {
  3942. queue : {
  3943. join: MP.api.queue.join,
  3944. leave: MP.api.queue.leave,
  3945. modAddDJ: MP.api.queue.modAddDJ,
  3946. modRemoveDJ: MP.api.queue.modRemoveDJ,
  3947. modSwapDJ: MP.api.queue.modSwapDJ,
  3948. modMoveDJ: MP.api.queue.modMoveDJ,
  3949. skip: MP.api.queue.skip,
  3950. selfSkip: MP.api.queue.skip,
  3951. modSkip: MP.api.queue.skip,
  3952. setLock: MP.api.queue.setLock,
  3953. setCycle: MP.api.queue.setCycle,
  3954. setLimit: MP.api.queue.setLimit,
  3955. getDJ: function() { return MP.copyObject(MP.api.queue.getDJ()); },
  3956. getDJs: function() { return MP.copyObject(MP.api.queue.getDJs()); },
  3957. getPosition: MP.api.queue.getPosition,
  3958. getInfo: function() { return MP.copyObject(MP.api.queue.getInfo()); },
  3959. },
  3960. room: {
  3961. getInfo: MP.api.room.getInfo,
  3962. isLoggedIn: MP.api.room.isLoggedIn,
  3963. getUser: function(uid, callback) {
  3964. if(callback) {
  3965. var obj = {
  3966. type: 'getUser',
  3967. data: {
  3968. uid: uid,
  3969. },
  3970. };
  3971. obj.id = MP.addCallback(obj.type, function(err, data){ callback(err || data.data.user); });
  3972. socket.sendJSON(obj);
  3973. } else {
  3974. return MP.api.room.getUser(uid);
  3975. }
  3976. },
  3977. getUsers: function(arr) { return MP.copyObject(MP.api.room.getUsers(arr)); },
  3978. getRoles: function(arr) { return MP.copyObject(MP.api.room.getRoles(arr)); },
  3979. getHistory: MP.api.room.getHistory,
  3980. getMedia: function() { return MP.copyObject(MP.api.room.getMedia()); },
  3981. getTimeElapsed: MP.api.room.getTimeElapsed,
  3982. getTimeRemaining: MP.api.room.getTimeRemaining,
  3983. setRole: MP.api.room.setRole,
  3984. getStaff: MP.api.room.getStaff,
  3985. getBannedUsers: MP.api.room.getBannedUsers,
  3986. banUser: MP.api.room.banUser,
  3987. unbanUser: MP.api.room.unbanUser,
  3988. },
  3989. chat: {
  3990. log: MP.api.chat.log,
  3991. system: MP.api.chat.system,
  3992. broadcast: MP.api.chat.broadcast,
  3993. staff: function(msg){ return MP.sendMessage(msg, true); },
  3994. send: MP.api.chat.send,
  3995. sendPrivate: MP.api.chat.sendPrivate,
  3996. delete: MP.api.chat.delete,
  3997. },
  3998. playlist: {
  3999. get: function(pid, arr) { return MP.copyObject(MP.api.playlist.get(pid, arr)); },
  4000. create: MP.api.playlist.create,
  4001. delete: MP.api.playlist.delete,
  4002. getActive: MP.api.playlist.getActive,
  4003. active: MP.api.playlist.active,
  4004. getNextSong: MP.api.playlist.getNextSong,
  4005. addSong: MP.api.playlist.addSong,
  4006. removeSong: MP.api.playlist.removeSong,
  4007. moveSong: MP.api.playlist.moveSong,
  4008. getContents: MP.api.playlist.getContents,
  4009. import: MP.api.playlist.playlistImport,
  4010. shuffle: MP.api.playlist.shuffle,
  4011. export: function(pid, format, callback){
  4012. if(!(pid = pid || MP.session.viewedPl)) return false;
  4013. format = format || API.DATA.EXPORT.FORMAT.JSON;
  4014. callback = callback || API.DATA.EXPORT.CALLBACK.DOWNLOAD;
  4015. MP.getPlaylistContents(pid, function(err, data){
  4016. if(err) return;
  4017. var out = {
  4018. name: MP.api.playlist.get(pid).name,
  4019. content: [],
  4020. };
  4021. for(var k in data.content){
  4022. out.content.push({
  4023. title: data.content[k].title,
  4024. cid: data.content[k].cid,
  4025. duration: {
  4026. h: ~~(data.content[k].duration / 360),
  4027. m: ~~(data.content[k].duration % 360 / 60),
  4028. s: data.content[k].duration % 60,
  4029. },
  4030. });
  4031. }
  4032. callback(MP.copyObject(out));
  4033. });
  4034. return true;
  4035. },
  4036. },
  4037. util: {
  4038. makeAlertModal: MP.api.util.makeAlertModal,
  4039. makeCustomModal: MP.api.util.makeCustomModal,
  4040. showBanModal: MP.api.util.showBanModal,
  4041. showRoleModal: MP.api.util.showRoleModal,
  4042. objectToArray: MP.api.util.objectToArray,
  4043. timeConvert: MP.api.util.timeConvert,
  4044. youtube_parser: MP.api.util.youtube_parser,
  4045. colourNameToHex: MP.api.util.colourNameToHex,
  4046. makeStyleString: MP.api.util.makeStyleString,
  4047. toggle_images: MP.api.util.toggle_images,
  4048. showImageModal: MP.chatImage.showModal
  4049. },
  4050. emotes: {
  4051. load: MP.loadEmoji,
  4052. match: MP.emojiReplace,
  4053. getEmotes: function(ascii){ return MP.copyObject(ascii ? MP.emotes_ascii : MP.emotes); },
  4054. },
  4055. on: function(event, cb){
  4056. return MP.on(event, cb, true);
  4057. },
  4058. off: function(event, cb){
  4059. return MP.off(event, cb, true);
  4060. },
  4061. once: function(event, cb){
  4062. return MP.once(event, cb, true);
  4063. },
  4064. fullscreen: function() {
  4065. $('.playback').toggleClass('fullscreen');
  4066. $('.video').toggleClass('fullscreen');
  4067. if (($('.btn-fullscreen > div').hasClass('mdi-fullscreen'))){
  4068. $('.btn-fullscreen > div').removeClass('mdi-fullscreen').addClass('mdi-fullscreen-exit');
  4069. //$(".playback").draggable({disabled:true}).resizable({disabled:true}).attr('style', '');
  4070. }
  4071. else {
  4072. $('.btn-fullscreen > div').removeClass('mdi-fullscreen-exit').addClass('mdi-fullscreen');
  4073. //$(".playback").draggable({disabled:false}).resizable({disabled:false});
  4074. }
  4075. },
  4076. player: {
  4077. setVolume: function(vol){
  4078. var voldiv = $('.btn-volume div');
  4079. vol = ~~(Math.max(0, Math.min(vol, 100)));
  4080. $('.volume-val').text(vol + "%");
  4081. $('.volume').val(vol+'');
  4082.  
  4083. if (!MP.mediaPreview.isOpened()){
  4084. API.player.getPlayer().setVolume(vol);
  4085. }
  4086. voldiv.removeClass('mdi-volume-off').removeClass('mdi-volume-low').removeClass('mdi-volume-medium').removeClass('mdi-volume-high');
  4087. if(vol == 0){
  4088. voldiv.addClass('mdi-volume-off');
  4089. } else if (vol <= 25) {
  4090. voldiv.addClass('mdi-volume-low');
  4091. } else if (vol >= 75) {
  4092. voldiv.addClass('mdi-volume-high');
  4093. } else {
  4094. voldiv.addClass('mdi-volume-medium');
  4095. }
  4096.  
  4097. var settings = JSON.parse(localStorage.getItem("settings"));
  4098. var oldVol = settings.player.volume;
  4099.  
  4100. if (oldVol != vol && vol > 0){
  4101. settings.player.mute = false;
  4102. }
  4103.  
  4104. if(!settings.player.mute) settings.player.volume = vol;
  4105. localStorage.setItem("settings", JSON.stringify(settings));
  4106. },
  4107. setMute: function(mute){
  4108. mute = mute || false;
  4109.  
  4110. var settings = JSON.parse(localStorage.getItem("settings"));
  4111.  
  4112. /* if (mute == settings.player.mute){
  4113. return;
  4114. }
  4115. */ settings.player.mute = mute;
  4116. localStorage.setItem("settings", JSON.stringify(settings));
  4117.  
  4118. if (mute){
  4119. $('.volume').val("0");
  4120. $('.btn-volume div').removeClass('mdi-volume-low').removeClass('mdi-volume-medium').removeClass('mdi-volume-high').addClass("mdi-volume-off");
  4121. $('.volume-val').text("0%");
  4122. if (!MP.mediaPreview.isOpened()){
  4123. API.player.setVolume(0);
  4124. }
  4125. } else {
  4126. this.setVolume(settings.player.volume);
  4127. }
  4128. },
  4129. refresh: function(){
  4130. //var seekto = API.player.getPlayer().getCurrentTime();
  4131. MP.session.snooze = false;
  4132. API.player.getPlayer().unMute();
  4133. API.player.getPlayer().loadVideoById(API.player.getPlayer().getVideoData().video_id);
  4134. var settings = JSON.parse(localStorage.getItem("settings"));
  4135. if (settings.player.hd){
  4136. API.player.getPlayer().setPlaybackQuality('hd720');
  4137. }
  4138. API.player.getPlayer().seekTo(API.seekTo);
  4139. },
  4140. snooze: function(snooze){
  4141. snooze = snooze || MP.session.snooze;
  4142. if(snooze){
  4143. API.player.getPlayer().unMute();
  4144. MP.session.snooze = false;
  4145. } else {
  4146. API.player.getPlayer().mute();
  4147. MP.session.snooze = true;
  4148. }
  4149. MP.applyModels();
  4150. },
  4151. },
  4152. tour: {
  4153. start: function(){
  4154. if($('.logo-menu').css('display') == 'none') $('.btn-logo').click();
  4155. delete localStorage.tour_current_step;
  4156. delete localStorage.tour_end;
  4157. var steps = [
  4158. {
  4159. element: ".btn-logo",
  4160. placement: "bottom",
  4161. content: "Click the Vaporwave.io logo to show playlists, settings, pad dj history, and logout. Pro tip: use ESC key as a shortcut!",
  4162. onShown: function() {
  4163. $('.popover.tour .modal-controls div[data-role="prev"]').hide();
  4164. }
  4165. },
  4166. {
  4167. element: ".nav.logo-btn-home",
  4168. placement: "right",
  4169. content: "Here you can browse various pads, hover over the rooms to see how many users are online and what is currently djing.",
  4170. onShow: function() {
  4171. if($('.logo-menu').css('display') != 'block') $('.btn-logo').click();
  4172. $('.nav.logo-btn-home').click();
  4173. },
  4174. onShown: function() {
  4175. $('.popover.tour .modal-controls div[data-role="prev"]').show();
  4176. }
  4177. },
  4178. {
  4179. element: ".nav.logo-btn-settings",
  4180. placement: "right",
  4181. content: "In this menu you can customize your Vaporwave.io experience, set various settings and even design your own badge!",
  4182. onShow: function() {
  4183. if($('.logo-menu').css('display') != 'block') $('.btn-logo').click();
  4184. $('.nav.logo-btn-settings').click();
  4185. }
  4186. },
  4187. {
  4188. element: ".nav.logo-btn-library",
  4189. placement: "right",
  4190. content: "Here you can manage your music library and browse YouTube for new music.",
  4191. onShow: function() {
  4192. if($('.logo-menu').css('display') != 'block') $('.btn-logo').click();
  4193. $('.nav.logo-btn-library').click();
  4194. }
  4195. },
  4196. {
  4197. element: ".nav.logo-btn-history",
  4198. placement: "right",
  4199. content: "This is the place to look for great music other users played.",
  4200. onShow: function() {
  4201. if($('.logo-menu').css('display') != 'block') $('.btn-logo').click();
  4202. $('.nav.logo-btn-history').click();
  4203. }
  4204. },
  4205. {
  4206. element: ".nav.logo-btn-tour",
  4207. placement: "right",
  4208. content: "By clicking this button you can bring up this tour again whenever you need it.",
  4209. onShow: function() {
  4210. if($('.logo-menu').css('display') != 'block') $('.btn-logo').click();
  4211. }
  4212. },
  4213. {
  4214. element: ".nav.logo-btn-logout",
  4215. placement: "right",
  4216. content: "Clicking here will log you out of Vaporwave.io.",
  4217. onShow: function() {
  4218. if($('.logo-menu').css('display') != 'block') $('.btn-logo').click();
  4219. }
  4220. },
  4221. {
  4222. element: ".btn-login",
  4223. placement: "bottom",
  4224. content: "Clicking here will bring up your account settings or, in case you are not logged in yet, the signup / login form.",
  4225. onShow: function() {
  4226. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4227. }
  4228. },
  4229. {
  4230. element: ".btn-downvote",
  4231. placement: "top",
  4232. content: "If there is an active DJ, click this button in case you'd like to tell others this song is not your cup of tea.",
  4233. onShow: function() {
  4234. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4235. }
  4236. },
  4237. {
  4238. element: ".btn-snooze",
  4239. placement: "top",
  4240. content: "Click this button to mute the current song, the volume will go back to it's original value after the song ends.",
  4241. onShow: function() {
  4242. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4243. }
  4244. },
  4245. {
  4246. element: ".btn-join",
  4247. placement: "top",
  4248. content: "Clicking this button will add you to the DJ queue if you have an active playlist with at least one song.",
  4249. onShow: function() {
  4250. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4251. }
  4252. },
  4253. {
  4254. element: ".btn-grab",
  4255. placement: "top",
  4256. content: "Click this to add the current song to one of your playlists.",
  4257. onShow: function() {
  4258. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4259. }
  4260. },
  4261. {
  4262. element: ".btn-upvote",
  4263. placement: "top",
  4264. content: "Show your love to the current song to everyone by clicking this button!",
  4265. onShow: function() {
  4266. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4267. }
  4268. },
  4269. {
  4270. element: ".dash .tray .btn-chat",
  4271. placement: "bottom",
  4272. content: "Click here to show the chat tab.",
  4273. onShow: function() {
  4274. $('.btn-chat').click();
  4275. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4276. }
  4277. },
  4278. {
  4279. element: ".dash .tray .btn-people",
  4280. placement: "bottom",
  4281. content: "Click here to view online users and staff members.",
  4282. onShow: function() {
  4283. $('.btn-people').click();
  4284. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4285. }
  4286. },
  4287. {
  4288. element: "#app-right .tray .btn-people",
  4289. placement: "bottom",
  4290. content: "Click here to view online users.",
  4291. onShow: function() {
  4292. $('.btn-people').click();
  4293. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4294. }
  4295. },
  4296. {
  4297. element: "#app-right .tray .btn-staff",
  4298. placement: "bottom",
  4299. content: "Click here to view all staff members.",
  4300. onShow: function() {
  4301. $('.btn-staff').click();
  4302. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4303. }
  4304. },
  4305. {
  4306. element: "#app-right .tray .btn-banned",
  4307. placement: "bottom",
  4308. content: "Click here to view all banned users.",
  4309. onShown: function() {
  4310. $('.btn-banned').click();
  4311. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4312. }
  4313. },
  4314. {
  4315. element: ".dash .tray .btn-waitlist",
  4316. placement: "bottom",
  4317. content: "Check who is the current dj and who will play next.",
  4318. onShown: function() {
  4319. $('.popover .modal-controls div[data-role="next"]').show();
  4320. },
  4321. onShow: function() {
  4322. $('.btn-waitlist').click();
  4323. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4324. }
  4325. },
  4326. {
  4327. element: ".playback",
  4328. placement: "top",
  4329. content: "Hover over the video player to toggle dj cycle and other video settings.",
  4330. onShown: function() {
  4331. $('.popover .modal-controls div[data-role="next"]').hide();
  4332. },
  4333. onShow: function() {
  4334. $('.btn-banned').click();
  4335. if($('.logo-menu').css('display') == 'block') $('.btn-logo').click();
  4336. }
  4337. }
  4338. ];
  4339. var max = steps.length;
  4340. var tour = new Tour({
  4341. template: '<div class="popover tour">\
  4342. <div class="arrow"></div>\
  4343. <div class="modal-title"></div>\
  4344. <div class="popover-content modal-text"></div>\
  4345. <div class="modal-controls">\
  4346. <div class="modal-ctrl" data-role="prev"><div class="mdi mdi-skip-previous"></div></div>\
  4347. <div class="modal-ctrl" data-role="end"><div class="mdi mdi-pause"></div></div>\
  4348. <div class="modal-ctrl" data-role="next"><div class="mdi mdi-skip-next"></div></div>\
  4349. </div>\
  4350. </div>',
  4351. onEnd: function() {
  4352. $('#app-right .tray .btn-people').click();
  4353. $('.dash .tray .btn-chat').click();
  4354. $('.nav.logo-btn-library').click();
  4355. if($('.logo-menu').css('display') == 'none') $('.logo-menu').click();
  4356. },
  4357. steps: steps
  4358. }).init().start();
  4359. }
  4360. },
  4361. DATA: {
  4362. PLAYER: {
  4363. QUALITY: {
  4364. HD2160: "hd2160",
  4365. HD1440: "hd1440",
  4366. HD1080: "hd1080",
  4367. HD720: "hd720",
  4368. LQ480: "large",
  4369. MQ360: "medium",
  4370. SQ240: "small",
  4371. TQ144: "tiny",
  4372. AUTO: "auto"
  4373. }
  4374. },
  4375. USER: {
  4376. BAN: {
  4377. MIN5: { text: '5 minutes', duration: 'PT5M' },
  4378. MIN30: { text: '30 minutes', duration: 'PT30M' },
  4379. HOUR: { text: '1 hour', duration: 'PT1H' },
  4380. HOUR12: { text: '12 hours', duration: 'PT12H' },
  4381. DAY: { text: '1 day', duration: 'P1DT' },
  4382. DAY10: { text: '10 days', duration: 'P10DT' },
  4383. DAY30: { text: '30 days', duration: 'P30DT' },
  4384. PERMA: { text: 'Permanent', duration: 'P100YT' }
  4385. },
  4386. },
  4387. CHAT: {
  4388. TSFORMAT: {
  4389. HR12: '12hr',
  4390. HR24: '24hr'
  4391. },
  4392. },
  4393. EXPORT: {
  4394. FORMAT: {
  4395. JSON: 'json',
  4396. },
  4397. CALLBACK: {
  4398. DOWNLOAD: function(data){
  4399. var el = document.createElement('a');
  4400. el.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(data)));
  4401. el.setAttribute('download', data.name + '.json');
  4402. el.style.display = 'none';
  4403. document.body.appendChild(el);
  4404. el.click();
  4405. document.body.removeChild(el);
  4406. },
  4407. },
  4408. },
  4409. EVENTS: {
  4410. ADVANCE: 'advance',
  4411. CHAT: 'chat',
  4412. DELETE_CHAT: 'deleteChat',
  4413. DJ_QUEUE_CYCLE: 'djQueueCycle',
  4414. DJ_QUEUE_LOCK: 'djQueueLock',
  4415. DJ_QUEUE_SKIP: 'djQueueSkip',
  4416. DJ_QUEUE_MOD_SKIP: 'djQueueModSkip',
  4417. DJ_QUEUE_MOD_MOVE: 'djQueueModMove',
  4418. DJ_QUEUE_MOD_SWAP: 'djQueueModSwap',
  4419. DJ_QUEUE_ADD: 'djQueueModAdd',
  4420. DJ_QUEUE_REMOVE: 'djQueueModRemove',
  4421. DJ_QUEUE_LIMIT: 'djQueueLimit',
  4422. USER_JOINED: 'userJoined',
  4423. USER_JOINED_QUEUE: 'userJoinedQueue',
  4424. USER_LEFT: 'userLeft',
  4425. USER_LEFT_QUEUE: 'userLeftQueue',
  4426. USER_UPDATE: 'userUpdate',
  4427. VOTE_UPDATE: 'voteUpdate',
  4428. USER_BANNED: 'userBanned',
  4429. USER_UNBANNED: 'userUnbanned',
  4430. USER_ROLE_CHANGE: 'moderateSetRole',
  4431. SYSTEM_MESSAGE: 'systemMessage',
  4432. BROADCAST_MESSAGE: 'broadcastMessage',
  4433. SERVER_RESPONSE: 'response',
  4434. PRIVATE_MESSAGE: 'privateMessage',
  4435. CHAT_COMMAND: 'chatCommand'
  4436. }
  4437. },
  4438. test: function(){ console.log(MP.user.playlists); },
  4439. };
  4440.  
  4441. var mentionSound = new Audio('../pads/lib/sound/mention.wav');
  4442.  
  4443. var onLogin = function(err, data, callback){ // There's probably a better place for this...
  4444. if (data.error){
  4445. alert('There was an error signing up or logging in: ' + data.error);
  4446. MP.cookie.setCookie(MP.getTokenName(), '', -1);
  4447. if (callback) callback(err);
  4448. return;
  4449. }
  4450.  
  4451. MP.user = data.user;
  4452. if (MP.userList.guests > 0 ) MP.userList.guests--;
  4453.  
  4454. MP.seenUsers[MP.user.uid] = MP.user;
  4455.  
  4456. // if (MP.user && data.users[i].uid == MP.user.uid) MP.user.role = data.users[i].role;
  4457.  
  4458. if (MP.userList.users.indexOf(MP.user.uid) == -1){
  4459. MP.userList.users.push(MP.user.uid);
  4460. }
  4461.  
  4462. MP.session.viewedPl = MP.user.activepl;
  4463. MP.session.lastdj = data.user.lastdj;
  4464.  
  4465. MP.applyModels();
  4466.  
  4467. if (data.token){
  4468. MP.cookie.setCookie(MP.getTokenName(), data.token, 7);
  4469. }
  4470. };
  4471.  
  4472. var socketPort = config.serverPort;
  4473.  
  4474. var socketDomain = config.serverHost || document.location.hostname;
  4475.  
  4476. var socket = null;
  4477.  
  4478.  
  4479. function initSocket(){
  4480. socket = new WebSocket((config.useSSL ? 'wss' : 'ws') + '://' + socketDomain + ':' + socketPort);
  4481.  
  4482. socket.sendJSON = function(inObj){ socket.send( JSON.stringify(inObj) );};
  4483. /*DEBUG*/
  4484. API.sendSocket = socket.sendJSON;
  4485. /*END DEBUG*/
  4486.  
  4487. socket.onopen = function(e){
  4488. if (typeof MP.onConnect === 'function') MP.onConnect.call(window);
  4489. };
  4490.  
  4491. socket.onerror = function(){
  4492. socket.close();
  4493. };
  4494. socket.onclose = function(e){
  4495. //API.player.getPlayer().destroy();
  4496. //API.player.getPlayer().loadVideoById( null );
  4497. var data = null;
  4498. try{
  4499. data = JSON.parse( e.reason );
  4500.  
  4501. if (!data.type){
  4502. throw new Error('No Type');
  4503. }
  4504.  
  4505. switch (data.type){
  4506. case 'ConnectedElsewhere':
  4507. MP.makeAlertModal({
  4508. content: 'You have logged in elsewhere. This session has been disconnected.',
  4509. dismissable: false
  4510. });
  4511. break;
  4512. case 'banned':
  4513. MP.makeAlertModal({
  4514. content: 'You have been banned until ' + (new Date(data.data.banEnd)).toString() + '<br>Reason: ' + data.data.reason + '<br><b>You now have the permissions of a Guest</b>',
  4515. dismissable: false,
  4516. onDismiss: function(){
  4517. document.location.reload();
  4518. }
  4519. });
  4520. break;
  4521. case 'ratelimit':
  4522. break;
  4523. }
  4524. }catch(e){
  4525. if (!$('.modal-bg').length){
  4526. MP.makeCustomModal({
  4527. content: 'Reconnecting...',
  4528. buttons: [],
  4529. dismissable: false
  4530. });
  4531. }
  4532. delete MP.user;
  4533. setTimeout(initSocket, 5e3);
  4534. /* MP.makeAlertModal({
  4535. content: 'Connection lost.',
  4536. dismissable: false,
  4537. callback: function(){
  4538. document.location.reload();
  4539. }
  4540. });*/
  4541. }
  4542. };
  4543.  
  4544. socket.onmessage = function(e){
  4545. if ( e.data == 'h') return;
  4546.  
  4547. //DEBUG
  4548. //console.log(e.data);
  4549. //END DEBUG
  4550.  
  4551. var data = null;
  4552.  
  4553. try {
  4554. data = JSON.parse(e.data);
  4555. } catch (e) {
  4556. return;
  4557. }
  4558.  
  4559. // This should ONLY be incoming events. No callbacks.
  4560. var settings = JSON.parse(window.localStorage.getItem("settings"));
  4561. switch(data.type){
  4562. case API.DATA.EVENTS.CHAT:
  4563. MP.addMessage(data.data);
  4564. break;
  4565. case API.DATA.EVENTS.SYSTEM_MESSAGE:
  4566. MP.addMessage(data.data, 'system');
  4567. break;
  4568. case API.DATA.EVENTS.BROADCAST_MESSAGE:
  4569. if (typeof data.data == 'object' && data.data.error) return;
  4570. MP.addMessage(data.data, 'broadcast');
  4571. break;
  4572. case API.DATA.EVENTS.USER_JOINED:
  4573. MP.userList.guests = data.data.guests;
  4574. if (data.data.user){
  4575. MP.seenUsers[ data.data.user.uid ] = data.data.user;
  4576. if (MP.userList.users.indexOf(data.data.user.uid) == -1){
  4577. MP.userList.users.push(data.data.user.uid);
  4578. if (settings.roomSettings && settings.roomSettings.userJoinLeaveMessages && !data.data.user.banned) {
  4579. MP.addMessage({ user: data.data.user, msg: 'entered the virtual plaza.', }, 'log');
  4580. }
  4581. }
  4582. console.log( 'User joined: ' + data.data.user.uid + ': ' + data.data.user.un);
  4583. }else{
  4584. console.log('Guest joined room');
  4585. }
  4586.  
  4587. MP.applyModels();
  4588. break;
  4589. case API.DATA.EVENTS.USER_LEFT:
  4590. MP.userList.guests = data.data.guests;
  4591. if (data.data.user){
  4592. var ind = MP.userList.users.indexOf(data.data.user.uid);
  4593. if (ind != -1){
  4594. MP.userList.users.splice( ind, 1);
  4595. if (settings.roomSettings && settings.roomSettings.userJoinLeaveMessages && !data.data.user.banned) {
  4596. MP.addMessage({user:data.data.user, msg:'left the virtual plaza.'}, 'log');
  4597. }
  4598. }
  4599.  
  4600. console.log( 'User left: ' + data.data.user.uid + ': ' + data.data.user.un);
  4601. } else {
  4602. console.log('Guest left room');
  4603. }
  4604. MP.applyModels();
  4605. break;
  4606. case API.DATA.EVENTS.USER_JOINED_QUEUE:
  4607. MP.session.queue.users = data.data.queueList;
  4608. MP.applyModels();
  4609. break;
  4610. case API.DATA.EVENTS.USER_LEFT_QUEUE:
  4611. MP.session.queue.users = data.data.queueList;
  4612. MP.applyModels();
  4613. break;
  4614. case API.DATA.EVENTS.ADVANCE:
  4615. MP.session.snooze = false;
  4616. var playerSettings = settings.player;
  4617. var player = API.player.getPlayer();
  4618.  
  4619. player.unMute();
  4620.  
  4621. if (data.data.next.song && playerSettings.stream){
  4622. player.loadVideoById(data.data.next.song.cid);
  4623. if (settings.player.hd){
  4624. player.setPlaybackQuality('hd720');
  4625. }
  4626. player.setVolume(settings.player.mute || MP.mediaPreview.isOpened() ? 0 : settings.player.volume);
  4627. }else{
  4628. player.loadVideoById(null);
  4629. }
  4630.  
  4631. //Changing the DJ's badge
  4632. if((MP.session.queue.currentdj || {}).uid != data.data.next.uid){
  4633. if(MP.session.queue.currentdj) {
  4634. var elem = $('#messages .cm.message .text .uname[data-uid=' + MP.session.queue.currentdj.uid + ']').parent().parent();
  4635. elem.find('.bdg-icon.bdg-icon-dj').remove();
  4636. elem.find('.bdg').attr('class', 'bdg');
  4637. }
  4638. if(data.data.next.uid) {
  4639. var elem = $('#messages .cm.message .text .uname[data-uid=' + data.data.next.uid + ']').parent().parent();
  4640. elem.find('.bdg').attr('class', 'bdg hidden');
  4641. elem.filter(function(_, e){ return $(e).find('.bdg-icon-dj').length == 0; }).find('svg').after('<div class="mdi mdi-headphones bdg-icon bdg-icon-dj"></div>')
  4642. $('.bdg-icon.bdg-icon-dj').css('color', (MP.getRole(MP.api.room.getUser(data.data.next.uid).role).style || { color: 'white', }).color);
  4643. }
  4644. }
  4645.  
  4646. //Just played chat message
  4647. if(settings.roomSettings.justplayed && data.data.last.song) MP.addMessage('<span data-uid="'+ MP.session.queue.currentdj.uid +'" class="uname" style="' + MP.makeUsernameStyle(MP.session.queue.currentdj.role) + '">' + MP.session.queue.currentdj.un + '</span>just played <b>' + data.data.last.song.title + '</b>', 'system');
  4648.  
  4649. MP.session.queue.votes = {};
  4650. MP.session.queue.currentdj = (data.data.next.uid ? MP.findUser(data.data.next.uid) : null);
  4651. MP.session.queue.currentsong = data.data.next.song;
  4652. MP.media.media = data.data.next.song;
  4653. MP.media.start = data.data.next.start;
  4654. if(data.data.last.uid == MP.api.room.getUser().uid) MP.session.lastdj = false;
  4655.  
  4656. if(data.data.next.song){
  4657. MP.media.timeRemaining = data.data.next.song.duration;
  4658. MP.startTimeRemaining();
  4659. }else{
  4660. MP.media.timeRemaining = 0;
  4661. }
  4662.  
  4663. MP.addCurrentToHistory();
  4664.  
  4665. MP.session.queue.users.shift();
  4666. if (data.data.next.uid && MP.user && data.data.next.uid == MP.user.uid){
  4667. var song = MP.user.playlists[ MP.user.activepl ].content.splice(0, 1)[0];
  4668. MP.user.playlists[ MP.user.activepl ].content.push(song);
  4669. //MP.api.util.changefavicon('/pads/lib/img/icon_dj.png');
  4670. }// else MP.api.util.changefavicon('/pads/lib/img/icon.png');
  4671.  
  4672. MP.applyModels();
  4673. break;
  4674. case API.DATA.EVENTS.DJ_QUEUE_LOCK:
  4675. if(!data.data.error){
  4676. MP.session.queue.lock = data.data.state;
  4677. MP.applyModels();
  4678.  
  4679. var user = MP.findUser(data.data.mid);
  4680. MP.addMessage('The DJ queue has been ' + (data.data.state ? 'locked' : 'unlocked') + ' by '+(user ? '<span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>' : 'Unknown'), 'system');
  4681. }
  4682. break;
  4683. case API.DATA.EVENTS.DJ_QUEUE_CYCLE:
  4684. if(!data.data.error){
  4685. $('.btn-cycle div').removeClass('mdi-sync').removeClass('mdi-sync-disabled').addClass(data.data.state ? 'mdi-sync' : 'mdi-sync-disabled');
  4686. MP.session.queue.cycle = data.data.state;
  4687. MP.applyModels();
  4688.  
  4689. var user = MP.findUser(data.data.mid);
  4690. MP.addMessage('DJ cycling has been ' + (data.data.state ? 'enabled' : 'disabled') + ' by '+(user ? '<span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>' : 'Unknown'), 'system');
  4691. }
  4692. break;
  4693. case API.DATA.EVENTS.DJ_QUEUE_SKIP:
  4694. var user = MP.findUser(data.data.uid);
  4695. MP.addMessage( (user ? '<span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>' : 'Unknown ') + 'has skipped', 'system');
  4696. break;
  4697. case API.DATA.EVENTS.DJ_QUEUE_MOD_SKIP:
  4698. var user = MP.findUser(data.data.mid);
  4699. var lsmsg = (typeof data.data.lockSkipPosition == 'number' ? (data.data.lockSkipPosition == 0 ? ' and repositioned the DJ to the booth' : ' and repositioned the DJ to spot ' + data.data.lockSkipPosition + ' in the DJ queue') : '');
  4700. MP.addMessage( (user ? '<span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>' : 'Unknown' ) + 'has mod skipped' + lsmsg, 'system');
  4701. break;
  4702. case API.DATA.EVENTS.VOTE_UPDATE:
  4703. var vote = data.data;
  4704.  
  4705. MP.session.queue.votes = vote.votes;
  4706. if (MP.historyList.historyInitialized) {
  4707. if (MP.historyList.history[0] && MP.session.queue.currentsong == MP.historyList.history[0].song) {
  4708. MP.historyList.history[0].votes = vote.votes;
  4709. }
  4710. }
  4711. MP.applyModels();
  4712. break;
  4713. case API.DATA.EVENTS.USER_UPDATE:
  4714. if (MP.user && data.data.user.uid == MP.user.uid) $.extend(MP.user, data.data.user);
  4715.  
  4716. //Update seen users list
  4717. if(MP.seenUsers[data.data.user.uid]) $.extend(MP.seenUsers[data.data.user.uid], data.data.user);
  4718.  
  4719. //Update staff list
  4720. if (MP.session.roomStaff.length){
  4721. for (var i = 0; i < MP.session.roomStaff.length; i++){
  4722. if (MP.session.roomStaff[i].uid == data.data.user.uid){
  4723. MP.session.roomStaff.splice(i, 1);
  4724. break;
  4725. }
  4726. }
  4727.  
  4728. if (MP.isStaffMember(data.data.user.uid)){
  4729. MP.session.roomStaff.push(data.data.user);
  4730. }
  4731. }
  4732.  
  4733. MP.applyModels();
  4734. break;
  4735. case API.DATA.EVENTS.DELETE_CHAT:
  4736. // TODO delete messages by a specific user: $('span[data-uid="data.data.uid"]').closest('.cm').remove();
  4737. // TODO clear chat: $('.cm.message').remove();
  4738.  
  4739. if (MP.checkPerm('chat.delete')) {
  4740. $('#cm-' + data.data.cid).fadeTo(250, 0.3).addClass('deleted');
  4741. }
  4742. else {
  4743. $('#cm-' + data.data.cid).slideUp( function(){ this.remove(); } );
  4744. }
  4745. break;
  4746. case API.DATA.EVENTS.USER_BANNED:
  4747. var user = MP.findUser(data.data.uid) || {un: 'Unknown'};
  4748. var banner = MP.findUser(data.data.bannedBy);
  4749.  
  4750. user.banned = true;
  4751.  
  4752. if (MP.session.bannedUsers.length && MP.findUser(data.data.uid)){
  4753. MP.session.bannedUsers.push(user);
  4754. } else {
  4755. // Reset object since it's either already empty, or now missing a user
  4756. MP.session.bannedUsers = [];
  4757. }
  4758.  
  4759. MP.applyModels();
  4760.  
  4761. if (banner){
  4762. MP.addMessage('<span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>was banned by ' +
  4763. '<span data-uid="'+ banner.uid +'" class="uname" style="' + MP.makeUsernameStyle(banner.role) + '">' + banner.un + '</span>', 'system');
  4764. }
  4765. break;
  4766. case API.DATA.EVENTS.USER_UNBANNED:
  4767. var user = MP.findUser(data.data.uid) || {un: 'Unknown'};
  4768. var banner = MP.findUser(data.data.unbannedBy);
  4769.  
  4770. user.banned = false;
  4771.  
  4772. if (MP.session.bannedUsers.length && MP.findUser(data.data.uid)){
  4773. for (var i = 0; i < MP.session.bannedUsers.length; i++){
  4774. if (MP.session.bannedUsers[i].uid == user.uid){
  4775. MP.session.bannedUsers.splice(i, 1);
  4776. break;
  4777. }
  4778. }
  4779. } else {
  4780. // Reset object since it's either already empty, or now missing a user
  4781. MP.session.bannedUsers = [];
  4782. }
  4783.  
  4784. MP.applyModels();
  4785.  
  4786. if (banner){
  4787. MP.addMessage('<span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>was unbanned by <span data-uid="'+ banner.uid +'" class="uname" style="' + MP.makeUsernameStyle(banner.role) + '">' + banner.un + '</span>', 'system');
  4788. }
  4789. break;
  4790. case API.DATA.EVENTS.USER_ROLE_CHANGE:
  4791. var setter = MP.findUser(data.data.mid);
  4792. var settee = MP.findUser(data.data.uid);
  4793. var role = MP.getRole(data.data.role);
  4794.  
  4795. MP.addMessage('<span data-uid="'+ setter.uid +'" class="uname" style="' + MP.makeUsernameStyle(setter.role) + '">' + setter.un + '</span>changed <span data-uid="'+ settee.uid +'" class="uname" style="' + MP.makeUsernameStyle(settee.role) + '">' + settee.un + '</span>\'s role', 'system');
  4796. break;
  4797. case API.DATA.EVENTS.DJ_QUEUE_REMOVE:
  4798. if(!data.data.mid || !data.data.uid) return;
  4799. var remover = MP.findUser(data.data.mid);
  4800. var removee = MP.findUser(data.data.uid);
  4801.  
  4802. MP.addMessage('<span data-uid="' + remover.uid + '" class="uname" style="' + MP.makeUsernameStyle(remover.role) + '">' + remover.un + '</span>removed <span data-uid="' + removee.uid + '" class="uname" style="' + MP.makeUsernameStyle(removee.role) + '">' + removee.un + '</span> from the DJ queue', 'system');
  4803. break;
  4804. case API.DATA.EVENTS.DJ_QUEUE_MOD_SWAP:
  4805. //STAHP EDITING MY CODE
  4806. MP.session.queue.users = data.data.queueList;
  4807.  
  4808. var mod = MP.findUser(data.data.mid);
  4809. var u1 = MP.findUser(data.data.uid1);
  4810. var u2 = MP.findUser(data.data.uid2);
  4811.  
  4812. MP.addMessage('<span data-uid="' + mod.uid + '" class="uname" style="' + MP.makeUsernameStyle(mod.role) + '">' + mod.un + '</span>swapped <span data-uid="' + u1.uid + '" class="uname" style="' + MP.makeUsernameStyle(u1.role) + '">' + u1.un + '</span> (position ' + (data.data.pos1 + 1) + ') with <span data-uid="' + u2.uid + '" class="uname" style="' + MP.makeUsernameStyle(u2.role) + '">' + u2.un + '</span> (position ' + (data.data.pos2 + 1) + ')', 'system');
  4813. MP.applyModels();
  4814. break;
  4815. case API.DATA.EVENTS.DJ_QUEUE_MOD_MOVE:
  4816. MP.session.queue.users = data.data.queueList;
  4817.  
  4818. var mod = MP.findUser(data.data.mid);
  4819. var user = MP.findUser(data.data.uid);
  4820.  
  4821. MP.addMessage('<span data-uid="' + mod.uid + '" class="uname" style="' + MP.makeUsernameStyle(mod.role) + '">' + mod.un + '</span>moved <span data-uid="' + user.uid + '" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span> from ' + (data.data.from + 1) + ' to ' + (data.data.to + 1), 'system');
  4822.  
  4823. MP.applyModels();
  4824. break;
  4825.  
  4826. case API.DATA.EVENTS.DJ_QUEUE_ADD:
  4827. var mod = MP.findUser(data.data.mid);
  4828. var user = MP.findUser(data.data.uid);
  4829. var position = (typeof data.data.position == 'number' ? data.data.position + 1 : null);
  4830.  
  4831. MP.addMessage('<span data-uid="' + mod.uid + '" class="uname" style="' + MP.makeUsernameStyle(mod.role) + '">' + mod.un + '</span>added <span data-uid="' + user.uid + '" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span> to the DJ queue' + (position ? ' at position ' + position : ''), 'system');
  4832. break;
  4833.  
  4834. case API.DATA.EVENTS.DJ_QUEUE_LIMIT:
  4835. //TODO save new limit in session attributes
  4836. var mod = MP.findUser(data.data.mid);
  4837.  
  4838. MP.addMessage('<span data-uid="' + mod.uid + '" class="uname" style="' + MP.makeUsernameStyle(mod.role) + '">' + mod.un + '</span>has changed the queue limit to ' + data.data.limit, 'system');
  4839. break;
  4840.  
  4841. case API.DATA.EVENTS.PRIVATE_MESSAGE:
  4842. MP.session.lastPMUid = data.data.uid;
  4843. var user = MP.findUser(data.data.uid);
  4844. API.chat.log('<br>' + MP.escape(data.data.message), '<span onclick="$(\'#msg-in\').val(\'/pm '+ user.un + ' \').focus();">Private Message received from </span><span data-uid="'+ user.uid +'" class="uname" style="' + MP.makeUsernameStyle(user.role) + '">' + user.un + '</span>');
  4845.  
  4846. if (!MP.session.hasfocus){
  4847. document.title = '! ' + document.title;
  4848. }
  4849.  
  4850. if (settings && settings.roomSettings && settings.roomSettings.soundMention){
  4851. mentionSound.play();
  4852. }
  4853. break;
  4854.  
  4855. case API.DATA.EVENTS.SERVER_RESPONSE:
  4856. if (data.id) MP.callCallback(data);
  4857. break;
  4858. }
  4859.  
  4860. MP.callListeners(data);
  4861. };
  4862. }
  4863. initSocket();
  4864.  
  4865. var getAutocompleteIndex = function(ind){
  4866. var $elem = $('#chat-back > .autocomplete li.active');
  4867.  
  4868. if (!$elem.length) return -1;
  4869.  
  4870. return $elem.index();
  4871. };
  4872.  
  4873. var changeAutocompleteIndex = function(ind){
  4874. var len = $('#chat-back > .autocomplete li').length;
  4875.  
  4876. if (!len) return;
  4877.  
  4878. if (ind < 0) ind = 0;
  4879. if (ind > len-1) ind = len-1;
  4880.  
  4881. $('#chat-back > .autocomplete li.active').removeClass('active');
  4882. $('#chat-back > .autocomplete li:eq(' + ind + ')').addClass('active');
  4883. };
  4884.  
  4885. var acceptAutocomplete = function(){
  4886. var mentionVal = $('#chat-back > .autocomplete li.active').text().replace(/\t/g, '');
  4887. var $target = $('#msg-in');
  4888. var pos = $target.caret();
  4889. var val = $target.val();
  4890.  
  4891. //Check if completing emoji or username
  4892. if($('#chat-back > .autocomplete.ac-user').length != 0){
  4893. var atPos = val.lastIndexOf('@', pos-1);
  4894. var nextSpacePos = val.indexOf(' ', atPos);
  4895. var stringVal = val.substr(atPos, (nextSpacePos > -1 ? nextSpacePos - atPos : undefined));
  4896.  
  4897. $target.val( $target.val().replace(stringVal, '@' + mentionVal + (nextSpacePos == -1 ? ' ' : '')) );
  4898. $target.trigger('input');
  4899.  
  4900. return atPos + mentionVal.length + 1;
  4901. } else if($('#chat-back > .autocomplete.ac-emote').length != 0){
  4902. var atPos = val.lastIndexOf(':', pos-1);
  4903. var nextSpacePos = val.indexOf(' ', atPos);
  4904. var stringVal = val.substr(atPos, (nextSpacePos > -1 ? nextSpacePos - atPos : undefined));
  4905.  
  4906. $target.val( $target.val().replace(stringVal, ':' + mentionVal.replace(' ', '') + ': ') );
  4907. $target.trigger('input');
  4908.  
  4909. return atPos + mentionVal.length + 1;
  4910. } else if($('#chat-back > .autocomplete.ac-cmd').length != 0){
  4911. var atPos = 0;
  4912. var nextSpacePos = val.indexOf(' ', atPos);
  4913. var stringVal = val.substr(atPos, (nextSpacePos > -1 ? nextSpacePos - atPos : undefined));
  4914.  
  4915. $target.val( $target.val().replace(stringVal, mentionVal.replace(' ', '') + ' ') );
  4916. $target.trigger('input');
  4917.  
  4918. return atPos + mentionVal.length + 1;
  4919. }
  4920. };
  4921.  
  4922. // Chat text box
  4923. $('#msg-in')
  4924. /*.on('submit', function(e){
  4925. e.preventDefault();
  4926. var $input = $(this).find('input');
  4927. var $chat = $('#chat');
  4928.  
  4929. if (!$input.val()) return;
  4930.  
  4931. MP.session.lastMessage = $input.val();
  4932. MP.sendMessage($input.val());
  4933. $chat.scrollTop( $chat[0].scrollHeight );
  4934. $input.val('');
  4935. return true;
  4936. })*/
  4937. .on('keydown', function(e){
  4938. var $input = $(this).find('input');
  4939. var autocomplete = $('#chat-back > .autocomplete');
  4940. var isAutocompleteUp = autocomplete.length;
  4941.  
  4942. if (e.which == 9) e.preventDefault();
  4943.  
  4944. if (e.which == 38) { // Up key
  4945. if (isAutocompleteUp){
  4946. e.preventDefault();
  4947. changeAutocompleteIndex( getAutocompleteIndex() - 1 );
  4948. }else{
  4949. $input.val(MP.session.lastMessage);
  4950.  
  4951. // .val is apparently not immediate...?
  4952. setTimeout(function(){$input.caret(-1);}, 1);
  4953. }
  4954. }else if (e.which == 40) { // Down key
  4955. if (isAutocompleteUp){
  4956. e.preventDefault();
  4957. changeAutocompleteIndex( getAutocompleteIndex() + 1 );
  4958. }
  4959. }else if (e.which == 9 || e.which == 13){ // Tab key / Enter key
  4960. if (isAutocompleteUp){
  4961. e.preventDefault();
  4962.  
  4963. var newPos = acceptAutocomplete();
  4964.  
  4965. $('#msg-in').caret(newPos + 1);
  4966. }else{
  4967. if (e.which == 13){
  4968. e.preventDefault();
  4969. var $input = $(this);
  4970. var $chat = $('#chat');
  4971.  
  4972. if (!$input.val()) return;
  4973.  
  4974. MP.session.lastMessage = $input.val();
  4975. MP.sendMessage($input.val());
  4976. $chat.scrollTop( $chat[0].scrollHeight );
  4977. $input.val('');
  4978. return true;
  4979. }
  4980. }
  4981. }
  4982. }).on('input', function(e){
  4983. var $target = $(e.target);
  4984. var pos = $target.caret();
  4985. var val = $target.val();
  4986.  
  4987. if (pos == 3 && MP.session.lastPMUid && /^\/r\s/i.test(val)){
  4988. var user = MP.findUser(MP.session.lastPMUid);
  4989. if (user){
  4990. $('#msg-in').val('/pm ' + user.un + ' ');
  4991. }
  4992. }
  4993.  
  4994. $('#chat-back > .autocomplete').remove();
  4995.  
  4996. if (pos != 0){
  4997. /*var atPos = val.lastIndexOf('@', pos-1);
  4998. var nextSpacePos = val.indexOf(' ', atPos);
  4999. nextSpacePos = (nextSpacePos == -1 ? val.length : nextSpacePos);
  5000. var stringVal = val.substr(atPos + 1, nextSpacePos - atPos - 1);
  5001.  
  5002. var doWeAutocompleteUsername = ( (atPos > -1 && pos <= nextSpacePos && pos > atPos) ?
  5003. stringVal : '');*/
  5004. var settings = JSON.parse(window.localStorage.getItem("settings"));
  5005. var un = (val.substr(0, pos).match(/.*@([a-z0-9_-]*)$/i) || [0]).slice(1);
  5006. var doWeAutocompleteUsername = un.length == 1 && un[0] != '';
  5007.  
  5008. var em = (val.substr(0, pos).match(/.*\s?:([+a-z0-9_-]*)$/i) || [0]).slice(1);
  5009. var doWeAutocompleteEmotes = em.length == 1 && em[0] != '' && settings.roomSettings.enableEmojis;
  5010.  
  5011. var cm = val.match(/^\/[a-z]*$/i);
  5012. var doWeAutocompleteCommand = Boolean(cm);
  5013.  
  5014. var list = [];
  5015.  
  5016. if(doWeAutocompleteUsername){
  5017. list = MP.userAutocomplete(un);
  5018.  
  5019. if(list.length == 0) return;
  5020. $('#chat-back').append('<div class="autocomplete ac-user">\
  5021. <ul>'+
  5022. (function(){
  5023. var first = true;
  5024. var out = '';
  5025. /*
  5026. {
  5027. user: {
  5028. badge: {
  5029. top,
  5030. bottom,
  5031. },
  5032. role,
  5033. },
  5034. mdi,
  5035. class,
  5036. style,
  5037. }
  5038. */
  5039. for (var i in list){
  5040. out += '<li ' + (first ? 'class="active"' : '') + ' style="' + MP.makeUsernameStyle(list[i].role) + '">' + MP.makeBadgeStyle({ user: list[i] }) + list[i].un + '</li>';
  5041. first = false;
  5042. }
  5043.  
  5044. return out;
  5045. })()
  5046. +'</ul>\
  5047. </div>');
  5048. } else if (doWeAutocompleteEmotes && MP.session.allowemojis){
  5049. em = em[0];
  5050.  
  5051. //Check for ASCII emotes
  5052. for(var e in MP.emotes_ascii){
  5053. if(e.slice(1) == em) return;
  5054. }
  5055.  
  5056. //Show autocomplete menu
  5057. list = MP.emojiAutocomplete(em);
  5058. if(list.length == 0) return;
  5059. $('#chat-back').append('<div class="autocomplete ac-emote">\
  5060. <ul>'+
  5061. (function(){
  5062. var first = true;
  5063. var out = '';
  5064.  
  5065. for (var i in list){
  5066. out += '<li ' + (first ? 'class="active"' : '') + '><img align="absmiddle" alt=":' + i + ':" class="emoji" src="' + list[i] + '" title=":' + i + ':" /> ' + i + '</li>';
  5067. first = false;
  5068. }
  5069.  
  5070. return out;
  5071. })()
  5072. +'</ul>\
  5073. </div>');
  5074. } else if (doWeAutocompleteCommand){
  5075. list = MP.commandAutocomplete(cm[0].slice(1));
  5076.  
  5077. if(list.length == 0) return;
  5078. $('#chat-back').append('<div class="autocomplete ac-cmd">\
  5079. <ul>'+
  5080. (function(){
  5081. var first = true;
  5082. var out = '';
  5083.  
  5084. for (var i in list){
  5085. out += '<li ' + (first ? 'class="active"' : '') + '>/' + list[i] + '</li>';
  5086. first = false;
  5087. }
  5088.  
  5089. return out;
  5090. })()
  5091. +'</ul>\
  5092. </div>');
  5093. }
  5094. /*var atPos = val.lastIndexOf('@', pos-1);
  5095. var spacePos = val.lastIndexOf(' ', pos-1);
  5096. var nextSpacePos = val.indexOf(' ', atPos);
  5097.  
  5098. if (atPos == -1 || spacePos > atPos || pos == atPos+1 || (atPos != 0 && val.charAt(atPos-1) != ' ')) return;
  5099.  
  5100. var stringVal = val.substr(atPos+1, (nextSpacePos > -1 ? nextSpacePos - atPos-1 : undefined));
  5101.  
  5102. var list = MP.userAutocomplete(stringVal);
  5103.  
  5104. if (!list.length) return;
  5105.  
  5106. $('#chat-back').append('<div class="mention-autocomplete">\
  5107. <ul>'+
  5108. (function(){
  5109. var first = true;
  5110. var out = '';
  5111.  
  5112. for (var i in list){
  5113. out += '<li ' + (first ? 'class="active"' : '') + ' style="' + MP.makeUsernameStyle(list[i].role) + '">' + MP.makeBadgeStyle(list[i].badge.top, list[i].badge.bottom, MP.getRole(list[i].role).style.color) + list[i].un + '</li>';
  5114. first = false;
  5115. }
  5116.  
  5117. return out;
  5118. })()
  5119. +'</ul>\
  5120. </div>');*/
  5121. }
  5122. });
  5123.  
  5124. $(document)
  5125. // Changing and accepting mentions
  5126. .on('mouseover', '.autocomplete li', function(){
  5127. var $ul = $(this).parents('ul');
  5128.  
  5129. $ul.find('li.active').removeClass('active');
  5130. $(this).addClass('active');
  5131. })
  5132. .on('click', '.autocomplete li.active', function(){
  5133. var newPos = acceptAutocomplete();
  5134.  
  5135. $('#msg-in')
  5136. .focus()
  5137. .caret(newPos + 1);
  5138. })
  5139. // Changing viewed playlist
  5140. .on('click', '.lib-fdr', function(){
  5141. var pid = $(this).attr('data-pid');
  5142.  
  5143. if (MP.user.playlists[pid]){
  5144. MP.session.viewedPl = pid;
  5145. MP.applyModels();
  5146.  
  5147. if (MP.user.playlists[pid].num != MP.user.playlists[pid].content.length){
  5148. MP.getPlaylistContents(pid);
  5149. }
  5150. }
  5151. })
  5152.  
  5153. // Changing active playlist
  5154. .on('dblclick taphold', '.lib-fdr', function(){
  5155. var pid = $(this).attr('data-pid');
  5156.  
  5157. if (MP.user.playlists[pid]){
  5158. MP.playlistActivate(pid);
  5159. }
  5160. })
  5161.  
  5162. // Deleting playlist
  5163. .on('click', '.btn-delete-playlist', function(e){
  5164. if (!MP.session.viewedPl) return;
  5165.  
  5166. MP.makeConfirmModal({
  5167. content: 'Are you sure you want to delete the playlist ' + $('<b></b>').text(MP.api.playlist.get(MP.session.viewedPl).name).prop('outerHTML') + '?',
  5168. dismissable: true,
  5169. callback: function(res){
  5170. if (res)
  5171. MP.playlistDelete( MP.session.viewedPl );
  5172. }
  5173. });
  5174. })
  5175.  
  5176. // Removing song
  5177. .on('click', '.btn-remove-song', function(){
  5178. var $base = $(this).parents('.lib-sng');
  5179.  
  5180. MP.playlistRemove(MP.session.viewedPl, $base.attr('data-cid'));
  5181. })
  5182.  
  5183. // Move song to bottom
  5184. .on('click', '.btn-song-bot', function(){
  5185. var $base = $(this).parents('.lib-sng');
  5186.  
  5187. MP.playlistMove(MP.session.viewedPl, $base.attr('data-cid'), MP.user.playlists[ MP.session.viewedPl ].content.length);
  5188. })
  5189. // On arrow_up right_click move to bottom
  5190. .on('contextmenu taphold', '.lib-sng:not(:first-child) .btn-song-top', function(){
  5191. var $base = $(this).parents('.lib-sng');
  5192.  
  5193. MP.playlistMove(MP.session.viewedPl, $base.attr('data-cid'), MP.user.playlists[ MP.session.viewedPl ].content.length);
  5194. return false;
  5195. })
  5196.  
  5197. //Move song to top
  5198. .on('click', '.btn-song-top', function(){
  5199. var $base = $(this).parents('.lib-sng');
  5200.  
  5201. MP.playlistMove(MP.session.viewedPl, $base.attr('data-cid'), 0);
  5202. })
  5203. // On arrow_down right_click move to top
  5204. .on('contextmenu taphold', '.lib-sng:first-child .btn-song-bot', function(){
  5205. var $base = $(this).parents('.lib-sng');
  5206.  
  5207. MP.playlistMove(MP.session.viewedPl, $base.attr('data-cid'), 0);
  5208. return false;
  5209. })
  5210.  
  5211. //Edit playlist name
  5212. .on('click', '.btn-rename-playlist', function(){
  5213. MP.showEditPlaylistModal(MP.session.viewedPl);
  5214. })
  5215.  
  5216. //Edit song name
  5217. .on('click', '.btn-rename-song', function(){
  5218. var $base = $(this).parents('.lib-sng');
  5219.  
  5220. MP.showEditPlaylistModal(MP.session.viewedPl, $base.attr('data-cid'));
  5221. })
  5222.  
  5223. // Open video to preview
  5224. .on('dblclick', '.lib-sng,.yt-sng,.hist-sng', function(){
  5225. var cid = $(this).attr('data-cid');
  5226.  
  5227. MP.mediaPreview.open(cid);
  5228. })
  5229.  
  5230. // Closing media preview
  5231. .on('click', '.logo-menu .modal-bg, .btn-logo', function(e){
  5232. if (!$(e.target).closest('.modal').length){
  5233. MP.mediaPreview.close();
  5234. $('.logo-menu .modal-bg').remove();
  5235. }
  5236. })
  5237. // Closing modals
  5238. .on('click', '.modal-bg',function(e, dismissable){
  5239. e.originalEvent.dismissable = (typeof e.originalEvent.dismissable !== 'undefined' ? e.originalEvent.dismissable : true);
  5240.  
  5241. if (!$(e.target).closest('.modal').length && e.originalEvent.dismissable)
  5242. $(this).remove();
  5243. })
  5244. // ESC key logo menu shortcut
  5245. .on('keydown', function(e){
  5246. var scope = angular.element($('body')).scope();
  5247.  
  5248. // Anything after this will be cancelled if keydown is input
  5249. if ($(e.target).closest("input")[0]) {
  5250. return;
  5251. }
  5252. if (e.which == 8) { // Backspace -> Cancels
  5253. e.preventDefault();
  5254. return;
  5255. }
  5256. if (e.which == 107 || e.which == 187){ // + -> Increase Volume
  5257. var currentVol = API.player.getPlayer().getVolume();
  5258. var vol_val = 0;
  5259. if (currentVol >= 98){
  5260. vol_val = 100;
  5261. }
  5262. else {
  5263. vol_val = currentVol + 2;
  5264. }
  5265.  
  5266. API.player.setVolume(vol_val);
  5267. }
  5268. if (e.which == 109 || e.which == 189){ // - -> Decrease Volume
  5269. var currentVol = API.player.getPlayer().getVolume();
  5270. var vol_val = 0;
  5271. if (currentVol <= 2){
  5272. vol_val = 0;
  5273. }
  5274. else {
  5275. vol_val = currentVol - 2;
  5276. }
  5277.  
  5278. API.player.setVolume(vol_val);
  5279. }
  5280. if (e.which == 77) { // M -> Mute/Unmute
  5281. var settings = JSON.parse(localStorage.getItem("settings"));
  5282.  
  5283. API.player.setMute(!settings.player.mute);
  5284. }
  5285. var keyMenuBinding = {
  5286. 76: 1, // L -> Lobby
  5287. 83: 2, // S -> Settings
  5288. 80: 3, // P -> Playlists
  5289. 72: 4 // H -> History
  5290. };
  5291. if (keyMenuBinding[e.which]) {
  5292. if ($('.logo-menu').css('display') == 'none') {
  5293. $('div.ico-logo').click();
  5294. }
  5295. else if (scope.prop.t == keyMenuBinding[e.which]) {
  5296. $('div.ico-logo').click();
  5297. }
  5298. scope.prop.t = keyMenuBinding[e.which];
  5299. scope.$apply();
  5300. }
  5301. })
  5302.  
  5303.  
  5304. // Onclick username mention
  5305. .on('contextmenu taphold','.cm .uname,.people-user .uname',function(){
  5306. var uname = $(this).text();
  5307. var val = $('#msg-in').val();
  5308. $('#msg-in').val(val + '@' + uname + ' ');
  5309. $('.btn-chat').click();
  5310. $('#msg-in').focus();
  5311. return false;
  5312. })
  5313.  
  5314.  
  5315. //OnRightClick or TapHold show user menu
  5316. .on('click','.cm .uname', function(){
  5317. var user = MP.seenUsers[parseInt($(this).attr('data-uid'))];
  5318. var $this = $(this).closest('.cm');
  5319. MP.showUserMenu(user,$this);
  5320. })
  5321. .on('click','#app-right .uname',function(){
  5322. var user = MP.seenUsers[parseInt($(this).attr('data-uid'))];
  5323. var $this = $(this);
  5324. MP.showUserMenu(user,$this);
  5325. })
  5326. .on('click','.user-menu .ban',function(){
  5327. MP.showBanModal(parseInt($(this).parent().attr('data-uid')));
  5328. })
  5329. .on('click','.user-menu .unban',function(){
  5330. MP.unbanUser(parseInt($(this).parent().attr('data-uid')));
  5331. })
  5332. .on('click','.user-menu .mute',function(){
  5333. MP.showMuteModal(parseInt($(this).parent().attr('data-uid')));
  5334. })
  5335. .on('click','.user-menu .set-role',function(){
  5336. MP.showRoleModal(parseInt($(this).parent().attr('data-uid')));
  5337. })
  5338. .on('click','.user-menu .add-dj',function(){
  5339. MP.djQueueModAdd(parseInt($(this).parent().attr('data-uid')));
  5340. })
  5341. .on('click','.user-menu .remove-dj',function(){
  5342. MP.djQueueModRemove(parseInt($(this).parent().attr('data-uid')));
  5343. })
  5344. .on('click','.user-menu .menu-mention',function(){
  5345. var val = $('#msg-in').val();
  5346. $('#msg-in').val(val + '@' + MP.seenUsers[parseInt($(this).parent().attr('data-uid'))].un + ' ');
  5347. $('.btn-chat').click();
  5348. $('#msg-in').focus();
  5349. })
  5350.  
  5351.  
  5352. //Hide user menu on outside click
  5353. .on('click contextmenu taphold', function() {
  5354. $('.user-menu').remove();
  5355. })
  5356. .on('click contextmenu taphold', '.user-menu, .uname', function(e) {
  5357. e.stopPropagation();
  5358. })
  5359. .on('click','.user-menu .modal-ctrl', function() {
  5360. $('.user-menu').remove();
  5361. })
  5362.  
  5363. //Onclick delete message
  5364. .on('click','.cm.message .msg-del-btn',function(){
  5365. var cid = $(this).parent().attr('id').match(/\d{1,}/);
  5366. if (!cid || cid.length == 0){
  5367. return;
  5368. }
  5369. MP.deleteChat(parseInt(cid[0]));
  5370. });
  5371.  
  5372. var addPlaylistButton = function(e){
  5373. if (window.PLAYLISTCREATEINPROGRESS) return;
  5374. window.PLAYLISTCREATEINPROGRESS = true;
  5375.  
  5376. e.preventDefault();
  5377. var $input = $('#lib-add');
  5378.  
  5379. if (!$input.val()){delete window.PLAYLISTCREATEINPROGRESS; return;}
  5380.  
  5381. MP.playlistCreate($input.val(), function(err, data){
  5382. delete window.PLAYLISTCREATEINPROGRESS;
  5383. if (err){MP.makeAlertModal({content: 'There was a problem adding the playlist: ' + err}); return;}
  5384.  
  5385. $input.val('');
  5386. });
  5387. return true;
  5388. };
  5389.  
  5390. // Adding playlist by clicking the add button
  5391. $('.btn-add-playlist').on('click', addPlaylistButton);
  5392.  
  5393. // Adding playlist by hitting the enter key while the input is focused
  5394. $('#lib-add').on('keydown', function(e){
  5395. if (e.which == 13) {
  5396. addPlaylistButton(e);
  5397. }
  5398. });
  5399.  
  5400. //Youtube search
  5401. $('#lib-search')
  5402. // Hide search when the text input goes empty
  5403. .on('input', function(e){
  5404. // if ( $(this).val() == '' ){
  5405. // //MP.session.songSearch = false;
  5406. // MP.session.searchResults = null;
  5407. // MP.applyModels();
  5408. // }
  5409. })
  5410.  
  5411. // Show search again if the text box isn't empty
  5412. .on('click', function(e){
  5413. if ( $(this).val() != '' && MP.session.searchResults ){
  5414. MP.session.viewedPl = null;
  5415. MP.applyModels();
  5416. }
  5417. })
  5418.  
  5419. // Execute search when the enter key is pressed
  5420. .on('keydown', function(e){
  5421. if (e.which == 13 && $(this).val() != '') {
  5422. //MP.session.songSearch = true;
  5423.  
  5424. /*if ( $(this).val() == '' ){
  5425. //MP.session.songSearch = false;
  5426. MP.session.searchResults = null;
  5427. MP.applyModels();
  5428. return;
  5429. }*/
  5430.  
  5431. MP.youtubeSearch($(this).val(), function(err, res){
  5432. MP.session.searchResults = res;
  5433. MP.session.viewedPl = null;
  5434. MP.applyModels();
  5435.  
  5436. $('.lib-search-list').scrollTop(0);
  5437.  
  5438. $('.yt-sng')
  5439. .draggable({
  5440. appendTo: '#app',
  5441. helper: function(){
  5442. return $(this).clone().css({'width': $(this).css('width'), 'font-weight': 'bold'});
  5443. },
  5444. opacity: 0.7,
  5445. cursor: 'grabbing',
  5446. zIndex: 10000000,
  5447. cursorAt: { top: 10, left: 10 }
  5448. })
  5449. .on('dragstart', function(){
  5450. $('.lib-fdr').droppable({
  5451. accept: '.yt-sng',
  5452. hoverClass: 'draghover',
  5453. tolerance: 'pointer',
  5454. drop: function(e, ui){
  5455. var pid = $(this).attr('data-pid');
  5456. var cid = $(ui.draggable).attr('data-cid');
  5457.  
  5458. MP.playlistAdd(pid, cid, 'top', function(err, data){
  5459. if(err == "SongAlreadyInPlaylist"){
  5460. MP.makeConfirmModal({
  5461. content: "Song is already in your playlist, would like to move it to the top?",
  5462. callback: function(res){
  5463. if(res) MP.api.playlist.moveSong(pid, cid, 'top');
  5464. }
  5465. });
  5466. }
  5467. });
  5468. }
  5469. });
  5470. })
  5471. .on('dragstop', function(){
  5472. setTimeout(function() { $('.lib-fdr').droppable('destroy'); }, 100);
  5473. });
  5474. });
  5475.  
  5476. }
  5477. });
  5478. //Playlist import
  5479. $('#lib-import').on('keydown', function(e){
  5480. if(e.which == 13 && $(this).val() != ''){
  5481. $('.btn-import').click();
  5482. }
  5483. });
  5484. $('.btn-import').on('click', function(){
  5485. MP.makeCustomModal({
  5486. content: '<div class="modal-import">\
  5487. <h3>Playlist Import</h3>\
  5488. <form action="" onsubmit="return false;">\
  5489. <div class="text">YouTube:</div><input id="yt-pl-import" type="text" placeholder="YouTube Playlist Link/ID" autocomplete="off"></input><br>\
  5490. <div class="text">musiqpad:</div><input id="mp-pl-import" type="file" /><br>\
  5491. <div class="text">Plug.DJ:</div><input id="plug-pl-import" type="file" />\
  5492. </form>\
  5493. </div>',
  5494. buttons: [
  5495. {
  5496. icon: 'mdi-close',
  5497. handler: function(){
  5498. $('.modal-bg').remove();
  5499. MP.mediaPreview.close();
  5500. },
  5501. classes: 'modal-no'
  5502. },
  5503. {
  5504. icon: 'mdi-import',
  5505. handler: function(){
  5506. var ytPl = document.getElementById("yt-pl-import").value;
  5507. var mpFile = document.getElementById("mp-pl-import").value;
  5508. var plugFile = document.getElementById("plug-pl-import").value;
  5509.  
  5510. if ((ytPl && (mpFile || plugFile)) || (mpFile && (ytPl || plugFile)) || (plugFile && (mpFile || ytPl))) {
  5511. MP.makeAlertModal({
  5512. content: 'You have specified more than 1 different import type. Please ensure that you only attempt to import 1 playlist type at a time.',
  5513. });
  5514. }
  5515. else {
  5516. if (ytPl) {
  5517. var el = $('#yt-pl-import');
  5518. var pid = (el.val().match(/list=[a-z0-9_-]+(?=&|$)/i) || el.val().match(/^([a-z0-9_-]+)$/i) || [])[0];
  5519.  
  5520. if(pid && pid != ''){
  5521. pid = pid.replace(/^list=/, '');
  5522. MP.makeCustomModal({
  5523. content: 'Your playlist is being imported, please wait...',
  5524. buttons: [],
  5525. dismissable: false,
  5526. });
  5527. MP.api.playlist.import(pid, false, function(err, data){
  5528. if(err){
  5529. var errors = ['PlaylistNotFound', 'PlaylistEmpty', 'ConnectionError'];
  5530. var errmsgs = ['The specified playlist was not found, make sure the playlist exists and is either public ounlisted', 'The playlist you are trying to import is empty', 'Could not connect to YouTube Data APIplease contact the pad owner'];
  5531. MP.makeAlertModal({
  5532. content: errmsgs[errors.indexOf(err)],
  5533. });
  5534. } else {
  5535. var names = '<b>' + data.content[0].name + '</b>';
  5536. if(data.content.length > 1)
  5537. for(var i = 1; i < data.content.length; i++)
  5538. names += ', ' + $('<b></b>').text(data.content[i].name).prop('outerHTML');
  5539. $('#lib-import').val('');
  5540. MP.makeAlertModal({
  5541. content: 'Playlist' + (data.content.length > 1 ? 's' : '') + ' ' + names + ' successfuly imported',
  5542. });
  5543. }
  5544. });
  5545. } else {
  5546. MP.makeAlertModal({
  5547. content: 'Invalid link or playlist ID',
  5548. });
  5549. }
  5550. }
  5551. else if (mpFile || plugFile) {
  5552. if (window.File && window.FileReader && window.FileList && window.Blob) {
  5553. var fileReader = new FileReader();
  5554. var element = document.getElementById(mpFile ? 'mp-pl-import' : 'plug-pl-import');
  5555. fileReader.onload = function () {
  5556. var data = fileReader.result;
  5557. if (data) {
  5558. try {
  5559. data = JSON.parse(data);
  5560. }
  5561. catch (e) {
  5562. MP.makeAlertModal({
  5563. content: 'Cannot parse the JSON in the file. Please make sure this is a valid JSON file.',
  5564. });
  5565. return;
  5566. }
  5567. if (mpFile) {
  5568. if (data.name && data.content && Array.isArray(data.content)) {
  5569. MP.makeCustomModal({
  5570. content: 'Importing playlist <b>"' + data.name + '"</b> containing ' + data.content.length + ' songs.<br>This may take a while.',
  5571. buttons: [],
  5572. dismissable: false,
  5573. });
  5574. var content = data.content;
  5575. MP.api.playlist.create(data.name, function(err, data) {
  5576. if (!err) {
  5577. var pl = data;
  5578. var songs = [];
  5579. for (var i = 0, len = content.length; i < len; i++) {
  5580. songs.push(content[i].cid);
  5581. }
  5582. MP.api.playlist.addSong(data.id, songs, function (err, data) {
  5583. $('.modal-bg').remove();
  5584. if (!err) {
  5585. MP.makeAlertModal({
  5586. content: 'Imported <b>' + pl.playlist.name + '</b> playlists successfully.',
  5587. });
  5588. }
  5589. else {
  5590. MP.makeAlertModal({
  5591. content: 'Failed to add songs to playist <b>' + pl.playlist.name + '</b>. Removing playlist due to it being empty.',
  5592. });
  5593. MP.api.playlist.delete(pl.id);
  5594. }
  5595. });
  5596. }
  5597. else {
  5598. $('.modal-bg').remove();
  5599. MP.makeAlertModal({
  5600. content: 'Failed to create playlist with the name <b>' + data.name + '</b>.',
  5601. });
  5602. }
  5603. });
  5604. }
  5605. else {
  5606. MP.makeAlertModal({
  5607. content: 'The JSON file selected does not appear to be using the correct format. This import only works using playlists exported from other musiqpad servers.',
  5608. });
  5609. }
  5610. }
  5611. else {
  5612. if (data.is_plugdj_playlist && data.playlists) {
  5613. try {
  5614. var loopPlaylists = function(plNames, arr, pl, sleep) {
  5615. var plName = plNames[pl];
  5616. var songCount = data.playlists[plName].length;
  5617. $('.modal-bg').remove();
  5618. MP.makeCustomModal({
  5619. content: 'Importing playlist <b>"' + plName + '"</b> containing ' + songCount + ' songs.<br>This may take a while.',
  5620. buttons: [],
  5621. dismissable: false,
  5622. });
  5623. if (sleep) {
  5624. setTimeout(function() {
  5625. loopPlaylists(plNames, arr, pl, !sleep);
  5626. }, 1000);
  5627. return;
  5628. }
  5629. MP.api.playlist.create(plName, function(err, data) {
  5630. if (!err) {
  5631. var songs = [];
  5632. var playlist = arr[data.playlist.name];
  5633. for (var i = 0, len = playlist.length; i < len; i++) {
  5634. if (playlist[i].type == "1") {
  5635. songs.push(playlist[i].id);
  5636. }
  5637. }
  5638. MP.api.playlist.addSong(data.id, songs, function (err, data) {
  5639. pl++;
  5640. $('.modal-bg').remove();
  5641. if(pl < plNames.length) {
  5642. loopPlaylists(plNames, arr, pl, !sleep);
  5643. }
  5644. else {
  5645. MP.makeAlertModal({
  5646. content: 'Imported ' + plNames.length + ' playlists successfully.',
  5647. });
  5648. }
  5649. });
  5650. }
  5651. else {
  5652. pl++;
  5653. $('.modal-bg').remove();
  5654. if(pl < plNames.length) {
  5655. loopPlaylists(plNames, arr, pl, !sleep);
  5656. }
  5657. else {
  5658. MP.makeAlertModal({
  5659. content: 'Imported ' + plNames.length + ' playlists successfully.',
  5660. });
  5661. }
  5662. }
  5663. });
  5664. }
  5665. var playlistNames = Object.getOwnPropertyNames(data.playlists);
  5666. loopPlaylists(playlistNames, data.playlists, 0, false);
  5667. }
  5668. catch (e) {
  5669. MP.makeAlertModal({
  5670. content: 'An error occurred whilst attempting to import your playlists. Please submit a buto a member of the musiqpad team including a screenshot of your console and a copy oyour JSON file.',
  5671. });
  5672. }
  5673. }
  5674. else {
  5675. MP.makeAlertModal({
  5676. content: 'The JSON file selected does not appear to be using the correct format. This import only works using playlists exported from Plug.DJ using pye.sq10.net',
  5677. });
  5678. }
  5679. }
  5680. }
  5681. else {
  5682. // Some Error
  5683. }
  5684. };
  5685. fileReader.readAsText(element.files[0]);
  5686. } else {
  5687. MP.makeAlertModal({
  5688. content: 'The browser you are using does not support the File APIs. Your import has been cancelled.',
  5689. });
  5690. }
  5691. }
  5692. }
  5693. },
  5694. classes: 'modal-yes'
  5695. }
  5696. ],
  5697. dismissable: true
  5698. });
  5699.  
  5700.  
  5701. // Import YouTube Playlist
  5702. //var el = $('#lib-import');
  5703. //var pid = (el.val().match(/list=[a-z0-9_-]+(?=&|$)/i) || el.val().match(/^([a-z0-9_-]+)$/i) || [])[0];
  5704. //
  5705. //if(pid && pid != ''){
  5706. // pid = pid.replace(/^list=/, '');
  5707. // MP.makeCustomModal({
  5708. // content: 'Your playlist is being imported, please wait...',
  5709. // buttons: [],
  5710. // dismissable: false,
  5711. // });
  5712. // MP.api.playlist.import(pid, false, function(err, data){
  5713. // if(err){
  5714. // var errors = ['PlaylistNotFound', 'PlaylistEmpty', 'ConnectionError'];
  5715. // var errmsgs = ['The specified playlist was not found, make sure the playlist exists and is either public or unlisted', 'The playlist you are trying to import is empty', 'Could not connect to YouTube Data API, please contact the pad owner'];
  5716. // MP.makeAlertModal({
  5717. // content: errmsgs[errors.indexOf(err)],
  5718. // });
  5719. // } else {
  5720. // var names = '<b>' + data.content[0].name + '</b>';
  5721. // if(data.content.length > 1)
  5722. // for(var i = 1; i < data.content.length; i++)
  5723. // names += ', ' + $('<b></b>').text(data.content[i].name).prop('outerHTML');
  5724. // $('#lib-import').val('');
  5725. // MP.makeAlertModal({
  5726. // content: 'Playlist' + (data.content.length > 1 ? 's' : '') + ' ' + names + ' successfuly imported',
  5727. // });
  5728. // }
  5729. // });
  5730. //} else {
  5731. // MP.makeAlertModal({
  5732. // content: 'Invalid link or playlist ID',
  5733. // });
  5734. //}
  5735. });
  5736.  
  5737. //Join DJ queue
  5738. $('.btn-join').on('click', function(){
  5739. if (!MP.isLoggedIn()) return;
  5740. if (!MP.session.queue.users) return;
  5741.  
  5742. var pos = MP.session.queue.users.indexOf(MP.user.uid);
  5743. var cb = function(err){
  5744. if (err){
  5745. MP.makeAlertModal({
  5746. content: 'Could not join/leave the waitlist: ' + err,
  5747. dismissable: true
  5748. })
  5749. }
  5750. };
  5751.  
  5752. if ( MP.session.queue.users.indexOf(MP.user.uid) > -1 || (MP.session.queue.currentdj && MP.session.queue.currentdj.uid == MP.user.uid) ) {
  5753. MP.makeConfirmModal({
  5754. content: 'Are you sure you want to leave the DJ queue?',
  5755. dismissable: true,
  5756. callback: function(res){
  5757. if (res)
  5758. MP.djQueueLeave(cb);
  5759. }
  5760. });
  5761. } else if (pos == -1) {
  5762. MP.djQueueJoin(cb);
  5763. }
  5764. });
  5765.  
  5766. //Skip song
  5767. $('.btn-skip').on('click', function(){
  5768. MP.djQueueSkip();
  5769. });
  5770.  
  5771. //Set last play before leave
  5772. $('.btn-lastdj').on('click', function(){
  5773. MP.toggleLastDj();
  5774. });
  5775.  
  5776. //Toggle cycle
  5777. $('.btn-cycle').on('click', function(){
  5778. MP.djQueueCycle();
  5779. });
  5780.  
  5781. //Toggle lock
  5782. $('.btn-lock').on('click', function(){
  5783. MP.djQueueLock();
  5784. });
  5785.  
  5786. // Remove active class on advance
  5787. MP.on('advance', function(){
  5788. $('.btn-grab.active, .btn-upvote.active, .btn-downvote.active').removeClass('active');
  5789. });
  5790.  
  5791. // Grab button
  5792. $('.btn-grab').on('click', function(e){
  5793. if ($(e.target).closest('.popup').length) return;
  5794. if (Object.keys(MP.user.playlists) == 0) {
  5795. MP.makeAlertModal({
  5796. content: 'You have no playlists. Please create a playlist in order to grab a song',
  5797. });
  5798. return;
  5799. }
  5800. var id = (MP.media.media ? MP.media.media.cid : null);
  5801. if (MP.user && MP.user.activepl && id !== false){
  5802. MP.playlistAdd(MP.user.activepl, id, 'bottom', function(err, data){
  5803. if(err == "SongAlreadyInPlaylist"){
  5804. MP.makeConfirmModal({
  5805. content: "Song is already in your playlist, would like to move it to the top?",
  5806. callback: function(res){
  5807. if(res) MP.api.playlist.moveSong(MP.user.activepl, id, 'top');
  5808. }
  5809. });
  5810. }
  5811. });
  5812. MP.vote('grab');
  5813. }
  5814. });
  5815.  
  5816. $('.playlists-grab').on('click', function(e){
  5817. var id = (MP.media.media ? MP.media.media.cid : null);
  5818.  
  5819. if (id == null) return;
  5820.  
  5821. if(!$(e.target).hasClass('pl-grab-create')){
  5822. var pid = e.target.attributes['data-pid'].textContent;
  5823. if (MP.user && pid && id !== false) {
  5824. MP.playlistAdd(pid, id, (MP.user.activepl == pid ? 'bottom' : 'top'), function(err, data){
  5825. if(err == 'SongAlreadyInPlaylist'){
  5826. MP.makeConfirmModal({
  5827. content: "Song is already in your playlist, would like to move it to the top?",
  5828. callback: function(res){
  5829. if(res) MP.api.playlist.moveSong(pid, id, 'top');
  5830. }
  5831. });
  5832. }
  5833. });
  5834.  
  5835. MP.vote('grab');
  5836. }
  5837. } else {
  5838. MP.makeCustomModal({
  5839. content: '<div>\
  5840. <h3>Please enter the name of your playlist</h3>\
  5841. <input type="text" class="new-playlist" id="new-playlist"/>\
  5842. </div>',
  5843. dismissable: true,
  5844. buttons: [
  5845. {
  5846. icon: 'mdi-close',
  5847. classes: 'modal-no',
  5848. handler: function(e){
  5849. $('.modal-bg').remove();
  5850. }
  5851. },
  5852. {
  5853. icon: 'mdi-check',
  5854. classes: 'modal-yes',
  5855. handler: function(e){
  5856. var name = $('#new-playlist').val();
  5857.  
  5858. MP.playlistCreate(name, function(err, data){
  5859. if (err) return; //add a alert or another modal here
  5860.  
  5861. MP.playlistAdd(data.id, id, 'top');
  5862. MP.vote('grab');
  5863. $('.modal-bg').remove();
  5864. });
  5865. }
  5866. }
  5867. ]
  5868. });
  5869.  
  5870. }
  5871. });
  5872.  
  5873. // Snooze button
  5874. $('.btn-snooze').on('click', function(){
  5875. API.player.snooze();
  5876. });
  5877.  
  5878. // Like button
  5879. $('.btn-upvote').on('click', function(){
  5880. MP.vote('like');
  5881. });
  5882.  
  5883. // Dislike button
  5884. $('.btn-downvote').on('click', function(){
  5885. MP.vote('dislike');
  5886. });
  5887.  
  5888. // Stream toggle button
  5889. $('.btn-stream').on('click',function(){
  5890. MP.toggleVideoStream();
  5891. });
  5892.  
  5893. //Toggle HD
  5894. $('.btn-hd').on('click',function(){
  5895. MP.toggleHighDefinitionQuality();
  5896. });
  5897.  
  5898. //Reset player position
  5899. $('.playback .navbar .draggable').on('contextmenu', function(e){
  5900. var scope = angular.element($('body')).scope();
  5901. scope.roomSettings.playerStyle = '';
  5902. scope.saveUISettings();
  5903. $('.playback').attr('style', '');
  5904. return false;
  5905. });
  5906.  
  5907. // Clickig various places to show login
  5908. $('#msg-in, .labels .uname, .btn-login, .btn-join').on('click', function(){
  5909. if (!MP.isLoggedIn()) MP.api.showLogin();
  5910. });
  5911.  
  5912. $('.lib-sng-search .nav').on('click', function(e){
  5913. if ($(this).find('div').html() == 'search') {
  5914. $('#lib-search').trigger({
  5915. type: 'keydown',
  5916. which: 13
  5917. });
  5918. }
  5919. });
  5920.  
  5921. // Used for closing the login view
  5922. $('#creds-back').on('click', function(e){
  5923. if ( !$(e.target).closest('#creds').length )
  5924. MP.api.hideLogin();
  5925. })
  5926.  
  5927. // Login form
  5928. $('#login')
  5929. .on('submit', function(e){
  5930. e.preventDefault();
  5931.  
  5932. var fields = {
  5933. email: $('#l-email'),
  5934. pw: $('#l-password')
  5935. };
  5936.  
  5937. for (var i in fields){
  5938. if (fields[i].val() == ''){
  5939. alert('No fields can be left blank');
  5940. return;
  5941. }
  5942. }
  5943. console.log(fields.email.val());
  5944. if (!/.*@.*\..*/.test(fields.email.val())){ alert("Use email to login, not username"); return; }
  5945.  
  5946. MP.login(fields.email.val(), fields.pw.val(), function(err, data){
  5947. if (err){ return; }
  5948. for (var i in fields){
  5949. fields[i].val('');
  5950. }
  5951.  
  5952. MP.api.hideLogin();
  5953. });
  5954. })
  5955. .on('keydown', function(e){
  5956. if (e.which == 13){
  5957. e.preventDefault();
  5958. $('#login').trigger('submit');
  5959. }
  5960. });
  5961. $('#login .btn-login').on('click', function(e){
  5962. $('#login').trigger('submit');
  5963. });
  5964.  
  5965. // Register form
  5966. $('#register')
  5967. .on('submit', function(e){
  5968. e.preventDefault();
  5969.  
  5970. var fields = {
  5971. email: $('#r-email').val(),
  5972. un: $('#r-username').val(),
  5973. pw: $('#r-password').val(),
  5974. captcha: grecaptcha.getResponse(),
  5975. };
  5976.  
  5977. for (var i in fields){
  5978. if (fields[i] == ''){
  5979. alert('No fields can be left blank');
  5980. return;
  5981. }
  5982. }
  5983.  
  5984. MP.signup(fields.email, fields.un, fields.pw, fields.captcha, function(err, data){
  5985. if (err) return;
  5986. MP.api.hideLogin();
  5987. });
  5988. })
  5989. .on('keydown', function(e){
  5990. if (e.which == 13){
  5991. e.preventDefault();
  5992. $('#register').trigger('submit');
  5993. }
  5994. });
  5995. // Submitting form on button click
  5996. $('#register div.ctrl').on('click', function(e){
  5997. $('#register').trigger('submit');
  5998. });
  5999.  
  6000. //Forgot password form
  6001. $('.btn-fgt-pw').on('click', function(){
  6002. MP.api.hideLogin();
  6003. MP.makeCustomModal({
  6004. content: '<h3>You are about to request a password reset.</h3>\
  6005. <div type="text">Please specify the email you registered with.</div>\
  6006. <form id="frm-fgt-pw">\
  6007. <input id="inp-fgt-pw" name="email" type="text" autofocus="" placeholder="E-mail">\
  6008. <input id="inp-rc" name="code" type="text" autofocus="" placeholder="Recovery Code">\
  6009. <input id="inp-new-pw" name="newpass" type="password" autofocus="" placeholder="New Password">\
  6010. <div class="fill">Fill in email only if you did not receive recovery email yet.</div>\
  6011. </form>',
  6012. dismissable: false,
  6013. buttons: [
  6014. {
  6015. icon: 'mdi-close',
  6016. classes: 'modal-no',
  6017. handler: function(){
  6018. $('.modal-bg').remove();
  6019. },
  6020. },
  6021. {
  6022. icon: 'mdi-check',
  6023. classes: 'modal-yes',
  6024. handler: function(){
  6025. //Get all fields
  6026. var fields = $('#frm-fgt-pw').serializeObject();
  6027.  
  6028. //Remove empty fields
  6029. for(var k in fields){
  6030. if(k == '') fields[k] = null;
  6031. }
  6032.  
  6033. //Hash new password
  6034. if(fields.newpass) fields.newpass = CryptoJS.SHA256(fields.newpass).toString();
  6035.  
  6036. //Build and send socket request
  6037. var obj = {
  6038. type: 'recovery',
  6039. data: fields,
  6040. };
  6041. obj.id = MP.addCallback(obj.type, function(err, data){
  6042. if(err) {
  6043. var errs = ['UserDoesNotExist', 'AwaitingRecovery', 'EmailAuthIssue', 'WrongRecoveryCode', 'RecoveryDisabled'];
  6044. var errmsgs = ['User with specified email does not exist', 'There is a recovery email already pending', 'There was an error with sending recovery email, please contact the pad owner', 'The recovery code you sent was invalid, please make sure you copied the code exactly as it is from your email', 'Password recovery is disabled'];
  6045. MP.makeAlertModal({
  6046. content: errmsgs[errs.indexOf(err)],
  6047. });
  6048. } else {
  6049. MP.makeAlertModal({
  6050. content: fields.code ? 'Recovery successful, you can now log in with your new password' : 'A recovery email was sent to specified email address, please follow the instructions to reset your email',
  6051. });
  6052. }
  6053. });
  6054. socket.sendJSON(obj);
  6055. },
  6056. },
  6057. ],
  6058. });
  6059. });
  6060.  
  6061. //Sidebar
  6062. $('.btn-logo').on('click', function(){
  6063. MP.historyList.filter = "";
  6064. MP.applyModels();
  6065.  
  6066. if($('.logo-menu').is(':animated')) return;
  6067.  
  6068. $('.logo-menu').slideToggle('1000');
  6069. });
  6070.  
  6071. $('.logo-btn-history').on('click', function() {
  6072. MP.historyList.filter = "";
  6073. MP.applyModels();
  6074. });
  6075.  
  6076. //Staff list
  6077. $('.btn-staff').on('click', function(){
  6078. if (!MP.session.roomStaff.length) {
  6079. MP.getRoomStaff();
  6080. }
  6081. });
  6082.  
  6083. //Banned users list
  6084. $('.btn-banned').on('click', function(){
  6085. if (!MP.session.bannedUsers.length) {
  6086. MP.getBannedUsers();
  6087. }
  6088. });
  6089.  
  6090. //Playlist shuffle
  6091. $('.btn-shuffle-playlist').on('click', function(){
  6092. if (!MP.session.viewedPl) return;
  6093.  
  6094. if (!MP.user.playlists[ MP.session.viewedPl ]) return;
  6095.  
  6096. MP.makeConfirmModal({
  6097. content: 'Are you sure want to shuffle playlist ' + $('<b></b>').text(MP.user.playlists[ MP.session.viewedPl ].name).prop('outerHTML'),
  6098. callback: function(res){
  6099. if (res) MP.api.playlist.shuffle();
  6100. }
  6101. });
  6102.  
  6103. });
  6104.  
  6105. //Playlist export
  6106. $('.btn-export-playlist').on('click', function(){
  6107. if (!MP.session.viewedPl) return;
  6108. if (!MP.user.playlists[ MP.session.viewedPl ]) return;
  6109. API.playlist.export();
  6110. });
  6111.  
  6112. //Switch between video and chat
  6113. $('.btn-video').on('click', function(){
  6114. $('#app-left').css('z-index','10');
  6115. $('#app-right').css('z-index','9');
  6116. });
  6117.  
  6118. /* Video frame elements */
  6119. //Fullscreen
  6120. $('.btn-fullscreen').on('click', function(){
  6121. API.fullscreen();
  6122.  
  6123. var settings = JSON.parse(localStorage.getItem("settings"));
  6124. settings.player.fullscreen = !settings.player.fullscreen;
  6125. localStorage.setItem("settings", JSON.stringify(settings));
  6126. });
  6127.  
  6128. //Volume control
  6129. $('.rng-volume').on('mousemove', function(){
  6130. var vol = Math.max(0, Math.min($('.volume').val(), 100));
  6131. if (vol == API.player.getPlayer().getVolume()){
  6132. return;
  6133. }
  6134.  
  6135. API.player.setVolume(vol);
  6136. });
  6137.  
  6138. $('.volume').bind('mousewheel DOMMouseScroll', function(event){
  6139. var that = $('.volume');
  6140. if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
  6141. that.val(Math.min(100, Number(that.val()) + 2));
  6142. API.player.setVolume(API.player.getPlayer().getVolume() + 2);
  6143. }
  6144. else {
  6145. that.val(Math.max(0, Number(that.val()) - 2));
  6146. API.player.setVolume(API.player.getPlayer().getVolume() - 2);
  6147. }
  6148. });
  6149.  
  6150. $('.btn-volume div').on('click', function(){
  6151. var settings = JSON.parse(localStorage.getItem("settings"));
  6152.  
  6153. API.player.setMute(!settings.player.mute);
  6154. });
  6155.  
  6156. //Open video in new tab / window
  6157. $('.btn-youtube').click(function(){
  6158. if (MP.api.room.getMedia())
  6159. window.open('https://youtu.be/' + MP.api.room.getMedia().cid, '_blank');
  6160. });
  6161.  
  6162. //Refresh video
  6163. $('.btn-refresh').click(function(){
  6164. var curTime = Date.now();
  6165. MP.getCurrentVideoTime(function(err, data){
  6166. API.seekTo = ((Date.now() - curTime) / 1000) + data.time;
  6167. API.player.refresh();
  6168. });
  6169. });
  6170.  
  6171. /* Right side bar tabs */
  6172. $('.btn-chat, .btn-people, .btn-waitlist').on('click', function(){
  6173. $('#app-right').css('z-index','10');
  6174. $('#app-left').css('z-index','9');
  6175. });
  6176.  
  6177. /* Utility buttons */
  6178. //Logout
  6179. $('.logo-btn-logout').on('click', function(){
  6180. MP.makeConfirmModal({
  6181. content: 'Are you sure you want to log out?',
  6182. dismissable: true,
  6183. callback: function(res){
  6184. if (res) {
  6185. MP.logout(function(){
  6186. if ($('div.logo-menu').is(':visible'))
  6187. $('div.ico-logo').click();
  6188. $('.btn-grab.active, .btn-upvote.active, .btn-downvote.active').removeClass('active');
  6189. });
  6190. }
  6191. }
  6192. });
  6193. });
  6194.  
  6195. //Tour
  6196. $('.logo-btn-tour').on('click', function(){
  6197. API.tour.start();
  6198. });
  6199.  
  6200. $('.settings-timestamp').on('click', function(e) {
  6201. $('.settings-timestamp').removeClass('active');
  6202. $(this).addClass('active');
  6203. });
  6204.  
  6205. /* Window focus */
  6206. $(window).on('focus', function(){
  6207. MP.session.hasfocus = true;
  6208. document.title = MP.session.oldPageTitle;
  6209. });
  6210.  
  6211. $(window).on('blur', function(){
  6212. MP.session.hasfocus = false;
  6213. });
  6214.  
  6215. /* Window resizing */
  6216. $(window).on('load', function(){
  6217. MP.session.oldPageTitle = document.title;
  6218. var win = $(this);
  6219. var settings = JSON.parse(localStorage.getItem("settings"));
  6220.  
  6221. if (settings.player.stream && win.width() < 800) {
  6222. API.chat.log('<br>Your screen is too small to display the video, use /stream to disable it','Tips');
  6223. }
  6224.  
  6225. if (win.width() < 1366) {
  6226. ($('.playback').hasClass('fullscreen')) ? null : API.fullscreen();
  6227. }else{
  6228. (settings.player.fullscreen && !$('.playback').hasClass('fullscreen')) ? API.fullscreen() : null;
  6229. }
  6230. });
  6231. $(window).on('resize', function(){
  6232. $('.user-menu').hide();
  6233. var win = $(this);
  6234. var settings = JSON.parse(localStorage.getItem("settings"));
  6235.  
  6236. if (win.width() < 1366) {
  6237. ($('.playback').hasClass('fullscreen')) ? null : API.fullscreen();
  6238. }
  6239. if (win.width() >= 1366) {
  6240. var fs = settings.player.fullscreen;
  6241. var pbfs = $('.playback').hasClass('fullscreen');
  6242.  
  6243. ( fs && !pbfs || !fs && pbfs) ? API.fullscreen() : null;
  6244. }
  6245. if (win.width() >= 1051) {
  6246. $('#app-right').css('z-index','10');
  6247. $('#app-left').css('z-index','10');
  6248. }
  6249. });
  6250.  
  6251. if (window.angular){
  6252.  
  6253. var ajsApp = angular.module('musiqpad', ['minicolors']);
  6254.  
  6255. ajsApp.filter('orderByPlaylist', function() {
  6256. return function(items, field, reverse) {
  6257. var filtered = [];
  6258. for (var i in items){
  6259. items[i].id = i;
  6260. filtered.push(items[i]);
  6261. }
  6262. filtered.sort(function (a, b) {
  6263. return (a[field].localeCompare(b[field]));
  6264. });
  6265. if(reverse) filtered.reverse();
  6266. return filtered;
  6267. };
  6268. });
  6269.  
  6270. ajsApp.filter('orderByRole', function() {
  6271. return function(items, field, reverse) {
  6272. var filtered = [];
  6273. for (var j in MP.session.roleOrder){
  6274. var temp = [];
  6275.  
  6276. for (var i in items){
  6277. items[i].id = i;
  6278.  
  6279. if (items[i].role == MP.session.roleOrder[j])
  6280. temp.push(items[i]);
  6281. }
  6282. temp.sort(function (a, b) {
  6283. return (a[field].localeCompare(b[field]));
  6284. });
  6285.  
  6286. filtered = filtered.concat(temp);
  6287. }
  6288.  
  6289. if(reverse) filtered.reverse();
  6290. return filtered;
  6291. };
  6292. });
  6293.  
  6294. ajsApp.filter('to_trusted', ['$sce', function($sce){
  6295. return function(text) {
  6296. return $sce.trustAsHtml(text);
  6297. };
  6298. }]);
  6299.  
  6300. ajsApp.controller('MainController', function($scope) {
  6301. $scope.prop = {
  6302. t: 3, // Logo menu
  6303. c: 1, // Right view (Chat, Waitlist, Userlist)
  6304. p: 1, // People tabs inside of Userlist
  6305. chatScroll: 0, // Chat scroll memory
  6306. leaveAfterPlay: false,
  6307. };
  6308.  
  6309. $scope.customSettings = {
  6310. theme: 'bootstrap',
  6311. position: 'bottom left',
  6312. defaultValue: '',
  6313. animationSpeed: 50,
  6314. animationEasing: 'swing',
  6315. change: null,
  6316. changeDelay: 0,
  6317. control: 'hue',
  6318. hide: null,
  6319. hideSpeed: 100,
  6320. inline: false,
  6321. letterCase: 'lowercase',
  6322. opacity: false,
  6323. show: null,
  6324. showSpeed: 100
  6325. };
  6326.  
  6327. $scope.userSettings = {
  6328. newUserName: '',
  6329. newBadgeTop: '',
  6330. newBadgeBottom: ''
  6331. };
  6332.  
  6333. $scope.roomSettings = {
  6334. userJoinLeaveMessages: false,
  6335. enableEmojis: true,
  6336. emojis: {
  6337. basic: true,
  6338. twitch: true,
  6339. tastycat: true,
  6340. betterttv: true,
  6341. },
  6342. playerStyle: '',
  6343. chatTimestampFormat: API.DATA.CHAT.TSFORMAT.HR24,
  6344. showImages: false,
  6345. soundMention: true,
  6346. leaveConfirmation: false,
  6347. chatlimit: 512,
  6348. justplayed: false,
  6349. library: {
  6350. thumbnails: false,
  6351. },
  6352. };
  6353.  
  6354. $scope.changeTab = function(inProp, val){
  6355. if (typeof $scope.prop[inProp] === 'undefined') return;
  6356. var curVal = $scope.prop[inProp];
  6357.  
  6358. // Leaving chat tab
  6359. if (inProp == 'c' && curVal == 1 && val != 1){
  6360. $scope.prop.chatScroll = MP.api.chat.getPos();
  6361. }
  6362.  
  6363.  
  6364. $scope.prop[inProp] = val;
  6365.  
  6366. if (inProp == 'c'){
  6367.  
  6368. // Entering chat tab
  6369. if (val == 1){
  6370.  
  6371. // If they were at the bottom of the chat tab before, they'll be at the bottom when they come back
  6372. if ($scope.prop.chatScroll >= 0){
  6373. $scope.prop.chatScroll = 0;
  6374.  
  6375. // Using setTimeout to give Angular the time to update. CAN'T scroll while tab is not visible.
  6376. setTimeout(function(){MP.api.chat.scrollBottom()}, 3);
  6377. }
  6378. }
  6379. }
  6380. };
  6381.  
  6382. $scope.makeUsernameStyle = function(uid){
  6383. var user = MP.findUser(uid);
  6384. if (!user) return MP.makeUsernameStyle('default');
  6385.  
  6386. return MP.makeUsernameStyle(user.role);
  6387. };
  6388.  
  6389. $scope.makeUsernameStyleByRole = function(role){
  6390. if (!role) return MP.makeUsernameStyle('default');
  6391.  
  6392. return MP.makeUsernameStyle(role);
  6393. };
  6394.  
  6395. $scope.checkPerm = MP.checkPerm;
  6396.  
  6397. $scope.makeTime = function(inTime, dur){
  6398. var h = Math.floor(inTime / 3600);
  6399. var m = Math.floor(inTime / 60) % 60;
  6400. var s = inTime % 60;
  6401.  
  6402. return (h + m + s || dur) ? (h > 0 ? h + ':' : '') + ( '0' + m ).slice(-2) + ':' + ( '0' + s ).slice(-2) : 'LIVE';
  6403. };
  6404. $scope.makeTimeElapsed = function(inTime){
  6405. var diff = MP.timeConvert(new Date().getTime(), inTime + MP.session.serverDateDiff);
  6406.  
  6407. if (diff.years > 0) return diff.years + ' years ago';
  6408. if (diff.months > 0) return diff.months + ' months ago';
  6409. if (diff.days > 0) return diff.days + ' days ago';
  6410. if (diff.hours > 0) return diff.hours + ' hours ago';
  6411. if (diff.minutes > 0) return diff.minutes + ' minutes ago';
  6412. return diff.seconds + ' seconds ago';
  6413. };
  6414. $scope.findPosInWaitlist = function(uid){
  6415. return MP.findPosInWaitlist(uid);
  6416. };
  6417.  
  6418. $scope.inHistory = function(cid){
  6419. if(!MP.historyList.historyInitialized) return false;
  6420. for(var k in MP.historyList.history)
  6421. if(MP.historyList.history[k].song.cid == cid) return true;
  6422. return false;
  6423. };
  6424.  
  6425. $scope.filteredHistory = function(filterBy) {
  6426. var result = [];
  6427. if (filterBy == undefined || filterBy == null || filterBy == "") {
  6428. return $scope.historyList ? $scope.historyList.history : [];
  6429. }
  6430. angular.forEach($scope.historyList.history, function(h) {
  6431. try {
  6432. if (h.song.title.toLowerCase().indexOf(filterBy.toLowerCase()) > -1) {
  6433. result.push(h);
  6434. }
  6435. else if (h.song.cid.toLowerCase().indexOf(filterBy.toLowerCase()) > -1) {
  6436. result.push(h);
  6437. }
  6438. else if (h.user.un.toLowerCase().indexOf(filterBy.toLowerCase()) > -1) {
  6439. result.push(h);
  6440. }
  6441. }
  6442. catch (e) {}
  6443. });
  6444. return result;
  6445. };
  6446.  
  6447. $scope.makeBadgeStyle = function(opts){
  6448. return MP.makeBadgeStyle(opts);
  6449. };
  6450.  
  6451. $scope.makeUsernameStyle = function(uid){
  6452. var user = MP.findUser(uid);
  6453. if (!user) return MP.makeUsernameStyle('default');
  6454.  
  6455. return MP.makeUsernameStyle(user.role);
  6456. };
  6457.  
  6458. $scope.getRole = function(role){
  6459. if (MP.getRole(role))
  6460. return MP.getRole(role);
  6461.  
  6462. return {};
  6463. };
  6464.  
  6465. $scope.$watch('roomSettings', function (newVal, oldVal) { $scope.saveUISettings() }, true);
  6466. //$scope.$watch('userSettings', function (newVal, oldVal) { $scope.saveSettings() }, true);
  6467.  
  6468. $scope.saveUISettings = function() {
  6469. $(window).unbind('beforeunload', MP.leaveConfirmation);
  6470. if ($scope.roomSettings.leaveConfirmation && MP.findPosInWaitlist() != -1){
  6471. $(window).bind('beforeunload', MP.leaveConfirmation);
  6472. }
  6473.  
  6474. var settings = JSON.parse(localStorage.getItem("settings"));
  6475. settings.roomSettings = $scope.roomSettings;
  6476. localStorage.setItem("settings", JSON.stringify(settings));
  6477. };
  6478.  
  6479. $scope.saveSettings = function() {
  6480. $scope.user.badge.top = $('#badge-top-color-input').val() || $scope.user.badge.top;
  6481. $scope.user.badge.bottom = $('#badge-bottom-color-input').val() || $scope.user.badge.bottom;
  6482. MP.updateBadge($scope.user.badge);
  6483. $('#badge-top-color-input').val('');
  6484. $('#badge-bottom-color-input').val('');
  6485. if ($scope.userSettings.newUserName != '' && $scope.userSettings.newUserName.toString().toLowerCase() != $scope.user.un.toString().toLowerCase()) {
  6486. // send name change request
  6487. // on success callback reset newUserName
  6488. $scope.userSettings.newUserName = '';
  6489. }
  6490. };
  6491.  
  6492. var settings = JSON.parse(localStorage.getItem("settings"));
  6493. if (settings) {
  6494. if (settings.roomSettings == undefined || settings.roomSettings == null) {
  6495. settings.roomSettings = $scope.roomSettings;
  6496. localStorage.setItem("settings", JSON.stringify(settings));
  6497. }
  6498. else {
  6499. for (var i in settings.roomSettings) {
  6500. $scope.roomSettings[i] = settings.roomSettings[i];
  6501. }
  6502. if (settings.roomSettings.leaveConfirmation){
  6503. $(window).bind('beforeunload', MP.leaveConfirmation);
  6504. }
  6505. if ($scope.roomSettings.playerStyle != "") {
  6506. $('.playback').attr('style', $scope.roomSettings.playerStyle);
  6507. }
  6508. }
  6509. }
  6510. });
  6511. }
  6512.  
  6513. /*
  6514.  
  6515. })();
  6516.  
  6517. //Loading
  6518. (function() {
  6519. */ var startLoad = 0;
  6520.  
  6521. var loadingText = [
  6522. "Initializing Vaporwave.io",
  6523. "Rendering Roman Busts",
  6524. "Running aesthetics.exe",
  6525. "Hacking the Mainframe",
  6526. "Loading DMT catalogue (this may take a while) ...",
  6527. "Embracing Modern Consumerism",
  6528. "Entering the Virtual Plaza",
  6529. "Rendering Overgrowth Cube",
  6530. "Loading Hardvapor (ERROR: 404)",
  6531. "Welcome to Vaporwave.io",
  6532. "Welcome to Vaporwave.io",
  6533. "Welcome to Vaporwave.io",
  6534. "Translating Google Translated Japanese",
  6535. "Booting A E S T H E T I C S"
  6536. ];
  6537.  
  6538. //Loading animation start
  6539. var interval = setInterval(function(){
  6540. $(".loading").fadeOut(function() {
  6541. $('.loading').text(loadingText[Math.floor(Math.random() * loadingText.length)]);
  6542. }).fadeIn();
  6543. }, 2000);
  6544.  
  6545. //LocalStorage check
  6546. if(!localStorage.getItem("settings")){
  6547. localStorage.setItem("settings", JSON.stringify({
  6548. player: {
  6549. volume: 50,
  6550. mute: false,
  6551. quality: API.DATA.PLAYER.QUALITY.HD720,
  6552. fullscreen: false,
  6553. stream: true
  6554. },
  6555. chat: {
  6556. //timestamp:
  6557. },
  6558. }));
  6559. }
  6560.  
  6561. //Lightbox options
  6562. /*lightbox.option({
  6563. fadeDuration: 150,
  6564. albumLabel: '',
  6565. showImageNumberLabel: false,
  6566. });*/
  6567.  
  6568. MP.getTokenName = function() {
  6569. if (config.selfHosted == true) {
  6570. if (MP.session.roomInfo.slug) {
  6571. return MP.session.roomInfo.slug + '-token';
  6572. }
  6573. else {
  6574. var urlParams = (location.pathname + '').split('/');
  6575. var i = urlParams.indexOf('p');
  6576. if (urlParams.length >= (i + 2)) {
  6577. var roomSlug = urlParams[i + 1];
  6578. return roomSlug + '-token';
  6579. }
  6580. }
  6581. return null;
  6582. }
  6583. else {
  6584. return 'token';
  6585. }
  6586. };
  6587.  
  6588. //Successful connection to the socket
  6589. MP.onConnect = function(){
  6590. var tok = MP.cookie.getCookie(MP.getTokenName());
  6591.  
  6592. var onLoad = function(){
  6593. MP.joinRoom(function(err, data){
  6594. if (err){
  6595. return;
  6596. }
  6597. if(!MP.historyList.historyInitialized) {
  6598. MP.getHistory();
  6599. }
  6600. // Alpha Only
  6601. if (!MP.isLoggedIn()) {
  6602. var token = MP.cookie.getCookie(MP.getTokenName());
  6603. MP.loginWithTok(token, function(err, data){
  6604. if (err){ console.log('Token is invalid.'); return;}
  6605. });
  6606. }
  6607.  
  6608. if (MP.session.roomInfo.bg) { $('#room-bg').css('background-image', 'url('+ MP.session.roomInfo.bg +')'); }
  6609. $('title').text(data.room.name);
  6610. $('.modal-bg').remove();
  6611. var $chat = $('#chat');
  6612. MP.loadEmoji(false, function(){
  6613. //Remove all current DJ badges and show real badges
  6614. var elem = $('#messages .cm.message');
  6615. elem.find('.bdg-icon-dj').remove();
  6616. elem.find('.bdg:hidden').attr('class', 'bdg');
  6617.  
  6618. //Render last chat
  6619. for(var i in data.lastChat){
  6620. if (data.lastChat[i].user.un && !MP.seenUsers[data.lastChat[i].user.uid]) MP.seenUsers[data.lastChat[i].user.uid] = data.lastChat[i].user;
  6621.  
  6622. MP.addMessage({
  6623. message: data.lastChat[i].message,
  6624. uid: data.lastChat[i].user.uid,
  6625. cid: data.lastChat[i].cid,
  6626. time: data.lastChat[i].time
  6627. });
  6628. }
  6629.  
  6630. //Render welcome message
  6631. $('#messages').append(
  6632. '<div class="cm room-greet">' +
  6633. '<div class="mdi mdi-send msg" style="color:#1C1C1F"></div>' +
  6634. '<div class="text">' +
  6635. '<span class="greet-uname">' + MP.emojiReplace(MP.session.roomInfo.name) + '</span>' +
  6636. '<br><span class="greet-umsg">' + MP.emojiReplace(MP.session.roomInfo.greet) + '</span></div></div></div>'
  6637. );
  6638.  
  6639. // Waits for the append to DOM to go through, then scrolls to bottom
  6640. setTimeout(function(){
  6641. MP.api.chat.scrollBottom();
  6642. }, 3);
  6643. });
  6644. $chat.scrollTop($chat[0].scrollHeight);
  6645.  
  6646. var playerSettings = JSON.parse(localStorage.settings).player;
  6647.  
  6648. if (typeof API.player.getPlayer === 'function'){
  6649. if (data.queue.currentsong && playerSettings.stream){
  6650. API.player.getPlayer().loadVideoById(data.queue.currentsong.cid);
  6651. if(data.queue.time) API.player.getPlayer().seekTo(data.queue.time);
  6652. API.player.getPlayer().setVolume(playerSettings.mute ? 0 : playerSettings.volume);
  6653. }else{
  6654. API.player.getPlayer().loadVideoById(null);
  6655. }
  6656. console.log('returned');
  6657. return;
  6658. }
  6659.  
  6660. //Bind escape button
  6661. $(document).on('keydown', function(e){
  6662. if (e.which == 27){
  6663. $('div.ico-logo').click();
  6664. }
  6665. });
  6666.  
  6667. //Get player ready
  6668. YT.ready(function(){
  6669. var player = new YT.Player('player', {
  6670. height: '390',
  6671. width: '640',
  6672. videoId: (playerSettings.stream && data.queue.currentsong) ? data.queue.currentsong.cid : null,
  6673. playerVars: {
  6674. controls: 0, //Disable controls
  6675. iv_load_policy: 3, //Disable annotations
  6676. showinfo: 0, //Disable video info
  6677. autoplay: 1, //Enable autoplay
  6678. fs: 0, //Disable fullscreen
  6679. rel: 0, //Disable showing related videos
  6680. disablekb: 1, //Disable keyboard
  6681. },
  6682. events: {
  6683. 'onReady': function(){
  6684. setTimeout(function(){ $('.loader, .loading').fadeOut(1000); $('.load').slideToggle(1000); },2 * 1000);
  6685. clearInterval(interval);
  6686. API.player.getPlayer = function(){
  6687. return player;
  6688. };
  6689.  
  6690. var vol = playerSettings.volume;
  6691.  
  6692. if (playerSettings.hd){
  6693. API.player.getPlayer().setPlaybackQuality('hd720');
  6694. $('.btn-hd div').addClass('active');
  6695. }
  6696.  
  6697. if(data.queue.time) API.player.getPlayer().seekTo(data.queue.time);
  6698.  
  6699. var voldiv = $('.volume');
  6700.  
  6701. if (!playerSettings.mute){
  6702. API.player.setVolume(vol);
  6703.  
  6704. if(vol == 0){
  6705. voldiv.text("volume_off");
  6706. } else if (vol <= 25) {
  6707. voldiv.text("volume_mute");
  6708. } else if (vol >= 75) {
  6709. voldiv.text("volume_up");
  6710. } else {
  6711. voldiv.text("volume_down");
  6712. }
  6713.  
  6714. voldiv.val(vol);
  6715. }else{
  6716. API.player.setMute(true);
  6717. }
  6718. },
  6719. 'onStateChange': function(e){
  6720. if (e.data == YT.PlayerState.PAUSED) API.player.getPlayer().playVideo();
  6721. if (e.data == YT.PlayerState.ENDED || e.data == YT.PlayerState.UNSTARTED) $('#player').hide();
  6722. if ((e.data == YT.PlayerState.CUED || e.data == YT.PlayerState.PLAYING ) && !MP.session.snooze) $('#player').show();
  6723.  
  6724. // Duration of video loaded: duration * API.player.getPlayer().getVideoLoadedFraction()
  6725. if (e.data == YT.PlayerState.BUFFERING && startLoad != -1){
  6726. startLoad = Date.now();
  6727. }else{
  6728. startLoad = 0;
  6729. }
  6730.  
  6731. if (e.data == YT.PlayerState.PLAYING && startLoad > 0) {
  6732. var loaded = API.player.getPlayer().getDuration() * API.player.getPlayer().getVideoLoadedFraction();
  6733. var curTime = API.player.getPlayer().getCurrentTime();
  6734. var adjustment = ((Date.now() - startLoad)/1000);
  6735.  
  6736. if ( (curTime + adjustment) > loaded ){
  6737. //startLoad = -1;
  6738. API.player.getPlayer().seekTo( loaded );
  6739. }else{
  6740. API.player.getPlayer().seekTo( curTime + adjustment );
  6741. }
  6742.  
  6743. startLoad = 0;
  6744. }
  6745.  
  6746. }
  6747. }
  6748. });
  6749. });
  6750. });
  6751. };
  6752.  
  6753. if (tok != ''){
  6754. console.log('Logging in with token');
  6755. MP.loginWithTok(tok, function(err, data){
  6756. onLoad();
  6757. if (err){ console.log('Token is invalid.'); return;}
  6758. });
  6759. }else{
  6760.  
  6761. onLoad();
  6762. }
  6763. };
  6764. })();
  6765.  
  6766. document.head = document.head || document.getElementsByTagName('head')[0];
  6767. $('.settings .set-check').children().each(function(){ $(this).after($('<label for="' + $(this).attr('id') + '"></label>')); })
  6768.  
  6769. $.fn.incVal = function(val) {
  6770. var n = typeof val !== 'undefined' ? val : 1;
  6771. var old = parseInt(this.val());
  6772. this.val(old + n);
  6773. };
  6774.  
  6775. $.fn.fadeIncVal = function(val) {
  6776. var $this = this;
  6777. if($this.val() < val) {
  6778. this.incVal();
  6779. setTimeout(function(){ $this.fadeIncVal(val); }, 10);
  6780. }
  6781. };
  6782.  
  6783. (function(d, s, id){
  6784. var js, fjs = d.getElementsByTagName(s)[0];
  6785. if (d.getElementById(id)) {return;}
  6786. js = d.createElement(s); js.id = id;
  6787. js.src = "//connect.facebook.net/en_US/sdk.js";
  6788. fjs.parentNode.insertBefore(js, fjs);
  6789. }(document, 'script', 'facebook-jssdk'));
  6790.  
  6791. window.fbAsyncInit = function() {
  6792. FB.init({
  6793. appId : '472932736241651',
  6794. cookie : true,
  6795. xfbml : true,
  6796. version : 'v2.5'
  6797. });
  6798. };
  6799.  
  6800. function testAPI() {
  6801. FB.api('/me', function(response) {
  6802. console.log(response);
  6803. });
  6804. }
  6805.  
  6806. /*$('.playback').draggable({
  6807. containment: "parent",
  6808. handle: ".draggable",
  6809. drag: function( event, ui ) {
  6810. ui.position.left = Math.max( 427, ui.position.left );
  6811. ui.position.top = Math.max( 260, ui.position.top );
  6812. },
  6813. stop: function( event, ui ) {
  6814. var scope = angular.element($('body')).scope();
  6815. scope.roomSettings.playerStyle = $('.playback').attr('style');
  6816. scope.saveUISettings();
  6817. }
  6818. });*/
  6819.  
  6820. $.fn.serializeObject = function()
  6821. {
  6822. var o = {};
  6823. var a = this.serializeArray();
  6824. $.each(a, function() {
  6825. if (o[this.name] !== undefined) {
  6826. if (!o[this.name].push) {
  6827. o[this.name] = [o[this.name]];
  6828. }
  6829. o[this.name].push(this.value || '');
  6830. } else {
  6831. o[this.name] = this.value || '';
  6832. }
  6833. });
  6834. return o;
  6835. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement