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