Implemented settings load and save

This commit is contained in:
RemixDev
2020-04-14 19:58:54 +02:00
parent a3c9d06e14
commit 14f91fa275
6 changed files with 68 additions and 33 deletions

223
public/js/app/app.js Normal file
View File

@@ -0,0 +1,223 @@
// Initialization
const socket = io.connect(window.location.href)
localStorage = window.localStorage;
// tabs stuff
search_selected = ""
main_selected=""
// toasts stuff
toastsWithId = {}
// settings
lastSettings = {}
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 = `<div class="circle-loader"></div>`
else
icon = `<i class="material-icons">${icon}</i>`
toastDOM.find(".toast-icon").html(icon)
}
console.log(dismiss)
if (dismiss !== null && dismiss){
setTimeout(function(){
toastObj.hideToast()
delete toastsWithId[id]
}, 3000);
}
}else{
if (icon == null)
icon = ""
else if (icon=='loading')
icon = `<div class="circle-loader"></div>`
else
icon = `<i class="material-icons">${icon}</i>`
let toastObj = Toastify({
text: `<span class="toast-icon">${icon}</span><span class="toast-message">${msg}</toast>`,
duration: dismiss ? 3000 : 0,
gravity: 'bottom',
position: 'left'
}).showToast()
if (id){
toastsWithId[id] = toastObj
$(toastObj.toastElement).attr('toast_id', id)
}
}
}
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)
})
window.addEventListener('pywebviewready', function() {
if (window.pywebview.platform == "gtk"){
$('#open_login_prompt').prop('disabled', false);
}
})
$(function(){
if (localStorage.getItem("arl")){
socket.emit("login", localStorage.getItem("arl"));
$("#login_input_arl").val(localStorage.getItem("arl"))
}
// Check if download tab should be open
if (eval(localStorage.getItem("downloadTabOpen")))
$("#show_download_tab").click()
else
$("#hide_download_tab").click()
// Open default tab
document.getElementById("main_home_tablink").click();
})
// Show/Hide Download Tab
document.querySelector("#show_download_tab").onclick = (ev)=>{
ev.preventDefault();
document.querySelector("#download_tab_bar").style.display = "none";
document.querySelector("#download_tab").style.display = "block";
localStorage.setItem("downloadTabOpen", true)
}
document.querySelector("#hide_download_tab").onclick = (ev)=>{
ev.preventDefault();
document.querySelector("#download_tab_bar").style.display = "block";
document.querySelector("#download_tab").style.display = "none";
localStorage.setItem("downloadTabOpen", false)
}
// Login stuff
function openLoginPrompt(){
socket.emit("loginpage")
}
function loginButton(){
let arl = document.querySelector("#login_input_arl").value
if (arl != "" && arl != localStorage.getItem("arl")){
socket.emit("login", arl, true)
}
}
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");
}
socket.on("logging_in", function(){
toast("Logging in", "loading", false, "login-toast")
})
socket.on("logged_in", function(data){
console.log(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`)
})
// settings stuff
var settingsTab = new Vue({
el: '#settings_tab',
data: {
settings: {}
}
})
socket.on("init_settings", function(settings){
loadSettings(settings)
toast("Settings loaded!", 'settings')
})
socket.on("updateSettings", function(settings){
loadSettings(settings)
toast("Settings updated!", 'settings')
})
function loadSettings(settings){
lastSettings = {...settings}
settingsTab.settings = settings
}
function saveSettings(){
lastSettings = {...settingsTab.settings}
socket.emit("saveSettings", lastSettings)
}
// tabs stuff
function changeTab(evt, section, tabName) {
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].className = tablinks[i].className.replace(" active", "");
}
if (tabName == "settings_tab" && main_selected != "settings_tab"){
settingsTab.settings = {...lastSettings}
}
document.getElementById(tabName).style.display = "block";
window[section+"_selected"] = tabName
evt.currentTarget.className += " active";
// Check if you need to load more content in the search tab
if (document.getElementById("content").offsetHeight >= document.getElementById("content").scrollHeight && main_selected == "search_tab" && ["track_search", "album_search", "artist_search", "playlist_search"].indexOf(search_selected) != -1){
scrolledSearch(window[search_selected.split("_")[0]+"Search"])
}
}

View File

@@ -0,0 +1,166 @@
var queueList = {}
var queue = []
var queueComplete = []
socket.on("init_downloadQueue", function(data){
console.log(data)
if (data.queueComplete.length){
data.queueComplete.forEach(item=>{
addToQueue(data.queueList[item])
})
}
if (data.currentItem){
addToQueue(data['queueList'][data.currentItem])
}
data.queue.forEach(item=>{
addToQueue(data.queueList[item])
})
})
function addToQueue(queueItem){
queueList[queueItem.uuid] = queueItem
if ((queueItem.downloaded + queueItem.failed) == queueItem.size)
queueComplete.push(queueItem.uuid)
else
queue.push(queueItem.uuid)
$("#download_list").append(
`<div class="download_object" id="download_${queueItem.uuid}" data-deezerid="${queueItem.id}">
<div class="download_info">
<img width="75px" class="rounded coverart" src="${queueItem.cover}" alt="Cover ${queueItem.title}"/>
<div class="download_info_data">
<span class="download_line">${queueItem.title}</span> <span class="download_slim_separator"> - </span>
<span class="secondary-text">${queueItem.artist}</span>
</div>
<div class="download_info_status">
<span class="download_line"><span class="queue_downloaded">${queueItem.downloaded + queueItem.failed}</span>/${queueItem.size}</span>
</div>
</div>
<div class="download_bar">
<div class="progress"><div id="bar_${queueItem.uuid}" class="indeterminate"></div></div>
<i onclick="downloadAction(event)" class="material-icons queue_icon" data-uuid="${queueItem.uuid}">remove</i>
</div>
</div>`)
if (queueItem.progress>0){
$('#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(`<span class="secondary-text inline-flex"><span class="download_slim_separator">(</span><span class="queue_failed">${queueItem.failed}</span><i class="material-icons">error_outline</i><span class="download_slim_separator">)</span></span>`)
}
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(`<span class="secondary-text inline-flex"><span class="download_slim_separator">(</span><span class="queue_failed">1</span> <i class="material-icons">error_outline</i><span class="download_slim_separator">)</span></span>`)
}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 + '%')
}
}
})

175
public/js/app/search.js Normal file
View File

@@ -0,0 +1,175 @@
// 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(window[search_selected.split("_")[0]+"Search"])
}
}
})
function scrolledSearch(vueTab){
query = vueTab.query
if (vueTab.results.next < vueTab.results.total){
socket.emit("search", {term: vueTab.query, type: vueTab.type, start: vueTab.results.next, nb: vueTab.nb});
}
}
function searchUpadate(result){
console.log(result)
vueTab = null;
switch (result.type) {
case "TRACK":
vueTab = trackSearch;
break;
case "ALBUM":
vueTab = albumSearch;
break;
case "ARTIST":
vueTab = artistSearch;
break;
case "PLAYLIST":
vueTab = playlistSearch;
break;
}
if (vueTab && vueTab.results.next != result.next){
vueTab.results.next = result.next
vueTab.results.data = vueTab.results.data.concat(result.data)
}
}
socket.on("search", function(result){searchUpadate(result)})
function clickElement(button){
return document.getElementById(button).click()
}
function sendAddToQueue(url, bitrate = null){
socket.emit("addToQueue", {url: url, bitrate:bitrate})
}
var mainSearch = new Vue({
el: '#main_search',
data: {
names: {
"TOP_RESULT": "Top Result",
"TRACK": "Tracks",
"ARTIST": "Artists",
"ALBUM": "Albums",
"PLAYLIST": "Playlists"
},
results: {
QUERY: "",
ORDER: [],
ALBUM: {},
ARTIST: {},
TRACK: {},
TOP_RESULT: [],
PLAYLIST: {}
},
},
methods: {
changeSearchTab: function (section) {
if (section != "TOP_RESULT")
clickElement('search_'+section.toLowerCase()+'_tab')
},
addToQueue: function(url){sendAddToQueue(url)}
}
})
var trackSearch = new Vue({
el: '#track_search',
data: {
type: "TRACK",
nb: 40,
query: "",
results: {
data: [],
next: 0,
total: 0
}
},
methods: {
addToQueue: function(url){sendAddToQueue(url)}
}
})
var albumSearch = new Vue({
el: '#album_search',
data: {
type: "ALBUM",
nb: 20,
query: "",
results: {
data: [],
next: 0,
total: 0
}
},
methods: {
addToQueue: function(url){sendAddToQueue(url)}
}
})
var artistSearch = new Vue({
el: '#artist_search',
data: {
type: "ARTIST",
nb: 20,
query: "",
results: {
data: [],
next: 0,
total: 0
}
},
methods: {
addToQueue: function(url){sendAddToQueue(url)}
}
})
var playlistSearch = new Vue({
el: '#playlist_search',
data: {
type: "PLAYLIST",
nb: 20,
query: "",
results: {
data: [],
next: 0,
total: 0
}
},
methods: {
addToQueue: function(url){sendAddToQueue(url)}
}
})
// Search section
$("#searchbar").keyup(function(e){
if(e.keyCode == 13){
term = this.value
console.log(term)
if (isValidURL(term))
socket.emit("addToQueue", {url: term});
else{
document.getElementById("search_tab_content").style.display = "none";
socket.emit("mainSearch", {term: term});
}
}
})
function mainSearchHandler(result){
console.log(result)
mainSearch.results = result
trackSearch.results = result.TRACK
albumSearch.results = result.ALBUM
artistSearch.results = result.ARTIST
playlistSearch.results = result.PLAYLIST
trackSearch.query = result.QUERY
albumSearch.query = result.QUERY
artistSearch.query = result.QUERY
playlistSearch.query = result.QUERY
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)})

33
public/js/app/utils.js Normal file
View File

@@ -0,0 +1,33 @@
function isValidURL(text){
if (text.toLowerCase().startsWith("http")){
if (text.toLowerCase().indexOf("deezer.com") >= 0 || text.toLowerCase().indexOf("open.spotify.com") >= 0)
return true
}else if (text.toLowerCase().startsWith("spotify:"))
return true
return false
}
function convertDuration(duration) {
//convert from seconds only to mm:ss format
var 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
}
function convertDurationSeparated(duration){
var hh, mm, ss
mm = Math.floor(duration / 60)
hh = Math.floor(mm / 60)
ss = duration - (mm * 60)
mm -= hh*60
return [hh, mm, ss]
}
function numberWithDots(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}