b601e18197766165eb72f746fe2f661850aa864b
[DeezloaderRemix.git] / app / public / js / main.js
1 // Starting area, boot up the API and proceed to eat memory
2
3 // Variables & constants
4 const socket = io.connect(window.location.href);
5 if(typeof mainApp !== "undefined"){
6         var defaultUserSettings = mainApp.defaultSettings;
7         var defaultDownloadLocation = mainApp.defaultDownloadDir;
8 }
9 let userSettings = [];
10 let Username = "";
11
12 let preview_track = document.getElementById('preview-track');
13 let preview_stopped = true;
14
15 function sleep(milliseconds) {
16   var start = new Date().getTime();
17   for (var i = 0; i < 1e7; i++) {
18     if ((new Date().getTime() - start) > milliseconds){
19       break;
20     }
21   }
22 }
23
24 socket.emit("autologin");
25
26 socket.on("message", function(title, msg){
27         message(title, msg);
28 });
29
30 //Login button
31 $('#modal_login_btn_login').click(function () {
32         $('#modal_login_btn_login').attr("disabled", true);
33         $('#modal_login_btn_login').html("Logging in...");
34         var username = $('#modal_login_input_username').val();
35         var password = $('#modal_login_input_password').val();
36         var autologin = $('#modal_login_input_autologin').prop("checked");
37         //Send to the software
38         Username = username;
39         socket.emit('login', username, password,autologin);
40 });
41
42 socket.on("autologin",function(username,password){
43         $('#modal_login_input_autologin').prop('checked', true);
44         $('#modal_login_btn_login').attr("disabled", true);
45         $('#modal_login_btn_login').html("Logging in...");
46         $('#modal_login_input_username').val(username);
47         Username = username;
48         $('#modal_login_input_password').val(password);
49         M.updateTextFields();
50         socket.emit('login', username, password,false);
51 });
52 socket.on("login", function (errmsg) {
53         if (errmsg == "none") {
54                 $("#modal_settings_username").html(Username);
55                 $('#initializing').addClass('animated fadeOut').on('webkitAnimationEnd', function () {
56                         $(this).css('display', 'none');
57                         $(this).removeClass('animated fadeOut');
58                 });
59
60         // Load top charts list for countries
61         socket.emit("getChartsCountryList", {selected: userSettings.chartsCountry});
62         socket.emit("getChartsTrackListByCountry", {country: userSettings.chartsCountry});
63         }
64         else{
65                         $('#login-res-text').text(errmsg);
66                         setTimeout(function(){$('#login-res-text').text("");},1000);
67         }
68         $('#modal_login_btn_login').attr("disabled", false);
69         $('#modal_login_btn_login').html("Login");
70 });
71
72 // Open downloads folder
73 $('#openDownloadsFolder').on('click', function () {
74         if(typeof shell !== "undefined"){
75                 shell.showItemInFolder(userSettings.downloadLocation + path.sep + '.');
76         }else{
77                 alert("For security reasons, this button will do nothing.");
78         }
79 });
80
81 // Do misc stuff on page load
82 $(document).ready(function () {
83         M.AutoInit();
84         preview_track.volume = 0;
85
86         $(window).scroll(function () {
87                 if ($(this).scrollTop() > 100) {
88                         $('#btn_scrollToTop a').removeClass('scale-out').addClass('scale-in');
89                 } else {
90                         $('#btn_scrollToTop a').removeClass('scale-in').addClass('scale-out');
91                 }
92         });
93
94         $('#btn_scrollToTop').click(function () {
95                 $('html, body').animate({scrollTop: 0}, 800);
96                 return false;
97         });
98
99         $(preview_track).on('canplay', ()=>{
100                 preview_track.play();
101                 preview_stopped = false;
102                 $(preview_track).animate({volume: 1}, 500);
103         });
104
105         $(preview_track).on('timeupdate', ()=>{
106                 if (preview_track.currentTime > preview_track.duration-1){
107                         $(preview_track).animate({volume: 0}, 800);
108                         preview_stopped = true;
109                         $("*").removeProp("playing");
110                         $('.preview_controls').text("play_arrow");
111                 }
112         })
113
114         $('.modal').modal();
115
116 });
117
118 // Load settings
119 socket.emit("getUserSettings");
120 socket.on('getUserSettings', function (data) {
121         userSettings = data.settings;
122         console.log('Settings refreshed');
123 });
124
125 /**
126  *      Modal Area START
127  */
128
129 // Prevent default behavior of closing button
130 $('.modal-close').click(function (e) {
131         e.preventDefault();
132 });
133
134 // Settings Modal START
135 const $settingsAreaParent = $('#modal_settings');
136
137 // Open settings panel
138 $('#nav_btn_openSettingsModal').click(function () {
139         fillSettingsModal(userSettings);
140 });
141
142 // Save settings button
143 $('#modal_settings_btn_saveSettings').click(function () {
144         let settings = {};
145
146         // Save
147         settings.userDefined = {
148                 trackNameTemplate: $('#modal_settings_input_trackNameTemplate').val(),
149                 playlistTrackNameTemplate: $('#modal_settings_input_playlistTrackNameTemplate').val(),
150                 albumTrackNameTemplate: $('#modal_settings_input_albumTrackNameTemplate').val(),
151                 albumNameTemplate: $('#modal_settings_input_albumNameTemplate').val(),
152                 createM3UFile: $('#modal_settings_cbox_createM3UFile').is(':checked'),
153                 createArtistFolder: $('#modal_settings_cbox_createArtistFolder').is(':checked'),
154                 createAlbumFolder: $('#modal_settings_cbox_createAlbumFolder').is(':checked'),
155                 downloadLocation: $('#modal_settings_input_downloadTracksLocation').val(),
156                 artworkSize: $('#modal_settings_select_artworkSize').val(),
157                 hifi: $('#modal_settings_cbox_hifi').is(':checked'),
158                 padtrck: $('#modal_settings_cbox_padtrck').is(':checked'),
159                 syncedlyrics: $('#modal_settings_cbox_syncedlyrics').is(':checked'),
160                 numplaylistbyalbum: $('#modal_settings_cbox_numplaylistbyalbum').is(':checked'),
161                 extendedTags: $('#modal_settings_cbox_extendedTags').is(':checked'),
162                 partOfSet: $('#modal_settings_cbox_partOfSet').is(':checked'),
163                 chartsCountry: $('#modal_settings_select_chartsCounrty').val()
164         };
165
166         // Send updated settings to be saved into config file
167         socket.emit('saveSettings', settings);
168         socket.emit("getUserSettings");
169 });
170
171 // Reset defaults button
172 $('#modal_settings_btn_defaultSettings').click(function () {
173         if(typeof defaultDownloadLocation !== "undefined"){
174                 defaultUserSettings.downloadLocation = defaultDownloadLocation;
175                 fillSettingsModal(defaultUserSettings);
176         }
177 });
178
179 $('#modal_login_btn_signup').click(function(){
180         if(typeof shell != 'undefined'){
181                 shell.openExternal("https://www.deezer.com/register");
182         }else{
183                 window.open("https://www.deezer.com/register");
184         }
185 });
186
187 $('#modal_settings_btn_logout').click(function () {
188                 $('#initializing').css('display', '');
189                 $('#initializing').addClass('animated fadeIn').on('webkitAnimationEnd', function () {
190                         $(this).removeClass('animated fadeIn');
191                         $(this).css('display', '');
192                 });
193                 socket.emit('logout');
194                 $('#modal_login_input_username').val("");
195                 $('#modal_login_input_password').val("");
196                 $('#modal_login_input_autologin').prop("checked",false);
197 });
198
199 // Populate settings fields
200 function fillSettingsModal(settings) {
201         $('#modal_settings_input_trackNameTemplate').val(settings.trackNameTemplate);
202         $('#modal_settings_input_playlistTrackNameTemplate').val(settings.playlistTrackNameTemplate);
203         $('#modal_settings_input_albumTrackNameTemplate').val(settings.albumTrackNameTemplate);
204         $('#modal_settings_input_albumNameTemplate').val(settings.albumNameTemplate);
205         $('#modal_settings_cbox_createM3UFile').prop('checked', settings.createM3UFile);
206         $('#modal_settings_cbox_createArtistFolder').prop('checked', settings.createArtistFolder);
207         $('#modal_settings_cbox_createAlbumFolder').prop('checked', settings.createAlbumFolder);
208         $('#modal_settings_cbox_hifi').prop('checked', settings.hifi);
209         $('#modal_settings_cbox_padtrck').prop('checked', settings.padtrck);
210         $('#modal_settings_cbox_syncedlyrics').prop('checked', settings.syncedlyrics);
211         $('#modal_settings_cbox_numplaylistbyalbum').prop('checked', settings.numplaylistbyalbum);
212         $('#modal_settings_input_downloadTracksLocation').val(settings.downloadLocation);
213         $('#modal_settings_select_artworkSize').val(settings.artworkSize).formSelect();
214         $('#modal_settings_cbox_extendedTags').prop('checked', settings.extendedTags);
215         $('#modal_settings_cbox_partOfSet').prop('checked', settings.partOfSet);
216         $('#modal_settings_select_chartsCounrty').val(settings.chartsCountry).formSelect();
217
218         M.updateTextFields()
219 }
220
221
222 //#############################################MODAL_MSG##############################################\\
223 function message(title, message) {
224
225         $('#modal_msg_title').html(title);
226
227         $('#modal_msg_message').html(message);
228
229         $('#modal_msg').modal('open');
230
231 }
232
233 //****************************************************************************************************\\
234 //************************************************TABS************************************************\\
235 //****************************************************************************************************\\
236
237 //###############################################TAB_URL##############################################\\
238 $('#tab_url_form_url').submit(function (ev) {
239
240         ev.preventDefault();
241
242         var urls = $("#song_url").val().split(";");
243         console.log(urls);
244         for(var i = 0; i < urls.length; i++){
245                 var url = urls[i];
246                 console.log(url);
247
248                 //Validate URL
249                 if (url.indexOf('deezer.com/') < 0 && url.indexOf('open.spotify.com/') < 0 && url.indexOf('spotify:')) {
250                         message('Wrong URL', 'The URL seems to be wrong. Please check it and try it again.');
251                         return false;
252                 }
253
254                 if (url.indexOf('?') > -1) {
255                         url = url.substring(0, url.indexOf("?"));
256                 }
257
258                 if (url.indexOf('open.spotify.com/') >= 0){
259                         if (url.indexOf('user') < 0 || url.indexOf('playlist') < 0){
260                                 message('Playlist not found', 'The URL seems to be wrong. Please check it and try it again.');
261                                 return false;
262                         }
263                         addToQueue(url, true);
264                 }else{
265                         addToQueue(url);
266                 }
267         }
268 });
269
270 //#############################################TAB_SEARCH#############################################\\
271 $('#tab_search_form_search').submit(function (ev) {
272
273         ev.preventDefault();
274
275         var searchString = $('#tab_search_form_search_input_searchString').val().trim();
276         var mode = $('#tab_search_form_search').find('input[name=searchMode]:checked').val();
277
278         if (searchString.length == 0) {
279                 message('Search can\'t be empty', 'You tried to search for nothing. But if you search nothing, you\'ll find nothing. So don\'t try it again.');
280
281                 return;
282         }
283
284         $('#tab_search_table_results').find('thead').find('tr').addClass('hide');
285         $('#tab_search_table_results_tbody_results').addClass('hide');
286         $('#tab_search_table_results_tbody_noResults').addClass('hide');
287         $('#tab_search_table_results_tbody_loadingIndicator').removeClass('hide');
288
289
290         socket.emit("search", {type: mode, text: searchString});
291
292 });
293
294 socket.on('search', function (data) {
295
296         $('#tab_search_table_results_tbody_loadingIndicator').addClass('hide');
297
298         if (data.items.length == 0) {
299                 $('#tab_search_table_results_tbody_noResults').removeClass('hide');
300                 return;
301         }
302
303         if (data.type == 'track') {
304
305                 showResults_table_track(data.items);
306
307         } else if (data.type == 'album') {
308
309                 showResults_table_album(data.items);
310
311         } else if (data.type == 'artist') {
312
313                 showResults_table_artist(data.items);
314
315         } else if (data.type == 'playlist') {
316
317                 showResults_table_playlist(data.items);
318
319         }
320
321         $('#tab_search_table_results_tbody_results').removeClass('hide');
322
323 });
324
325 function showResults_table_track(tracks) {
326
327         var tableBody = $('#tab_search_table_results_tbody_results');
328
329         $(tableBody).html('');
330
331         $('#tab_search_table_results_thead_track').removeClass('hide');
332
333         for (var i = 0; i < tracks.length; i++) {
334
335                 var currentResultTrack = tracks[i];
336
337                 $(tableBody).append(
338                         '<tr class="animated fadeInUp">' +
339                         '<td><a href="#" class="circle single-cover" preview="'+currentResultTrack['preview']+'"><i class="material-icons preview_controls white-text">play_arrow</i><img class="circle" src="' + currentResultTrack['album']['cover_small'] + '"/></a></td>' +
340                         '<td>' + currentResultTrack['title'] + (currentResultTrack.explicit_lyrics ? ' <i class="material-icons valignicon tiny materialize-red-text">error_outline</i>' : '')+ '</td>' +
341                         '<td>' + currentResultTrack['artist']['name'] + '</td>' +
342                         '<td>' + currentResultTrack['album']['title'] + '</td>' +
343                         '<td>' + convertDuration(currentResultTrack['duration']) + '</td>' +
344                         '</tr>');
345
346                 generateDownloadLink(currentResultTrack['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
347
348         }
349
350         reloadPreviewPlayers()
351 }
352
353 function reloadPreviewPlayers(){
354         $('.preview_controls').hover( function () {
355                 $(this).css({opacity: 1});
356         }, function () {
357                 if (($(this).parent().prop("playing") && preview_stopped) || !$(this).parent().prop("playing")){
358                         $(this).css({opacity: 0}, 200);
359                 }
360         });
361
362         $('.single-cover').click(function (e) {
363                 e.preventDefault();
364                 if ($(this).prop("playing")){
365                         if (preview_track.paused){
366                                 preview_track.play();
367                                 preview_stopped = false;
368                                 $(this).children('i').text("pause");
369                                 $(preview_track).animate({volume: 1}, 500);
370                         }else{
371                                 preview_stopped = true;
372                                 $(this).children('i').text("play_arrow");
373                                 $(preview_track).animate({volume: 0}, 250, "swing", ()=>{ preview_track.pause() });
374                         }
375                 }else{
376                         $("*").removeProp("playing");
377                         $(this).prop("playing","playing");
378                         $('.preview_controls').text("play_arrow");
379                         $('.preview_controls').css({opacity:0});
380                         $(this).children('i').text("pause");
381                         $(this).children('i').css({opacity: 1});
382                         preview_stopped = false;
383                         $(preview_track).animate({volume: 0}, 250, "swing", ()=>{
384                                 preview_track.pause();
385                                 $('#preview-track_source').prop("src", $(this).attr("preview"));
386                                 preview_track.load();
387                         });
388                 }
389         });
390 }
391
392 function showResults_table_album(albums) {
393
394         var tableBody = $('#tab_search_table_results_tbody_results');
395
396         $(tableBody).html('');
397         $('#tab_search_table_results_thead_album').removeClass('hide');
398
399         for (var i = 0; i < albums.length; i++) {
400
401                 var currentResultAlbum = albums[i];
402
403                 $(tableBody).append(
404                                 '<tr class="animated fadeInUp">' +
405                                 '<td><img src="' + currentResultAlbum['cover_small'] + '" class="circle" /></td>' +
406                                 (currentResultAlbum.explicit_lyrics ? '<td><i class="material-icons valignicon tiny materialize-red-text tooltipped" data-tooltip="Explicit">error_outline</i> ' : '<td> ') + currentResultAlbum['title'] + '</td>' +
407                                 '<td>' + currentResultAlbum['artist']['name'] + '</td>' +
408                                 '<td>' + currentResultAlbum['nb_tracks'] + '</td>' +
409                                 '<td>' + currentResultAlbum['record_type'] + '</td>' +
410                                 '</tr>');
411
412                 generateShowTracklistSelectiveButton(currentResultAlbum['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
413                 generateDownloadLink(currentResultAlbum['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
414
415         }
416         $('.tooltipped').tooltip({delay: 100});
417 }
418
419 function showResults_table_artist(artists) {
420
421         var tableBody = $('#tab_search_table_results_tbody_results');
422
423         $(tableBody).html('');
424
425         $('#tab_search_table_results_thead_artist').removeClass('hide');
426
427         for (var i = 0; i < artists.length; i++) {
428
429                 var currentResultArtist = artists[i];
430
431                 $(tableBody).append(
432                                 '<tr class="animated fadeInUp">' +
433                                 '<td><img src="' + currentResultArtist['picture_small'] + '" class="circle" /></td>' +
434                                 '<td>' + currentResultArtist['name'] + '</td>' +
435                                 '<td>' + currentResultArtist['nb_album'] + '</td>' +
436                                 '</tr>');
437
438                 generateShowTracklistButton(currentResultArtist['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
439                 generateDownloadLink(currentResultArtist['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
440
441         }
442
443 }
444
445 function showResults_table_playlist(playlists) {
446
447         var tableBody = $('#tab_search_table_results_tbody_results');
448
449         $(tableBody).html('');
450
451         $('#tab_search_table_results_thead_playlist').removeClass('hide');
452
453         for (var i = 0; i < playlists.length; i++) {
454
455                 var currentResultPlaylist = playlists[i];
456
457                 $(tableBody).append(
458                                 '<tr class="animated fadeInUp">' +
459                                 '<td><img src="' + currentResultPlaylist['picture_small'] + '" class="circle" /></td>' +
460                                 '<td>' + currentResultPlaylist['title'] + '</td>' +
461                                 '<td>' + currentResultPlaylist['nb_tracks'] + '</td>' +
462                                 '</tr>');
463
464                 generateShowTracklistSelectiveButton(currentResultPlaylist['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
465                 generateDownloadLink(currentResultPlaylist['link']).appendTo(tableBody.children('tr:last')).wrap('<td>');
466
467         }
468         $('.tooltipped').tooltip({delay: 100});
469 }
470
471 function generateShowTracklistSelectiveButton(link) {
472
473         var btn_showTrackListSelective = $('<a href="#" class="waves-effect btn-flat"><i class="material-icons">list</i></a>');
474
475         $(btn_showTrackListSelective).click(function (ev){
476                 ev.preventDefault();
477
478                 showTrackListSelective(link);
479         });
480
481         return btn_showTrackListSelective;
482 }
483
484 function generateShowTracklistButton(link) {
485
486         var btn_showTrackList = $('<a href="#" class="waves-effect btn-flat"><i class="material-icons">list</i></a>');
487
488         $(btn_showTrackList).click(function (ev) {
489
490                 ev.preventDefault();
491
492                 showTrackList(link);
493
494         });
495
496         return btn_showTrackList;
497
498 }
499
500 var trackListSelectiveModalApp = new Vue({
501         el: '#modal_trackListSelective',
502         data: {
503                 title: null,
504                 head: null,
505                 body: []
506         }
507 });
508
509 var trackListModalApp = new Vue({
510         el: '#modal_trackList',
511         data: {
512                 title: null,
513                 head: null,
514                 body: []
515         }
516 });
517
518 function showTrackListSelective(link) {
519
520         $('#modal_trackListSelective_table_trackListSelective_tbody_trackListSelective').addClass('hide');
521         $('#modal_trackListSelective_table_trackListSelective_tbody_loadingIndicator').removeClass('hide');
522
523         $('#modal_trackListSelective').modal('open');
524
525         socket.emit('getTrackList', {id: getIDFromLink(link), type: getTypeFromLink(link)});
526 }
527
528 $('#download_track_selection').click(function(e){
529         e.preventDefault();
530         var urls = [];
531         $("input:checkbox.trackCheckbox:checked").each(function(){
532                 urls.push($(this).val());
533         });
534
535         if(urls.length != 0){
536                 for (var ia = 0; ia < urls.length; ia++) {
537                         addToQueue(urls[ia]);
538                 }
539         }
540         $('#modal_trackListSelective').modal('close');
541 });
542
543 function showTrackList(link) {
544
545         $('#modal_trackList_table_trackList_tbody_trackList').addClass('hide');
546         $('#modal_trackList_table_trackList_tbody_loadingIndicator').removeClass('hide');
547
548         $('#modal_trackList').modal('open');
549
550         socket.emit("getTrackList", {id: getIDFromLink(link), type: getTypeFromLink(link)});
551
552 }
553 socket.on("getTrackList", function (data) {
554         //data.err                      -> undefined/err
555         //data.id                        -> passed id
556         //data.response -> API response
557
558         var trackList = data.response.data, content = '';
559         var trackListSelective = data.response.data, content = '';
560
561         if (typeof trackList == 'undefined') {
562                 alert('Well, there seems to be a problem with this part of the app. Please notify the developer.');
563                 return;
564         }
565
566         // ########################################
567         if(data.reqType == 'album' || data.reqType == 'playlist'){
568                 var tableBody = $('#modal_trackListSelective_table_trackListSelective_tbody_trackListSelective');
569         } else {
570                 var tableBody = $('#modal_trackList_table_trackList_tbody_trackList');
571         }
572
573         $(tableBody).html('');
574
575         //############################################
576
577         if (data.reqType == 'artist') {
578                 trackListModalApp.title = 'Album List';
579                 trackListModalApp.head = [
580                         {title: '#'},
581                         {title: ''},
582                         {title: 'Album Title'},
583                         {title: 'Release Date'},
584                         {title: 'Record Type'},
585                         {title: 'Download Album'}
586                 ];
587
588                 for (var i = 0; i < trackList.length; i++) {
589
590                         $(tableBody).append('<tr><td>' + (i + 1) + '</td>' +
591                                         (trackList[i].explicit_lyrics ? '<td><i class="material-icons valignicon tiny materialize-red-text tooltipped" data-tooltip="Explicit">error_outline</i></td>' : '<td></td>') +
592                                         '<td><a href="#" class="album_chip" data-link="' + trackList[i].link + '"><div class="chip"><img src="' + trackList[i].cover_small + '" />' + trackList[i].title + '</div></a></td>' +
593                                         '<td>' + trackList[i].release_date + '</td><td>' + trackList[i].record_type + '</td></tr>');
594
595                         generateDownloadLink(trackList[i].link).appendTo(tableBody.children('tr:last')).wrap('<td>');
596                 }
597         } else if(data.reqType == 'playlist') {
598                 trackListSelectiveModalApp.title = 'Playlist';
599
600                 trackListSelectiveModalApp.head = [
601                         {title: '#'},
602                         {title: 'Song'},
603                         {title: 'Artist'},
604                         {title: '<i class="material-icons">timer</i>'},
605                         {title: '<div class="valign-wrapper"><label><input class="selectAll" type="checkbox" id="selectAll"><span></span></label></div>'}
606                 ];
607
608                 $('.selectAll').prop('checked', false);
609
610                 for (var i = 0; i < trackList.length; i++) {
611                         $(tableBody).append('<tr><td>' + (i + 1) + '</td>' +
612                                         (trackList[i].explicit_lyrics ? '<td><i class="material-icons valignicon tiny materialize-red-text tooltipped" data-tooltip="Explicit">error_outline</i> ' : '<td> ') + trackList[i].title + '</td>' +
613                                         '<td>' + trackList[i].artist.name + '</td>' +
614                                         '<td>' + convertDuration(trackList[i].duration) + '</td>' +
615                                         '<td><div class="valign-wrapper"><label><input class="trackCheckbox valign" type="checkbox" id="trackChk'+ i +'" value="' + trackList[i].link + '"><span></span></label></div></tr>');
616                 }
617         } else if(data.reqType == 'album') {
618                 trackListSelectiveModalApp.title = 'Tracklist';
619
620                 trackListSelectiveModalApp.head = [
621                         {title: '#'},
622                         {title: 'Song'},
623                         {title: 'Artist'},
624                         {title: '<i class="material-icons">timer</i>'},
625                         {title: '<div class="valign-wrapper"><label><input class="selectAll" type="checkbox" id="selectAll"><span></span></label></div>'}
626                 ];
627
628                 $('.selectAll').prop('checked', false);
629
630                 if (trackList[trackList.length-1].disk_number != 1){
631                         baseDisc = 0
632                 } else {
633                         baseDisc =1
634                 };
635
636                 for (var i = 0; i < trackList.length; i++) {
637                         discNum = trackList[i].disk_number
638                         if (discNum != baseDisc){
639                                 $(tableBody).append('<tr><td colspan="4" style="opacity: 0.54;"><i class="material-icons valignicon tiny">album</i> '+discNum+'</td></tr>');
640                                 baseDisc = discNum;
641                         }
642                         $(tableBody).append('<tr><td>' + trackList[i].track_position + '</td>' +
643                                         (trackList[i].explicit_lyrics ? '<td><i class="material-icons valignicon tiny materialize-red-text tooltipped" data-tooltip="Explicit">error_outline</i> ' : '<td> ') + trackList[i].title + '</td>' +
644                                         '<td>' + trackList[i].artist.name + '</td>' +
645                                         '<td>' + convertDuration(trackList[i].duration) + '</td>' +
646                                         '<td><div class="valign-wrapper"><label><input class="trackCheckbox valign" type="checkbox" id="trackChk'+ i +'" value="' + trackList[i].link + '"><span></span></label></div></tr>');
647                 }
648         } else {
649                 trackListModalApp.title = 'Tracklist';
650                 trackListModalApp.head = [
651                         {title: '#'},
652                         {title: 'Song'},
653                         {title: 'Artist'},
654                         {title: '<i class="material-icons">timer</i>'}
655                 ];
656
657                 for (var i = 0; i < trackList.length; i++) {
658
659                         $(tableBody).append('<tr><td>' + (i + 1) + '</td>' +
660                                         (trackList[i].explicit_lyrics ? '<td><i class="material-icons valignicon tiny materialize-red-text tooltipped" data-tooltip="Explicit">error_outline</i> ' : '<td> ') +
661                                         trackList[i].title + '</td>' +
662                                         '<td>' + trackList[i].artist.name + '</td>' +
663                                         '<td>' + convertDuration(trackList[i].duration) + '</td></tr>');
664                 }
665         }
666         if(data.reqType == 'album' || data.reqType == 'playlist'){
667                 $('#modal_trackListSelective_table_trackListSelective_tbody_loadingIndicator').addClass('hide');
668                 $('#modal_trackListSelective_table_trackListSelective_tbody_trackListSelective').removeClass('hide');
669         } else {
670                 $('#modal_trackList_table_trackList_tbody_loadingIndicator').addClass('hide');
671                 $('#modal_trackList_table_trackList_tbody_trackList').removeClass('hide');
672         }
673
674         //$('#modal_trackList_table_trackList_tbody_trackList').html(content);
675
676         $('.album_chip').click(function(e){
677                 $('#modal_trackList').modal('close');
678                 showTrackListSelective($(this).data('link'));
679         });
680
681 });
682
683 //#############################################TAB_CHARTS#############################################\\
684 socket.on("getChartsCountryList", function (data) {
685         //data.countries                -> Array
686         //data.countries[0].country -> String (country name)
687         //data.countries[0].picture_small/picture_medium/picture_big -> url to cover
688
689         for (var i = 0; i < data.countries.length; i++) {
690                 $('#tab_charts_select_country').append('<option value="' + data.countries[i]['country'] + '" data-icon="' + data.countries[i]['picture_small'] + '" class="left circle">' + data.countries[i]['country'] + '</option>');
691                 $('#modal_settings_select_chartsCounrty').append('<option value="' + data.countries[i]['country'] + '" data-icon="' + data.countries[i]['picture_small'] + '" class="left circle">' + data.countries[i]['country'] + '</option>');
692         }
693
694         $('#tab_charts_select_country').find('option[value="' + data.selected + '"]').attr("selected", true);
695         $('#modal_settings_select_chartsCounrty').find('option[value="' + data.selected + '"]').attr("selected", true);
696
697         $('select').formSelect();
698 });
699
700 $('#tab_charts_select_country').on('change', function () {
701
702         var country = $(this).find('option:selected').val();
703
704         $('#tab_charts_table_charts_tbody_charts').addClass('hide');
705         $('#tab_charts_table_charts_tbody_loadingIndicator').removeClass('hide');
706
707         socket.emit("getChartsTrackListByCountry", {country: country});
708
709 });
710
711 socket.on("getChartsTrackListByCountry", function (data) {
712         //data.playlist         -> Object with Playlist information
713         //data.tracks                   -> Array
714         //data.tracks[0]         -> Object of track 0
715
716         var chartsTableBody = $('#tab_charts_table_charts_tbody_charts'), currentChartTrack;
717
718         chartsTableBody.html('');
719
720         for (var i = 0; i < data.tracks.length; i++) {
721
722                 currentChartTrack = data.tracks[i];
723
724                 $(chartsTableBody).append(
725                                 '<tr>' +
726                                 '<td>' + (i + 1) + '</td>' +
727                                 '<td><a href="#" class="circle single-cover" preview="'+currentChartTrack['preview']+'"><i class="material-icons preview_controls white-text">play_arrow</i><img src="' + currentChartTrack['album']['cover_small'] + '" class="circle" /></a></td>' +
728                                 '<td>' + currentChartTrack['title'] + '</td>' +
729                                 '<td>' + currentChartTrack['artist']['name'] + '</td>' +
730                                 '<td>' + currentChartTrack['album']['title'] + '</td>' +
731                                 '<td>' + convertDuration(currentChartTrack['duration']) + '</td>' +
732                                 '</tr>');
733
734                 generateDownloadLink(currentChartTrack['link']).appendTo(chartsTableBody.children('tr:last')).wrap('<td>');
735
736         }
737
738         reloadPreviewPlayers();
739
740         $('#tab_charts_table_charts_tbody_loadingIndicator').addClass('hide');
741         chartsTableBody.removeClass('hide');
742
743 });
744
745 //############################################TAB_DOWNLOADS###########################################\\
746 function addToQueue(url, spotify=false) {
747         if (!spotify){
748                 var type = getTypeFromLink(url), id = getIDFromLink(url);
749         } else {
750                 var type = 'spotifyplaylist', [user, id] = getPlayUserFromURI(url);
751                 userSettings.spotifyUser = user;
752         }
753
754         if (type == 'track') {
755                 userSettings.filename = userSettings.trackNameTemplate;
756                 userSettings.foldername = userSettings.albumNameTemplate;
757         } else if (type == 'playlist' || type == 'spotifyplaylist') {
758                 userSettings.filename = userSettings.playlistTrackNameTemplate;
759                 userSettings.foldername = userSettings.albumNameTemplate;
760         } else if (type == 'album' || type == 'artist'){
761                 userSettings.filename = userSettings.albumTrackNameTemplate;
762                 userSettings.foldername = userSettings.albumNameTemplate;
763         } else {
764                 $('#modal_wrongURL').modal('open');
765                 return false;
766         }
767
768         if (alreadyInQueue(id)) {
769                 M.toast({html: '<i class="material-icons">playlist_add_check</i>Already in download-queue!', displayLength: 5000, classes: 'rounded'});
770
771                 return false;
772         }
773
774         if (id.match(/^[0-9]+$/) == null && !spotify) {
775                 $('#modal_wrongURL').modal('open');
776
777                 return false;
778         }
779         socket.emit("download" + type, {id: id, settings: userSettings});
780
781         M.toast({html: '<i class="material-icons">add</i>Added to download-queue', displayLength: 5000, classes: 'rounded'});
782
783 }
784
785 function alreadyInQueue(id) {
786
787         var alreadyInQueue = false;
788
789         $('#tab_downloads_table_downloads').find('tbody').find('tr').each(function () {
790
791                 if ($(this).data('deezerid') == id) {
792                         alreadyInQueue = true;
793
794                         return false
795                 }
796
797         });
798
799         return alreadyInQueue;
800
801 }
802
803 socket.on('addToQueue', function (data) {
804
805         var tableBody = $('#tab_downloads_table_downloads').find('tbody');
806
807         $(tableBody).append(
808                         '<tr id="' + data.queueId + '" data-deezerid="' + data.id + '">' +
809                         '<td class="queueTitle">' + data.name + '</td>' +
810                         '<td class="queueSize">' + data.size + '</td>' +
811                         '<td class="queueDownloaded">' + data.downloaded + '</td>' +
812                         '<td class="queueFailed">' + data.failed + '</td>' +
813                         '<td><div class="progress"><div class="indeterminate"></div></div></td>' +
814                         '</tr>');
815
816         var btn_remove = $('<a href="#" class="btn-flat waves-effect"><i class="material-icons">remove</i></a>');
817
818         $(btn_remove).click(function (ev) {
819
820                 ev.preventDefault();
821
822                 socket.emit("cancelDownload", {queueId: data.queueId});
823
824         });
825
826         btn_remove.appendTo(tableBody.children('tr:last')).wrap('<td class="eventBtn center">');
827
828 });
829
830 socket.on("downloadStarted", function (data) {
831         //data.queueId -> queueId of started download
832
833         //Switch progress type indeterminate to determinate
834         $('#' + data.queueId).find('.indeterminate').removeClass('indeterminate').addClass('determinate');
835         $('#' + data.queueId).find('.eventBtn').find('a').html('<i class="material-icons">clear</i>');
836
837 });
838
839 socket.on('updateQueue', function (data) {
840
841         if (data.cancelFlag) {
842                 return;
843         }
844
845         $('#' + data.queueId).find('.queueDownloaded').html(data.downloaded);
846         $('#' + data.queueId).find('.queueFailed').html(data.failed);
847
848         if (data.failed == 0 && ((data.downloaded + data.failed) >= data.size)) {
849                 $('#' + data.queueId).find('.eventBtn').html('<i class="material-icons">done</i>');
850                 $('#' + data.queueId).addClass('finished');
851                 M.toast({html: '<i class="material-icons">done</i>One download completed!', displayLength: 5000, classes: 'rounded'})
852         } else if (data.downloaded == 0 && ((data.downloaded + data.failed) >= data.size)) {
853                 $('#' + data.queueId).find('.eventBtn').html('<i class="material-icons">error</i>');
854                 $('#' + data.queueId).addClass('error');
855                 M.toast({html: '<i class="material-icons">error</i>One download failed!', displayLength: 5000, classes: 'rounded'})
856         }
857
858 });
859
860 socket.on("downloadProgress", function (data) {
861         //data.queueId -> id (string)
862         //data.percentage -> float/double, percentage
863         //updated in 1% steps
864
865         $('#' + data.queueId).find('.determinate').css('width', data.percentage + '%');
866
867 });
868
869 socket.on("emptyDownloadQueue", function () {
870
871         M.toast({html: '<i class="material-icons">done_all</i>All downloads completed!', displayLength: 5000, classes: 'rounded'});
872
873 });
874
875 socket.on("cancelDownload", function (data) {
876         //data.queueId          -> queueId of item which was canceled
877         $('#' + data.queueId).addClass('animated fadeOutRight').on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
878                 $(this).remove();
879                 M.toast({html: '<i class="material-icons">clear</i>One download removed!', displayLength: 5000, classes: 'rounded'})
880         });
881 });
882
883 $('#clearTracksTable').click(function (ev) {
884
885         $('#tab_downloads_table_downloads').find('tbody').find('.finished', '.error').addClass('animated fadeOutRight').on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
886                 $(this).remove();
887         });
888
889         return false;
890
891 });
892
893 //****************************************************************************************************\\
894 //******************************************HELPER-FUNCTIONS******************************************\\
895 //****************************************************************************************************\\
896
897 /**
898  * Given a spotify playlist URL or URI it returns the username of the owner of the playlist and the ID of the playlist
899  * @param url URL or URI
900  * @return string[] Array containing user and playlist id
901  */
902 function getPlayUserFromURI(url){
903         var spotyUser, playlistID;
904         if ((url.startsWith("http") && url.indexOf('open.spotify.com/') >= 0)){
905                 if (url.indexOf('user') < 0 || url.indexOf('playlist') < 0){
906                         message('Playlist not found', 'The URL seems to be wrong. Please check it and try it again.');
907                         return [false,false];
908                 }
909                 if (url.indexOf('?') > -1) {
910                         url = url.substring(0, url.indexOf("?"));
911                 }
912                 spotyUser = url.slice(url.indexOf("/user/")+6);
913                 spotyUser = spotyUser.substring(0, spotyUser.indexOf("/"));
914                 playlistID = url.slice(url.indexOf("/playlist/")+10);
915         } else if (url.startsWith("spotify:")){
916                 spotyUser = url.slice(url.indexOf("user:")+5);
917                 spotyUser = spotyUser.substring(0, spotyUser.indexOf(":"));
918                 playlistID = url.slice(url.indexOf("playlist:")+9);
919         } else {
920                 return [false,false];
921         }
922         return [spotyUser, playlistID]
923 }
924
925 function getIDFromLink(link) {
926         return link.substring(link.lastIndexOf("/") + 1);
927 }
928
929 function getTypeFromLink(link) {
930
931         var type;
932
933         if (link.indexOf('track') > -1) {
934                 type = "track";
935         } else if (link.indexOf('playlist') > -1) {
936                 type = "playlist";
937         } else if (link.indexOf('album') > -1) {
938                 type = "album";
939         } else if (link.indexOf('artist')) {
940                 type = "artist";
941         }
942
943         return type;
944
945 }
946
947 function generateDownloadLink(url) {
948
949         var btn_download = $('<a href="#" class="waves-effect btn-flat"><i class="material-icons">file_download</i></a>');
950
951         $(btn_download).click(function (ev) {
952
953                 ev.preventDefault();
954
955                 addToQueue(url);
956
957         });
958
959         return btn_download;
960
961 }
962
963 function convertDuration(duration) {
964
965         //convert from seconds only to mm:ss format
966         var mm, ss;
967         mm = Math.floor(duration / 60);
968         ss = duration - (mm * 60);
969
970         //add leading zero if ss < 0
971         if (ss < 10) {
972                 ss = "0" + ss;
973         }
974
975         return mm + ":" + ss;
976
977 }