1.1.14 - importing and what not
This commit is contained in:
@ -27,8 +27,8 @@
|
||||
permanent
|
||||
fixed
|
||||
app
|
||||
mini-variant
|
||||
expand-on-hover
|
||||
:mini-variant='!this.$root.settings.sidebarOpen'
|
||||
:expand-on-hover='!this.$root.settings.sidebarOpen'
|
||||
><v-list nav dense>
|
||||
|
||||
<!-- Profile -->
|
||||
@ -127,6 +127,16 @@
|
||||
<v-list-item-title>{{$t('Downloads')}}</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<!-- Importer -->
|
||||
<v-list-item link to='/importer'>
|
||||
<v-list-item-icon>
|
||||
<v-icon v-if='!$root.importer.done && !$root.importer.active'>mdi-import</v-icon>
|
||||
<v-icon v-if='$root.importer.done' color='primary'>mdi-check</v-icon>
|
||||
<v-progress-circular indeterminate style='top: -8px' size='42' v-if='$root.importer.active'></v-progress-circular>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-title>{{$t('Importer')}}</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<!-- About -->
|
||||
<v-list-item link to='/about'>
|
||||
<v-list-item-icon>
|
||||
@ -243,8 +253,7 @@
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<!-- Volume -->
|
||||
<v-col cols='auto' class='d-none d-sm-flex px-2' @click.stop>
|
||||
|
||||
<v-col cols='auto' class='d-none d-sm-flex px-2' @click.stop ref='volumeBar'>
|
||||
<div style='width: 180px;' class='d-flex'>
|
||||
<v-slider
|
||||
dense
|
||||
@ -445,6 +454,23 @@ export default {
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
//Scroll on volume
|
||||
this.$refs.volumeBar.addEventListener('wheel', e => {
|
||||
//Volup
|
||||
if (e.deltaY < 0) {
|
||||
if (this.volume + 0.05 > 1)
|
||||
this.volume = 1;
|
||||
else
|
||||
this.volume += 0.05;
|
||||
} else {
|
||||
//Voldown
|
||||
if (this.volume - 0.05 < 0)
|
||||
this.volume = 0;
|
||||
else
|
||||
this.volume -= 0.05;
|
||||
}
|
||||
});
|
||||
|
||||
//onClick for footer
|
||||
this.$refs.footer.addEventListener('click', () => {
|
||||
if (this.$root.track) this.showPlayer = true;
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<v-card max-width='175px' max-height='210px' @click='play' :loading='loading' elevation='0' color='transparent'>
|
||||
<v-card max-width='175px' max-height='220px' height='220px' @click='play' :loading='loading' elevation='0' color='transparent'>
|
||||
<v-img :src='stl.cover.thumb'>
|
||||
</v-img>
|
||||
|
||||
<div class='pa-2 text-subtitle-2 text-center text-truncate'>{{stl.title}}</div>
|
||||
<div class='pa-2 text-subtitle-2'>{{stl.subtitle}}</div>
|
||||
</v-card>
|
||||
|
||||
</div>
|
||||
|
@ -12,6 +12,7 @@ import Settings from '@/views/Settings.vue';
|
||||
import DeezerPage from '@/views/DeezerPage.vue';
|
||||
import DownloadsPage from '@/views/DownloadsPage.vue';
|
||||
import About from '@/views/About.vue';
|
||||
import Importer from '@/views/Importer.vue';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
@ -79,6 +80,10 @@ const routes = [
|
||||
{
|
||||
path: '/about',
|
||||
component: About
|
||||
},
|
||||
{
|
||||
path: '/importer',
|
||||
component: Importer
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -146,5 +146,12 @@
|
||||
"Collaborative": "Collaborative",
|
||||
"Edit playlist": "Edit playlist",
|
||||
"Save": "Save",
|
||||
"Edit": "Edit"
|
||||
"Edit": "Edit",
|
||||
"Importer": "Importer",
|
||||
"Enter URL": "Enter URL",
|
||||
"Currently only Spotify is supported and limited to 100 tracks.": "Currently only Spotify is supported and limited to 100 tracks.",
|
||||
"Import into playlist": "Import into playlist",
|
||||
"Keep sidebar open": "Keep sidebar open",
|
||||
"WARNING: Might require reload to work properly!": "WARNING: Might require reload to work properly!",
|
||||
"An error occured, URL might be invalid or unsupported.": "An error occured, URL might be invalid or unsupported."
|
||||
}
|
@ -106,6 +106,14 @@ new Vue({
|
||||
}
|
||||
},
|
||||
|
||||
//Importer
|
||||
importer: {
|
||||
active: false,
|
||||
done: false,
|
||||
error: false,
|
||||
tracks: []
|
||||
},
|
||||
|
||||
//Used to prevent double listen logging
|
||||
logListenId: null,
|
||||
|
||||
@ -586,6 +594,27 @@ new Vue({
|
||||
this.seek(data.position);
|
||||
});
|
||||
|
||||
//Importer
|
||||
|
||||
//Start
|
||||
this.sockets.subscribe('importerInit', (data) => {
|
||||
this.importer = data;
|
||||
});
|
||||
//New track imported
|
||||
this.sockets.subscribe('importerTrack', (data) => {
|
||||
this.importer.tracks.push(data);
|
||||
});
|
||||
//Mark as done
|
||||
this.sockets.subscribe('importerDone', () => {
|
||||
this.importer.active = false;
|
||||
this.importer.done = true;
|
||||
});
|
||||
this.sockets.subscribe('importerError', () => {
|
||||
this.importer.error = true;
|
||||
this.importer.active = false;
|
||||
this.importer.done = false;
|
||||
});
|
||||
|
||||
r();
|
||||
},
|
||||
|
||||
@ -605,6 +634,9 @@ new Vue({
|
||||
document.addEventListener('keyup', (e) => {
|
||||
//Don't handle keystrokes in text fields
|
||||
if (e.target.tagName == "INPUT") return;
|
||||
//Don't handle if specials
|
||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
|
||||
|
||||
//K toggle playback
|
||||
if (e.code == "KeyK" || e.code == "Space") this.$root.toggle();
|
||||
//L +10s (from YT)
|
||||
|
@ -100,23 +100,25 @@
|
||||
</v-btn>
|
||||
|
||||
<!-- Volume -->
|
||||
<v-slider
|
||||
min='0.00'
|
||||
:prepend-icon='$root.muted ? "mdi-volume-off" : "mdi-volume-high"'
|
||||
max='1.00'
|
||||
step='0.01'
|
||||
v-model='$root.volume'
|
||||
class='px-8'
|
||||
style='padding-top: 2px;'
|
||||
@change='updateVolume'
|
||||
@click:prepend='$root.toggleMute()'
|
||||
>
|
||||
<template v-slot:append>
|
||||
<div style='position: absolute; padding-top: 4px;'>
|
||||
{{Math.round($root.volume * 100)}}%
|
||||
</div>
|
||||
</template>
|
||||
</v-slider>
|
||||
<div ref='volumeBar' style='width: 100%;'>
|
||||
<v-slider
|
||||
min='0.00'
|
||||
:prepend-icon='$root.muted ? "mdi-volume-off" : "mdi-volume-high"'
|
||||
max='1.00'
|
||||
step='0.01'
|
||||
v-model='$root.volume'
|
||||
class='px-8'
|
||||
style='padding-top: 2px;'
|
||||
@change='updateVolume'
|
||||
@click:prepend='$root.toggleMute()'
|
||||
>
|
||||
<template v-slot:append>
|
||||
<div style='position: absolute; padding-top: 4px;'>
|
||||
{{Math.round($root.volume * 100)}}%
|
||||
</div>
|
||||
</template>
|
||||
</v-slider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -328,6 +330,22 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
//Scroll on volume
|
||||
this.$refs.volumeBar.addEventListener('wheel', e => {
|
||||
//Volup
|
||||
if (e.deltaY < 0) {
|
||||
if (this.$root.volume + 0.05 > 1)
|
||||
this.$root.volume = 1;
|
||||
else
|
||||
this.$root.volume += 0.05;
|
||||
} else {
|
||||
//Voldown
|
||||
if (this.$root.volume - 0.05 < 0)
|
||||
this.$root.volume = 0;
|
||||
else
|
||||
this.$root.volume -= 0.05;
|
||||
}
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
|
86
app/client/src/views/Importer.vue
Normal file
86
app/client/src/views/Importer.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<h1>{{$t("Importer")}}</h1><br>
|
||||
<span class='text-h6'>
|
||||
<v-icon right color='warning' class='mr-2'>mdi-alert</v-icon>
|
||||
{{$t("Currently only Spotify is supported and limited to 100 tracks.")}}
|
||||
</span>
|
||||
<br>
|
||||
<!-- URL entry and buttons -->
|
||||
<div class='d-flex mt-4' v-if='!$root.importer.done && !$root.importer.active && !$root.importer.error'>
|
||||
<v-text-field
|
||||
v-model=input
|
||||
:label='$t("Enter URL")'
|
||||
:rules='[valid]'
|
||||
></v-text-field>
|
||||
<v-btn class='mx-2 mt-4' color='primary' :disabled='!valid' @click='start("import")'>
|
||||
<v-icon left>mdi-playlist-plus</v-icon>
|
||||
{{$t("Import into playlist")}}
|
||||
</v-btn>
|
||||
<v-btn class='mx-2 mt-4' color='green' :disabled='!valid' @click='start("download")'>
|
||||
<v-icon left>mdi-download</v-icon>
|
||||
{{$t("Download")}}
|
||||
</v-btn>
|
||||
</div>
|
||||
<!-- Tracks -->
|
||||
<div class='mt-4' v-if='$root.importer.done || $root.importer.active'>
|
||||
<h2 class='mb-2'>Tracks:</h2>
|
||||
<v-list>
|
||||
<v-list-item v-for='(track, i) in $root.importer.tracks' :key='i'>
|
||||
<v-list-item-avatar>
|
||||
<v-img :src='track.art'></v-img>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{track.title}}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{track.artist}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-icon v-if='track.ok' color='green'>mdi-check</v-icon>
|
||||
<v-icon v-if='!track.ok' color='red'></v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
<div v-if='$root.importer.error' class='text-center mt-4'>
|
||||
<h2>{{$t("An error occured, URL might be invalid or unsupported.")}}</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Importer',
|
||||
data() {
|
||||
return {
|
||||
input: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async start(type) {
|
||||
await this.$axios.post('/import', {url: this.input, type});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
valid() {
|
||||
let i = this.input || '';
|
||||
return i.startsWith('https://open.spotify.com/playlist/') && !i.includes(' ');
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
destroyed() {
|
||||
//If done
|
||||
if (this.$root.importer.done || this.$root.importer.error) {
|
||||
this.$root.importer.done = false;
|
||||
this.$root.importer.active = false;
|
||||
this.$root.importer.error = false;
|
||||
this.$root.importer.tracks = [];
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
@ -144,7 +144,6 @@
|
||||
<v-list-item-title class='pl-2'>{{$t("Select primary color")}}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<!-- Autocomplete -->
|
||||
<v-list-item>
|
||||
<v-list-item-action>
|
||||
@ -154,6 +153,17 @@
|
||||
<v-list-item-title>{{$t("Show autocomplete in search")}}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<!-- Keep sidebar open -->
|
||||
<v-list-item>
|
||||
<v-list-item-action>
|
||||
<v-checkbox v-model='$root.settings.sidebarOpen' class='pl-2'></v-checkbox>
|
||||
</v-list-item-action>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{$t("Keep sidebar open")}}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{$t("WARNING: Might require reload to work properly!")}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
|
||||
<!-- Accounts -->
|
||||
<v-subheader>{{$t("Integrations")}}</v-subheader>
|
||||
|
Reference in New Issue
Block a user