From 0b3420cb7146e0a33bfab6b07f4df9a8aaf1b725 Mon Sep 17 00:00:00 2001 From: Roberto Tonino Date: Sun, 19 Apr 2020 22:02:06 +0200 Subject: [PATCH] started refactoring of js --- public/index.html | 987 +++++++++++--------- public/js/app.js | 905 ++++++++++++++++++ public/js/app/app.js | 161 ---- public/js/app/downloadList.js | 183 ---- public/js/app/modals.js | 39 - public/js/app/search.js | 168 ---- public/js/app/settings.js | 54 -- public/js/app/stackedTabs.js | 198 ---- public/js/app/tabs.js | 102 -- public/js/modules/search-tab/main-search.js | 74 ++ public/js/{app => modules}/utils.js | 38 +- 11 files changed, 1529 insertions(+), 1380 deletions(-) create mode 100644 public/js/app.js delete mode 100644 public/js/app/app.js delete mode 100644 public/js/app/downloadList.js delete mode 100644 public/js/app/modals.js delete mode 100644 public/js/app/search.js delete mode 100644 public/js/app/settings.js delete mode 100644 public/js/app/stackedTabs.js delete mode 100644 public/js/app/tabs.js create mode 100644 public/js/modules/search-tab/main-search.js rename public/js/{app => modules}/utils.js (50%) diff --git a/public/index.html b/public/index.html index d47a25a..18ad9fe 100644 --- a/public/index.html +++ b/public/index.html @@ -1,477 +1,562 @@ + deemix - + +
- -
-
-
- - - - - -
-
- - - - - -
+
@@ -501,13 +586,7 @@

