# Conflicts:
#	public/js/app/app.js
#	public/js/app/downloadList.js
#	public/js/app/search.js
This commit is contained in:
Roberto Tonino 2020-04-16 20:00:35 +02:00
commit bf6da9a51b
7 changed files with 165 additions and 63 deletions

View File

@ -121,6 +121,7 @@ button {
min-width: 64px; min-width: 64px;
text-transform: uppercase; text-transform: uppercase;
color: var(--accent-text); color: var(--accent-text);
cursor: pointer;
} }
button[disabled] { button[disabled] {

View File

@ -48,20 +48,50 @@
width: 90%; width: 90%;
} }
/* The Modal (background) */
.smallmodal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1250; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
animation-duration: 0.3s;
}
/* Modal Content */
.smallmodal-content {
background-color: none;
margin: auto;
width: 30%;
align-items: center;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.smallmodal-content button{
width: 100%;
margin-bottom: 8px;
}
@media only screen and (min-width: 601px) { @media only screen and (min-width: 601px) {
#container { #container, .smallmodal-content {
width: 85%; width: 85%;
} }
} }
@media only screen and (min-width: 993px) { @media only screen and (min-width: 993px) {
#container { #container, .smallmodal-content {
width: 70%; width: 70%;
} }
} }
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {
#container { #container, .smallmodal-content {
width: 100%; width: 100%;
} }
} }

View File

@ -15,3 +15,7 @@
.side_icon.active { .side_icon.active {
color: var(--accent-color); color: var(--accent-color);
} }
.main_tablinks {
cursor: pointer;
}

View File

@ -19,15 +19,15 @@
</script> --> </script> -->
</head> </head>
<body> <body>
<aside id="sidebar"> <aside role="navigation" id="sidebar">
<i class="material-icons side_icon">menu</i> <i class="material-icons side_icon">menu</i>
<i onclick="changeTab(event, 'main', 'search_tab')" id="main_search_tablink" class="main_tablinks"></i> <i onclick="changeTab(event, 'main', 'search_tab')" id="main_search_tablink" class="main_tablinks"></i>
<i onclick="changeTab(event, 'main', 'home_tab')" id="main_home_tablink" class="material-icons side_icon main_tablinks">home</i> <i role="link" aria-label="home" onclick="changeTab(event, 'main', 'home_tab')" id="main_home_tablink" class="material-icons side_icon main_tablinks">home</i>
<i onclick="changeTab(event, 'main', 'charts_tab')" id="main_charts_tablink" class="material-icons side_icon main_tablinks">bubble_chart</i> <i role="link" aria-label="charts" onclick="changeTab(event, 'main', 'charts_tab')" id="main_charts_tablink" class="material-icons side_icon main_tablinks">bubble_chart</i>
<i onclick="changeTab(event, 'main', 'favorites_tab')" id="main_favorites_tablink" class="material-icons side_icon main_tablinks">album</i> <i role="link" aria-label="favorites" onclick="changeTab(event, 'main', 'favorites_tab')" id="main_favorites_tablink" class="material-icons side_icon main_tablinks">album</i>
<i onclick="changeTab(event, 'main', 'analyzer_tab')" id="main_analyzer_tablink" class="material-icons side_icon main_tablinks">link</i> <i role="link" aria-label="link analyzer" onclick="changeTab(event, 'main', 'analyzer_tab')" id="main_analyzer_tablink" class="material-icons side_icon main_tablinks">link</i>
<i onclick="changeTab(event, 'main', 'settings_tab')" id="main_settings_tablink" class="material-icons side_icon main_tablinks">settings</i> <i role="link" aria-label="settings" onclick="changeTab(event, 'main', 'settings_tab')" id="main_settings_tablink" class="material-icons side_icon main_tablinks">settings</i>
<i onclick="changeTab(event, 'main', 'about_tab')" id="main_about_tablink" class="material-icons side_icon main_tablinks">info</i> <i role="link" aria-label="about" onclick="changeTab(event, 'main', 'about_tab')" id="main_about_tablink" class="material-icons side_icon main_tablinks">info</i>
</aside> </aside>
<main id="main_content"> <main id="main_content">
<div id="middle_section"> <div id="middle_section">
@ -319,9 +319,13 @@ <h1>Settings</h1>
<p>Save images as png</p> <p>Save images as png</p>
<input type="checkbox" v-model="settings.PNGcovers"> <input type="checkbox" v-model="settings.PNGcovers">
</div> </div>
<div class="input_group">
<p>JPEG image quality</p>
<input type="number" min="1" max="100" v-model.number="settings.jpegImageQuality">
</div>
<div class="input_group"> <div class="input_group">
<p>Save playlists as compilation</p> <p>Save playlists as compilation</p>
<input type="checkbox" v-model="settings.savePlaylistAsCompilation"> <input type="checkbox" v-model="settings.tags.savePlaylistAsCompilation">
</div> </div>
<div class="input_group"> <div class="input_group">
<p>Remove album version from track title</p> <p>Remove album version from track title</p>
@ -356,6 +360,16 @@ <h1>Settings</h1>
</select> </select>
</div> </div>
</div> </div>
<div id="settings_spotify_tab">
<div class="input_group">
<p>Spotify clientID</p>
<input type="text" v-model="spotifyFeatures.clientId">
</div>
<div class="input_group">
<p>Spotify Client Secret</p>
<input type="password" v-model="spotifyFeatures.clientSecret">
</div>
</div>
<footer> <footer>
<button onclick="saveSettings()">Save</button> <button onclick="saveSettings()">Save</button>
</footer> </footer>
@ -381,6 +395,17 @@ <h1>Settings</h1>
</div> </div>
</div> </div>
</main> </main>
<div id="modal_quality" class="smallmodal">
<!-- Modal content -->
<div class="smallmodal-content">
<button onclick="modalQualityButton(9)">Download FLAC</button><br>
<button onclick="modalQualityButton(3)">Download MP3 320kbps</button><br>
<button onclick="modalQualityButton(1)">Download MP3 128kbps</button><br>
<button onclick="modalQualityButton(15)">Download 360 Reality Audio [HQ]</button><br>
<button onclick="modalQualityButton(14)">Download 360 Reality Audio [MQ]</button><br>
<button onclick="modalQualityButton(13)">Download 360 Reality Audio [LQ]</button><br>
</div>
</div>
</body> </body>
<script type="text/javascript" src="/public/js/vendor/httpVueLoader.js"></script> <script type="text/javascript" src="/public/js/vendor/httpVueLoader.js"></script>
<script type="text/javascript" src="/public/js/vendor/socket.io.js"></script> <script type="text/javascript" src="/public/js/vendor/socket.io.js"></script>

