app.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. History = new Mongo.Collection("history");
  2. Playlists = new Mongo.Collection("playlists");
  3. Rooms = new Mongo.Collection("rooms");
  4. Queues = new Mongo.Collection("queues");
  5. Chat = new Mongo.Collection("chat");
  6. if (Meteor.isClient) {
  7. Meteor.startup(function() {
  8. reCAPTCHA.config({
  9. publickey: '6LcVxg0TAAAAAE18vBiH00UAyaJggsmLm890SjZl'
  10. });
  11. });
  12. Meteor.subscribe("queues");
  13. var minterval;
  14. var hpSound = undefined;
  15. var songsArr = [];
  16. var ytArr = [];
  17. var _sound = undefined;
  18. var parts = location.href.split('/');
  19. var id = parts.pop();
  20. var type = id.toLowerCase();
  21. function getSpotifyInfo(title, cb, artist) {
  22. var q = "";
  23. q = title;
  24. if (artist !== undefined) {
  25. q += " artist:" + artist;
  26. }
  27. $.ajax({
  28. type: "GET",
  29. url: 'https://api.spotify.com/v1/search?q=' + encodeURIComponent(q) + '&type=track',
  30. applicationType: "application/json",
  31. contentType: "json",
  32. success: function (data) {
  33. cb(data);
  34. }
  35. });
  36. }
  37. function getSpotifyArtist(data) {
  38. var temp = "";
  39. var artist;
  40. if(data.artists.length >= 2){
  41. for(var k in data.artists){
  42. temp = temp + data.artists[k].name + ", ";
  43. }
  44. } else{
  45. for(var k in data.artists){
  46. temp = temp + data.artists[k].name;
  47. }
  48. }
  49. if(temp[temp.length-2] === ","){
  50. artist = temp.substr(0,temp.length-2);
  51. } else{
  52. artist = temp;
  53. }
  54. return artist;
  55. }
  56. Template.profile.helpers({
  57. "username": function() {
  58. return Session.get("username");
  59. },
  60. "first_joined": function() {
  61. return moment(Session.get("first_joined")).format("DD/MM/YYYY HH:mm:ss");
  62. },
  63. "rank": function() {
  64. return Session.get("rank");
  65. },
  66. loaded: function() {
  67. return Session.get("loaded");
  68. }
  69. });
  70. Template.profile.onCreated(function() {
  71. var parts = location.href.split('/');
  72. var username = parts.pop();
  73. Session.set("loaded", false);
  74. Meteor.subscribe("userProfiles", function() {
  75. if (Meteor.users.find({"profile.usernameL": username.toLowerCase()}).count() === 0) {
  76. window.location = "/";
  77. } else {
  78. var data = Meteor.users.find({"profile.usernameL": username.toLowerCase()}).fetch()[0];
  79. Session.set("username", data.profile.username);
  80. Session.set("first_joined", data.createdAt);
  81. Session.set("rank", data.profile.rank);
  82. Session.set("loaded", true);
  83. }
  84. });
  85. });
  86. curPath=function(){var c=window.location.pathname;var b=c.slice(0,-1);var a=c.slice(-1);if(b==""){return"/"}else{if(a=="/"){return b}else{return c}}};
  87. Handlebars.registerHelper('active', function(path) {
  88. return curPath() == path ? 'active' : '';
  89. });
  90. Template.header.helpers({
  91. currentUser: function() {
  92. return Meteor.user();
  93. },
  94. isAdmin: function() {
  95. if (Meteor.user() && Meteor.user().profile) {
  96. return Meteor.user().profile.rank === "admin";
  97. } else {
  98. return false;
  99. }
  100. }
  101. });
  102. Template.header.events({
  103. "click .logout": function(e){
  104. e.preventDefault();
  105. Meteor.logout();
  106. if (hpSound !== undefined) {
  107. hpSound.stop();
  108. }
  109. }
  110. });
  111. Template.register.events({
  112. "submit form": function(e){
  113. e.preventDefault();
  114. var username = e.target.registerUsername.value;
  115. var email = e.target.registerEmail.value;
  116. var password = e.target.registerPassword.value;
  117. var captchaData = grecaptcha.getResponse();
  118. Meteor.call("createUserMethod", {username: username, email: email, password: password}, captchaData, function(err, res) {
  119. grecaptcha.reset();
  120. console.log(username, password, err, res);
  121. if (err) {
  122. console.log(err);
  123. var errAlert = $('<div class="alert alert-danger" role="alert"><strong>Oh Snap!</strong> ' + err.reason + '</div>');
  124. $("#login").after(errAlert);
  125. errAlert.fadeOut(20000, function() {
  126. errAlert.remove();
  127. });
  128. } else {
  129. console.log();
  130. Meteor.loginWithPassword(username, password);
  131. }
  132. });
  133. },
  134. "click #github-login": function(){
  135. Meteor.loginWithGithub()
  136. },
  137. "click #login": function(){
  138. $("#register-view").hide();
  139. $("#login-view").show();
  140. }
  141. });
  142. Template.login.events({
  143. "submit form": function(e){
  144. e.preventDefault();
  145. var username = e.target.loginUsername.value;
  146. var password = e.target.loginPassword.value;
  147. Meteor.loginWithPassword(username, password);
  148. Accounts.onLoginFailure(function(){
  149. $("input").css("background-color","indianred").addClass("animated shake");
  150. $("input").on("click",function(){
  151. $("input").css({
  152. "background-color": "transparent",
  153. "width": "250px"
  154. });
  155. })
  156. });
  157. },
  158. "click #github-login": function(){
  159. Meteor.loginWithGithub()
  160. },
  161. "click #register": function(){
  162. $("#login-view").hide();
  163. $("#register-view").show();
  164. }
  165. });
  166. Template.dashboard.helpers({
  167. rooms: function() {
  168. return Rooms.find({});
  169. },
  170. currentSong: function() {
  171. var history = History.find({type: this.type}).fetch();
  172. if (history.length < 1) {
  173. return {};
  174. } else {
  175. history = history[0];
  176. return history.history[history.history.length - 1];
  177. }
  178. }
  179. });
  180. Template.dashboard.onCreated(function() {
  181. if (_sound !== undefined) _sound.stop();
  182. if (minterval !== undefined) {
  183. Meteor.clearInterval(minterval);
  184. }
  185. Meteor.subscribe("history");
  186. });
  187. Template.room.events({
  188. "click #add-song-button": function(e){
  189. e.preventDefault();
  190. parts = location.href.split('/');
  191. id = parts.pop();
  192. var genre = id.toLowerCase();
  193. var type = $("#type").val();
  194. id = $("#id").val();
  195. var title = $("#title").val();
  196. var artist = $("#artist").val();
  197. var img = $("#img").val();
  198. var songData = {type: type, id: id, title: title, artist: artist, img: img};
  199. Meteor.call("addSongToQueue", genre, songData, function(err, res) {
  200. console.log(err, res);
  201. });
  202. },
  203. "click #toggle-video": function(e){
  204. e.preventDefault();
  205. if (Session.get("mediaHidden")) {
  206. $("#media-container").removeClass("hidden");
  207. $("#toggle-video").text("Hide video");
  208. Session.set("mediaHidden", false);
  209. } else {
  210. $("#media-container").addClass("hidden");
  211. $("#toggle-video").text("Show video");
  212. Session.set("mediaHidden", true);
  213. }
  214. },
  215. "click #return": function(e){
  216. $("#add-info").hide();
  217. $("#search-info").show();
  218. },
  219. "click #search-song": function(){
  220. $("#song-results").empty();
  221. var search_type = $("#search_type").val();
  222. if (search_type === "YouTube") {
  223. $.ajax({
  224. type: "GET",
  225. url: "https://www.googleapis.com/youtube/v3/search?part=snippet&q=" + $("#song-input").val() + "&key=AIzaSyAgBdacEWrHCHVPPM4k-AFM7uXg-Q__YXY",
  226. applicationType: "application/json",
  227. contentType: "json",
  228. success: function(data){
  229. for(var i in data.items){
  230. $("#song-results").append("<p>" + data.items[i].snippet.title + "</p>");
  231. ytArr.push({title: data.items[i].snippet.title, id: data.items[i].id.videoId});
  232. }
  233. $("#song-results p").click(function(){
  234. $("#search-info").hide();
  235. $("#add-info").show();
  236. var title = $(this).text();
  237. for(var i in ytArr){
  238. if(ytArr[i].title === title){
  239. var songObj = {
  240. id: ytArr[i].id,
  241. title: ytArr[i].title,
  242. type: "youtube"
  243. };
  244. $("#title").val(songObj.title);
  245. $("#artist").val("");
  246. $("#id").val(songObj.id);
  247. $("#type").val("YouTube");
  248. getSpotifyInfo(songObj.title.replace(/\[.*\]/g, ""), function(data) {
  249. if (data.tracks.items.length > 0) {
  250. $("#title").val(data.tracks.items[0].name);
  251. var artists = [];
  252. $("#img").val(data.tracks.items[0].album.images[1].url);
  253. data.tracks.items[0].artists.forEach(function(artist) {
  254. artists.push(artist.name);
  255. });
  256. $("#artist").val(artists.join(", "));
  257. }
  258. });
  259. }
  260. }
  261. })
  262. }
  263. })
  264. } else if (search_type === "SoundCloud") {
  265. SC.get('/tracks', { q: $("#song-input").val()}, function(tracks) {
  266. for(var i in tracks){
  267. $("#song-results").append("<p>" + tracks[i].title + "</p>")
  268. songsArr.push({title: tracks[i].title, id: tracks[i].id, duration: tracks[i].duration / 1000});
  269. }
  270. $("#song-results p").click(function(){
  271. $("#search-info").hide();
  272. $("#add-info").show();
  273. var title = $(this).text();
  274. for(var i in songsArr){
  275. if(songsArr[i].title === title){
  276. var id = songsArr[i].id;
  277. var duration = songsArr[i].duration;
  278. var songObj = {
  279. title: songsArr[i].title,
  280. id: id,
  281. duration: duration,
  282. type: "soundcloud"
  283. }
  284. $("#title").val(songObj.title);
  285. // Set ID field
  286. $("#id").val(songObj.id);
  287. $("#type").val("SoundCloud");
  288. getSpotifyInfo(songObj.title.replace(/\[.*\]/g, ""), function(data) {
  289. if (data.tracks.items.length > 0) {
  290. $("#title").val(data.tracks.items[0].name);
  291. var artists = [];
  292. data.tracks.items[0].artists.forEach(function(artist) {
  293. artists.push(artist.name);
  294. });
  295. $("#artist").val(artists.join(", "));
  296. }
  297. // Set title field again if possible
  298. // Set artist if possible
  299. });
  300. }
  301. }
  302. })
  303. });
  304. }
  305. },
  306. "click #add-songs": function(){
  307. $("#add-songs-modal").show();
  308. },
  309. "click #close-modal": function(){
  310. $("#search-info").show();
  311. $("#add-info").hide();
  312. },
  313. "click #submit-message": function(){
  314. var message = $("#chat-input").val();
  315. $("#chat-ul").scrollTop(1000000);
  316. $("#chat-input").val("");
  317. Meteor.call("sendMessage", type, message);
  318. }
  319. });
  320. Template.room.onRendered(function() {
  321. $(document).ready(function() {
  322. function makeSlider(){
  323. var slider = $("#volume-slider").slider();
  324. var volume = localStorage.getItem("volume") || 20;
  325. $("#volume-slider").slider("setValue", volume);
  326. if (slider.length === 0) {
  327. Meteor.setTimeout(function() {
  328. makeSlider();
  329. }, 500);
  330. } else {
  331. slider.on("slide", function(val) {
  332. if (yt_player !== undefined) {
  333. yt_player.setVolume(val.value);
  334. localStorage.setItem("volume", val.value);
  335. } else if (_sound !== undefined) {
  336. //_sound
  337. var volume = val.value / 100;
  338. _sound.setVolume(volume);
  339. localStorage.setItem("volume", val.value);
  340. }
  341. });
  342. }
  343. }
  344. makeSlider();
  345. });
  346. });
  347. Template.room.helpers({
  348. type: function() {
  349. var parts = location.href.split('/');
  350. var id = parts.pop();
  351. return id.toUpperCase();
  352. },
  353. title: function(){
  354. return Session.get("title");
  355. },
  356. artist: function(){
  357. return Session.get("artist");
  358. },
  359. title_next: function(){
  360. return Session.get("title_next");
  361. },
  362. artist_next: function(){
  363. return Session.get("artist_next");
  364. },
  365. title_after: function(){
  366. return Session.get("title_after");
  367. },
  368. artist_after: function(){
  369. return Session.get("artist_after");
  370. },
  371. loaded: function() {
  372. return Session.get("loaded");
  373. }
  374. });
  375. Template.admin.helpers({
  376. queues: function() {
  377. return Queues.find({});
  378. }
  379. });
  380. var yt_player = undefined;
  381. var _sound = undefined;
  382. Template.admin.events({
  383. "click .preview-button": function(e){
  384. Session.set("song", this);
  385. },
  386. "click .edit-button": function(e){
  387. Session.set("song", this);
  388. Session.set("genre", $(e.toElement).data("genre"));
  389. $("#type").val(this.type);
  390. $("#artist").val(this.artist);
  391. $("#title").val(this.title);
  392. $("#img").val(this.img);
  393. $("#id").val(this.id);
  394. $("#duration").val(this.duration);
  395. },
  396. "click #add-song-button": function(e){
  397. var genre = $(e.toElement).data("genre") || $(e.toElement).parent().data("genre");
  398. Meteor.call("addSongToPlaylist", genre, this);
  399. },
  400. "click #deny-song-button": function(e){
  401. var genre = $(e.toElement).data("genre") || $(e.toElement).parent().data("genre");
  402. Meteor.call("removeSongFromQueue", genre, this.id);
  403. },
  404. "click #play": function() {
  405. $("#play").attr("disabled", true);
  406. $("#stop").attr("disabled", false);
  407. var song = Session.get("song");
  408. var id = song.id;
  409. var type = song.type;
  410. var volume = localStorage.getItem("volume") || 20;
  411. if (type === "YouTube") {
  412. if (yt_player === undefined) {
  413. yt_player = new YT.Player("previewPlayer", {
  414. height: 540,
  415. width: 568,
  416. videoId: id,
  417. playerVars: {autoplay: 1, controls: 0, iv_load_policy: 3, showinfo: 0},
  418. events: {
  419. 'onReady': function(event) {
  420. event.target.playVideo();
  421. event.target.setVolume(volume);
  422. },
  423. 'onStateChange': function(event){
  424. if (event.data == YT.PlayerState.PAUSED) {
  425. event.target.playVideo();
  426. }
  427. if (event.data == YT.PlayerState.PLAYING) {
  428. $("#play").attr("disabled", true);
  429. $("#stop").attr("disabled", false);
  430. } else {
  431. $("#play").attr("disabled", false);
  432. $("#stop").attr("disabled", true);
  433. }
  434. }
  435. }
  436. });
  437. } else {
  438. yt_player.loadVideoById(id);
  439. }
  440. $("#previewPlayer").show();
  441. } else if (type === "SoundCloud") {
  442. SC.stream("/tracks/" + song.id, function(sound) {
  443. _sound = sound;
  444. sound.setVolume(volume / 100);
  445. sound.play();
  446. });
  447. }
  448. },
  449. "click #stop": function() {
  450. $("#play").attr("disabled", false);
  451. $("#stop").attr("disabled", true);
  452. if (yt_player !== undefined) {
  453. yt_player.stopVideo();
  454. }
  455. if (_sound !== undefined) {
  456. _sound.stop();
  457. }
  458. },
  459. "click #croom_create": function() {
  460. Meteor.call("createRoom", $("#croom").val(), function (err, res) {
  461. if (err) {
  462. alert("Error " + err.error + ": " + err.reason);
  463. } else {
  464. window.location = "/" + $("#croom").val();
  465. }
  466. });
  467. },
  468. "click #find-img-button": function() {
  469. getSpotifyInfo($("#title").val().replace(/\[.*\]/g, ""), function(data) {
  470. if (data.tracks.items.length > 0) {
  471. $("#img").val(data.tracks.items[0].album.images[1].url);
  472. }
  473. }, $("#artist").val());
  474. },
  475. "click #save-song-button": function() {
  476. var newSong = {};
  477. newSong.title = $("#title").val();
  478. newSong.artist = $("#artist").val();
  479. newSong.img = $("#img").val();
  480. newSong.type = $("#type").val();
  481. newSong.duration = $("#duration").val();
  482. Meteor.call("updateQueueSong", Session.get("genre"), Session.get("song"), newSong, function() {
  483. $('#editModal').modal('hide');
  484. });
  485. }
  486. });
  487. Template.admin.onCreated(function() {
  488. var tag = document.createElement("script");
  489. tag.src = "https://www.youtube.com/iframe_api";
  490. var firstScriptTag = document.getElementsByTagName('script')[0];
  491. firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  492. });
  493. Template.admin.onRendered(function() {
  494. $("#previewModal").on("hidden.bs.modal", function() {
  495. if (yt_player !== undefined) {
  496. $("#play").attr("disabled", false);
  497. $("#stop").attr("disabled", true);
  498. $("#previewPlayer").hide();
  499. yt_player.loadVideoById("", 0);
  500. yt_player.seekTo(0);
  501. yt_player.stopVideo();
  502. }
  503. if (_sound !== undefined) {
  504. _sound.stop();
  505. $("#play").attr("disabled", false);
  506. $("#stop").attr("disabled", true);
  507. }
  508. });
  509. $(document).ready(function() {
  510. function makeSlider(){
  511. var slider = $("#volume-slider").slider();
  512. var volume = localStorage.getItem("volume") || 20;
  513. $("#volume-slider").slider("setValue", volume);
  514. if (slider.length === 0) {
  515. Meteor.setTimeout(function() {
  516. makeSlider();
  517. }, 500);
  518. } else {
  519. slider.on("slide", function(val) {
  520. localStorage.setItem("volume", val.value);
  521. if (yt_player !== undefined) {
  522. yt_player.setVolume(val.value);
  523. } else if (_sound !== undefined) {
  524. var volume = val.value / 100;
  525. _sound.setVolume(volume);
  526. }
  527. });
  528. }
  529. }
  530. makeSlider();
  531. });
  532. });
  533. Template.playlist.helpers({
  534. playlist_songs: function() {
  535. var data = Playlists.find({type: type}).fetch();
  536. if (data !== undefined && data.length > 0) {
  537. data[0].songs.map(function(song) {
  538. if (song.title === Session.get("title")) {
  539. song.current = true;
  540. } else {
  541. song.current = false;
  542. }
  543. return song;
  544. });
  545. return data[0].songs;
  546. } else {
  547. return [];
  548. }
  549. }
  550. });
  551. Meteor.subscribe("rooms");
  552. Meteor.subscribe("chat");
  553. Template.room.onCreated(function () {
  554. yt_player = undefined;
  555. _sound = undefined;
  556. Session.set("videoHidden", false)
  557. var tag = document.createElement("script");
  558. tag.src = "https://www.youtube.com/iframe_api";
  559. var firstScriptTag = document.getElementsByTagName('script')[0];
  560. firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  561. var currentSong = undefined;
  562. var nextSong = undefined;
  563. var afterSong = undefined;
  564. var size = 0;
  565. var artistStr;
  566. var temp = "";
  567. var currentArt;
  568. function getTimeElapsed() {
  569. if (currentSong !== undefined) {
  570. return Date.now() - currentSong.started;
  571. }
  572. return 0;
  573. }
  574. function getSongInfo(songData){
  575. Session.set("title", songData.title);
  576. Session.set("artist", songData.artist);
  577. $("#song-img").attr("src", songData.img);
  578. Session.set("duration", songData.duration);
  579. }
  580. function resizeSeekerbar() {
  581. $("#seeker-bar").width(((getTimeElapsed() / 1000) / Session.get("duration") * 100) + "%");
  582. }
  583. function startSong() {
  584. if (currentSong !== undefined) {
  585. if (_sound !== undefined) _sound.stop();
  586. if (yt_player !== undefined && yt_player.stopVideo !== undefined) yt_player.stopVideo();
  587. var volume = localStorage.getItem("volume") || 20;
  588. $("#media-container").empty();
  589. yt_player = undefined;
  590. if (currentSong.type === "SoundCloud") {
  591. // Change id from visualizer to media-container
  592. $("#player").attr("src", "");
  593. getSongInfo(currentSong);
  594. SC.stream("/tracks/" + currentSong.id, function(sound){
  595. _sound = sound;
  596. sound.setVolume(volume / 100);
  597. startVisualizer(sound._player._html5Audio);
  598. sound.play();
  599. var interval = setInterval(function() {
  600. if (sound.getState() === "playing") {
  601. sound.seek(getTimeElapsed());
  602. window.clearInterval(interval);
  603. }
  604. }, 200);
  605. // Session.set("title", currentSong.title || "Title");
  606. // Session.set("artist", currentSong.artist || "Artist");
  607. Session.set("duration", currentSong.duration);
  608. resizeSeekerbar();
  609. });
  610. } else {
  611. $("#media-container").append('<div id="player" class="embed-responsive-item"></div>');
  612. if (yt_player === undefined) {
  613. yt_player = new YT.Player("player", {
  614. height: 540,
  615. width: 960,
  616. videoId: currentSong.id,
  617. playerVars: {controls: 0, iv_load_policy: 3, rel: 0, showinfo: 0},
  618. events: {
  619. 'onReady': function(event) {
  620. event.target.seekTo(getTimeElapsed() / 1000);
  621. event.target.playVideo();
  622. event.target.setVolume(volume);
  623. resizeSeekerbar();
  624. },
  625. 'onStateChange': function(event){
  626. if (event.data == YT.PlayerState.PAUSED) {
  627. event.target.seekTo(getTimeElapsed() / 1000);
  628. event.target.playVideo();
  629. }
  630. }
  631. }
  632. });
  633. } else {
  634. yt_player.loadVideoById(currentSong.id);
  635. }
  636. // Session.set("title", currentSong.title || "Title");
  637. // Session.set("artist", currentSong.artist || "Artist");
  638. getSongInfo(currentSong);
  639. //Session.set("duration", currentSong.duration);
  640. }
  641. }
  642. }
  643. Meteor.subscribe("history");
  644. Meteor.subscribe("playlists");
  645. Session.set("loaded", false);
  646. Meteor.subscribe("rooms", function() {
  647. var parts = location.href.split('/');
  648. var id = parts.pop();
  649. var type = id.toLowerCase();
  650. if (Rooms.find({type: type}).count() !== 1) {
  651. window.location = "/";
  652. } else {
  653. Session.set("loaded", true);
  654. minterval = Meteor.setInterval(function () {
  655. var data = undefined;
  656. var dataCursorH = History.find({type: type});
  657. var dataCursorP = Playlists.find({type: type});
  658. dataCursorH.forEach(function (doc) {
  659. if (data === undefined) {
  660. data = doc;
  661. }
  662. });
  663. if (data !== undefined && data.history.length > size) {
  664. //currentSong = data.history[data.history.length - 1];
  665. var songArray = Playlists.find({type: type}).fetch()[0].songs;
  666. var historyObj = data.history[data.history.length - 1];
  667. songArray.forEach(function(song) {
  668. if (song.id === historyObj.song.id) {
  669. currentSong = song;
  670. }
  671. });
  672. currentSong.started = historyObj.started;
  673. var songs = dataCursorP.fetch()[0].songs;
  674. songs.forEach(function(song, index) {
  675. if (currentSong.title === song.title) {
  676. if (index + 1 < songs.length) {
  677. nextSong = songs[index + 1];
  678. } else {
  679. nextSong = songs[0];
  680. }
  681. Session.set("title_next", nextSong.title);
  682. Session.set("artist_next", nextSong.artist);
  683. $("#song-img-next").attr("src", nextSong.img);
  684. if (index + 2 < songs.length) {
  685. afterSong = songs[index + 2];
  686. } else if (songs.length === index + 1 && songs.length > 1 ) {
  687. afterSong = songs[1];
  688. } else {
  689. afterSong = songs[0];
  690. }
  691. Session.set("title_after", afterSong.title);
  692. Session.set("artist_after", afterSong.artist);
  693. $("#song-img-after").attr("src",afterSong.img);
  694. }
  695. });
  696. size = data.history.length;
  697. startSong();
  698. }
  699. }, 1000);
  700. Meteor.setInterval(function () {
  701. resizeSeekerbar();
  702. }, 50);
  703. }
  704. });
  705. });
  706. }
  707. if (Meteor.isServer) {
  708. Meteor.startup(function() {
  709. reCAPTCHA.config({
  710. privatekey: '6LcVxg0TAAAAAI2fgIEEWHFxwNXeVIs8mzq5cfRM'
  711. });
  712. });
  713. Meteor.users.deny({update: function () { return true; }});
  714. Meteor.users.deny({insert: function () { return true; }});
  715. Meteor.users.deny({remove: function () { return true; }});
  716. function getSongDuration(query, artistName){
  717. var duration;
  718. var search = query;
  719. query = query.toLowerCase().split(" ").join("%20");
  720. var res = Meteor.http.get('https://api.spotify.com/v1/search?q=' + query + '&type=track');
  721. for(var i in res.data){
  722. for(var j in res.data[i].items){
  723. if(search.indexOf(res.data[i].items[j].name) !== -1 && artistName.indexOf(res.data[i].items[j].artists[0].name) !== -1){
  724. duration = res.data[i].items[j].duration_ms / 1000;
  725. return duration;
  726. }
  727. }
  728. }
  729. }
  730. function getSongAlbumArt(query, artistName){
  731. var albumart;
  732. var search = query;
  733. query = query.toLowerCase().split(" ").join("%20");
  734. var res = Meteor.http.get('https://api.spotify.com/v1/search?q=' + query + '&type=track');
  735. for(var i in res.data){
  736. for(var j in res.data[i].items){
  737. if(search.indexOf(res.data[i].items[j].name) !== -1 && artistName.indexOf(res.data[i].items[j].artists[0].name) !== -1){
  738. albumart = res.data[i].items[j].album.images[1].url
  739. return albumart;
  740. }
  741. }
  742. }
  743. }
  744. //var room_types = ["edm", "nightcore"];
  745. var songsArr = [];
  746. function getSongsByType(type) {
  747. if (type === "edm") {
  748. return [
  749. {id: "aE2GCa-_nyU", title: "Radioactive", duration: getSongDuration("Radioactive - Lindsey Stirling and Pentatonix", "Lindsey Stirling, Pentatonix"), artist: "Lindsey Stirling, Pentatonix", type: "youtube", img: "https://i.scdn.co/image/62167a9007cef2e8ef13ab1d93019312b9b03655"},
  750. {id: "aHjpOzsQ9YI", title: "Crystallize", artist: "Lindsey Stirling", duration: getSongDuration("Crystallize", "Lindsey Stirling"), type: "youtube", img: "https://i.scdn.co/image/b0c1ccdd0cd7bcda741ccc1c3e036f4ed2e52312"}
  751. ];
  752. } else if (type === "nightcore") {
  753. return [{id: "f7RKOP87tt4", title: "Monster (DotEXE Remix)", duration: getSongDuration("Monster (DotEXE Remix)", "Meg & Dia"), artist: "Meg & Dia", type: "youtube", img: "https://i.scdn.co/image/35ecdfba9c31a6c54ee4c73dcf1ad474c560cd00"}];
  754. } else {
  755. return [{id: "dQw4w9WgXcQ", title: "Never Gonna Give You Up", duration: getSongDuration("Never Gonna Give You Up", "Rick Astley"), artist: "Rick Astley", type: "youtube", img: "https://i.scdn.co/image/5246898e19195715e65e261899baba890a2c1ded"}];
  756. }
  757. }
  758. Rooms.find({}).fetch().forEach(function(room) {
  759. var type = room.type;
  760. if (Playlists.find({type: type}).count() === 0) {
  761. if (type === "edm") {
  762. Playlists.insert({type: type, songs: getSongsByType(type)});
  763. } else if (type === "nightcore") {
  764. Playlists.insert({type: type, songs: getSongsByType(type)});
  765. } else {
  766. Playlists.insert({type: type, songs: getSongsByType(type)});
  767. }
  768. }
  769. if (History.find({type: type}).count() === 0) {
  770. History.insert({type: type, history: []});
  771. }
  772. if (Playlists.find({type: type}).fetch()[0].songs.length === 0) {
  773. // Add a global video to Playlist so it can proceed
  774. } else {
  775. var startedAt = Date.now();
  776. var playlist = Playlists.find({type: type}).fetch()[0];
  777. var songs = playlist.songs;
  778. if (playlist.lastSong === undefined) {
  779. Playlists.update({type: type}, {$set: {lastSong: 0}});
  780. playlist = Playlists.find({type: type}).fetch()[0];
  781. songs = playlist.songs;
  782. }
  783. var currentSong = playlist.lastSong;
  784. addToHistory(songs[currentSong], startedAt);
  785. function addToHistory(song, startedAt) {
  786. History.update({type: type}, {$push: {history: {song: song, started: startedAt}}});
  787. }
  788. function skipSong() {
  789. songs = Playlists.find({type: type}).fetch()[0].songs;
  790. if (currentSong < (songs.length - 1)) {
  791. currentSong++;
  792. } else currentSong = 0;
  793. Playlists.update({type: type}, {$set: {lastSong: currentSong}});
  794. songTimer();
  795. addToHistory(songs[currentSong], startedAt);
  796. }
  797. function songTimer() {
  798. startedAt = Date.now();
  799. Meteor.setTimeout(function() {
  800. skipSong();
  801. }, songs[currentSong].duration * 1000);
  802. }
  803. songTimer();
  804. }
  805. });
  806. Accounts.onCreateUser(function(options, user) {
  807. var username;
  808. if (user.services) {
  809. if (user.services.github) {
  810. username = user.services.github.username;
  811. } else if (user.services.facebook) {
  812. username = user.services.facebook.first_name;
  813. } else if (user.services.password) {
  814. username = user.username;
  815. }
  816. }
  817. user.profile = {username: username, usernameL: username.toLowerCase(), rank: "default"};
  818. return user;
  819. });
  820. ServiceConfiguration.configurations.remove({
  821. service: "facebook"
  822. });
  823. ServiceConfiguration.configurations.insert({
  824. service: "facebook",
  825. appId: "1496014310695890",
  826. secret: "9a039f254a08a1488c08bb0737dbd2a6"
  827. });
  828. ServiceConfiguration.configurations.remove({
  829. service: "github"
  830. });
  831. ServiceConfiguration.configurations.insert({
  832. service: "github",
  833. clientId: "dcecd720f47c0e4001f7",
  834. secret: "375939d001ef1a0ca67c11dbf8fb9aeaa551e01b"
  835. });
  836. Meteor.publish("history", function() {
  837. return History.find({})
  838. });
  839. Meteor.publish("playlists", function() {
  840. return Playlists.find({})
  841. });
  842. Meteor.publish("rooms", function() {
  843. return Rooms.find({});
  844. });
  845. Meteor.publish("queues", function() {
  846. return Queues.find({});
  847. });
  848. Meteor.publish("chat", function() {
  849. return Chat.find({});
  850. });
  851. Meteor.publish("userProfiles", function() {
  852. //console.log(Meteor.users.find({}, {profile: 1, createdAt: 1, services: 0, username: 0, emails: 0})).fetch();
  853. return Meteor.users.find({}, {fields: {profile: 1, createdAt: 1}});
  854. });
  855. Meteor.publish("isAdmin", function() {
  856. return Meteor.users.find({_id: this.userId, "profile.rank": "admin"});
  857. });
  858. Meteor.methods({
  859. createUserMethod: function(formData, captchaData) {
  860. var verifyCaptchaResponse = reCAPTCHA.verifyCaptcha(this.connection.clientAddress, captchaData);
  861. if (!verifyCaptchaResponse.success) {
  862. console.log('reCAPTCHA check failed!', verifyCaptchaResponse);
  863. throw new Meteor.Error(422, 'reCAPTCHA Failed: ' + verifyCaptchaResponse.error);
  864. } else {
  865. console.log('reCAPTCHA verification passed!');
  866. Accounts.createUser({
  867. username: formData.username,
  868. email: formData.email,
  869. password: formData.password
  870. });
  871. }
  872. return true;
  873. },
  874. addSongToQueue: function(type, songData) {
  875. if (Meteor.userId()) {
  876. type = type.toLowerCase();
  877. if (Rooms.find({type: type}).count() === 1) {
  878. if (Queues.find({type: type}).count() === 0) {
  879. Queues.insert({type: type, songs: []});
  880. }
  881. if (songData !== undefined && Object.keys(songData).length === 5 && songData.type !== undefined && songData.title !== undefined && songData.title !== undefined && songData.artist !== undefined && songData.img !== undefined) {
  882. songData.duration = getSongDuration(songData.title, songData.artist);
  883. songData.img = getSongAlbumArt(songData.title, songData.artist);
  884. Queues.update({type: type}, {
  885. $push: {
  886. songs: {
  887. id: songData.id,
  888. title: songData.title,
  889. artist: songData.artist,
  890. duration: songData.duration,
  891. img: songData.img,
  892. type: songData.type
  893. }
  894. }
  895. });
  896. return true;
  897. } else {
  898. throw new Meteor.error(403, "Invalid data.");
  899. }
  900. } else {
  901. throw new Meteor.error(403, "Invalid genre.");
  902. }
  903. } else {
  904. throw new Meteor.error(403, "Invalid permissions.");
  905. }
  906. },
  907. updateQueueSong: function(genre, oldSong, newSong) {
  908. var userData = Meteor.users.find(Meteor.userId());
  909. if (Meteor.userId() && userData.count !== 0 && userData.fetch()[0].profile.rank === "admin") {
  910. newSong.id = oldSong.id;
  911. Queues.update({type: genre, "songs": oldSong}, {$set: {"songs.$": newSong}});
  912. return true;
  913. } else {
  914. throw new Meteor.error(403, "Invalid permissions.");
  915. }
  916. },
  917. removeSongFromQueue: function(type, songId) {
  918. var userData = Meteor.users.find(Meteor.userId());
  919. if (Meteor.userId() && userData.count !== 0 && userData.fetch()[0].profile.rank === "admin") {
  920. type = type.toLowerCase();
  921. Queues.update({type: type}, {$pull: {songs: {id: songId}}});
  922. } else {
  923. throw new Meteor.error(403, "Invalid permissions.");
  924. }
  925. },
  926. addSongToPlaylist: function(type, songData) {
  927. var userData = Meteor.users.find(Meteor.userId());
  928. if (Meteor.userId() && userData.count !== 0 && userData.fetch()[0].profile.rank === "admin") {
  929. type = type.toLowerCase();
  930. if (Rooms.find({type: type}).count() === 1) {
  931. if (Playlists.find({type: type}).count() === 0) {
  932. Playlists.insert({type: type, songs: []});
  933. }
  934. if (songData !== undefined && Object.keys(songData).length === 6 && songData.type !== undefined && songData.title !== undefined && songData.title !== undefined && songData.artist !== undefined && songData.duration !== undefined && songData.img !== undefined) {
  935. Playlists.update({type: type}, {
  936. $push: {
  937. songs: {
  938. id: songData.id,
  939. title: songData.title,
  940. artist: songData.artist,
  941. duration: songData.duration,
  942. img: songData.img,
  943. type: songData.type
  944. }
  945. }
  946. });
  947. Queues.update({type: type}, {$pull: {songs: {id: songData.id}}});
  948. return true;
  949. } else {
  950. throw new Meteor.error(403, "Invalid data.");
  951. }
  952. } else {
  953. throw new Meteor.error(403, "Invalid genre.");
  954. }
  955. } else {
  956. throw new Meteor.error(403, "Invalid permissions.");
  957. }
  958. },
  959. createRoom: function(type) {
  960. var userData = Meteor.users.find(Meteor.userId());
  961. if (Meteor.userId() && userData.count !== 0 && userData.fetch()[0].profile.rank === "admin") {
  962. if (Rooms.find({type: type}).count() === 0) {
  963. Rooms.insert({type: type}, function(err) {
  964. if (err) {
  965. throw err;
  966. } else {
  967. if (Playlists.find({type: type}).count() === 1) {
  968. if (History.find({type: type}).count() === 0) {
  969. History.insert({type: type, history: []}, function(err3) {
  970. if (err3) {
  971. throw err3;
  972. } else {
  973. startStation();
  974. return true;
  975. }
  976. });
  977. } else {
  978. startStation();
  979. return true;
  980. }
  981. } else {
  982. Playlists.insert({type: type, songs: getSongsByType(type)}, function (err2) {
  983. if (err2) {
  984. throw err2;
  985. } else {
  986. if (History.find({type: type}).count() === 0) {
  987. History.insert({type: type, history: []}, function(err3) {
  988. if (err3) {
  989. throw err3;
  990. } else {
  991. startStation();
  992. return true;
  993. }
  994. });
  995. } else {
  996. startStation();
  997. return true;
  998. }
  999. }
  1000. });
  1001. }
  1002. }
  1003. });
  1004. } else {
  1005. throw "Room already exists";
  1006. }
  1007. } else {
  1008. return false;
  1009. }
  1010. function startStation() {
  1011. var startedAt = Date.now();
  1012. var songs = Playlists.find({type: type}).fetch()[0].songs;
  1013. var currentSong = 0;
  1014. addToHistory(songs[currentSong], startedAt);
  1015. function addToHistory(song, startedAt) {
  1016. History.update({type: type}, {$push: {history: {song: song, started: startedAt}}});
  1017. }
  1018. function skipSong() {
  1019. songs = Playlists.find({type: type}).fetch()[0].songs;
  1020. if (currentSong < (songs.length - 1)) {
  1021. currentSong++;
  1022. } else currentSong = 0;
  1023. songTimer();
  1024. addToHistory(songs[currentSong], startedAt);
  1025. }
  1026. function songTimer() {
  1027. startedAt = Date.now();
  1028. Meteor.setTimeout(function() {
  1029. skipSong();
  1030. }, songs[currentSong].duration * 1000);
  1031. }
  1032. songTimer();
  1033. }
  1034. }
  1035. });
  1036. }
  1037. /*Router.waitOn(function() {
  1038. Meteor.subscribe("isAdmin", Meteor.userId());
  1039. });*/
  1040. /*Router.onBeforeAction(function() {
  1041. /*Meteor.autorun(function () {
  1042. if (admin.ready()) {
  1043. this.next();
  1044. }
  1045. });*/
  1046. /*this.next();
  1047. });*/
  1048. Router.route("/", {
  1049. template: "home"
  1050. });
  1051. Router.route("/terms", {
  1052. template: "terms"
  1053. });
  1054. Router.route("/privacy", {
  1055. template: "privacy"
  1056. });
  1057. Router.route("/about", {
  1058. template: "about"
  1059. });
  1060. Router.route("/admin", {
  1061. waitOn: function() {
  1062. return Meteor.subscribe("isAdmin", Meteor.userId());
  1063. },
  1064. action: function() {
  1065. var user = Meteor.users.find({}).fetch();
  1066. if (user[0] !== undefined && user[0].profile !== undefined && user[0].profile.rank === "admin") {
  1067. this.render("admin");
  1068. } else {
  1069. this.redirect("/");
  1070. }
  1071. }
  1072. });
  1073. Router.route("/:type", {
  1074. template: "room"
  1075. });
  1076. Router.route("/u/:user", {
  1077. template: "profile"
  1078. });