Merge branch 'restful-refactor'
This commit is contained in:
commit
1b063ac24c
@ -7,5 +7,6 @@
|
|||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"arrowParens": "avoid",
|
"arrowParens": "avoid",
|
||||||
"vueIndentScriptAndStyle": false
|
"vueIndentScriptAndStyle": false,
|
||||||
|
"endOfLine": "lf"
|
||||||
}
|
}
|
@ -17,7 +17,6 @@
|
|||||||
"@vue/composition-api": "^1.0.0-beta.21",
|
"@vue/composition-api": "^1.0.0-beta.21",
|
||||||
"flag-icon-css": "^3.5.0",
|
"flag-icon-css": "^3.5.0",
|
||||||
"lodash-es": "^4.17.15",
|
"lodash-es": "^4.17.15",
|
||||||
"socket.io-client": "^3.1.0",
|
|
||||||
"svg-country-flags": "^1.2.9",
|
"svg-country-flags": "^1.2.9",
|
||||||
"toastify-js": "^1.9.3",
|
"toastify-js": "^1.9.3",
|
||||||
"vue": "^2.6.12",
|
"vue": "^2.6.12",
|
||||||
|
File diff suppressed because one or more lines are too long
@ -28,10 +28,6 @@ export default {
|
|||||||
find: 'vue',
|
find: 'vue',
|
||||||
replacement: 'vue/dist/vue.esm'
|
replacement: 'vue/dist/vue.esm'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
find: 'socket.io-client',
|
|
||||||
replacement: 'socket.io-client/dist/socket.io.min'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
find: '@',
|
find: '@',
|
||||||
replacement: __dirname + '/src'
|
replacement: __dirname + '/src'
|
||||||
|
@ -69,7 +69,8 @@ export default {
|
|||||||
// ConfirmModal
|
// ConfirmModal
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
socket.on('connect', () => {
|
socket.addEventListener('open', (event) => {
|
||||||
|
console.log("Connected to WebSocket")
|
||||||
this.isSocketConnected = true
|
this.isSocketConnected = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
59
src/app.js
59
src/app.js
@ -19,18 +19,42 @@ import router from '@/router'
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
|
import { fetchData } from '@/utils/api'
|
||||||
import { toast } from '@/utils/toasts'
|
import { toast } from '@/utils/toasts'
|
||||||
import { isValidURL } from '@/utils/utils'
|
import { isValidURL } from '@/utils/utils'
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
|
|
||||||
/* ===== App initialization ===== */
|
/* ===== App initialization ===== */
|
||||||
function startApp() {
|
async function startApp() {
|
||||||
new Vue({
|
new Vue({
|
||||||
store,
|
store,
|
||||||
router,
|
router,
|
||||||
i18n,
|
i18n,
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|
||||||
|
const connectResponse = await (await fetch('connect')).json()
|
||||||
|
|
||||||
|
store.dispatch('setAppInfo', connectResponse.update)
|
||||||
|
|
||||||
|
if (connectResponse.autologin) {
|
||||||
|
console.info('Autologin')
|
||||||
|
let arl = localStorage.getItem('arl')
|
||||||
|
const accountNum = localStorage.getItem('accountNum')
|
||||||
|
|
||||||
|
if (arl) {
|
||||||
|
arl = arl.trim()
|
||||||
|
let result
|
||||||
|
|
||||||
|
if (accountNum !== 0) {
|
||||||
|
result = await fetchData('login', { arl, force: true, child: accountNum || 0 })
|
||||||
|
} else {
|
||||||
|
result = await fetchData('login', { arl })
|
||||||
|
}
|
||||||
|
|
||||||
|
loggedIn(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initClient() {
|
function initClient() {
|
||||||
@ -52,7 +76,7 @@ document.addEventListener('paste', pasteEvent => {
|
|||||||
if (router.currentRoute.name === 'Link Analyzer') {
|
if (router.currentRoute.name === 'Link Analyzer') {
|
||||||
socket.emit('analyzeLink', pastedText)
|
socket.emit('analyzeLink', pastedText)
|
||||||
} else {
|
} else {
|
||||||
if (pastedText.indexOf("\n") != -1) pastedText = pastedText.replace(/\n/g, ';');
|
if (pastedText.indexOf('\n') != -1) pastedText = pastedText.replace(/\n/g, ';')
|
||||||
sendAddToQueue(pastedText)
|
sendAddToQueue(pastedText)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -86,26 +110,7 @@ socket.on('message', function(msg) {
|
|||||||
console.log(msg)
|
console.log(msg)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('logging_in', function() {
|
function loggedIn(data) {
|
||||||
toast(i18n.t('toasts.loggingIn'), 'loading', false, 'login-toast')
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.on('init_autologin', function() {
|
|
||||||
let arl = localStorage.getItem('arl')
|
|
||||||
let accountNum = localStorage.getItem('accountNum')
|
|
||||||
|
|
||||||
if (arl) {
|
|
||||||
arl = arl.trim()
|
|
||||||
|
|
||||||
if (accountNum != 0) {
|
|
||||||
socket.emit('login', arl, true, accountNum)
|
|
||||||
} else {
|
|
||||||
socket.emit('login', arl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.on('logged_in', function(data) {
|
|
||||||
const { status, user } = data
|
const { status, user } = data
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -138,6 +143,15 @@ socket.on('logged_in', function(data) {
|
|||||||
// $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`)
|
// $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`)
|
||||||
// document.getElementById('home_not_logged_in').classList.remove('hide')
|
// document.getElementById('home_not_logged_in').classList.remove('hide')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
socket.on('logging_in', function() {
|
||||||
|
toast(i18n.t('toasts.loggingIn'), 'loading', false, 'login-toast')
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on('logged_in', function(data) {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('logged_out', function() {
|
socket.on('logged_out', function() {
|
||||||
@ -145,6 +159,7 @@ socket.on('logged_out', function() {
|
|||||||
|
|
||||||
store.dispatch('logout')
|
store.dispatch('logout')
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
socket.on('restoringQueue', function () {
|
socket.on('restoringQueue', function () {
|
||||||
toast(i18n.t('toasts.restoringQueue'), 'loading', false, 'restoring_queue')
|
toast(i18n.t('toasts.restoringQueue'), 'loading', false, 'restoring_queue')
|
||||||
|
@ -113,23 +113,20 @@
|
|||||||
import { computed, defineComponent, reactive, toRefs } from '@vue/composition-api'
|
import { computed, defineComponent, reactive, toRefs } from '@vue/composition-api'
|
||||||
|
|
||||||
import { links } from '@/data/sidebar'
|
import { links } from '@/data/sidebar'
|
||||||
import { socket } from '@/utils/socket'
|
|
||||||
import { useTheme } from '@/use/theme'
|
import { useTheme } from '@/use/theme'
|
||||||
|
|
||||||
import deemixIcon from '@/assets/deemix-icon.svg'
|
import deemixIcon from '@/assets/deemix-icon.svg'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup(props, ctx) {
|
setup(props, ctx) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeTablink: 'home',
|
activeTablink: 'home',
|
||||||
updateAvailable: false,
|
|
||||||
links
|
links
|
||||||
})
|
})
|
||||||
const { THEMES, currentTheme } = useTheme()
|
const { THEMES, currentTheme } = useTheme()
|
||||||
|
|
||||||
/* === Add update notification near info === */
|
/* === Add update notification near info === */
|
||||||
socket.on('updateAvailable', () => {
|
const updateAvailable = computed(() => ctx.root.$store.state.appInfo.updateAvailable)
|
||||||
state.updateAvailable = true
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx.root.$router.afterEach((to, from) => {
|
ctx.root.$router.afterEach((to, from) => {
|
||||||
const linkInSidebar = state.links.find(link => link.routerName === to.name)
|
const linkInSidebar = state.links.find(link => link.routerName === to.name)
|
||||||
@ -141,6 +138,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
|
updateAvailable,
|
||||||
THEMES,
|
THEMES,
|
||||||
currentTheme,
|
currentTheme,
|
||||||
isSlim: computed(() => ctx.root.$store.getters.getSlimSidebar),
|
isSlim: computed(() => ctx.root.$store.getters.getSlimSidebar),
|
||||||
|
@ -26,9 +26,7 @@
|
|||||||
<li v-html="$t('about.thanks')"></li>
|
<li v-html="$t('about.thanks')"></li>
|
||||||
<i18n path="about.upToDate.text" tag="li">
|
<i18n path="about.upToDate.text" tag="li">
|
||||||
<template #newsChannel>
|
<template #newsChannel>
|
||||||
<a href="https://t.me/RemixDevNews" target="_blank">{{
|
<a href="https://t.me/RemixDevNews" target="_blank">{{ $t('about.upToDate.newsChannel') }}</a>
|
||||||
$t('about.upToDate.newsChannel')
|
|
||||||
}}</a>
|
|
||||||
</template>
|
</template>
|
||||||
</i18n>
|
</i18n>
|
||||||
</ul>
|
</ul>
|
||||||
@ -42,9 +40,7 @@
|
|||||||
<a href="https://git.rip/RemixDev/deemix" target="_blank">🚀 {{ $t('about.officialRepo') }}</a>
|
<a href="https://git.rip/RemixDev/deemix" target="_blank">🚀 {{ $t('about.officialRepo') }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://git.rip/RemixDev/deemix-webui" target="_blank">
|
<a href="https://git.rip/RemixDev/deemix-webui" target="_blank"> 💻 {{ $t('about.officialWebuiRepo') }} </a>
|
||||||
💻 {{ $t('about.officialWebuiRepo') }}
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://www.reddit.com/r/deemix" target="_blank">🤖 {{ $t('about.officialSubreddit') }}</a>
|
<a href="https://www.reddit.com/r/deemix" target="_blank">🤖 {{ $t('about.officialSubreddit') }}</a>
|
||||||
@ -63,9 +59,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<i18n path="about.questions.text" tag="li">
|
<i18n path="about.questions.text" tag="li">
|
||||||
<template #subreddit>
|
<template #subreddit>
|
||||||
<a href="https://www.reddit.com/r/deemix" target="_blank">{{
|
<a href="https://www.reddit.com/r/deemix" target="_blank">{{ $t('about.questions.subreddit') }}</a>
|
||||||
$t('about.questions.subreddit')
|
|
||||||
}}</a>
|
|
||||||
</template>
|
</template>
|
||||||
</i18n>
|
</i18n>
|
||||||
<li>
|
<li>
|
||||||
@ -241,7 +235,7 @@ ul {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, ref, reactive, toRefs, onMounted, computed } from '@vue/composition-api'
|
import { computed, defineComponent, onMounted, reactive, toRefs } from '@vue/composition-api'
|
||||||
|
|
||||||
import { useOnline } from '@/use/online'
|
import { useOnline } from '@/use/online'
|
||||||
|
|
||||||
|
@ -92,7 +92,6 @@ import { orderBy } from 'lodash-es'
|
|||||||
|
|
||||||
import { BaseTabs, BaseTab } from '@components/globals/BaseTabs'
|
import { BaseTabs, BaseTab } from '@components/globals/BaseTabs'
|
||||||
|
|
||||||
import { socket } from '@/utils/socket'
|
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import { checkNewRelease } from '@/utils/dates'
|
import { checkNewRelease } from '@/utils/dates'
|
||||||
import { formatArtistData, getArtistData } from '@/data/artist'
|
import { formatArtistData, getArtistData } from '@/data/artist'
|
||||||
|
@ -6,38 +6,38 @@
|
|||||||
<div class="release-grid">
|
<div class="release-grid">
|
||||||
<div
|
<div
|
||||||
v-for="release in countries"
|
v-for="release in countries"
|
||||||
role="button"
|
|
||||||
:aria-label="release.title"
|
|
||||||
class="w-40 h-40 release clickable"
|
|
||||||
@click="getTrackList"
|
|
||||||
:data-title="release.title"
|
|
||||||
:data-id="release.id"
|
|
||||||
:key="release.id"
|
:key="release.id"
|
||||||
|
:aria-label="release.title"
|
||||||
|
:data-id="release.id"
|
||||||
|
:data-title="release.title"
|
||||||
|
class="w-40 h-40 release clickable"
|
||||||
|
role="button"
|
||||||
|
@click="getTrackList"
|
||||||
>
|
>
|
||||||
<img class="w-full rounded coverart" :src="release.picture_medium" />
|
<img :src="release.picture_medium" class="w-full rounded coverart" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<button class="btn btn-primary" @click="onChangeCountry">{{ $t('charts.changeCountry') }}</button>
|
<button class="btn btn-primary" @click="onChangeCountry">{{ $t('charts.changeCountry') }}</button>
|
||||||
<button class="btn btn-primary" @click.stop="addToQueue" :data-link="'https://www.deezer.com/playlist/' + id">
|
<button :data-link="'https://www.deezer.com/playlist/' + id" class="btn btn-primary" @click.stop="addToQueue">
|
||||||
{{ $t('charts.download') }}
|
{{ $t('charts.download') }}
|
||||||
</button>
|
</button>
|
||||||
<table class="table table--charts">
|
<table class="table table--charts">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="track in chart" class="track_row">
|
<tr v-for="track in chart" class="track_row">
|
||||||
<td class="p-3 text-center cursor-default" :class="{ first: track.position === 1 }">
|
<td :class="{ first: track.position === 1 }" class="p-3 text-center cursor-default">
|
||||||
{{ track.position }}
|
{{ track.position }}
|
||||||
</td>
|
</td>
|
||||||
<td class="table__icon table__icon--big">
|
<td class="table__icon table__icon--big">
|
||||||
<span
|
<span
|
||||||
@click="playPausePreview"
|
|
||||||
class="relative inline-block rounded cursor-pointer"
|
|
||||||
:data-preview="track.preview"
|
:data-preview="track.preview"
|
||||||
|
class="relative inline-block rounded cursor-pointer"
|
||||||
|
@click="playPausePreview"
|
||||||
>
|
>
|
||||||
<PreviewControls v-if="track.preview" />
|
<PreviewControls v-if="track.preview" />
|
||||||
<img class="rounded coverart" :src="track.album.cover_small" />
|
<img :src="track.album.cover_small" class="rounded coverart" />
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="table__cell--large">
|
<td class="table__cell--large">
|
||||||
@ -47,16 +47,16 @@
|
|||||||
}}
|
}}
|
||||||
</td>
|
</td>
|
||||||
<router-link
|
<router-link
|
||||||
tag="td"
|
|
||||||
class="table__cell table__cell--medium table__cell--center clickable"
|
|
||||||
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
|
class="table__cell table__cell--medium table__cell--center clickable"
|
||||||
|
tag="td"
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
tag="td"
|
|
||||||
class="table__cell--medium table__cell--center clickable"
|
|
||||||
:to="{ name: 'Album', params: { id: track.album.id } }"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
|
class="table__cell--medium table__cell--center clickable"
|
||||||
|
tag="td"
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -64,15 +64,15 @@
|
|||||||
{{ convertDuration(track.duration) }}
|
{{ convertDuration(track.duration) }}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
class="cursor-pointer group"
|
|
||||||
@click.stop="addToQueue"
|
|
||||||
:data-link="track.link"
|
:data-link="track.link"
|
||||||
role="button"
|
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
|
class="cursor-pointer group"
|
||||||
|
role="button"
|
||||||
|
@click.stop="addToQueue"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="transition-colors duration-150 ease-in-out material-icons group-hover:text-primary"
|
|
||||||
:title="$t('globals.download_hint')"
|
:title="$t('globals.download_hint')"
|
||||||
|
class="transition-colors duration-150 ease-in-out material-icons group-hover:text-primary"
|
||||||
>
|
>
|
||||||
get_app
|
get_app
|
||||||
</i>
|
</i>
|
||||||
@ -85,14 +85,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
import { getChartsData } from '@/data/charts'
|
import { getChartsData, getChartTracks } from '@/data/charts'
|
||||||
|
|
||||||
import PreviewControls from '@components/globals/PreviewControls.vue'
|
import PreviewControls from '@components/globals/PreviewControls.vue'
|
||||||
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
|
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
|
||||||
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -116,12 +116,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
socket.on('setChartTracks', this.setTracklist)
|
// socket.on('setChartTracks', this.setTracklist)
|
||||||
this.$on('hook:destroyed', () => {
|
// this.$on('hook:destroyed', () => {
|
||||||
socket.off('setChartTracks')
|
// socket.off('setChartTracks')
|
||||||
})
|
// })
|
||||||
|
|
||||||
let chartsData = await getChartsData()
|
let { data: chartsData } = await getChartsData()
|
||||||
let worldwideChart
|
let worldwideChart
|
||||||
|
|
||||||
chartsData = chartsData.filter(item => {
|
chartsData = chartsData.filter(item => {
|
||||||
@ -147,17 +147,13 @@ export default {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
currentTarget: {
|
currentTarget: {
|
||||||
dataset: { title }
|
dataset: { title, id }
|
||||||
},
|
|
||||||
currentTarget: {
|
|
||||||
dataset: { id }
|
|
||||||
}
|
}
|
||||||
} = event
|
} = event
|
||||||
|
|
||||||
this.country = title
|
this.country = title
|
||||||
localStorage.setItem('chart', this.country)
|
localStorage.setItem('chart', this.country)
|
||||||
this.id = id
|
this.id = id
|
||||||
socket.emit('getChartTracks', this.id)
|
|
||||||
},
|
},
|
||||||
setTracklist(data) {
|
setTracklist(data) {
|
||||||
this.chart = data
|
this.chart = data
|
||||||
@ -185,6 +181,15 @@ export default {
|
|||||||
localStorage.setItem('chart', this.country)
|
localStorage.setItem('chart', this.country)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
id(newId) {
|
||||||
|
const isActualChart = newId !== 0
|
||||||
|
|
||||||
|
if (isActualChart) {
|
||||||
|
getChartTracks(newId).then(response => this.setTracklist(response.result))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
<h1 class="mb-8 text-5xl">
|
<h1 class="mb-8 text-5xl">
|
||||||
{{ $t('favorites.title') }}
|
{{ $t('favorites.title') }}
|
||||||
<div
|
<div
|
||||||
@click="refreshFavorites"
|
|
||||||
class="inline-block clickable"
|
|
||||||
ref="reloadButton"
|
ref="reloadButton"
|
||||||
role="button"
|
|
||||||
aria-label="reload"
|
aria-label="reload"
|
||||||
|
class="inline-block clickable"
|
||||||
|
role="button"
|
||||||
|
@click="refreshFavorites"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :class="{ spin: isRefreshingFavorites }">sync</i>
|
<i :class="{ spin: isRefreshingFavorites }" class="material-icons">sync</i>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -19,7 +19,7 @@
|
|||||||
</BaseTab>
|
</BaseTab>
|
||||||
</BaseTabs>
|
</BaseTabs>
|
||||||
|
|
||||||
<button class="btn btn-primary" v-if="!activeTabEmpty" style="margin-bottom: 2rem" @click="downloadAllOfType">
|
<button v-if="!activeTabEmpty" class="btn btn-primary" style="margin-bottom: 2rem" @click="downloadAllOfType">
|
||||||
{{ $t('globals.download', { thing: $tc(`globals.listTabs.${activeTab}N`, getTabLength()) }) }}
|
{{ $t('globals.download', { thing: $tc(`globals.listTabs.${activeTab}N`, getTabLength()) }) }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -27,10 +27,10 @@
|
|||||||
<div v-if="playlists.length == 0">
|
<div v-if="playlists.length == 0">
|
||||||
<h1>{{ $t('favorites.noPlaylists') }}</h1>
|
<h1>{{ $t('favorites.noPlaylists') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release-grid" v-if="playlists.length > 0 || spotifyPlaylists > 0">
|
<div v-if="playlists.length > 0 || spotifyPlaylists > 0" class="release-grid">
|
||||||
<div class="release" v-for="release in playlists" :key="release.id">
|
<div v-for="release in playlists" :key="release.id" class="release">
|
||||||
<router-link tag="div" class="cursor-pointer" :to="{ name: 'Playlist', params: { id: release.id } }">
|
<router-link :to="{ name: 'Playlist', params: { id: release.id } }" class="cursor-pointer" tag="div">
|
||||||
<CoverContainer is-rounded :cover="release.picture_medium" :link="release.link" @click.stop="addToQueue" />
|
<CoverContainer :cover="release.picture_medium" :link="release.link" is-rounded @click.stop="addToQueue" />
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
@ -44,9 +44,9 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="release" v-for="release in spotifyPlaylists" :key="release.id">
|
<div v-for="release in spotifyPlaylists" :key="release.id" class="release">
|
||||||
<router-link tag="div" class="cursor-pointer" :to="{ name: 'Spotify Playlist', params: { id: release.id } }">
|
<router-link :to="{ name: 'Spotify Playlist', params: { id: release.id } }" class="cursor-pointer" tag="div">
|
||||||
<CoverContainer is-rounded :cover="release.picture_medium" :link="release.link" @click.stop="addToQueue" />
|
<CoverContainer :cover="release.picture_medium" :link="release.link" is-rounded @click.stop="addToQueue" />
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
@ -66,15 +66,15 @@
|
|||||||
<div v-if="albums.length == 0">
|
<div v-if="albums.length == 0">
|
||||||
<h1>{{ $t('favorites.noAlbums') }}</h1>
|
<h1>{{ $t('favorites.noAlbums') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release-grid" v-if="albums.length > 0">
|
<div v-if="albums.length > 0" class="release-grid">
|
||||||
<router-link
|
<router-link
|
||||||
tag="div"
|
|
||||||
class="release clickable"
|
|
||||||
v-for="release in albums"
|
v-for="release in albums"
|
||||||
:key="release.id"
|
:key="release.id"
|
||||||
:to="{ name: 'Album', params: { id: release.id } }"
|
:to="{ name: 'Album', params: { id: release.id } }"
|
||||||
|
class="release clickable"
|
||||||
|
tag="div"
|
||||||
>
|
>
|
||||||
<CoverContainer is-rounded :cover="release.cover_medium" :link="release.link" @click.stop="addToQueue" />
|
<CoverContainer :cover="release.cover_medium" :link="release.link" is-rounded @click.stop="addToQueue" />
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -85,15 +85,15 @@
|
|||||||
<div v-if="artists.length == 0">
|
<div v-if="artists.length == 0">
|
||||||
<h1>{{ $t('favorites.noArtists') }}</h1>
|
<h1>{{ $t('favorites.noArtists') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release-grid" v-if="artists.length > 0">
|
<div v-if="artists.length > 0" class="release-grid">
|
||||||
<router-link
|
<router-link
|
||||||
tag="div"
|
|
||||||
class="release clickable"
|
|
||||||
v-for="release in artists"
|
v-for="release in artists"
|
||||||
:key="release.id"
|
:key="release.id"
|
||||||
:to="{ name: 'Artist', params: { id: release.id } }"
|
:to="{ name: 'Artist', params: { id: release.id } }"
|
||||||
|
class="release clickable"
|
||||||
|
tag="div"
|
||||||
>
|
>
|
||||||
<CoverContainer is-circle :cover="release.picture_medium" :link="release.link" @click.stop="addToQueue" />
|
<CoverContainer :cover="release.picture_medium" :link="release.link" is-circle @click.stop="addToQueue" />
|
||||||
<p class="primary-text">{{ release.name }}</p>
|
<p class="primary-text">{{ release.name }}</p>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
@ -105,17 +105,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<table v-if="tracks.length > 0" class="table">
|
<table v-if="tracks.length > 0" class="table">
|
||||||
<tr v-for="track in tracks" class="track_row">
|
<tr v-for="track in tracks" class="track_row">
|
||||||
<td class="p-3 text-center cursor-default" :class="{ first: track.position === 1 }">
|
<td :class="{ first: track.position === 1 }" class="p-3 text-center cursor-default">
|
||||||
{{ track.position }}
|
{{ track.position }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span
|
<span
|
||||||
|
:data-preview="track.preview"
|
||||||
class="relative inline-block rounded cursor-pointer"
|
class="relative inline-block rounded cursor-pointer"
|
||||||
@click="playPausePreview"
|
@click="playPausePreview"
|
||||||
:data-preview="track.preview"
|
|
||||||
>
|
>
|
||||||
<PreviewControls v-if="track.preview" />
|
<PreviewControls v-if="track.preview" />
|
||||||
<img class="rounded coverart" :src="track.album.cover_small" />
|
<img :src="track.album.cover_small" class="rounded coverart" />
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="table__cell--large">
|
<td class="table__cell--large">
|
||||||
@ -125,16 +125,16 @@
|
|||||||
}}
|
}}
|
||||||
</td>
|
</td>
|
||||||
<router-link
|
<router-link
|
||||||
tag="td"
|
|
||||||
class="table__cell table__cell--medium table__cell--center clickable"
|
|
||||||
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
|
class="table__cell table__cell--medium table__cell--center clickable"
|
||||||
|
tag="td"
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
tag="td"
|
|
||||||
class="table__cell--medium table__cell--center clickable"
|
|
||||||
:to="{ name: 'Album', params: { id: track.album.id } }"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
|
class="table__cell--medium table__cell--center clickable"
|
||||||
|
tag="td"
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -142,16 +142,16 @@
|
|||||||
{{ convertDuration(track.duration) }}
|
{{ convertDuration(track.duration) }}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
class="cursor-pointer group"
|
|
||||||
@click.stop="addToQueue"
|
|
||||||
:data-link="track.link"
|
:data-link="track.link"
|
||||||
role="button"
|
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
|
class="cursor-pointer group"
|
||||||
|
role="button"
|
||||||
|
@click.stop="addToQueue"
|
||||||
>
|
>
|
||||||
<div class="table__cell-content table__cell-content--vertical-center">
|
<div class="table__cell-content table__cell-content--vertical-center">
|
||||||
<i
|
<i
|
||||||
class="transition-colors duration-150 ease-in-out material-icons group-hover:text-primary"
|
|
||||||
:title="$t('globals.download_hint')"
|
:title="$t('globals.download_hint')"
|
||||||
|
class="transition-colors duration-150 ease-in-out material-icons group-hover:text-primary"
|
||||||
>
|
>
|
||||||
get_app
|
get_app
|
||||||
</i>
|
</i>
|
||||||
@ -164,14 +164,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, onMounted, reactive, toRefs, watchEffect, ref, computed, watch } from '@vue/composition-api'
|
import { defineComponent, reactive, toRefs, watch } from '@vue/composition-api'
|
||||||
|
|
||||||
import PreviewControls from '@components/globals/PreviewControls.vue'
|
import PreviewControls from '@components/globals/PreviewControls.vue'
|
||||||
import CoverContainer from '@components/globals/CoverContainer.vue'
|
import CoverContainer from '@components/globals/CoverContainer.vue'
|
||||||
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
|
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
|
||||||
import { BaseTabs, BaseTab } from '@components/globals/BaseTabs'
|
import { BaseTab, BaseTabs } from '@components/globals/BaseTabs'
|
||||||
|
|
||||||
import { sendAddToQueue, aggregateDownloadLinks } from '@/utils/downloads'
|
import { aggregateDownloadLinks, sendAddToQueue } from '@/utils/downloads'
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
import { toast } from '@/utils/toasts'
|
import { toast } from '@/utils/toasts'
|
||||||
import { useFavorites } from '@/use/favorites'
|
import { useFavorites } from '@/use/favorites'
|
||||||
@ -197,7 +197,8 @@ export default defineComponent({
|
|||||||
isRefreshingFavorites,
|
isRefreshingFavorites,
|
||||||
refreshFavorites
|
refreshFavorites
|
||||||
} = useFavorites()
|
} = useFavorites()
|
||||||
const reloadButton = computed(() => ctx.refs.reloadButton)
|
|
||||||
|
refreshFavorites({ isInitial: true })
|
||||||
|
|
||||||
watch(isRefreshingFavorites, (newVal, oldVal) => {
|
watch(isRefreshingFavorites, (newVal, oldVal) => {
|
||||||
// If oldVal is true and newOne is false, it means that a refreshing has just terminated
|
// If oldVal is true and newOne is false, it means that a refreshing has just terminated
|
||||||
|
@ -783,6 +783,7 @@ import { copyToClipboard } from '@/utils/utils'
|
|||||||
|
|
||||||
import BaseAccordion from '@/components/globals/BaseAccordion.vue'
|
import BaseAccordion from '@/components/globals/BaseAccordion.vue'
|
||||||
import TemplateVariablesList from '@components/settings/TemplateVariablesList.vue'
|
import TemplateVariablesList from '@components/settings/TemplateVariablesList.vue'
|
||||||
|
import { fetchData, sendToServer } from '@/utils/api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -949,16 +950,17 @@ export default {
|
|||||||
this.lastCredentials = JSON.parse(JSON.stringify(credentials))
|
this.lastCredentials = JSON.parse(JSON.stringify(credentials))
|
||||||
this.spotifyFeatures = JSON.parse(JSON.stringify(credentials))
|
this.spotifyFeatures = JSON.parse(JSON.stringify(credentials))
|
||||||
},
|
},
|
||||||
loggedInViaDeezer(arl) {
|
async loggedInViaDeezer(arl) {
|
||||||
this.dispatchARL({ arl })
|
this.dispatchARL({ arl })
|
||||||
socket.emit('login', arl, true, this.accountNum)
|
|
||||||
// this.login()
|
// this.login()
|
||||||
|
// const res = await fetchData('login', { arl, force: true, child: this.accountNum })
|
||||||
},
|
},
|
||||||
login() {
|
async login() {
|
||||||
let newArl = this.$refs.loginInput.value.trim()
|
let newArl = this.$refs.loginInput.value.trim()
|
||||||
|
|
||||||
if (newArl && newArl !== this.arl) {
|
if (newArl && newArl !== this.arl) {
|
||||||
socket.emit('login', newArl, true, this.accountNum)
|
const res = await fetchData('login', { arl: newArl, force: true, child: this.accountNum })
|
||||||
|
this.loggedInViaDeezer(res.arl)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
appLogin(e) {
|
appLogin(e) {
|
||||||
@ -969,9 +971,7 @@ export default {
|
|||||||
},
|
},
|
||||||
accountChanged(user, accountNum) {
|
accountChanged(user, accountNum) {
|
||||||
this.$refs.username.innerText = user.name
|
this.$refs.username.innerText = user.name
|
||||||
this.$refs.userpicture.src = `https://e-cdns-images.dzcdn.net/images/user/${
|
this.$refs.userpicture.src = `https://e-cdns-images.dzcdn.net/images/user/${user.picture}/125x125-000000-80-0-0.jpg`
|
||||||
user.picture
|
|
||||||
}/125x125-000000-80-0-0.jpg`
|
|
||||||
this.accountNum = accountNum
|
this.accountNum = accountNum
|
||||||
|
|
||||||
localStorage.setItem('accountNum', this.accountNum)
|
localStorage.setItem('accountNum', this.accountNum)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative fixed-footer bg-background-main image-header" ref="root">
|
<div ref="root" class="relative fixed-footer bg-background-main image-header">
|
||||||
<header
|
<header
|
||||||
:style="{
|
:style="{
|
||||||
'background-image':
|
'background-image':
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<i class="material-icons">timer</i>
|
<i class="material-icons">timer</i>
|
||||||
</th>
|
</th>
|
||||||
<th class="table__icon table__cell--center clickable">
|
<th class="table__icon table__cell--center clickable">
|
||||||
<input @click="toggleAll" class="selectAll" type="checkbox" />
|
<input class="selectAll" type="checkbox" @click="toggleAll" />
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -41,15 +41,15 @@
|
|||||||
<td class="table__cell--x-small table__cell--center">
|
<td class="table__cell--x-small table__cell--center">
|
||||||
<div class="table__cell-content table__cell-content--vertical-center">
|
<div class="table__cell-content table__cell-content--vertical-center">
|
||||||
<i
|
<i
|
||||||
class="material-icons"
|
v-on="{ click: track.preview ? playPausePreview : false }"
|
||||||
:class="{
|
:class="{
|
||||||
preview_playlist_controls: track.preview,
|
preview_playlist_controls: track.preview,
|
||||||
'cursor-pointer': track.preview,
|
'cursor-pointer': track.preview,
|
||||||
disabled: !track.preview
|
disabled: !track.preview
|
||||||
}"
|
}"
|
||||||
v-on="{ click: track.preview ? playPausePreview : false }"
|
|
||||||
:data-preview="track.preview"
|
:data-preview="track.preview"
|
||||||
:title="$t('globals.play_hint')"
|
:title="$t('globals.play_hint')"
|
||||||
|
class="material-icons"
|
||||||
>
|
>
|
||||||
play_arrow
|
play_arrow
|
||||||
</i>
|
</i>
|
||||||
@ -70,28 +70,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<router-link
|
<router-link
|
||||||
tag="td"
|
|
||||||
class="table__cell--medium table__cell--center clickable"
|
|
||||||
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
|
class="table__cell--medium table__cell--center clickable"
|
||||||
|
tag="td"
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
tag="td"
|
|
||||||
v-if="type === 'playlist'"
|
v-if="type === 'playlist'"
|
||||||
class="table__cell--medium table__cell--center clickable"
|
|
||||||
:to="{ name: 'Album', params: { id: track.album.id } }"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
|
class="table__cell--medium table__cell--center clickable"
|
||||||
|
tag="td"
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<td
|
<td
|
||||||
class="table__cell--center"
|
|
||||||
:class="{ 'table__cell--small': type === 'album', 'table__cell--x-small': type === 'playlist' }"
|
:class="{ 'table__cell--small': type === 'album', 'table__cell--x-small': type === 'playlist' }"
|
||||||
|
class="table__cell--center"
|
||||||
>
|
>
|
||||||
{{ convertDuration(track.duration) }}
|
{{ convertDuration(track.duration) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="table__icon table__cell--center">
|
<td class="table__icon table__cell--center">
|
||||||
<input class="clickable" type="checkbox" v-model="track.selected" />
|
<input v-model="track.selected" class="clickable" type="checkbox" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-else-if="track.type == 'disc_separator'" class="table__row-no-highlight" style="opacity: 0.54">
|
<tr v-else-if="track.type == 'disc_separator'" class="table__row-no-highlight" style="opacity: 0.54">
|
||||||
@ -112,14 +112,14 @@
|
|||||||
<td>
|
<td>
|
||||||
<i
|
<i
|
||||||
v-if="track.preview_url"
|
v-if="track.preview_url"
|
||||||
@click="playPausePreview"
|
|
||||||
class="material-icons"
|
|
||||||
:class="{
|
:class="{
|
||||||
preview_playlist_controls: track.preview_url,
|
preview_playlist_controls: track.preview_url,
|
||||||
'cursor-pointer': track.preview_url
|
'cursor-pointer': track.preview_url
|
||||||
}"
|
}"
|
||||||
:data-preview="track.preview_url"
|
:data-preview="track.preview_url"
|
||||||
:title="$t('globals.play_hint')"
|
:title="$t('globals.play_hint')"
|
||||||
|
class="material-icons"
|
||||||
|
@click="playPausePreview"
|
||||||
>
|
>
|
||||||
play_arrow
|
play_arrow
|
||||||
</i>
|
</i>
|
||||||
@ -133,17 +133,17 @@
|
|||||||
<td>{{ track.artists[0].name }}</td>
|
<td>{{ track.artists[0].name }}</td>
|
||||||
<td>{{ track.album.name }}</td>
|
<td>{{ track.album.name }}</td>
|
||||||
<td>{{ convertDuration(Math.floor(track.duration_ms / 1000)) }}</td>
|
<td>{{ convertDuration(Math.floor(track.duration_ms / 1000)) }}</td>
|
||||||
<td><input class="clickable" type="checkbox" v-model="track.selected" /></td>
|
<td><input v-model="track.selected" class="clickable" type="checkbox" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<span v-if="label" style="opacity: 0.4; margin-top: 8px; display: inline-block; font-size: 13px">{{ label }}</span>
|
<span v-if="label" style="opacity: 0.4; margin-top: 8px; display: inline-block; font-size: 13px">{{ label }}</span>
|
||||||
<footer class="bg-background-main">
|
<footer class="bg-background-main">
|
||||||
<button class="mr-2 btn btn-primary" @click.stop="addToQueue" :data-link="link">
|
<button :data-link="link" class="mr-2 btn btn-primary" @click.stop="addToQueue">
|
||||||
{{ `${$t('globals.download', { thing: $tc(`globals.listTabs.${type}`, 1) })}` }}
|
{{ `${$t('globals.download', { thing: $tc(`globals.listTabs.${type}`, 1) })}` }}
|
||||||
</button>
|
</button>
|
||||||
<button class="flex items-center btn btn-primary" @click.stop="addToQueue" :data-link="selectedLinks()">
|
<button :data-link="selectedLinks()" class="flex items-center btn btn-primary" @click.stop="addToQueue">
|
||||||
{{ $t('tracklist.downloadSelection') }}<i class="ml-2 material-icons">file_download</i>
|
{{ $t('tracklist.downloadSelection') }}<i class="ml-2 material-icons">file_download</i>
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
@ -156,6 +156,7 @@ import { socket } from '@/utils/socket'
|
|||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import Utils from '@/utils/utils'
|
import Utils from '@/utils/utils'
|
||||||
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
|
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
|
||||||
|
import EventBus from '@/utils/EventBus'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@ -172,9 +173,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
socket.on('show_album', this.showAlbum)
|
EventBus.$on('showAlbum', this.showAlbum)
|
||||||
socket.on('show_playlist', this.showPlaylist)
|
EventBus.$on('showPlaylist', this.showPlaylist)
|
||||||
socket.on('show_spotifyplaylist', this.showSpotifyPlaylist)
|
EventBus.$on('showSpotifyPlaylist', this.showSpotifyPlaylist)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
playPausePreview,
|
playPausePreview,
|
||||||
@ -193,17 +194,17 @@ export default {
|
|||||||
},
|
},
|
||||||
toggleAll(e) {
|
toggleAll(e) {
|
||||||
this.body.forEach(item => {
|
this.body.forEach(item => {
|
||||||
if (item.type == 'track') {
|
if (item.type === 'track') {
|
||||||
item.selected = e.currentTarget.checked
|
item.selected = e.currentTarget.checked
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
selectedLinks() {
|
selectedLinks() {
|
||||||
var selected = []
|
const selected = []
|
||||||
if (this.body) {
|
if (this.body) {
|
||||||
this.body.forEach(item => {
|
this.body.forEach(item => {
|
||||||
if (item.type == 'track' && item.selected)
|
if (item.type === 'track' && item.selected)
|
||||||
selected.push(this.type == 'spotifyPlaylist' ? item.uri : item.link)
|
selected.push(this.type === 'spotifyPlaylist' ? item.uri : item.link)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return selected.join(';')
|
return selected.join(';')
|
||||||
@ -305,4 +306,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { socket } from '@/utils/socket'
|
|
||||||
import { getPropertyWithFallback } from '@/utils/utils'
|
import { getPropertyWithFallback } from '@/utils/utils'
|
||||||
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
export function formatArtistData(artistData) {
|
export function formatArtistData(artistData) {
|
||||||
return {
|
return {
|
||||||
@ -36,15 +36,8 @@ function formatArtistReleases(artistReleases) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getArtistData(artistID) {
|
export function getArtistData(artistID) {
|
||||||
socket.emit('getTracklist', {
|
return fetchData('getTracklist', {
|
||||||
type: 'artist',
|
type: 'artist',
|
||||||
id: artistID
|
id: artistID
|
||||||
})
|
})
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
socket.on('show_artist', data => {
|
|
||||||
socket.off('show_artist')
|
|
||||||
resolve(data)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,9 @@
|
|||||||
import { socket } from '@/utils/socket'
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
let chartsData = {}
|
|
||||||
let cached = false
|
|
||||||
|
|
||||||
export function getChartsData() {
|
export function getChartsData() {
|
||||||
if (cached) {
|
return fetchData('getCharts')
|
||||||
return chartsData
|
|
||||||
} else {
|
|
||||||
socket.emit('get_charts_data')
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
socket.on('init_charts', data => {
|
|
||||||
chartsData = data
|
|
||||||
cached = true
|
|
||||||
|
|
||||||
socket.off('init_charts')
|
|
||||||
resolve(data)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getChartTracks(chartId) {
|
||||||
|
return fetchData('getChartTracks', { id: chartId })
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,17 @@
|
|||||||
import { socket } from '@/utils/socket'
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
let homeData = {}
|
let homeData = {}
|
||||||
let cached = false
|
let cached = false
|
||||||
|
|
||||||
export function getHomeData() {
|
export async function getHomeData() {
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return homeData
|
return homeData
|
||||||
} else {
|
} else {
|
||||||
socket.emit('get_home_data')
|
const data = await fetchData('getHome')
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
socket.on('init_home', data => {
|
|
||||||
homeData = data
|
homeData = data
|
||||||
cached = true
|
cached = true
|
||||||
|
|
||||||
socket.off('init_home')
|
return data
|
||||||
resolve(data)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,5 @@
|
|||||||
"@components/*": ["./components/*"]
|
"@components/*": ["./components/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typeAcquisition": {
|
|
||||||
"include": ["socket.io-client"]
|
|
||||||
},
|
|
||||||
"exclude": ["assets/**/*", "styles/**/*"]
|
"exclude": ["assets/**/*", "styles/**/*"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import { socket } from '@/utils/socket'
|
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
import About from '@components/pages/About.vue'
|
import About from '@components/pages/About.vue'
|
||||||
@ -15,6 +14,8 @@ import LinkAnalyzer from '@components/pages/LinkAnalyzer.vue'
|
|||||||
import Search from '@components/pages/Search.vue'
|
import Search from '@components/pages/Search.vue'
|
||||||
import Settings from '@components/pages/Settings.vue'
|
import Settings from '@components/pages/Settings.vue'
|
||||||
import Tracklist from '@components/pages/Tracklist.vue'
|
import Tracklist from '@components/pages/Tracklist.vue'
|
||||||
|
import { fetchData } from '@/utils/api'
|
||||||
|
import EventBus from '@/utils/EventBus'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@ -125,44 +126,51 @@ const router = new VueRouter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
let getTracklistParams = null
|
|
||||||
|
|
||||||
switch (to.name) {
|
switch (to.name) {
|
||||||
case 'Tracklist':
|
case 'Tracklist': {
|
||||||
getTracklistParams = {
|
// const getTracklistParams = {
|
||||||
type: to.params.type,
|
// type: to.params.type,
|
||||||
id: to.params.id
|
// id: to.params.id
|
||||||
}
|
// }
|
||||||
|
console.warn('This should never happen.')
|
||||||
break
|
break
|
||||||
case 'Album':
|
}
|
||||||
getTracklistParams = {
|
case 'Album': {
|
||||||
|
const getTracklistParams = {
|
||||||
type: 'album',
|
type: 'album',
|
||||||
id: to.params.id
|
id: to.params.id
|
||||||
}
|
}
|
||||||
|
fetchData('getTracklist', getTracklistParams).then(albumData => {
|
||||||
|
EventBus.$emit('showAlbum', albumData)
|
||||||
|
})
|
||||||
break
|
break
|
||||||
case 'Playlist':
|
}
|
||||||
getTracklistParams = {
|
case 'Playlist': {
|
||||||
|
const getTracklistParams = {
|
||||||
type: 'playlist',
|
type: 'playlist',
|
||||||
id: to.params.id
|
id: to.params.id
|
||||||
}
|
}
|
||||||
|
fetchData('getTracklist', getTracklistParams).then(playlistData => {
|
||||||
|
EventBus.$emit('showPlaylist', playlistData)
|
||||||
|
})
|
||||||
break
|
break
|
||||||
case 'Spotify Playlist':
|
}
|
||||||
getTracklistParams = {
|
case 'Spotify Playlist': {
|
||||||
|
const getTracklistParams = {
|
||||||
type: 'spotifyplaylist',
|
type: 'spotifyplaylist',
|
||||||
id: to.params.id
|
id: to.params.id
|
||||||
}
|
}
|
||||||
break
|
fetchData('getTracklist', getTracklistParams).then(spotifyPlaylistData => {
|
||||||
|
EventBus.$emit('showSpotifyPlaylist', spotifyPlaylistData)
|
||||||
default:
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getTracklistParams) {
|
default:
|
||||||
socket.emit('getTracklist', getTracklistParams)
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ref } from '@vue/composition-api'
|
import { ref } from '@vue/composition-api'
|
||||||
|
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import { socket } from '@/utils/socket'
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
const favoriteArtists = ref([])
|
const favoriteArtists = ref([])
|
||||||
const favoriteAlbums = ref([])
|
const favoriteAlbums = ref([])
|
||||||
@ -11,22 +11,35 @@ const favoriteTracks = ref([])
|
|||||||
|
|
||||||
const isRefreshingFavorites = ref(false)
|
const isRefreshingFavorites = ref(false)
|
||||||
|
|
||||||
if (store.getters.isLoggedIn) {
|
|
||||||
refreshFavorites({ isInitial: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshFavorites({ isInitial = false }) {
|
function refreshFavorites({ isInitial = false }) {
|
||||||
if (!isInitial) {
|
if (!isInitial) {
|
||||||
isRefreshingFavorites.value = true
|
isRefreshingFavorites.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('get_favorites_data')
|
fetchData('getUserFavorites').then(setAllFavorites).catch(console.error)
|
||||||
|
|
||||||
if (store.getters.isLoggedWithSpotify) {
|
if (store.getters.isLoggedWithSpotify) {
|
||||||
socket.emit('update_userSpotifyPlaylists', store.getters.getSpotifyUser.id)
|
fetchData('getUserSpotifyPlaylists', {
|
||||||
|
spotifyUser: store.getters.getSpotifyUser.id
|
||||||
|
})
|
||||||
|
.then(({ data: spotifyPlaylists }) => {
|
||||||
|
favoriteSpotifyPlaylists.value = spotifyPlaylists
|
||||||
|
})
|
||||||
|
.catch(console.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setAllFavorites(data) {
|
||||||
|
const { tracks, albums, artists, playlists } = data
|
||||||
|
|
||||||
|
isRefreshingFavorites.value = false
|
||||||
|
|
||||||
|
favoriteArtists.value = artists
|
||||||
|
favoriteAlbums.value = albums
|
||||||
|
favoritePlaylists.value = playlists
|
||||||
|
favoriteTracks.value = tracks
|
||||||
|
}
|
||||||
|
|
||||||
export function useFavorites() {
|
export function useFavorites() {
|
||||||
return {
|
return {
|
||||||
favoriteArtists,
|
favoriteArtists,
|
||||||
@ -38,42 +51,3 @@ export function useFavorites() {
|
|||||||
refreshFavorites
|
refreshFavorites
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAllFavorites(data) {
|
|
||||||
const { tracks, albums, artists, playlists } = data
|
|
||||||
|
|
||||||
favoriteArtists.value = artists
|
|
||||||
favoriteAlbums.value = albums
|
|
||||||
favoritePlaylists.value = playlists
|
|
||||||
favoriteTracks.value = tracks
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.on('updated_userFavorites', data => {
|
|
||||||
setAllFavorites(data)
|
|
||||||
// Commented out because the corresponding emit function is never called at the moment
|
|
||||||
// therefore isRefreshingFavorites is never set to true
|
|
||||||
// isRefreshingFavorites.value = false
|
|
||||||
})
|
|
||||||
socket.on('init_favorites', data => {
|
|
||||||
setAllFavorites(data)
|
|
||||||
isRefreshingFavorites.value = false
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.on('updated_userSpotifyPlaylists', data => {
|
|
||||||
favoriteSpotifyPlaylists.value = data
|
|
||||||
})
|
|
||||||
socket.on('updated_userSpotifyPlaylists', data => {
|
|
||||||
favoriteSpotifyPlaylists.value = data
|
|
||||||
})
|
|
||||||
socket.on('updated_userPlaylists', data => {
|
|
||||||
favoritePlaylists.value = data
|
|
||||||
})
|
|
||||||
socket.on('updated_userAlbums', data => {
|
|
||||||
favoriteAlbums.value = data
|
|
||||||
})
|
|
||||||
socket.on('updated_userArtist', data => {
|
|
||||||
favoriteArtists.value = data
|
|
||||||
})
|
|
||||||
socket.on('updated_userTracks', data => {
|
|
||||||
favoriteTracks.value = data
|
|
||||||
})
|
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import { ref } from '@vue/composition-api'
|
import { ref } from '@vue/composition-api'
|
||||||
import { socket } from '@/utils/socket'
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
const searchResult = ref({})
|
const searchResult = ref({})
|
||||||
|
|
||||||
function performMainSearch(searchTerm) {
|
function performMainSearch(searchTerm) {
|
||||||
socket.emit('mainSearch', { term: searchTerm })
|
fetchData('mainSearch', { term: searchTerm }).then(data => {
|
||||||
|
|
||||||
socket.on('mainSearch', data => {
|
|
||||||
searchResult.value = data
|
searchResult.value = data
|
||||||
|
|
||||||
socket.off('mainSearch')
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
import { ref } from '@vue/composition-api'
|
import { ref } from '@vue/composition-api'
|
||||||
import { socket } from '@/utils/socket'
|
import { fetchData } from '@/utils/api'
|
||||||
|
|
||||||
const result = ref({})
|
const result = ref({})
|
||||||
|
|
||||||
function performSearch({ term, type, start = 0, nb = 30 }) {
|
function performSearch({ term, type, start = 0, nb = 30 }) {
|
||||||
socket.emit('search', {
|
fetchData('search', {
|
||||||
term,
|
term,
|
||||||
type,
|
type,
|
||||||
start,
|
start,
|
||||||
nb
|
nb
|
||||||
})
|
}).then(data => {
|
||||||
|
|
||||||
socket.on('search', data => {
|
|
||||||
result.value = data
|
result.value = data
|
||||||
|
|
||||||
socket.off('search')
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/utils/api.js
Normal file
21
src/utils/api.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export function fetchData(key, data = {}) {
|
||||||
|
const url = new URL(`${window.location.origin}/api/${key}`)
|
||||||
|
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
url.searchParams.append(key, data[key])
|
||||||
|
})
|
||||||
|
|
||||||
|
return fetch(url.href)
|
||||||
|
.then(response => response.json())
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sendToServer(key, data) {
|
||||||
|
const url = new URL(`${window.location.origin}/api/${key}`)
|
||||||
|
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
url.searchParams.append(key, data[key])
|
||||||
|
})
|
||||||
|
|
||||||
|
fetch(url.href).catch(console.error)
|
||||||
|
}
|
@ -1,13 +1,13 @@
|
|||||||
import { socket } from '@/utils/socket'
|
import { sendToServer } from '@/utils/api'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @param {number} bitrate
|
* @param {number|null} bitrate
|
||||||
*/
|
*/
|
||||||
export function sendAddToQueue(url, bitrate = null) {
|
export function sendAddToQueue(url, bitrate = null) {
|
||||||
if (!url) throw new Error('No URL given to sendAddToQueue function!')
|
if (!url) throw new Error('No URL given to sendAddToQueue function!')
|
||||||
|
|
||||||
socket.emit('addToQueue', { url, bitrate }, () => {})
|
sendToServer('addToQueue', { url, bitrate })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function aggregateDownloadLinks(releases) {
|
export function aggregateDownloadLinks(releases) {
|
||||||
|
@ -1,8 +1,35 @@
|
|||||||
import store from '@/store'
|
class CustomSocket extends WebSocket {
|
||||||
import io from 'socket.io-client'
|
constructor(args) {
|
||||||
|
super(args)
|
||||||
|
this.listeners = {}
|
||||||
|
}
|
||||||
|
emit(key, data) {
|
||||||
|
if (this.readyState !== WebSocket.OPEN) return false
|
||||||
|
|
||||||
export const socket = io.connect('/')
|
this.send(JSON.stringify({ key, data }))
|
||||||
|
}
|
||||||
|
on(key, cb) {
|
||||||
|
if (Object.keys(this.listeners).indexOf(key) == -1){
|
||||||
|
console.log('on:', key)
|
||||||
|
this.listeners[key] = cb
|
||||||
|
|
||||||
socket.on('init_update', data => {
|
this.addEventListener('message', event => {
|
||||||
store.dispatch('setAppInfo', data)
|
const messageData = JSON.parse(event.data)
|
||||||
|
|
||||||
|
if (messageData.key === key) {
|
||||||
|
cb(messageData.data)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
off(key) {
|
||||||
|
if (Object.keys(this.listeners).indexOf(key) != -1){
|
||||||
|
console.log('off:', key)
|
||||||
|
this.removeEventListener('message', this.listeners[key])
|
||||||
|
delete this.listeners[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const socket = new CustomSocket('ws://' + location.host + '/')
|
||||||
|
Loading…
Reference in New Issue
Block a user