View File

@ -7,7 +7,8 @@ let main_selected = ''
// toasts stuff // toasts stuff
let toastsWithId = {} let toastsWithId = {}
// settings // settings
let lastSettings = {} lastSettings = {}
lastCredentials = {}
function toast(msg, icon = null, dismiss = true, id = null) { function toast(msg, icon = null, dismiss = true, id = null) {
if (toastsWithId[id]) { if (toastsWithId[id]) {
@ -21,9 +22,8 @@ function toast(msg, icon = null, dismiss = true, id = null) {
else icon = `<i class="material-icons">${icon}</i>` else icon = `<i class="material-icons">${icon}</i>`
toastDOM.find('.toast-icon').html(icon) toastDOM.find('.toast-icon').html(icon)
} }
console.log({ dismiss }) if (dismiss !== null && dismiss){
if (dismiss !== null && dismiss) { setTimeout(function(){
setTimeout(function () {
toastObj.hideToast() toastObj.hideToast()
delete toastsWithId[id] delete toastsWithId[id]
}, 3000) }, 3000)
@ -163,30 +163,35 @@ socket.on('logged_out', function () {
// settings stuff // settings stuff
var settingsTab = new Vue({ var settingsTab = new Vue({
el: '#settings_tab', el: '#settings_tab',
data: { data: {
settings: {} settings: {tags: {}},
} spotifyFeatures: {}
}
}) })
socket.on('init_settings', function (settings) { socket.on("init_settings", function(settings, credentials){
loadSettings(settings) console.log(settings,credentials)
toast('Settings loaded!', 'settings') loadSettings(settings, credentials)
toast("Settings loaded!", 'settings')
}) })
socket.on('updateSettings', function (settings) { socket.on("updateSettings", function(settings, credentials){
loadSettings(settings) loadSettings(settings, credentials)
toast('Settings updated!', 'settings') toast("Settings updated!", 'settings')
}) })
function loadSettings(settings) { function loadSettings(settings, spotifyCredentials){
lastSettings = { ...settings } lastSettings = {...settings}
lastCredentials = {...spotifyCredentials}
settingsTab.settings = settings settingsTab.settings = settings
settingsTab.spotifyFeatures = spotifyCredentials
} }
function saveSettings() { function saveSettings(){
lastSettings = { ...settingsTab.settings } lastSettings = {...settingsTab.settings}
socket.emit('saveSettings', lastSettings) lastCredentials = {...settingsTab.spotifyFeatures}
socket.emit("saveSettings", lastSettings, lastCredentials)
} }
// tabs stuff // tabs stuff
@ -217,3 +222,44 @@ function changeTab(evt, section, tabName) {
scrolledSearch(window[search_selected.split('_')[0] + 'Search']) scrolledSearch(window[search_selected.split('_')[0] + 'Search'])
} }
} }
// 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(bitrate){
var url=$(modalQuality).data("url")
if (url.indexOf(";") != -1){
urls = url.split(";")
urls.forEach(url=>{
sendAddToQueue(url, bitrate)
})
}else{
sendAddToQueue(url, bitrate)
}
$(modalQuality).addClass('animated fadeOut')
}

View File

@ -9,15 +9,15 @@ socket.on('init_downloadQueue', function (data) {
addToQueue(data.queueList[item]) addToQueue(data.queueList[item])
}) })
} }
if (data.currentItem) { if (data.currentItem){
addToQueue(data['queueList'][data.currentItem]) addToQueue(data['queueList'][data.currentItem], true)
} }
data.queue.forEach(item => { data.queue.forEach(item => {
addToQueue(data.queueList[item]) addToQueue(data.queueList[item])
}) })
}) })
function addToQueue(queueItem) { function addToQueue(queueItem, current=false){
queueList[queueItem.uuid] = queueItem queueList[queueItem.uuid] = queueItem
if (queueItem.downloaded + queueItem.failed == queueItem.size) queueComplete.push(queueItem.uuid) if (queueItem.downloaded + queueItem.failed == queueItem.size) queueComplete.push(queueItem.uuid)
else queue.push(queueItem.uuid) else queue.push(queueItem.uuid)
@ -39,12 +39,9 @@ function addToQueue(queueItem) {
<div class="progress"><div id="bar_${queueItem.uuid}" class="indeterminate"></div></div> <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> <i onclick="downloadAction(event)" class="material-icons queue_icon" data-uuid="${queueItem.uuid}">remove</i>
</div> </div>
</div>` </div>`)
) if (queueItem.progress>0 || current){
if (queueItem.progress > 0) { $('#bar_' + queueItem.uuid).removeClass('indeterminate').addClass('determinate')
$('#bar_' + queueItem.uuid)
.removeClass('indeterminate')
.addClass('determinate')
} }
$('#bar_' + queueItem.uuid).css('width', queueItem.progress + '%') $('#bar_' + queueItem.uuid).css('width', queueItem.progress + '%')
if (queueItem.failed >= 1) { if (queueItem.failed >= 1) {

View File

@ -82,9 +82,8 @@ let MainSearch = new Vue({
changeSearchTab(section) { changeSearchTab(section) {
if (section != 'TOP_RESULT') clickElement('search_' + section.toLowerCase() + '_tab') if (section != 'TOP_RESULT') clickElement('search_' + section.toLowerCase() + '_tab')
}, },
addToQueue(url) { addToQueue: function(e){sendAddToQueue(e.currentTarget.dataset.link)},
sendAddToQueue(url) openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}
}
} }
}) })
@ -101,9 +100,8 @@ var trackSearch = new Vue({
} }
}, },
methods: { methods: {
addToQueue: function (url) { addToQueue: function(e){sendAddToQueue(e.currentTarget.dataset.link)},
sendAddToQueue(url) openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}
}
} }
}) })
@ -120,9 +118,8 @@ var albumSearch = new Vue({
} }
}, },
methods: { methods: {
addToQueue: function (url) { addToQueue: function(e){sendAddToQueue(e.currentTarget.dataset.link)},
sendAddToQueue(url) openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}
}
} }
}) })
@ -139,9 +136,8 @@ var artistSearch = new Vue({
} }
}, },
methods: { methods: {
addToQueue: function (url) { addToQueue: function(e){sendAddToQueue(e.currentTarget.dataset.link)},
sendAddToQueue(url) openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}
}
} }
}) })
@ -158,23 +154,26 @@ var playlistSearch = new Vue({
} }
}, },
methods: { methods: {
addToQueue: function (url) { addToQueue: function(e){sendAddToQueue(e.currentTarget.dataset.link)},
sendAddToQueue(url) openQualityModal: function(e){e.preventDefault(); openQualityModal(e.currentTarget.dataset.link)}
}
} }
}) })
let term = null let term = null
// Search section // Search section
$('#searchbar').keyup(function (e) { $("#searchbar").keyup(function(e){
if (e.keyCode == 13) { if(e.keyCode == 13){
term = this.value term = this.value
console.log(term) if (isValidURL(term)){
if (isValidURL(term)) socket.emit('addToQueue', { url: term }) if (e.ctrlKey){
else { openQualityModal(term);
document.getElementById('search_tab_content').style.display = 'none' }else{
socket.emit('mainSearch', { term: term }) sendAddToQueue(term);
}
}else{
document.getElementById("search_tab_content").style.display = "none";
socket.emit("mainSearch", {term: term});
} }
} }
}) })