{{ metadata }}{{ rele - - - - - - - - - - + + + + \ No newline at end of file diff --git a/public/js/app.js b/public/js/app.js new file mode 100644 index 0000000..fa7c164 --- /dev/null +++ b/public/js/app.js @@ -0,0 +1,905 @@ +import * as Utils from './modules/utils.js' +import { MainSearch } from './modules/search-tab/main-search.js' + +const socket = io.connect(window.location.href) +const localStorage = window.localStorage + +// Toasts stuff +window.toastsWithId = {} + +// Settings +window.lastSettings = {} +window.lastCredentials = {} + +window.toast = function (msg, icon = null, dismiss = true, id = null) { + if (toastsWithId[id]) { + let toastObj = toastsWithId[id] + let toastDOM = $(`div.toastify[toast_id=${id}]`) + if (msg) { + toastDOM.find('.toast-message').html(msg) + } + if (icon) { + if (icon == 'loading') icon = `
` + else icon = `${icon}` + toastDOM.find('.toast-icon').html(icon) + } + if (dismiss !== null && dismiss) { + setTimeout(function () { + toastObj.hideToast() + delete toastsWithId[id] + }, 3000) + } + } else { + if (icon == null) icon = '' + else if (icon == 'loading') icon = `
` + else icon = `${icon}` + let toastObj = Toastify({ + text: `${icon}${msg}`, + duration: dismiss ? 3000 : 0, + gravity: 'bottom', + position: 'left' + }).showToast() + if (id) { + toastsWithId[id] = toastObj + $(toastObj.toastElement).attr('toast_id', id) + } + } +} + +/* ===== Socketio listeners ===== */ +socket.on('toast', data => { + toast(data.msg, data.icon || null, data.dismiss !== undefined ? data.dismiss : true, data.id || null) +}) + +// Debug messages for socketio +socket.on('message', function (msg) { + console.log(msg) +}) + +// Login stuff + +window.loginButton = function () { + let arl = document.querySelector('#login_input_arl').value + if (arl != '' && arl != localStorage.getItem('arl')) { + socket.emit('login', arl, true) + } +} + +socket.on('logging_in', function () { + toast('Logging in', 'loading', false, 'login-toast') +}) + +socket.on('logged_in', function (data) { + switch (data.status) { + case 1: + case 3: + toast('Logged in', 'done', true, 'login-toast') + if (data.arl) { + localStorage.setItem('arl', data.arl) + $('#login_input_arl').val(data.arl) + } + $('#open_login_prompt').hide() + if (data.user) { + $('#settings_username').text(data.user.name) + $('#settings_picture').attr( + 'src', + `https://e-cdns-images.dzcdn.net/images/user/${data.user.picture}/125x125-000000-80-0-0.jpg` + ) + $('#logged_in_info').show() + } + break + case 2: + toast('Already logged in', 'done', true, 'login-toast') + if (data.user) { + $('#settings_username').text(data.user.name) + $('#settings_picture').attr( + 'src', + `https://e-cdns-images.dzcdn.net/images/user/${data.user.picture}/125x125-000000-80-0-0.jpg` + ) + $('#logged_in_info').show() + } + break + case 0: + toast("Couldn't log in", 'close', true, 'login-toast') + localStorage.removeItem('arl') + $('#login_input_arl').val('') + $('#open_login_prompt').show() + $('#logged_in_info').hide() + $('#settings_username').text('Not Logged') + $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`) + break + } +}) + +socket.on('logged_out', function () { + toast('Logged out', 'done', true, 'login-toast') + localStorage.removeItem('arl') + $('#login_input_arl').val('') + $('#open_login_prompt').show() + $('#logged_in_info').hide() + $('#settings_username').text('Not Logged') + $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`) +}) + +/** + * Adds event listeners. + * @returns {void} + * @since 0.1.0 (?) + */ +function linkEventListeners() { + document.getElementById('toggle_download_tab').addEventListener('click', toggleDownloadTab) + document.getElementById('modal_quality').addEventListener('click', modalQualityButton) + document.getElementById('settings_btn_updateArl').addEventListener('click', loginButton) +} + +/** + * App initialization. + * @returns {void} + * @since 0.1.0 (?) + */ +function init() { + linkEventListeners() + + if ('true' === localStorage.darkMode) { + document.documentElement.classList.add('dark-theme') + } + + if (localStorage.getItem('arl')) { + let arl = localStorage.getItem('arl') + + socket.emit('login', arl) + $('#login_input_arl').val(arl) + } + + // Check if download tab should be open + if ('true' === localStorage.getItem('downloadTabOpen')) { + document.querySelector('#download_tab_container').classList.remove('tab_hidden') + } + + // Open default tab + document.getElementById('main_home_tablink').click() +} + +document.addEventListener('DOMContentLoaded', init) + +/* tabs.js */ +window.search_selected = '' +window.main_selected = '' +window.windows_stack = [] +window.currentStack = {} + +window.changeTab = function (evt, section, tabName) { + windows_stack = [] + currentStack = {} + var i, tabcontent, tablinks + tabcontent = document.getElementsByClassName(section + '_tabcontent') + for (i = 0; i < tabcontent.length; i++) { + tabcontent[i].style.display = 'none' + } + tablinks = document.getElementsByClassName(section + '_tablinks') + for (i = 0; i < tablinks.length; i++) { + tablinks[i].classList.remove('active') + } + if (tabName == 'settings_tab' && main_selected != 'settings_tab') { + SettingsTab.settings = { ...lastSettings } + } + + document.getElementById(tabName).style.display = 'block' + window[section + '_selected'] = tabName + + // Not choosing .currentTarget beacuse the event + // is delegated, so it refers to #sidebar + evt.target.classList.add('active') + + // Check if you need to load more content in the search tab + if ( + main_selected == 'search_tab' && + ['track_search', 'album_search', 'artist_search', 'playlist_search'].indexOf(search_selected) != -1 && + MainSearch.results[search_selected.split('_')[0] + 'Tab'].data.length == 0 + ) { + search(search_selected.split('_')[0]) + } +} + +window.showTab = function (type, id, back = false) { + if (windows_stack.length == 0) windows_stack.push({ tab: main_selected }) + else if (!back) windows_stack.push(currentStack) + if (type == 'artist') { + window.tab = 'artist_tab' + } else { + window.tab = 'tracklist_tab' + } + currentStack = { type: type, id: id } + let tabcontent = document.getElementsByClassName('main_tabcontent') + for (let i = 0; i < tabcontent.length; i++) { + tabcontent[i].style.display = 'none' + } + document.getElementById(tab).style.display = 'block' +} + +window.backTab = function () { + if (windows_stack.length == 1) { + clickElement('main_' + main_selected + 'link') + } else { + let tabObj = windows_stack.pop() + if (tabObj.type == 'artist') resetArtistTab() + else resetTracklistTab() + socket.emit('getTracklist', { type: tabObj.type, id: tabObj.id }) + showTab(tabObj.type, tabObj.id, true) + } +} + +/** + * Handles click Event on the sidebar and changes tab + * according to clicked icon. + * Uses event delegation + * @param {Event} event + * @since 0.1.0 + */ +window.handleSidebarClick = function (event) { + let targetID = event.target.id + + switch (targetID) { + case 'main_search_tablink': + changeTab(event, 'main', 'search_tab') + break + case 'main_home_tablink': + changeTab(event, 'main', 'home_tab') + break + case 'main_charts_tablink': + changeTab(event, 'main', 'charts_tab') + break + case 'main_favorites_tablink': + changeTab(event, 'main', 'favorites_tab') + break + case 'main_analyzer_tablink': + changeTab(event, 'main', 'analyzer_tab') + break + case 'main_settings_tablink': + changeTab(event, 'main', 'settings_tab') + break + case 'main_about_tablink': + changeTab(event, 'main', 'about_tab') + break + + default: + break + } +} + +document.getElementById('sidebar').addEventListener('click', handleSidebarClick) + +/* stackedTabs.js */ +var artistTab = new Vue({ + el: '#artist_tab', + data: { + currentTab: '', + sortKey: 'release_date', + sortOrder: 'desc', + title: '', + image: '', + type: '', + link: '', + head: null, + body: null + }, + methods: { + addToQueue: function (e) { + e.stopPropagation() + sendAddToQueue(e.currentTarget.dataset.link) + }, + openQualityModal: function (e) { + e.preventDefault() + openQualityModal(e.currentTarget.dataset.link) + }, + moreInfo: function (url, e) { + if (e) e.preventDefault() + showTrackListSelective(url, true) + }, + sortBy: function (key) { + if (key == this.sortKey) { + this.sortOrder = this.sortOrder == 'asc' ? 'desc' : 'asc' + } else { + this.sortKey = key + this.sortOrder = 'asc' + } + }, + changeTab: function (tab) { + this.currentTab = tab + }, + checkNewRelease: function (date) { + var g1 = new Date() + var g2 = new Date(date) + g2.setDate(g2.getDate() + 3) + g1.setHours(0, 0, 0, 0) + if (g1.getTime() <= g2.getTime()) { + return true + } else { + return false + } + } + }, + computed: { + showTable() { + if (this.body) return _.orderBy(this.body[this.currentTab], this.sortKey, this.sortOrder) + else return [] + } + } +}) + +var tracklistTab = new Vue({ + el: '#tracklist_tab', + data: { + title: '', + metadata: '', + release_date: '', + label: '', + explicit: false, + image: '', + type: '', + link: '', + head: null, + body: [] + }, + methods: { + addToQueue: function (e) { + e.stopPropagation() + sendAddToQueue(e.currentTarget.dataset.link) + }, + openQualityModal: function (e) { + e.preventDefault() + openQualityModal(e.currentTarget.dataset.link) + }, + toggleAll: function (e) { + this.body.forEach(item => { + if (item.type == 'track') { + item.selected = e.currentTarget.checked + } + }) + }, + selectedLinks: function () { + var selected = [] + if (this.body) { + this.body.forEach(item => { + if (item.type == 'track' && item.selected) selected.push(item.link) + }) + } + return selected.join(';') + } + } +}) + +window.resetArtistTab = function () { + artistTab.title = 'Loading...' + artistTab.image = '' + artistTab.type = '' + artistTab.currentTab = '' + artistTab.sortKey = 'release_date' + artistTab.sortOrder = 'desc' + artistTab.link = '' + artistTab.head = [] + artistTab.body = null +} + +window.resetTracklistTab = function () { + tracklistTab.title = 'Loading...' + tracklistTab.image = '' + tracklistTab.metadata = '' + tracklistTab.label = '' + tracklistTab.release_date = '' + tracklistTab.explicit = false + tracklistTab.type = '' + tracklistTab.head = [] + tracklistTab.body = [] +} + +window.artistView = function (ev) { + let id = ev.currentTarget.dataset.id + resetArtistTab() + socket.emit('getTracklist', { type: 'artist', id: id }) + showTab('artist', id) +} +window.albumView = function (ev) { + let id = ev.currentTarget.dataset.id + resetTracklistTab() + socket.emit('getTracklist', { type: 'album', id: id }) + showTab('album', id) +} +window.playlistView = function (ev) { + let id = ev.currentTarget.dataset.id + resetTracklistTab() + socket.emit('getTracklist', { type: 'playlist', id: id }) + showTab('playlist', id) +} + +socket.on('show_artist', function (data) { + artistTab.title = data.name + artistTab.image = data.picture_xl + artistTab.type = 'Artist' + artistTab.link = `https://www.deezer.com/artist/${data.id}` + artistTab.currentTab = Object.keys(data.releases)[0] + artistTab.sortKey = 'release_date' + artistTab.sortOrder = 'desc' + artistTab.head = [ + { title: 'Title', sortKey: 'title' }, + { title: 'Release Date', sortKey: 'release_date' }, + { title: '', width: '56px' } + ] + if (_.isEmpty(data.releases)) { + artistTab.body = null + } else { + artistTab.body = data.releases + } +}) + +socket.on('show_album', function (data) { + tracklistTab.type = 'Album' + tracklistTab.link = `https://www.deezer.com/album/${data.id}` + tracklistTab.title = data.title + tracklistTab.explicit = data.explicit_lyrics + tracklistTab.label = data.label + tracklistTab.metadata = `${data.artist.name} • ${data.tracks.length} songs` + tracklistTab.release_date = data.release_date.substring(0, 10) + tracklistTab.image = data.cover_xl + tracklistTab.head = [ + { title: 'music_note', width: '24px' }, + { title: '#' }, + { title: 'Song' }, + { title: 'Artist' }, + { title: 'timer', width: '40px' }, + { + title: '', + width: '24px' + } + ] + if (_.isEmpty(data.tracks)) { + tracklistTab.body = null + } else { + tracklistTab.body = data.tracks + } +}) + +socket.on('show_playlist', function (data) { + tracklistTab.type = 'Playlist' + tracklistTab.link = `https://www.deezer.com/playlist/${data.id}` + tracklistTab.title = data.title + tracklistTab.image = data.picture_xl + tracklistTab.release_date = data.creation_date.substring(0, 10) + tracklistTab.metadata = `by ${data.creator.name} • ${data.tracks.length} songs` + tracklistTab.head = [ + { title: 'music_note', width: '24px' }, + { title: '#' }, + { title: 'Song' }, + { title: 'Artist' }, + { title: 'Album' }, + { title: 'timer', width: '40px' }, + { + title: '', + width: '24px' + } + ] + if (_.isEmpty(data.tracks)) { + tracklistTab.body = null + } else { + tracklistTab.body = data.tracks + } +}) + +/* search.js */ +// Load more content when the search page is at the end +$('#content').on('scroll', function () { + if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { + if ( + main_selected == 'search_tab' && + ['track_search', 'album_search', 'artist_search', 'playlist_search'].indexOf(search_selected) != -1 + ) { + scrolledSearch(search_selected.split('_')[0]) + } + } +}) + +window.search = function (type) { + let query = MainSearch.results.query + socket.emit('search', { + term: query, + type: type, + start: MainSearch.results[type + 'Tab'].next, + nb: 30 + }) +} + +window.scrolledSearch = function (type) { + query = MainSearch.results.query + if (MainSearch.results[type + 'Tab'].next < MainSearch.results[type + 'Tab'].total) { + socket.emit('search', { + term: query, + type: type, + start: MainSearch.results[type + 'Tab'].next, + nb: 30 + }) + } +} + +window.searchUpdate = function (result) { + let next = 0 + if (result.next) next = parseInt(result.next.match(/index=(\d*)/)[1]) + else next = result.total + if (MainSearch.results[result.type + 'Tab'].total != result.total) + MainSearch.results[result.type + 'Tab'].total = result.total + if (MainSearch.results[result.type + 'Tab'].next != next) { + MainSearch.results[result.type + 'Tab'].next = next + MainSearch.results[result.type + 'Tab'].data = MainSearch.results[result.type + 'Tab'].data.concat(result.data) + } + MainSearch.results[result.type + 'Tab'].loaded = true +} + +socket.on('search', function (result) { + searchUpdate(result) +}) + +window.clickElement = function (button) { + return document.getElementById(button).click() +} + +window.sendAddToQueue = function (url, bitrate = null) { + if (url.indexOf(';') != -1) { + urls = url.split(';') + urls.forEach(url => { + socket.emit('addToQueue', { url: url, bitrate: bitrate }) + }) + } else if (url != '') { + socket.emit('addToQueue', { url: url, bitrate: bitrate }) + } +} + +window.handleTabClick = function (event) { + let targetID = event.target.id + + switch (targetID) { + case 'search_all_tab': + changeTab(event, 'search', 'main_search') + break + case 'search_track_tab': + changeTab(event, 'search', 'track_search') + break + case 'search_album_tab': + changeTab(event, 'search', 'album_search') + break + case 'search_artist_tab': + changeTab(event, 'search', 'artist_search') + break + case 'search_playlist_tab': + changeTab(event, 'search', 'playlist_search') + break + + default: + break + } +} + +document.getElementById('search_tab').addEventListener('click', handleTabClick) + +// Search section +$('#searchbar').keyup(function (e) { + if (e.keyCode == 13) { + let term = this.value + if (Utils.isValidURL(term)) { + if (e.ctrlKey) { + openQualityModal(term) + } else { + sendAddToQueue(term) + } + } else { + if (term != MainSearch.query || main_selected == 'search_tab') { + document.getElementById('search_tab_content').style.display = 'none' + socket.emit('mainSearch', { term: term }) + } else { + document.getElementById('search_all_tab').click() + document.getElementById('search_tab_content').style.display = 'block' + document.getElementById('main_search_tablink').click() + } + } + } +}) + +window.mainSearchHandler = function (result) { + let resetObj = { data: [], next: 0, total: 0, loaded: false } + MainSearch.results.allTab = result + MainSearch.results.query = result.QUERY + MainSearch.results.trackTab = { ...resetObj } + MainSearch.results.albumTab = { ...resetObj } + MainSearch.results.artistTab = { ...resetObj } + MainSearch.results.playlistTab = { ...resetObj } + document.getElementById('search_all_tab').click() + document.getElementById('search_tab_content').style.display = 'block' + document.getElementById('main_search_tablink').click() +} + +socket.on('mainSearch', function (result) { + mainSearchHandler(result) +}) + +/* settings.js */ +const SettingsTab = new Vue({ + el: '#settings_tab', + data: { + settings: { tags: {} }, + spotifyFeatures: {} + }, + methods: { + addListeners() { + document.getElementById('settings_btn_save').addEventListener('click', window.saveSettings) + document.getElementById('settings_btn_copyArl').addEventListener('click', window.copyARLtoClipboard) + document.getElementById('settings_btn_logout').addEventListener('click', window.logout) + } + }, + mounted() { + this.addListeners() + } +}) + +socket.on('init_settings', function (settings, credentials) { + loadSettings(settings, credentials) + toast('Settings loaded!', 'settings') +}) + +socket.on('updateSettings', function (settings, credentials) { + loadSettings(settings, credentials) + toast('Settings updated!', 'settings') +}) + +window.loadSettings = function (settings, spotifyCredentials) { + lastSettings = { ...settings } + lastCredentials = { ...spotifyCredentials } + SettingsTab.settings = settings + SettingsTab.spotifyFeatures = spotifyCredentials +} + +window.saveSettings = function () { + lastSettings = { ...SettingsTab.settings } + lastCredentials = { ...SettingsTab.spotifyFeatures } + socket.emit('saveSettings', lastSettings, lastCredentials) +} + +window.copyARLtoClipboard = function () { + $('#login_input_arl').attr('type', 'text') + let copyText = document.querySelector('#login_input_arl') + copyText.select() + copyText.setSelectionRange(0, 99999) + document.execCommand('copy') + $('#login_input_arl').attr('type', 'password') + toast('ARL copied to clipboard', 'assignment') +} + +window.logout = function () { + socket.emit('logout') +} + +/* downloadList.js */ +// Show/Hide Download Tab +window.toggleDownloadTab = function (ev) { + ev.preventDefault() + + let isHidden = document.querySelector('#download_tab_container').classList.toggle('tab_hidden') + + localStorage.setItem('downloadTabOpen', !isHidden) +} + +var queueList = {} +var queue = [] +var queueComplete = [] + +socket.on('init_downloadQueue', function (data) { + if (data.queueComplete.length) { + data.queueComplete.forEach(item => { + addToQueue(data.queueList[item]) + }) + } + if (data.currentItem) { + addToQueue(data['queueList'][data.currentItem], true) + } + data.queue.forEach(item => { + addToQueue(data.queueList[item]) + }) +}) + +window.addToQueue = function (queueItem, current = false) { + queueList[queueItem.uuid] = queueItem + if (queueItem.downloaded + queueItem.failed == queueItem.size) queueComplete.push(queueItem.uuid) + else queue.push(queueItem.uuid) + $('#download_list').append( + `
+
+ Cover ${queueItem.title} +
+ ${queueItem.title} - + ${queueItem.artist} +
+
+ ${queueItem.downloaded + queueItem.failed}/${ + queueItem.size + } +
+
+
+
+ remove +
+
` + ) + if (queueItem.progress > 0 || current) { + $('#bar_' + queueItem.uuid) + .removeClass('indeterminate') + .addClass('determinate') + } + $('#bar_' + queueItem.uuid).css('width', queueItem.progress + '%') + if (queueItem.failed >= 1) { + $('#download_' + queueItem.uuid + ' .download_info_status').append( + `(${queueItem.failed}error_outline)` + ) + } + if (queueItem.downloaded + queueItem.failed == queueItem.size) { + let result_icon = $('#download_' + queueItem.uuid).find('.queue_icon') + if (queueItem.failed == 0) { + result_icon.text('done') + } else if (queueItem.failed == queueItem.size) { + result_icon.text('error') + } else { + result_icon.text('warning') + } + } +} + +socket.on('addedToQueue', function (queueItem) { + addToQueue(queueItem) +}) + +window.downloadAction = function (evt) { + let icon = $(evt.currentTarget).text() + let uuid = $(evt.currentTarget).data('uuid') + switch (icon) { + case 'remove': + socket.emit('removeFromQueue', uuid) + break + default: + } +} + +socket.on('removedFromQueue', function (uuid) { + let index = queue.indexOf(uuid) + if (index > -1) { + queue.splice(index, 1) + $(`#download_${queueList[uuid].uuid}`).remove() + delete queueList[uuid] + } +}) + +socket.on('startDownload', function (uuid) { + $('#bar_' + uuid) + .removeClass('indeterminate') + .addClass('determinate') +}) + +socket.on('finishDownload', function (uuid) { + if (queue.indexOf(uuid) > -1) { + toast(`${queueList[uuid].title} finished downloading.`, 'done') + $('#bar_' + uuid).css('width', '100%') + let result_icon = $('#download_' + uuid).find('.queue_icon') + if (queueList[uuid].failed == 0) { + result_icon.text('done') + } else if (queueList[uuid].failed >= queueList[uuid].size) { + result_icon.text('error') + } else { + result_icon.text('warning') + } + let index = queue.indexOf(uuid) + if (index > -1) { + queue.splice(index, 1) + queueComplete.push(uuid) + } + if (queue.length <= 0) { + toast('All downloads completed!', 'done_all') + } + } +}) + +socket.on('removedAllDownloads', function (currentItem) { + queueComplete = [] + if (currentItem == '') { + queue = [] + queueList = {} + $('#download_list').html('') + } else { + queue = [currentItem] + let tempQueueItem = queueList[currentItem] + queueList = {} + queueList[currentItem] = tempQueueItem + $('.download_object').each(function (index) { + if ($(this).attr('id') != 'download_' + currentItem) $(this).remove() + }) + } +}) + +socket.on('removedFinishedDownloads', function () { + queueComplete.forEach(item => { + $('#download_' + item).remove() + }) + queueComplete = [] +}) + +$('#clean_queue').on('click', function () { + socket.emit('removeFinishedDownloads') +}) + +$('#cancel_queue').on('click', function () { + socket.emit('cancelAllDownloads') +}) + +socket.on('updateQueue', function (update) { + if (update.uuid && queue.indexOf(update.uuid) > -1) { + if (update.downloaded) { + queueList[update.uuid].downloaded++ + $('#download_' + update.uuid + ' .queue_downloaded').text( + queueList[update.uuid].downloaded + queueList[update.uuid].failed + ) + } + if (update.failed) { + queueList[update.uuid].failed++ + $('#download_' + update.uuid + ' .queue_downloaded').text( + queueList[update.uuid].downloaded + queueList[update.uuid].failed + ) + if (queueList[update.uuid].failed == 1) { + $('#download_' + update.uuid + ' .download_info_status').append( + `(1 error_outline)` + ) + } else { + $('#download_' + update.uuid + ' .queue_failed').text(queueList[update.uuid].failed) + } + } + if (update.progress) { + queueList[update.uuid].progress = update.progress + $('#bar_' + update.uuid).css('width', update.progress + '%') + } + } +}) + +/* modals.js */ +// quality modal stuff +var modalQuality = document.getElementById('modal_quality') +modalQuality.open = false + +window.onclick = function (event) { + if (event.target == modalQuality && modalQuality.open) { + $(modalQuality).addClass('animated fadeOut') + } +} + +$(modalQuality).on('webkitAnimationEnd', function () { + if (modalQuality.open) { + $(this).removeClass('animated fadeOut') + $(this).css('display', 'none') + modalQuality.open = false + } else { + $(this).removeClass('animated fadeIn') + $(this).css('display', 'block') + modalQuality.open = true + } +}) + +window.openQualityModal = function (link) { + $(modalQuality).data('url', link) + $(modalQuality).css('display', 'block') + $(modalQuality).addClass('animated fadeIn') +} + +window.modalQualityButton = function (event) { + if (!event.target.matches('.quality-button')) { + return + } + + let bitrate = event.target.dataset.qualityValue + + var url = $(modalQuality).data('url') + sendAddToQueue(url, bitrate) + $(modalQuality).addClass('animated fadeOut') +} diff --git a/public/js/app/app.js b/public/js/app/app.js deleted file mode 100644 index 753cdd3..0000000 --- a/public/js/app/app.js +++ /dev/null @@ -1,161 +0,0 @@ -// Initialization -const socket = io.connect(window.location.href) -var localStorage = window.localStorage -// toasts stuff -var toastsWithId = {} -// settings -var lastSettings = {} -var lastCredentials = {} - -function toast(msg, icon = null, dismiss = true, id = null) { - if (toastsWithId[id]) { - let toastObj = toastsWithId[id] - let toastDOM = $(`div.toastify[toast_id=${id}]`) - if (msg) { - toastDOM.find('.toast-message').html(msg) - } - if (icon) { - if (icon == 'loading') icon = `
` - else icon = `${icon}` - toastDOM.find('.toast-icon').html(icon) - } - if (dismiss !== null && dismiss) { - setTimeout(function () { - toastObj.hideToast() - delete toastsWithId[id] - }, 3000) - } - } else { - if (icon == null) icon = '' - else if (icon == 'loading') icon = `
` - else icon = `${icon}` - let toastObj = Toastify({ - text: `${icon}${msg}`, - duration: dismiss ? 3000 : 0, - gravity: 'bottom', - position: 'left' - }).showToast() - if (id) { - toastsWithId[id] = toastObj - $(toastObj.toastElement).attr('toast_id', id) - } - } -} - -/* ===== Socketio listeners ===== */ -socket.on('toast', data => { - toast(data.msg, data.icon || null, data.dismiss !== undefined ? data.dismiss : true, data.id || null) -}) - -// Debug messages for socketio -socket.on('message', function (msg) { - console.log(msg) -}) - -// Login stuff - -function loginButton() { - let arl = document.querySelector('#login_input_arl').value - if (arl != '' && arl != localStorage.getItem('arl')) { - socket.emit('login', arl, true) - } -} - -socket.on('logging_in', function () { - toast('Logging in', 'loading', false, 'login-toast') -}) - -socket.on('logged_in', function (data) { - switch (data.status) { - case 1: - case 3: - toast('Logged in', 'done', true, 'login-toast') - if (data.arl) { - localStorage.setItem('arl', data.arl) - $('#login_input_arl').val(data.arl) - } - $('#open_login_prompt').hide() - if (data.user) { - $('#settings_username').text(data.user.name) - $('#settings_picture').attr( - 'src', - `https://e-cdns-images.dzcdn.net/images/user/${data.user.picture}/125x125-000000-80-0-0.jpg` - ) - $('#logged_in_info').show() - } - break - case 2: - toast('Already logged in', 'done', true, 'login-toast') - if (data.user) { - $('#settings_username').text(data.user.name) - $('#settings_picture').attr( - 'src', - `https://e-cdns-images.dzcdn.net/images/user/${data.user.picture}/125x125-000000-80-0-0.jpg` - ) - $('#logged_in_info').show() - } - break - case 0: - toast("Couldn't log in", 'close', true, 'login-toast') - localStorage.removeItem('arl') - $('#login_input_arl').val('') - $('#open_login_prompt').show() - $('#logged_in_info').hide() - $('#settings_username').text('Not Logged') - $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`) - break - } -}) - -socket.on('logged_out', function () { - toast('Logged out', 'done', true, 'login-toast') - localStorage.removeItem('arl') - $('#login_input_arl').val('') - $('#open_login_prompt').show() - $('#logged_in_info').hide() - $('#settings_username').text('Not Logged') - $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`) -}) - - - -/** - * Adds event listeners. - * @returns {void} - * @since 0.1.0 (?) - */ -function linkEventListeners() { - document.getElementById('toggle_download_tab').addEventListener('click', toggleDownloadTab) - document.getElementById('modal_quality').addEventListener('click', modalQualityButton) - document.getElementById('settings_btn_updateArl').addEventListener('click', loginButton) -} - -/** - * App initialization. - * @returns {void} - * @since 0.1.0 (?) - */ -function init() { - linkEventListeners() - - if ('true' === localStorage.darkMode) { - document.documentElement.classList.add('dark-theme') - } - - if (localStorage.getItem('arl')) { - let arl = localStorage.getItem('arl') - - socket.emit('login', arl) - $('#login_input_arl').val(arl) - } - - // Check if download tab should be open - if ('true' === localStorage.getItem('downloadTabOpen')) { - document.querySelector('#download_tab_container').classList.remove('tab_hidden') - } - - // Open default tab - document.getElementById('main_home_tablink').click() -} - -document.addEventListener('DOMContentLoaded', init) \ No newline at end of file diff --git a/public/js/app/downloadList.js b/public/js/app/downloadList.js deleted file mode 100644 index b7112f7..0000000 --- a/public/js/app/downloadList.js +++ /dev/null @@ -1,183 +0,0 @@ -// Show/Hide Download Tab -function toggleDownloadTab(ev) { - ev.preventDefault() - - let isHidden = document.querySelector('#download_tab_container').classList.toggle('tab_hidden') - - localStorage.setItem('downloadTabOpen', !isHidden) -} - -var queueList = {} -var queue = [] -var queueComplete = [] - -socket.on('init_downloadQueue', function (data) { - if (data.queueComplete.length) { - data.queueComplete.forEach(item => { - addToQueue(data.queueList[item]) - }) - } - if (data.currentItem){ - addToQueue(data['queueList'][data.currentItem], true) - } - data.queue.forEach(item => { - addToQueue(data.queueList[item]) - }) -}) - -function addToQueue(queueItem, current=false){ - queueList[queueItem.uuid] = queueItem - if (queueItem.downloaded + queueItem.failed == queueItem.size) queueComplete.push(queueItem.uuid) - else queue.push(queueItem.uuid) - $('#download_list').append( - `
-
- Cover ${queueItem.title} -
- ${queueItem.title} - - ${queueItem.artist} -
-
- ${queueItem.downloaded + queueItem.failed}/${ - queueItem.size - } -
-
-
-
- remove -
-
`) - if (queueItem.progress>0 || current){ - $('#bar_' + queueItem.uuid).removeClass('indeterminate').addClass('determinate') - } - $('#bar_' + queueItem.uuid).css('width', queueItem.progress + '%') - if (queueItem.failed >= 1) { - $('#download_' + queueItem.uuid + ' .download_info_status').append( - `(${queueItem.failed}error_outline)` - ) - } - if (queueItem.downloaded + queueItem.failed == queueItem.size) { - let result_icon = $('#download_' + queueItem.uuid).find('.queue_icon') - if (queueItem.failed == 0) { - result_icon.text('done') - } else if (queueItem.failed == queueItem.size) { - result_icon.text('error') - } else { - result_icon.text('warning') - } - } -} - -socket.on('addedToQueue', function (queueItem) { - addToQueue(queueItem) -}) - -function downloadAction(evt) { - let icon = $(evt.currentTarget).text() - let uuid = $(evt.currentTarget).data('uuid') - switch (icon) { - case 'remove': - socket.emit('removeFromQueue', uuid) - break - default: - } -} - -socket.on('removedFromQueue', function (uuid) { - let index = queue.indexOf(uuid) - if (index > -1) { - queue.splice(index, 1) - $(`#download_${queueList[uuid].uuid}`).remove() - delete queueList[uuid] - } -}) - -socket.on('startDownload', function (uuid) { - $('#bar_' + uuid) - .removeClass('indeterminate') - .addClass('determinate') -}) - -socket.on('finishDownload', function (uuid) { - if (queue.indexOf(uuid) > -1) { - toast(`${queueList[uuid].title} finished downloading.`, 'done') - $('#bar_' + uuid).css('width', '100%') - let result_icon = $('#download_' + uuid).find('.queue_icon') - if (queueList[uuid].failed == 0) { - result_icon.text('done') - } else if (queueList[uuid].failed >= queueList[uuid].size) { - result_icon.text('error') - } else { - result_icon.text('warning') - } - let index = queue.indexOf(uuid) - if (index > -1) { - queue.splice(index, 1) - queueComplete.push(uuid) - } - if (queue.length <= 0) { - toast('All downloads completed!', 'done_all') - } - } -}) - -socket.on('removedAllDownloads', function (currentItem) { - queueComplete = [] - if (currentItem == '') { - queue = [] - queueList = {} - $('#download_list').html('') - } else { - queue = [currentItem] - tempQueueItem = queueList[currentItem] - queueList = {} - queueList[currentItem] = tempQueueItem - $('.download_object').each(function (index) { - if ($(this).attr('id') != 'download_' + currentItem) $(this).remove() - }) - } -}) - -socket.on('removedFinishedDownloads', function () { - queueComplete.forEach(item => { - $('#download_' + item).remove() - }) - queueComplete = [] -}) - -$('#clean_queue').on('click', function () { - socket.emit('removeFinishedDownloads') -}) - -$('#cancel_queue').on('click', function () { - socket.emit('cancelAllDownloads') -}) - -socket.on('updateQueue', function (update) { - if (update.uuid && queue.indexOf(update.uuid) > -1) { - if (update.downloaded) { - queueList[update.uuid].downloaded++ - $('#download_' + update.uuid + ' .queue_downloaded').text( - queueList[update.uuid].downloaded + queueList[update.uuid].failed - ) - } - if (update.failed) { - queueList[update.uuid].failed++ - $('#download_' + update.uuid + ' .queue_downloaded').text( - queueList[update.uuid].downloaded + queueList[update.uuid].failed - ) - if (queueList[update.uuid].failed == 1) { - $('#download_' + update.uuid + ' .download_info_status').append( - `(1 error_outline)` - ) - } else { - $('#download_' + update.uuid + ' .queue_failed').text(queueList[update.uuid].failed) - } - } - if (update.progress) { - queueList[update.uuid].progress = update.progress - $('#bar_' + update.uuid).css('width', update.progress + '%') - } - } -}) \ No newline at end of file diff --git a/public/js/app/modals.js b/public/js/app/modals.js deleted file mode 100644 index 734af2f..0000000 --- a/public/js/app/modals.js +++ /dev/null @@ -1,39 +0,0 @@ -// quality modal stuff -var modalQuality = document.getElementById('modal_quality') -modalQuality.open = false - -window.onclick = function (event) { - if (event.target == modalQuality && modalQuality.open) { - $(modalQuality).addClass('animated fadeOut') - } -} - -$(modalQuality).on('webkitAnimationEnd', function () { - if (modalQuality.open) { - $(this).removeClass('animated fadeOut') - $(this).css('display', 'none') - modalQuality.open = false - } else { - $(this).removeClass('animated fadeIn') - $(this).css('display', 'block') - modalQuality.open = true - } -}) - -function openQualityModal(link) { - $(modalQuality).data('url', link) - $(modalQuality).css('display', 'block') - $(modalQuality).addClass('animated fadeIn') -} - -function modalQualityButton(event) { - if (!event.target.matches('.quality-button')) { - return - } - - let bitrate = event.target.dataset.qualityValue - - var url = $(modalQuality).data('url') - sendAddToQueue(url, bitrate) - $(modalQuality).addClass('animated fadeOut') -} \ No newline at end of file diff --git a/public/js/app/search.js b/public/js/app/search.js deleted file mode 100644 index 944f00b..0000000 --- a/public/js/app/search.js +++ /dev/null @@ -1,168 +0,0 @@ -// Load more content when the search page is at the end -$('#content').on('scroll', function () { - if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { - if ( - main_selected == 'search_tab' && - ['track_search', 'album_search', 'artist_search', 'playlist_search'].indexOf(search_selected) != -1 - ) { - scrolledSearch(search_selected.split('_')[0]) - } - } -}) - -function search(type) { - query = MainSearch.results.query - socket.emit('search', { - term: query, - type: type, - start: MainSearch.results[type + 'Tab'].next, - nb: 30 - }) -} - -function scrolledSearch(type) { - query = MainSearch.results.query - if (MainSearch.results[type + 'Tab'].next < MainSearch.results[type + 'Tab'].total) { - socket.emit('search', { - term: query, - type: type, - start: MainSearch.results[type + 'Tab'].next, - nb: 30 - }) - } -} - -function searchUpdate(result) { - let next = 0 - if (result.next) next = parseInt(result.next.match(/index=(\d*)/)[1]) - else next = result.total - if (MainSearch.results[result.type + 'Tab'].total != result.total) - MainSearch.results[result.type + 'Tab'].total = result.total - if (MainSearch.results[result.type + 'Tab'].next != next) { - MainSearch.results[result.type + 'Tab'].next = next - MainSearch.results[result.type + 'Tab'].data = MainSearch.results[result.type + 'Tab'].data.concat(result.data) - } - MainSearch.results[result.type + 'Tab'].loaded = true -} - -socket.on('search', function (result) { - searchUpdate(result) -}) - -function clickElement(button) { - return document.getElementById(button).click() -} - -function sendAddToQueue(url, bitrate = null) { - if (url.indexOf(';') != -1) { - urls = url.split(';') - urls.forEach(url => { - socket.emit('addToQueue', { url: url, bitrate: bitrate }) - }) - } else if (url != '') { - socket.emit('addToQueue', { url: url, bitrate: bitrate }) - } -} - -const MainSearch = new Vue({ - el: '#search_tab', - data: { - names: { - TOP_RESULT: 'Top Result', - TRACK: 'Tracks', - ARTIST: 'Artists', - ALBUM: 'Albums', - PLAYLIST: 'Playlists' - }, - results: { - query: '', - allTab: { - ORDER: [], - TOP_RESULT: [], - ALBUM: {}, - ARTIST: {}, - TRACK: {}, - PLAYLIST: {} - }, - trackTab: { - data: [], - next: 0, - total: 0, - loaded: false - }, - albumTab: { - data: [], - next: 0, - total: 0, - loaded: false - }, - artistTab: { - data: [], - next: 0, - total: 0, - loaded: false - }, - playlistTab: { - data: [], - next: 0, - total: 0, - loaded: false - } - } - }, - methods: { - changeSearchTab(section) { - if (section != 'TOP_RESULT') clickElement('search_' + section.toLowerCase() + '_tab') - }, - addToQueue: function (e) { - e.stopPropagation() - sendAddToQueue(e.currentTarget.dataset.link) - }, - openQualityModal: function (e) { - e.preventDefault() - openQualityModal(e.currentTarget.dataset.link) - } - } -}) - -console.log(MainSearch) - -// Search section -$('#searchbar').keyup(function (e) { - if (e.keyCode == 13) { - let term = this.value - if (isValidURL(term)) { - if (e.ctrlKey) { - openQualityModal(term) - } else { - sendAddToQueue(term) - } - } else { - if (term != MainSearch.query || main_selected == 'search_tab') { - document.getElementById('search_tab_content').style.display = 'none' - socket.emit('mainSearch', { term: term }) - } else { - document.getElementById('search_all_tab').click() - document.getElementById('search_tab_content').style.display = 'block' - document.getElementById('main_search_tablink').click() - } - } - } -}) - -function mainSearchHandler(result) { - let resetObj = { data: [], next: 0, total: 0, loaded: false } - MainSearch.results.allTab = result - MainSearch.results.query = result.QUERY - MainSearch.results.trackTab = { ...resetObj } - MainSearch.results.albumTab = { ...resetObj } - MainSearch.results.artistTab = { ...resetObj } - MainSearch.results.playlistTab = { ...resetObj } - document.getElementById('search_all_tab').click() - document.getElementById('search_tab_content').style.display = 'block' - document.getElementById('main_search_tablink').click() -} - -socket.on('mainSearch', function (result) { - mainSearchHandler(result) -}) diff --git a/public/js/app/settings.js b/public/js/app/settings.js deleted file mode 100644 index 94101b5..0000000 --- a/public/js/app/settings.js +++ /dev/null @@ -1,54 +0,0 @@ -const SettingsTab = new Vue({ - el: '#settings_tab', - data: { - settings: { tags: {} }, - spotifyFeatures: {} - }, - methods: { - addListeners() { - document.getElementById('settings_btn_save').addEventListener('click', saveSettings) - document.getElementById('settings_btn_copyArl').addEventListener('click', copyARLtoClipboard) - document.getElementById('settings_btn_logout').addEventListener('click', logout) - } - }, - mounted() { - this.addListeners() - } -}) - -socket.on('init_settings', function (settings, credentials) { - loadSettings(settings, credentials) - toast('Settings loaded!', 'settings') -}) - -socket.on('updateSettings', function (settings, credentials) { - loadSettings(settings, credentials) - toast('Settings updated!', 'settings') -}) - -function loadSettings(settings, spotifyCredentials) { - lastSettings = { ...settings } - lastCredentials = { ...spotifyCredentials } - SettingsTab.settings = settings - SettingsTab.spotifyFeatures = spotifyCredentials -} - -function saveSettings() { - lastSettings = { ...SettingsTab.settings } - lastCredentials = { ...SettingsTab.spotifyFeatures } - socket.emit('saveSettings', lastSettings, lastCredentials) -} - -function copyARLtoClipboard() { - $('#login_input_arl').attr('type', 'text') - let copyText = document.querySelector('#login_input_arl') - copyText.select() - copyText.setSelectionRange(0, 99999) - document.execCommand('copy') - $('#login_input_arl').attr('type', 'password') - toast('ARL copied to clipboard', 'assignment') -} - -function logout() { - socket.emit('logout') -} diff --git a/public/js/app/stackedTabs.js b/public/js/app/stackedTabs.js deleted file mode 100644 index 0c39f0b..0000000 --- a/public/js/app/stackedTabs.js +++ /dev/null @@ -1,198 +0,0 @@ -var artistTab = new Vue({ - el: '#artist_tab', - data: { - currentTab: '', - sortKey: 'release_date', - sortOrder: 'desc', - title: "", - image: "", - type: "", - link: "", - head: null, - body: null - }, - methods: { - addToQueue: function(e){e.stopPropagation(); sendAddToQueue(e.currentTarget.dataset.link)}, - openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}, - moreInfo: function(url, e){ - if (e) e.preventDefault(); - showTrackListSelective(url, true) - }, - sortBy: function(key) { - if (key == this.sortKey) { - this.sortOrder = (this.sortOrder == 'asc') ? 'desc' : 'asc'; - } else { - this.sortKey = key; - this.sortOrder = 'asc'; - } - }, - changeTab: function(tab){ - this.currentTab = tab - }, - checkNewRelease: function(date){ - var g1 = new Date(); - var g2 = new Date(date); - g2.setDate(g2.getDate()+3) - g1.setHours(0,0,0,0) - if (g1.getTime() <= g2.getTime()){ - return true; - }else { - return false; - } - } - }, - computed: { - showTable() { - if (this.body) - return _.orderBy(this.body[this.currentTab], this.sortKey, this.sortOrder) - else - return [] - } - } -}) - -var tracklistTab = new Vue({ - el: '#tracklist_tab', - data: { - title: "", - metadata : "", - release_date: "", - label: "", - explicit: false, - image: "", - type: "", - link: "", - head: null, - body: [] - }, - methods: { - addToQueue: function(e){e.stopPropagation(); sendAddToQueue(e.currentTarget.dataset.link)}, - openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}, - toggleAll: function(e){ - this.body.forEach((item) => { - if (item.type == 'track'){ - item.selected = e.currentTarget.checked - } - }); - }, - selectedLinks: function(){ - selected = [] - if (this.body){ - this.body.forEach((item) => { - if (item.type == 'track' && item.selected) selected.push(item.link) - }) - } - return selected.join(";") - } - } -}) - -function resetArtistTab(){ - artistTab.title = "Loading..." - artistTab.image = "" - artistTab.type = "" - artistTab.currentTab = '' - artistTab.sortKey = 'release_date' - artistTab.sortOrder = 'desc' - artistTab.link = '' - artistTab.head = [] - artistTab.body = null -} - -function resetTracklistTab(){ - tracklistTab.title = "Loading..." - tracklistTab.image = "" - tracklistTab.metadata = "" - tracklistTab.label = "" - tracklistTab.release_date = "" - tracklistTab.explicit = false - tracklistTab.type = "" - tracklistTab.head = [] - tracklistTab.body = [] -} - -function artistView(ev){ - let id = ev.currentTarget.dataset.id - resetArtistTab() - socket.emit('getTracklist', {type: 'artist', id: id}) - showTab('artist', id) -} -function albumView(ev){ - let id = ev.currentTarget.dataset.id - resetTracklistTab() - socket.emit('getTracklist', {type: 'album', id: id}) - showTab('album', id) -} -function playlistView(ev){ - let id = ev.currentTarget.dataset.id - resetTracklistTab() - socket.emit('getTracklist', {type: 'playlist', id: id}) - showTab('playlist', id) -} - -socket.on('show_artist', function(data){ - artistTab.title = data.name - artistTab.image = data.picture_xl - artistTab.type = "Artist" - artistTab.link = `https://www.deezer.com/artist/${data.id}` - artistTab.currentTab = Object.keys(data.releases)[0] - artistTab.sortKey = 'release_date' - artistTab.sortOrder = 'desc' - artistTab.head = [ - {title: 'Title', sortKey: "title"}, - {title: 'Release Date', sortKey: "release_date"}, - {title: '', width: "56px"} - ] - if (_.isEmpty(data.releases)){ - artistTab.body = null - }else{ - artistTab.body = data.releases - } -}) - -socket.on('show_album', function(data){ - tracklistTab.type = 'Album' - tracklistTab.link = `https://www.deezer.com/album/${data.id}` - tracklistTab.title = data.title - tracklistTab.explicit = data.explicit_lyrics - tracklistTab.label = data.label - tracklistTab.metadata = `${data.artist.name} • ${data.tracks.length} songs` - tracklistTab.release_date = data.release_date.substring(0,10) - tracklistTab.image = data.cover_xl - tracklistTab.head = [ - {title: 'music_note', width: "24px"}, - {title: '#'}, - {title: 'Song'}, - {title: 'Artist'}, - {title: 'timer', width: "40px"}, - {title: '', width: "24px"} - ] - if (_.isEmpty(data.tracks)){ - tracklistTab.body = null - }else{ - tracklistTab.body = data.tracks - } -}) - -socket.on('show_playlist', function(data){ - tracklistTab.type = "Playlist" - tracklistTab.link = `https://www.deezer.com/playlist/${data.id}` - tracklistTab.title = data.title - tracklistTab.image = data.picture_xl - tracklistTab.release_date = data.creation_date.substring(0,10) - tracklistTab.metadata = `by ${data.creator.name} • ${data.tracks.length} songs` - tracklistTab.head = [ - {title: 'music_note', width: "24px"}, - {title: '#'}, - {title: 'Song'}, - {title: 'Artist'}, - {title: 'Album'}, - {title: 'timer', width: "40px"}, - {title: '', width: "24px"} - ] - if (_.isEmpty(data.tracks)){ - tracklistTab.body = null - }else{ - tracklistTab.body = data.tracks - } -}) diff --git a/public/js/app/tabs.js b/public/js/app/tabs.js deleted file mode 100644 index ce19b13..0000000 --- a/public/js/app/tabs.js +++ /dev/null @@ -1,102 +0,0 @@ -var search_selected = '' -var main_selected = '' -var windows_stack = [] -var currentStack = {} - -function changeTab(evt, section, tabName) { - windows_stack = [] - currentStack = {} - var i, tabcontent, tablinks - tabcontent = document.getElementsByClassName(section + '_tabcontent') - for (i = 0; i < tabcontent.length; i++) { - tabcontent[i].style.display = 'none' - } - tablinks = document.getElementsByClassName(section + '_tablinks') - for (i = 0; i < tablinks.length; i++) { - tablinks[i].classList.remove('active') - } - if (tabName == 'settings_tab' && main_selected != 'settings_tab') { - SettingsTab.settings = { ...lastSettings } - } - - document.getElementById(tabName).style.display = 'block' - window[section + '_selected'] = tabName - - // Not choosing .currentTarget beacuse the event - // is delegated, so it refers to #sidebar - evt.target.classList.add('active') - - // Check if you need to load more content in the search tab - if ( - main_selected == 'search_tab' && - ['track_search', 'album_search', 'artist_search', 'playlist_search'].indexOf(search_selected) != -1 && - MainSearch.results[search_selected.split('_')[0]+"Tab"].data.length == 0 - ) { - search(search_selected.split('_')[0]) - } -} - -function showTab(type, id, back=false) { - if (windows_stack.length == 0) windows_stack.push({ tab: main_selected }) - else if (!back) windows_stack.push(currentStack) - if (type == 'artist') tab = 'artist_tab' - else tab = 'tracklist_tab' - currentStack = { type: type, id: id } - let tabcontent = document.getElementsByClassName('main_tabcontent') - for (let i = 0; i < tabcontent.length; i++) { - tabcontent[i].style.display = 'none' - } - document.getElementById(tab).style.display = 'block' -} - -function backTab() { - if (windows_stack.length == 1) { - clickElement('main_' + main_selected + 'link') - } else { - let tabObj = windows_stack.pop() - if (tabObj.type == 'artist') resetArtistTab() - else resetTracklistTab() - socket.emit('getTracklist', {type: tabObj.type, id: tabObj.id}) - showTab(tabObj.type, tabObj.id, true) - } -} - -/** - * Handles click Event on the sidebar and changes tab - * according to clicked icon. - * Uses event delegation - * @param {Event} event - * @since 0.1.0 - */ -function handleSidebarClick(event) { - let targetID = event.target.id - - switch (targetID) { - case 'main_search_tablink': - changeTab(event, 'main', 'search_tab') - break - case 'main_home_tablink': - changeTab(event, 'main', 'home_tab') - break - case 'main_charts_tablink': - changeTab(event, 'main', 'charts_tab') - break - case 'main_favorites_tablink': - changeTab(event, 'main', 'favorites_tab') - break - case 'main_analyzer_tablink': - changeTab(event, 'main', 'analyzer_tab') - break - case 'main_settings_tablink': - changeTab(event, 'main', 'settings_tab') - break - case 'main_about_tablink': - changeTab(event, 'main', 'about_tab') - break - - default: - break - } -} - -document.getElementById('sidebar').addEventListener('click', handleSidebarClick) diff --git a/public/js/modules/search-tab/main-search.js b/public/js/modules/search-tab/main-search.js new file mode 100644 index 0000000..73fcc44 --- /dev/null +++ b/public/js/modules/search-tab/main-search.js @@ -0,0 +1,74 @@ +export const MainSearch = new Vue({ + el: '#search_tab', + data: { + names: { + TOP_RESULT: 'Top Result', + TRACK: 'Tracks', + ARTIST: 'Artists', + ALBUM: 'Albums', + PLAYLIST: 'Playlists' + }, + results: { + query: '', + allTab: { + ORDER: [], + TOP_RESULT: [], + ALBUM: {}, + ARTIST: {}, + TRACK: {}, + PLAYLIST: {} + }, + trackTab: { + data: [], + next: 0, + total: 0, + loaded: false + }, + albumTab: { + data: [], + next: 0, + total: 0, + loaded: false + }, + artistTab: { + data: [], + next: 0, + total: 0, + loaded: false + }, + playlistTab: { + data: [], + next: 0, + total: 0, + loaded: false + } + } + }, + methods: { + changeSearchTab(section) { + if (section != 'TOP_RESULT') clickElement('search_' + section.toLowerCase() + '_tab') + }, + addToQueue: function (e) { + e.stopPropagation() + sendAddToQueue(e.currentTarget.dataset.link) + }, + openQualityModal: function (e) { + e.preventDefault() + openQualityModal(e.currentTarget.dataset.link) + }, + numberWithDots(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') + }, + convertDuration(duration) { + //convert from seconds only to mm:ss format + let mm, ss + mm = Math.floor(duration / 60) + ss = duration - mm * 60 + //add leading zero if ss < 0 + if (ss < 10) { + ss = '0' + ss + } + return mm + ':' + ss + } + } +}) \ No newline at end of file diff --git a/public/js/app/utils.js b/public/js/modules/utils.js similarity index 50% rename from public/js/app/utils.js rename to public/js/modules/utils.js index 191d856..4a5556d 100644 --- a/public/js/app/utils.js +++ b/public/js/modules/utils.js @@ -1,4 +1,4 @@ -function isValidURL(text) { +export function isValidURL(text) { if (text.toLowerCase().startsWith('http')) { if (text.toLowerCase().indexOf('deezer.com') >= 0 || text.toLowerCase().indexOf('open.spotify.com') >= 0) return true @@ -6,7 +6,7 @@ function isValidURL(text) { return false } -function convertDuration(duration) { +export function convertDuration(duration) { //convert from seconds only to mm:ss format let mm, ss mm = Math.floor(duration / 60) @@ -18,7 +18,7 @@ function convertDuration(duration) { return mm + ':' + ss } -function convertDurationSeparated(duration) { +export function convertDurationSeparated(duration) { let hh, mm, ss mm = Math.floor(duration / 60) hh = Math.floor(mm / 60) @@ -27,22 +27,18 @@ function convertDurationSeparated(duration) { return [hh, mm, ss] } -function numberWithDots(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') +export function debounce(func, wait, immediate) { + var timeout + return function () { + var context = this + var args = arguments + var later = function () { + timeout = null + if (!immediate) func.apply(context, args) + } + var callNow = immediate && !timeout + clearTimeout(timeout) + timeout = setTimeout(later, wait) + if (callNow) func.apply(context, args) + } } - -function debounce(func, wait, immediate) { - var timeout - return function() { - var context = this - var args = arguments - var later = function() { - timeout = null - if (!immediate) func.apply(context, args) - } - var callNow = immediate && !timeout - clearTimeout(timeout) - timeout = setTimeout(later, wait) - if (callNow) func.apply(context, args) - } -} \ No newline at end of file