started turning js Vue components files in SFCs
This commit is contained in:
parent
2cb0986928
commit
56e7d80363
@ -4,6 +4,8 @@ This is just the WebUI for deemix, it should be used with deemix-pyweb or someth
|
||||
|
||||
## What's left to do?
|
||||
|
||||
- Use Vue as much as possible
|
||||
- First step: Single File Components
|
||||
- Completely remove jQuery dependency
|
||||
- Make the UI look coherent
|
||||
- Style buttons
|
||||
|
1132
public/index.html
1132
public/index.html
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
4
src/js/EventBus.js
Normal file
4
src/js/EventBus.js
Normal file
@ -0,0 +1,4 @@
|
||||
// https://alligator.io/vuejs/global-event-bus/
|
||||
import Vue from 'vue'
|
||||
|
||||
export default new Vue()
|
@ -1,18 +1,21 @@
|
||||
// Global Vue components
|
||||
import '@components/LoadingPlaceholder.js'
|
||||
import Vue from 'vue'
|
||||
|
||||
// Vue views components
|
||||
import '@components/artist-tab.js'
|
||||
import '@components/charts-tab.js'
|
||||
import '@components/errors-tab.js'
|
||||
import '@components/favorites-tab.js'
|
||||
import '@components/home-tab.js'
|
||||
import '@components/link-analyzer-tab.js'
|
||||
import '@components/main-search.js'
|
||||
import '@components/settings-tab.js'
|
||||
import '@components/tracklist-tab.js'
|
||||
import TheSidebar from '@components/TheSidebar.vue'
|
||||
import ArtistTab from '@components/ArtistTab.vue'
|
||||
import TheChartsTab from '@components/TheChartsTab.vue'
|
||||
import TheFavoritesTab from '@components/TheFavoritesTab.vue'
|
||||
import TheErrorsTab from '@components/TheErrorsTab.vue'
|
||||
import TheHomeTab from '@components/TheHomeTab.vue'
|
||||
import TheLinkAnalyzerTab from '@components/TheLinkAnalyzerTab.vue'
|
||||
import TheAboutTab from '@components/TheAboutTab.vue'
|
||||
|
||||
import '@components/TestComponent.vue'
|
||||
// Must be imported before settings tab at the moment
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import TheSettingsTab from '@components/TheSettingsTab.vue'
|
||||
|
||||
import '@components/main-search.js'
|
||||
import TracklistTab from '@components/TracklistTab.vue'
|
||||
|
||||
import $ from 'jquery'
|
||||
import { socket } from '@/js/socket.js'
|
||||
@ -21,11 +24,11 @@ import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import Tabs from '@/js/tabs.js'
|
||||
import Search from '@/js/search.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
|
||||
/* ===== App initialization ===== */
|
||||
|
||||
function startApp() {
|
||||
mountComponents()
|
||||
setCurrentUserTheme()
|
||||
|
||||
Downloads.init()
|
||||
@ -35,6 +38,23 @@ function startApp() {
|
||||
TrackPreview.init()
|
||||
}
|
||||
|
||||
/**
|
||||
* This funcion is temporary. It will be removed when all components will be as SFC and all their methods will be called
|
||||
* by using the EventBus.
|
||||
*/
|
||||
function mountComponents() {
|
||||
new Vue({ render: h => h(TheSidebar) }).$mount('#sidebar-placeholder')
|
||||
new Vue({ render: h => h(ArtistTab) }).$mount('#artist-tab-placeholder')
|
||||
new Vue({ render: h => h(TheChartsTab) }).$mount('#charts-tab-placeholder')
|
||||
new Vue({ render: h => h(TheFavoritesTab) }).$mount('#favorites-tab-placeholder')
|
||||
new Vue({ render: h => h(TheHomeTab) }).$mount('#home-tab-placeholder')
|
||||
new Vue({ render: h => h(TheLinkAnalyzerTab) }).$mount('#link-analyzer-tab-placeholder')
|
||||
new Vue({ render: h => h(TheSettingsTab) }).$mount('#settings-tab-placeholder')
|
||||
new Vue({ render: h => h(TracklistTab) }).$mount('#tracklist-tab-placeholder')
|
||||
new Vue({ render: h => h(TheAboutTab) }).$mount('#about-tab-placeholder')
|
||||
new Vue({ render: h => h(TheErrorsTab) }).$mount('#errors-tab-placeholder')
|
||||
}
|
||||
|
||||
function initClient() {
|
||||
window.clientMode = true
|
||||
document.querySelector(`#open_downloads_folder`).classList.remove('hide')
|
||||
|
197
src/js/components/ArtistTab.vue
Normal file
197
src/js/components/ArtistTab.vue
Normal file
@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div id="artist_tab" class="main_tabcontent fixed_footer image_header">
|
||||
<header
|
||||
class="inline-flex"
|
||||
:style="{
|
||||
'background-image':
|
||||
'linear-gradient(to bottom, transparent 0%, var(--main-background) 100%), url(\'' + image + '\')'
|
||||
}"
|
||||
>
|
||||
<h1>{{ title }}</h1>
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="link"
|
||||
class="fab right"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="tab">
|
||||
<template v-for="(item, name, index) in body">
|
||||
<button
|
||||
:class="'selective' + (name == currentTab ? ' active' : '')"
|
||||
:href="'#artist_' + name"
|
||||
@click="changeTab(name)"
|
||||
>
|
||||
{{ name }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
v-for="data in head"
|
||||
@click="data.sortKey ? sortBy(data.sortKey) : null"
|
||||
:style="{ width: data.width ? data.width : 'auto' }"
|
||||
:class="{
|
||||
'sort-asc': data.sortKey == sortKey && sortOrder == 'asc',
|
||||
'sort-desc': data.sortKey == sortKey && sortOrder == 'desc',
|
||||
sortable: data.sortKey,
|
||||
clickable: data.sortKey
|
||||
}"
|
||||
>
|
||||
{{ data.title }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="release in showTable">
|
||||
<td class="inline-flex clickable" @click="albumView" :data-id="release.id">
|
||||
<img
|
||||
class="rounded coverart"
|
||||
:src="release.cover_small"
|
||||
style="margin-right: 16px; width: 56px; height: 56px;"
|
||||
/>
|
||||
<i v-if="release.explicit_lyrics" class="material-icons explicit_icon">
|
||||
explicit
|
||||
</i>
|
||||
{{ release.title }}
|
||||
<i v-if="checkNewRelease(release.release_date)" class="material-icons" style="color:#FF7300;">
|
||||
fiber_new
|
||||
</i>
|
||||
</td>
|
||||
<td>{{ release.release_date }}</td>
|
||||
<td
|
||||
@click.stop="addToQueue"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
:data-link="release.link"
|
||||
class="clickable"
|
||||
>
|
||||
<i class="material-icons">
|
||||
file_download
|
||||
</i>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<footer>
|
||||
<button class="back-button">Back</button>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isEmpty, orderBy } from 'lodash-es'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import { showView, updateSelected } from '@/js/tabs.js'
|
||||
import EventBus from '@/js/EventBus'
|
||||
|
||||
export default {
|
||||
name: 'artist-tab',
|
||||
data() {
|
||||
return {
|
||||
currentTab: '',
|
||||
sortKey: 'release_date',
|
||||
sortOrder: 'desc',
|
||||
title: '',
|
||||
image: '',
|
||||
type: '',
|
||||
link: '',
|
||||
head: null,
|
||||
body: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
albumView: showView.bind(null, 'album'),
|
||||
reset() {
|
||||
this.title = 'Loading...'
|
||||
this.image = ''
|
||||
this.type = ''
|
||||
this.currentTab = ''
|
||||
this.sortKey = 'release_date'
|
||||
this.sortOrder = 'desc'
|
||||
this.link = ''
|
||||
this.head = []
|
||||
this.body = null
|
||||
},
|
||||
addToQueue(e) {
|
||||
e.stopPropagation()
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
sortBy(key) {
|
||||
if (key == this.sortKey) {
|
||||
this.sortOrder = this.sortOrder == 'asc' ? 'desc' : 'asc'
|
||||
} else {
|
||||
this.sortKey = key
|
||||
this.sortOrder = 'asc'
|
||||
}
|
||||
},
|
||||
changeTab(tab) {
|
||||
this.currentTab = tab
|
||||
},
|
||||
getCurrentTab() {
|
||||
return this.currentTab
|
||||
},
|
||||
updateSelected() {
|
||||
updateSelected(this.currentTab)
|
||||
},
|
||||
checkNewRelease(date) {
|
||||
let g1 = new Date()
|
||||
let g2 = new Date(date)
|
||||
g2.setDate(g2.getDate() + 3)
|
||||
g1.setHours(0, 0, 0, 0)
|
||||
|
||||
return g1.getTime() <= g2.getTime()
|
||||
},
|
||||
showArtist(data) {
|
||||
const { name, picture_xl, id, releases } = data
|
||||
|
||||
this.title = name
|
||||
this.image = picture_xl
|
||||
this.type = 'Artist'
|
||||
this.link = `https://www.deezer.com/artist/${id}`
|
||||
if (this.currentTab === '') this.currentTab = Object.keys(releases)[0]
|
||||
this.sortKey = 'release_date'
|
||||
this.sortOrder = 'desc'
|
||||
this.head = [
|
||||
{ title: 'Title', sortKey: 'title' },
|
||||
{ title: 'Release Date', sortKey: 'release_date' },
|
||||
{ title: '', width: '32px' }
|
||||
]
|
||||
if (isEmpty(releases)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = releases
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showTable() {
|
||||
if (this.body) return orderBy(this.body[this.currentTab], this.sortKey, this.sortOrder)
|
||||
else return []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('show_artist', this.showArtist)
|
||||
|
||||
EventBus.$on('artistTab:reset', this.reset)
|
||||
EventBus.$on('artistTab:updateSelected', this.updateSelected)
|
||||
EventBus.$on('artistTab:changeTab', this.changeTab)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
23
src/js/components/BaseLoadingPlaceholder.vue
Normal file
23
src/js/components/BaseLoadingPlaceholder.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="loading_placeholder">
|
||||
<span class="loading_placeholder__text">Loading...</span>
|
||||
<div class="lds-ring">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-loading-placeholder',
|
||||
// Without this empty data rollup watcher throws an error
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,13 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
Vue.component('loading-placeholder', {
|
||||
template: `<div class="loading_placeholder">
|
||||
<span class="loading_placeholder__text">Loading...</span>
|
||||
<div class="lds-ring">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<div>Test</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
test: 'super test'
|
||||
}),
|
||||
mounted() {
|
||||
console.log('abcdefghi')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
94
src/js/components/TheAboutTab.vue
Normal file
94
src/js/components/TheAboutTab.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div id="about_tab" class="main_tabcontent">
|
||||
<h2 class="page_heading">About</h2>
|
||||
<p>
|
||||
This app uses the <a href="https://deemix.app" target="_blank">deemix</a> library, you can use this
|
||||
library to make your own UI for deemix.</br>
|
||||
Here's the <a href="https://notabug.org/RemixDev/deemix" target="_blank">official repo</a> for the
|
||||
library.
|
||||
</p>
|
||||
<p>
|
||||
Thanks to rtonno, uhwot and lollilol for helping me with this project.<br>
|
||||
Also thanks to BasCurtiz and <a href="http://linktr.ee/scarvimane" target="_blank">scarvimane</a> for
|
||||
making the icon.
|
||||
</p>
|
||||
<p>
|
||||
Stay up to date with the updates by following the <a href="https://t.me/RemixDevNews"
|
||||
target="_blank">news channel</a> on Telegram.
|
||||
</p>
|
||||
<br />
|
||||
<h1>Bug Reports</h1>
|
||||
<p>
|
||||
If you have questions or problems with the app, search for a solution in the
|
||||
<a href="https://www.reddit.com/r/deemix" target="_blank">subreddit</a> first and then, if you don't
|
||||
find anything
|
||||
you can make a post with your issue on the subreddit.
|
||||
</p>
|
||||
<p>
|
||||
Before reporting a bug make sure you're running the latest version of the app and that the thing you
|
||||
want
|
||||
to report is actually a bug and not something that's wrong only on your end.<br />
|
||||
Make sure the bug is reproducible on another machines and also <b>DO NOT</b> report a bug if it's been
|
||||
already reported.
|
||||
</p>
|
||||
<p>
|
||||
<b>DO NOT</b> open issues for asking questions, there is a subreddit for that.
|
||||
</p>
|
||||
<br />
|
||||
<h2>Donations</h2>
|
||||
<h3>You want to contribute to this project? You can do that <b>in different ways!</b></h3>
|
||||
<p>
|
||||
If you're fluent in python you could try to make a new UI for the app using the base library, or fix
|
||||
bugs in the library with a pull request on the <a href="https://notabug.org/RemixDev/deemix"
|
||||
target="_blank">repo</a>.<br>
|
||||
I accept features as well, but no complex things, as they can be implementend directly in the app and
|
||||
not the library.</p>
|
||||
<p>
|
||||
If you're fluent in another programming language you could try to port deemix into other programming
|
||||
languages!<br>
|
||||
You need help understanding the code? Just hit RemixDev up on Telegram or Reddit.</p>
|
||||
<p>If you know JavaScript, HTML or CSS you could contribute to the <a
|
||||
href="https://notabug.org/RemixDev/deemix-webui" target="_blank">webui</a>.</p>
|
||||
<p>
|
||||
If you find some bugs you can report them in the repo, just make sure your bug isn't something that
|
||||
only
|
||||
affects you and it can be reproducible by other users as well.<br>
|
||||
Duplicate bug reports will be closed, so keep an eye out on that.</p>
|
||||
<hr>
|
||||
<h3>You want to contribute monetarily? You could make a donation!</h3>
|
||||
<p>
|
||||
If you can donate you can do that with this links.<br>
|
||||
You shoud remember that <b>this is a free project</b> and <b>you should support the artists you
|
||||
love</b>
|
||||
before supporting the developers.<br>
|
||||
Don't feel obligated to donate, I appreciate you anyway!</p>
|
||||
<p>
|
||||
<b>PayPal:</b> <a href="https://paypal.me/RemixDev" target="_blank">PayPal.me/RemixDev</a><br>
|
||||
<b>Bitcoin:</b> 1sdNymSJrMBWyHM4u2m9uco5nv6uV4Qs1<br>
|
||||
<b>Ethereum:</b> 0x1d2aa67e671485CD4062289772B662e0A6Ff976c
|
||||
</p>
|
||||
<br />
|
||||
<h2>License</h2>
|
||||
<p>
|
||||
<a rel="license" href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">
|
||||
<img alt="GNU General Public License" style="border-width:0"
|
||||
src="https://www.gnu.org/graphics/gplv3-127x51.png" />
|
||||
</a><br />
|
||||
This work is licensed under a <a rel="license" href="https://www.gnu.org/licenses/gpl-3.0.en.html"
|
||||
target="_blank">GNU General Public License 3.0</a>.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'the-about-tab',
|
||||
// Without this empty data rollup watcher throws an error
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
198
src/js/components/TheChartsTab.vue
Normal file
198
src/js/components/TheChartsTab.vue
Normal file
@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div id="charts_tab" class="main_tabcontent">
|
||||
<h2 class="page_heading">Charts</h2>
|
||||
<div v-if="country === ''" id="charts_selection">
|
||||
<div class="release_grid charts_grid">
|
||||
<!-- Ugly af -->
|
||||
<template v-for="release in countries">
|
||||
<div
|
||||
role="button"
|
||||
:aria-label="release.title"
|
||||
v-if="release.title === 'Worldwide'"
|
||||
class="release clickable"
|
||||
@click="getTrackList"
|
||||
:data-title="release.title"
|
||||
:data-id="release.id"
|
||||
:key="release.id"
|
||||
>
|
||||
<img class="rounded coverart" :src="release.picture_medium" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-for="release in countries">
|
||||
<div
|
||||
role="button"
|
||||
:aria-label="release.title"
|
||||
v-if="release.title !== 'Worldwide'"
|
||||
class="release clickable"
|
||||
@click="getTrackList"
|
||||
:data-title="release.title"
|
||||
:data-id="release.id"
|
||||
:key="release.id"
|
||||
>
|
||||
<img class="rounded coverart" :src="release.picture_medium" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else id="charts_table">
|
||||
<button @click="changeCountry">Change Country</button>
|
||||
<button
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="'https://www.deezer.com/playlist/' + id"
|
||||
>
|
||||
Download Chart
|
||||
</button>
|
||||
<table class="table table--charts">
|
||||
<tbody>
|
||||
<tr v-for="track in chart" class="track_row">
|
||||
<td class="top-tracks-position" :class="{ first: track.position === 1 }">
|
||||
{{ track.position }}
|
||||
</td>
|
||||
<td class="table__icon table__icon--big">
|
||||
<a
|
||||
href="#"
|
||||
@click="playPausePreview"
|
||||
class="rounded"
|
||||
:class="{ 'single-cover': track.preview }"
|
||||
:data-preview="track.preview"
|
||||
>
|
||||
<i
|
||||
@mouseenter="previewMouseEnter"
|
||||
@mouseleave="previewMouseLeave"
|
||||
v-if="track.preview"
|
||||
class="material-icons preview_controls"
|
||||
>
|
||||
play_arrow
|
||||
</i>
|
||||
<img class="rounded coverart" :src="track.album.cover_small" />
|
||||
</a>
|
||||
</td>
|
||||
<td class="table__cell--large breakline">
|
||||
{{
|
||||
track.title +
|
||||
(track.title_version && track.title.indexOf(track.title_version) == -1
|
||||
? ' ' + track.title_version
|
||||
: '')
|
||||
}}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--medium table__cell--center breakline clickable"
|
||||
@click="artistView"
|
||||
:data-id="track.artist.id"
|
||||
>
|
||||
{{ track.artist.name }}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--medium table__cell--center breakline clickable"
|
||||
@click="albumView"
|
||||
:data-id="track.album.id"
|
||||
>
|
||||
{{ track.album.title }}
|
||||
</td>
|
||||
<td class="table__cell--small table__cell--center">
|
||||
{{ convertDuration(track.duration) }}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="track.link"
|
||||
role="button"
|
||||
aria-label="download"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
|
||||
export default {
|
||||
name: 'the-charts-tab',
|
||||
data() {
|
||||
return {
|
||||
country: '',
|
||||
id: 0,
|
||||
countries: [],
|
||||
chart: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playPausePreview: TrackPreview.playPausePreview,
|
||||
previewMouseEnter: TrackPreview.previewMouseEnter,
|
||||
previewMouseLeave: TrackPreview.previewMouseLeave,
|
||||
convertDuration: Utils.convertDuration,
|
||||
addToQueue(e) {
|
||||
e.stopPropagation()
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
getTrackList(event) {
|
||||
document.getElementById('content').scrollTo(0, 0)
|
||||
|
||||
const {
|
||||
currentTarget: {
|
||||
dataset: { title }
|
||||
},
|
||||
currentTarget: {
|
||||
dataset: { id }
|
||||
}
|
||||
} = event
|
||||
|
||||
this.country = title
|
||||
localStorage.setItem('chart', this.country)
|
||||
this.id = id
|
||||
socket.emit('getChartTracks', this.id)
|
||||
},
|
||||
setTracklist(data) {
|
||||
this.chart = data
|
||||
},
|
||||
changeCountry() {
|
||||
this.country = ''
|
||||
this.id = 0
|
||||
},
|
||||
initCharts(data) {
|
||||
this.countries = data
|
||||
this.country = localStorage.getItem('chart') || ''
|
||||
|
||||
if (!this.country) return
|
||||
|
||||
let i = 0
|
||||
for (; i < this.countries.length; i++) {
|
||||
if (this.countries[i].title == this.country) break
|
||||
}
|
||||
|
||||
if (i !== this.countries.length) {
|
||||
this.id = this.countries[i].id
|
||||
socket.emit('getChartTracks', this.id)
|
||||
} else {
|
||||
this.country = ''
|
||||
localStorage.setItem('chart', this.country)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('init_charts', this.initCharts)
|
||||
socket.on('setChartTracks', this.setTracklist)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
47
src/js/components/TheErrorsTab.vue
Normal file
47
src/js/components/TheErrorsTab.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div id="errors_tab" class="main_tabcontent">
|
||||
<h1>Errors for {{ title }}</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Artist</th>
|
||||
<th>Title</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
<tr v-for="error in errors">
|
||||
<td>{{ error.data.id }}</td>
|
||||
<td>{{ error.data.artist }}</td>
|
||||
<td>{{ error.data.title }}</td>
|
||||
<td>{{ error.message }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EventBus from '@/js/EventBus'
|
||||
|
||||
export default {
|
||||
name: 'the-errors-tab',
|
||||
data: () => ({
|
||||
title: '',
|
||||
errors: []
|
||||
}),
|
||||
methods: {
|
||||
reset() {
|
||||
this.title = ''
|
||||
this.errors = []
|
||||
},
|
||||
showErrors(data) {
|
||||
this.title = data.artist + ' - ' + data.title
|
||||
this.errors = data.errors
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
EventBus.$on('showErrors', this.showErrors)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
277
src/js/components/TheFavoritesTab.vue
Normal file
277
src/js/components/TheFavoritesTab.vue
Normal file
@ -0,0 +1,277 @@
|
||||
<template>
|
||||
<div id="favorites_tab" class="main_tabcontent">
|
||||
<h2 class="page_heading">
|
||||
Favorites
|
||||
<div
|
||||
@click="reloadTabs"
|
||||
class="clickable reload-button reload-button--inline"
|
||||
ref="reloadButton"
|
||||
role="button"
|
||||
aria-label="reload"
|
||||
>
|
||||
<i class="material-icons">sync</i>
|
||||
</div>
|
||||
</h2>
|
||||
<div class="section-tabs">
|
||||
<div class="section-tabs__tab favorites_tablinks" id="favorites_playlist_tab">Playlists</div>
|
||||
<div class="section-tabs__tab favorites_tablinks" id="favorites_album_tab">Albums</div>
|
||||
<div class="section-tabs__tab favorites_tablinks" id="favorites_artist_tab">Artists</div>
|
||||
<div class="section-tabs__tab favorites_tablinks" id="favorites_track_tab">Tracks</div>
|
||||
</div>
|
||||
|
||||
<div id="playlist_favorites" class="favorites_tabcontent">
|
||||
<div v-if="playlists.length == 0">
|
||||
<h1>No Playlists found</h1>
|
||||
</div>
|
||||
<div class="release_grid" v-if="playlists.length > 0 || spotifyPlaylists > 0">
|
||||
<div v-for="release in playlists" class="release clickable" @click="playlistView" :data-id="release.id">
|
||||
<div class="cover_container">
|
||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="release.link"
|
||||
class="download_overlay"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="primary-text">{{ release.title }}</p>
|
||||
<p class="secondary-text">{{ 'by ' + release.creator.name + ' - ' + release.nb_tracks + ' tracks' }}</p>
|
||||
</div>
|
||||
<div
|
||||
v-for="release in spotifyPlaylists"
|
||||
class="release clickable"
|
||||
@click="spotifyPlaylistView"
|
||||
:data-id="release.id"
|
||||
>
|
||||
<div class="cover_container">
|
||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="release.link"
|
||||
class="download_overlay"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="primary-text">{{ release.title }}</p>
|
||||
<p class="secondary-text">{{ 'by ' + release.creator.name + ' - ' + release.nb_tracks + ' tracks' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="album_favorites" class="favorites_tabcontent">
|
||||
<div v-if="albums.length == 0">
|
||||
<h1>No Favorite Albums found</h1>
|
||||
</div>
|
||||
<div class="release_grid" v-if="albums.length > 0">
|
||||
<div v-for="release in albums" class="release clickable" @click="albumView" :data-id="release.id">
|
||||
<div class="cover_container">
|
||||
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="release.link"
|
||||
class="download_overlay"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="primary-text">{{ release.title }}</p>
|
||||
<p class="secondary-text">{{ 'by ' + release.artist.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="artist_favorites" class="favorites_tabcontent">
|
||||
<div v-if="artists.length == 0">
|
||||
<h1>No Favorite Artist found</h1>
|
||||
</div>
|
||||
<div class="release_grid" v-if="artists.length > 0">
|
||||
<div v-for="release in artists" class="release clickable" @click="artistView" :data-id="release.id">
|
||||
<div class="cover_container">
|
||||
<img aria-hidden="true" class="circle coverart" :src="release.picture_medium" />
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="release.link"
|
||||
class="download_overlay"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="primary-text">{{ release.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="track_favorites" class="favorites_tabcontent">
|
||||
<div v-if="tracks.length == 0">
|
||||
<h1>No Favorite Tracks found</h1>
|
||||
</div>
|
||||
<table v-if="tracks.length > 0" class="table">
|
||||
<tr v-for="track in tracks" class="track_row">
|
||||
<td class="top-tracks-position" :class="{ first: track.position === 1 }">
|
||||
{{ track.position }}
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
href="#"
|
||||
class="rounded"
|
||||
:class="{ 'single-cover': !!track.preview }"
|
||||
@click="playPausePreview"
|
||||
:data-preview="track.preview"
|
||||
>
|
||||
<i
|
||||
@mouseenter="previewMouseEnter"
|
||||
@mouseleave="previewMouseLeave"
|
||||
v-if="track.preview"
|
||||
class="material-icons preview_controls"
|
||||
>
|
||||
play_arrow
|
||||
</i>
|
||||
<img class="rounded coverart" :src="track.album.cover_small" />
|
||||
</a>
|
||||
</td>
|
||||
<td class="table__cell--large breakline">
|
||||
{{
|
||||
track.title +
|
||||
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
|
||||
}}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--medium table__cell--center breakline clickable"
|
||||
@click="artistView"
|
||||
:data-id="track.artist.id"
|
||||
>
|
||||
{{ track.artist.name }}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--medium table__cell--center breakline clickable"
|
||||
@click="albumView"
|
||||
:data-id="track.album.id"
|
||||
>
|
||||
{{ track.album.title }}
|
||||
</td>
|
||||
<td class="table__cell--small">
|
||||
{{ convertDuration(track.duration) }}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--download clickable"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="track.link"
|
||||
role="button"
|
||||
aria-label="download"
|
||||
>
|
||||
<div class="table__cell-content table__cell-content--vertical-center">
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
import { toast } from '@/js/toasts'
|
||||
|
||||
export default {
|
||||
name: 'the-favorites-tab',
|
||||
data() {
|
||||
return {
|
||||
tracks: [],
|
||||
albums: [],
|
||||
artists: [],
|
||||
playlists: [],
|
||||
spotifyPlaylists: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playlistView: showView.bind(null, 'playlist'),
|
||||
spotifyPlaylistView: showView.bind(null, 'spotifyplaylist'),
|
||||
playPausePreview: TrackPreview.playPausePreview,
|
||||
previewMouseEnter: TrackPreview.previewMouseEnter,
|
||||
previewMouseLeave: TrackPreview.previewMouseLeave,
|
||||
convertDuration: Utils.convertDuration,
|
||||
addToQueue(e) {
|
||||
e.stopPropagation()
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
updated_userSpotifyPlaylists(data) {
|
||||
this.spotifyPlaylists = data
|
||||
},
|
||||
updated_userPlaylists(data) {
|
||||
this.playlists = data
|
||||
},
|
||||
updated_userAlbums(data) {
|
||||
this.albums = data
|
||||
},
|
||||
updated_userArtist(data) {
|
||||
this.artists = data
|
||||
},
|
||||
updated_userTracks(data) {
|
||||
this.tracks = data
|
||||
},
|
||||
reloadTabs() {
|
||||
this.$refs.reloadButton.classList.add('spin')
|
||||
socket.emit('update_userFavorites')
|
||||
if (localStorage.getItem('spotifyUser'))
|
||||
socket.emit('update_userSpotifyPlaylists', localStorage.getItem('spotifyUser'))
|
||||
},
|
||||
updated_userFavorites(data) {
|
||||
const { tracks, albums, artists, playlists } = data
|
||||
this.tracks = tracks
|
||||
this.albums = albums
|
||||
this.artists = artists
|
||||
this.playlists = playlists
|
||||
|
||||
// Removing animation class only when the animation has completed an iteration
|
||||
// Prevents animation ugly stutter
|
||||
this.$refs.reloadButton.addEventListener(
|
||||
'animationiteration',
|
||||
() => {
|
||||
this.$refs.reloadButton.classList.remove('spin')
|
||||
toast('Refresh completed!', 'done', true)
|
||||
},
|
||||
{ once: true }
|
||||
)
|
||||
},
|
||||
initFavorites(data) {
|
||||
this.updated_userFavorites(data)
|
||||
document.getElementById('favorites_playlist_tab').click()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('init_favorites', this.initFavorites)
|
||||
socket.on('updated_userFavorites', this.updated_userFavorites)
|
||||
socket.on('updated_userSpotifyPlaylists', this.updated_userSpotifyPlaylists)
|
||||
socket.on('updated_userPlaylists', this.updated_userPlaylists)
|
||||
socket.on('updated_userAlbums', this.updated_userAlbums)
|
||||
socket.on('updated_userArtist', this.updated_userArtist)
|
||||
socket.on('updated_userTracks', this.updated_userTracks)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
103
src/js/components/TheHomeTab.vue
Normal file
103
src/js/components/TheHomeTab.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div id="home_tab" class="main_tabcontent">
|
||||
<h2 class="page_heading">Welcome to deemix</h2>
|
||||
<section id="home_not_logged_in" class="home_section" ref="notLogged">
|
||||
<p id="home_not_logged_text">You need to log into your deezer account before you can start downloading.</p>
|
||||
<button type="button" name="button" @click="openSettings">Open Settings</button>
|
||||
</section>
|
||||
<section v-if="playlists.length" class="home_section">
|
||||
<h3 class="section_heading">Popular playlists</h3>
|
||||
<div class="release_grid">
|
||||
<div v-for="release in playlists" class="release clickable" @click="playlistView" :data-id="release.id">
|
||||
<div class="cover_container">
|
||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="release.link"
|
||||
class="download_overlay"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="primary-text">{{ release.title }}</p>
|
||||
<p class="secondary-text">{{ 'by ' + release.user.name + ' - ' + release.nb_tracks + ' tracks' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section v-if="albums.length" class="home_section">
|
||||
<h3 class="section_heading">Most streamed albums</h3>
|
||||
<div class="release_grid">
|
||||
<div v-for="release in albums" class="release clickable" @click="albumView" :data-id="release.id">
|
||||
<div class="cover_container">
|
||||
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="release.link"
|
||||
class="download_overlay"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="primary-text">{{ release.title }}</p>
|
||||
<p class="secondary-text">{{ 'by ' + release.artist.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
|
||||
export default {
|
||||
name: 'the-home-tab',
|
||||
data() {
|
||||
return {
|
||||
playlists: [],
|
||||
albums: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playlistView: showView.bind(null, 'playlist'),
|
||||
openSettings() {
|
||||
document.getElementById('main_settings_tablink').click()
|
||||
},
|
||||
addToQueue(e) {
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
initHome(data) {
|
||||
const {
|
||||
playlists: { data: playlistData },
|
||||
albums: { data: albumData }
|
||||
} = data
|
||||
|
||||
this.playlists = playlistData
|
||||
this.albums = albumData
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (localStorage.getItem('arl')) {
|
||||
this.$refs.notLogged.classList.add('hide')
|
||||
}
|
||||
|
||||
socket.on('init_home', this.initHome)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
186
src/js/components/TheLinkAnalyzerTab.vue
Normal file
186
src/js/components/TheLinkAnalyzerTab.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div id="analyzer_tab" class="main_tabcontent image_header">
|
||||
<h2 class="page_heading">Link Analyzer</h2>
|
||||
<div v-if="link == ''">
|
||||
<p>
|
||||
You can use this section to find out more information about the link you are trying to download<br />This is
|
||||
usefull if you're trying to download some tracks that are not available in your country and want to know where
|
||||
they are available
|
||||
</p>
|
||||
</div>
|
||||
<div v-else-if="link == 'error'">
|
||||
<h2>This link is not supported</h2>
|
||||
<p>Seems like this link is not yet supported, try analyzing another one.</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<header
|
||||
class="inline-flex"
|
||||
:style="{
|
||||
'background-image':
|
||||
'linear-gradient(to bottom, transparent 0%, var(--main-background) 100%), url(\'' + image + '\')'
|
||||
}"
|
||||
>
|
||||
<div>
|
||||
<h1>{{ title }}</h1>
|
||||
<h2 v-if="type == 'track'">
|
||||
by <span class="clickable" @click="artistView" :data-id="data.artist.id">{{ data.artist.name }}</span> • in
|
||||
<span class="clickable" @click="albumView" :data-id="data.album.id">{{ data.album.title }}</span>
|
||||
</h2>
|
||||
<h2 v-else-if="type == 'album'">
|
||||
by <span class="clickable" @click="artistView" :data-id="data.artist.id">{{ data.artist.name }}</span> •
|
||||
{{ data.nb_tracks }} tracks
|
||||
</h2>
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
aria-label="download"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="link"
|
||||
class="fab right"
|
||||
>
|
||||
<i class="material-icons">get_app</i>
|
||||
</div>
|
||||
</header>
|
||||
<table class="table">
|
||||
<tr v-if="data.id">
|
||||
<td>ID</td>
|
||||
<td>{{ data.id }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.isrc">
|
||||
<td>ISRC</td>
|
||||
<td>{{ data.isrc }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.upc">
|
||||
<td>UPC</td>
|
||||
<td>{{ data.upc }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.duration">
|
||||
<td>Duration</td>
|
||||
<td>{{ convertDuration(data.duration) }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.disk_number">
|
||||
<td>Disk Number</td>
|
||||
<td>{{ data.disk_number }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.track_position">
|
||||
<td>Track Number</td>
|
||||
<td>{{ data.track_position }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.release_date">
|
||||
<td>Release Date</td>
|
||||
<td>{{ data.release_date }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.bpm">
|
||||
<td>BPM</td>
|
||||
<td>{{ data.bpm }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.label">
|
||||
<td>Label</td>
|
||||
<td>{{ data.label }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.record_type">
|
||||
<td>Record Type</td>
|
||||
<td>{{ data.record_type }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.genres && data.genres.data.length">
|
||||
<td>Genres</td>
|
||||
<td>{{ data.genres.data.map(x => x.name).join('; ') }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-if="type == 'album'">
|
||||
<button @click="albumView" :data-id="id">Tracklist</button>
|
||||
</div>
|
||||
<div v-if="countries.length">
|
||||
<p v-for="country in countries">{{ country[0] }} - {{ country[1] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
import EventBus from '@/js/EventBus'
|
||||
|
||||
export default {
|
||||
name: 'the-link-analyzer-tab',
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
subtitle: '',
|
||||
image: '',
|
||||
data: {},
|
||||
type: '',
|
||||
link: '',
|
||||
id: '0',
|
||||
countries: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
convertDuration: Utils.convertDuration,
|
||||
reset() {
|
||||
this.title = 'Loading...'
|
||||
this.subtitle = ''
|
||||
this.image = ''
|
||||
this.data = {}
|
||||
this.type = ''
|
||||
this.link = ''
|
||||
this.countries = []
|
||||
},
|
||||
showTrack(data) {
|
||||
const {
|
||||
title,
|
||||
title_version,
|
||||
album: { cover_xl },
|
||||
link,
|
||||
available_countries,
|
||||
id
|
||||
} = data
|
||||
|
||||
this.title = title + (title_version && title.indexOf(title_version) == -1 ? ' ' + title_version : '')
|
||||
this.image = cover_xl
|
||||
this.type = 'track'
|
||||
this.link = link
|
||||
this.id = id
|
||||
|
||||
available_countries.forEach(cc => {
|
||||
let temp = []
|
||||
let chars = [...cc].map(c => c.charCodeAt() + 127397)
|
||||
temp.push(String.fromCodePoint(...chars))
|
||||
temp.push(Utils.COUNTRIES[cc])
|
||||
this.countries.push(temp)
|
||||
})
|
||||
|
||||
this.data = data
|
||||
},
|
||||
showAlbum(data) {
|
||||
const { title, cover_xl, link, id } = data
|
||||
|
||||
this.title = title
|
||||
this.image = cover_xl
|
||||
this.type = 'album'
|
||||
this.link = link
|
||||
this.data = data
|
||||
this.id = id
|
||||
},
|
||||
notSupported() {
|
||||
this.link = 'error'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
EventBus.$on('linkAnalyzerTab:reset', this.reset)
|
||||
|
||||
socket.on('analyze_track', this.showTrack)
|
||||
socket.on('analyze_album', this.showAlbum)
|
||||
socket.on('analyze_notSupported', this.notSupported)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
665
src/js/components/TheSettingsTab.vue
Normal file
665
src/js/components/TheSettingsTab.vue
Normal file
@ -0,0 +1,665 @@
|
||||
<template>
|
||||
<div id="settings_tab" class="main_tabcontent fixed_footer">
|
||||
<h2 class="page_heading">Settings</h2>
|
||||
|
||||
<div id="logged_in_info" ref="loggedInInfo">
|
||||
<img id="settings_picture" src="" alt="Profile Picture" ref="userpicture" class="circle" />
|
||||
<p>You are logged in as <strong id="settings_username" ref="username"></strong></p>
|
||||
<button id="settings_btn_logout" @click="logout">Logout</button>
|
||||
<select v-if="accounts.length" id="family_account" v-model="accountNum" @change="changeAccount">
|
||||
<option v-for="(account, i) in accounts" :value="i.toString()">{{ account.BLOG_NAME }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">person</i>Login
|
||||
</h3>
|
||||
<div class="inline-flex">
|
||||
<input autocomplete="off" type="password" id="login_input_arl" ref="loginInput" placeholder="ARL" />
|
||||
<button id="settings_btn_copyArl" @click="copyARLtoClipboard">
|
||||
<i class="material-icons">assignment</i>
|
||||
</button>
|
||||
</div>
|
||||
<a href="https://notabug.org/RemixDevs/DeezloaderRemix/wiki/Login+via+userToken" target="_blank">
|
||||
How do I get my own ARL?
|
||||
</a>
|
||||
<button id="settings_btn_updateArl" @click="login" style="width:100%;">Update ARL</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">web</i>Appearance
|
||||
</h3>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="changeSlimDownloads" />
|
||||
<span class="checkbox_text">Slim download tab</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">folder</i>Download Path
|
||||
</h3>
|
||||
<input type="text" v-model="settings.downloadLocation" />
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">font_download</i>Templates
|
||||
</h3>
|
||||
|
||||
<p>Trackname template</p>
|
||||
<input type="text" v-model="settings.tracknameTemplate" />
|
||||
|
||||
<p>Album track template</p>
|
||||
<input type="text" v-model="settings.albumTracknameTemplate" />
|
||||
|
||||
<p>Playlist track template</p>
|
||||
<input type="text" v-model="settings.playlistTracknameTemplate" />
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">create_new_folder</i>Folders
|
||||
</h3>
|
||||
<div class="settings-container">
|
||||
<div class="settings-container__third">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createPlaylistFolder" />
|
||||
<span class="checkbox_text">Create folder for playlist</span>
|
||||
</label>
|
||||
<div class="input_group" v-if="settings.createPlaylistFolder">
|
||||
<p class="input_group_text">Playlist folder template</p>
|
||||
<input type="text" v-model="settings.playlistNameTemplate" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-container__third">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createArtistFolder" />
|
||||
<span class="checkbox_text">Create folder for artist</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group" v-if="settings.createArtistFolder">
|
||||
<p class="input_group_text">Artist folder template</p>
|
||||
<input type="text" v-model="settings.artistNameTemplate" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-container__third">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createAlbumFolder" />
|
||||
<span class="checkbox_text">Create folder for album</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group" v-if="settings.createAlbumFolder">
|
||||
<p class="input_group_text">Album folder template</p>
|
||||
<input type="text" v-model="settings.albumNameTemplate" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createCDFolder" />
|
||||
<span class="checkbox_text">Create folder for CDs</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createStructurePlaylist" />
|
||||
<span class="checkbox_text">Create folder structure for playlists</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createSingleFolder" />
|
||||
<span class="checkbox_text">Create folder structure for singles</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">title</i>Track titles
|
||||
</h3>
|
||||
|
||||
<div class="settings-container">
|
||||
<div class="settings-container__third settings-container__third--only-checkbox">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.padTracks" />
|
||||
<span class="checkbox_text">Pad tracks</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-container__third">
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Overwrite padding size</p>
|
||||
<input type="number" v-model="settings.paddingSize" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-container__third">
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Illegal Character replacer</p>
|
||||
<input type="text" v-model="settings.illegalCharacterReplacer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">get_app</i>Downloads
|
||||
</h3>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Concurrent Downloads</p>
|
||||
<input type="number" v-model.number="settings.queueConcurrency" />
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Preferred Bitrate</p>
|
||||
<select v-model="settings.maxBitrate">
|
||||
<option value="9">FLAC 1411kbps</option>
|
||||
<option value="3">MP3 320kbps</option>
|
||||
<option value="1">MP3 128kbps</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Should I overwrite the files?</p>
|
||||
<select v-model="settings.overwriteFile">
|
||||
<option value="y">Yes, overwrite the file</option>
|
||||
<option value="n">No, don't overwrite the file</option>
|
||||
<option value="t">Overwrite only the tags</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="settings-container">
|
||||
<div class="settings-container__third settings-container__third--only-checkbox">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.fallbackBitrate" />
|
||||
<span class="checkbox_text">Bitrate fallback</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.fallbackSearch" />
|
||||
<span class="checkbox_text">Search fallback</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-container__third settings-container__third--only-checkbox">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.logErrors" />
|
||||
<span class="checkbox_text">Create log file for errors</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.logSearched" />
|
||||
<span class="checkbox_text">Create log file for searched tracks</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-container__third settings-container__third--only-checkbox">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.syncedLyrics" />
|
||||
<span class="checkbox_text">Create .lyr files (Sync Lyrics)</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.createM3U8File" />
|
||||
<span class="checkbox_text">Create playlist file</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input_group" v-if="settings.createM3U8File">
|
||||
<p class="input_group_text">Playlist filename template</p>
|
||||
<input type="text" v-model="settings.playlistFilenameTemplate" />
|
||||
</div>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.saveDownloadQueue" />
|
||||
<span class="checkbox_text">Save download queue when closing the app</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons">album</i>Album covers
|
||||
</h3>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.saveArtwork" />
|
||||
<span class="checkbox_text">Save covers</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group" v-if="settings.saveArtwork">
|
||||
<p class="input_group_text">Cover name template</p>
|
||||
<input type="text" v-model="settings.coverImageTemplate" />
|
||||
</div>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.saveArtworkArtist" />
|
||||
<span class="checkbox_text">Save artist image</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group" v-if="settings.saveArtworkArtist">
|
||||
<p class="input_group_text">Artist image name template</p>
|
||||
<input type="text" v-model="settings.artistImageTemplate" />
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Local artwork size</p>
|
||||
<input type="number" min="100" max="1800" step="100" v-model.number="settings.localArtworkSize" />
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Embedded artwork size</p>
|
||||
<input type="number" min="100" max="1800" step="100" v-model.number="settings.embeddedArtworkSize" />
|
||||
</div>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.PNGcovers" />
|
||||
<span class="checkbox_text">Save images as png</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">JPEG image quality</p>
|
||||
<input type="number" min="1" max="100" v-model.number="settings.jpegImageQuality" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<i class="material-icons" style="width: 1em; height: 1em;">bookmarks</i>Which tags to save
|
||||
</h3>
|
||||
|
||||
<div class="settings-container">
|
||||
<div class="settings-container__half">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.title" />
|
||||
<span class="checkbox_text">Title</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.artist" />
|
||||
<span class="checkbox_text">Artists</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.album" />
|
||||
<span class="checkbox_text">Album</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.cover" />
|
||||
<span class="checkbox_text">Cover</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.trackNumber" />
|
||||
<span class="checkbox_text">Track Number</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.trackTotal" />
|
||||
<span class="checkbox_text">Track Total</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.discNumber" />
|
||||
<span class="checkbox_text">Disc Number</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.discTotal" />
|
||||
<span class="checkbox_text">Disc Total</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.albumArtist" />
|
||||
<span class="checkbox_text">Album Artist</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.genre" />
|
||||
<span class="checkbox_text">Genre</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.year" />
|
||||
<span class="checkbox_text">Year</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.date" />
|
||||
<span class="checkbox_text">Date</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings-container__half">
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.explicit" />
|
||||
<span class="checkbox_text">Explicit Lyrics</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.isrc" />
|
||||
<span class="checkbox_text">ISRC</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.length" />
|
||||
<span class="checkbox_text">Track Length</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.barcode" />
|
||||
<span class="checkbox_text">Album Barcode (UPC)</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.bpm" />
|
||||
<span class="checkbox_text">BPM</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.replayGain" />
|
||||
<span class="checkbox_text">Replay Gain</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.label" />
|
||||
<span class="checkbox_text">Album Label</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.lyrics" />
|
||||
<span class="checkbox_text">Unsynchronized Lyrics</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.copyright" />
|
||||
<span class="checkbox_text">Copyright</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.composer" />
|
||||
<span class="checkbox_text">Composer</span>
|
||||
</label>
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.involvedPeople" />
|
||||
<span class="checkbox_text">Involved People</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon"><i class="material-icons">list</i>Other</h3>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.savePlaylistAsCompilation" />
|
||||
<span class="checkbox_text">Save playlists as compilation</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.useNullSeparator" />
|
||||
<span class="checkbox_text">Use null separator</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.tags.saveID3v1" />
|
||||
<span class="checkbox_text">Save ID3v1 as well</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">How would you like to separate your artists?</p>
|
||||
<select v-model="settings.tags.multitagSeparator">
|
||||
<option value="default">Using standard specification</option>
|
||||
<option value="andFeat">Using & and feat.</option>
|
||||
<option value=" & ">Using " & "</option>
|
||||
<option value=",">Using ","</option>
|
||||
<option value=", ">Using ", "</option>
|
||||
<option value="/">Using "/"</option>
|
||||
<option value=" / ">Using "/ "</option>
|
||||
<option value=";">Using ";"</option>
|
||||
<option value="; ">Using "; "</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.albumVariousArtists" />
|
||||
<span class="checkbox_text">Keep "Various Artists" in the Album Artists</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.removeAlbumVersion" />
|
||||
<span class="checkbox_text">Remove "album version" from track title</span>
|
||||
</label>
|
||||
|
||||
<label class="with_checkbox">
|
||||
<input type="checkbox" v-model="settings.removeDuplicateArtists" />
|
||||
<span class="checkbox_text">Remove combinations of artists</span>
|
||||
</label>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Date format for FLAC files</p>
|
||||
<select v-model="settings.dateFormat">
|
||||
<option value="Y-M-D">YYYY-MM-DD</option>
|
||||
<option value="Y-D-M">YYYY-DD-MM</option>
|
||||
<option value="D-M-Y">DD-MM-YYYY</option>
|
||||
<option value="M-D-Y">MM-DD-YYYY</option>
|
||||
<option value="Y">YYYY</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">What should I do with featured artists?</p>
|
||||
<select v-model="settings.featuredToTitle">
|
||||
<option value="0">Nothing</option>
|
||||
<option value="1">Remove it from the title</option>
|
||||
<option value="3">Remove it from the title and the album title</option>
|
||||
<option value="2">Move it to the title</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Title casing</p>
|
||||
<select v-model="settings.titleCasing">
|
||||
<option value="nothing">Keep unchanged</option>
|
||||
<option value="lower">lowercase</option>
|
||||
<option value="upper">UPPERCASE</option>
|
||||
<option value="start">Start Of Each Word</option>
|
||||
<option value="sentence">Like a sentence</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Artist casing</p>
|
||||
<select v-model="settings.artistCasing">
|
||||
<option value="nothing">Keep unchanged</option>
|
||||
<option value="lower">lowercase</option>
|
||||
<option value="upper">UPPERCASE</option>
|
||||
<option value="start">Start Of Each Word</option>
|
||||
<option value="sentence">Like a sentence</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Preview Volume</p>
|
||||
<input
|
||||
type="range"
|
||||
@change="updateMaxVolume"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
class="slider"
|
||||
v-model.number="previewVolume.preview_max_volume"
|
||||
/>
|
||||
<span>{{ previewVolume.preview_max_volume }}%</span>
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Command to execute after download</p>
|
||||
<p class="secondary-text">Leave blank for no action</p>
|
||||
<input type="text" v-model="settings.executeCommand" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<h3 class="settings-group__header settings-group__header--with-icon">
|
||||
<svg id="spotify_icon" enable-background="new 0 0 24 24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="m12 24c6.624 0 12-5.376 12-12s-5.376-12-12-12-12 5.376-12 12 5.376 12 12 12zm4.872-6.344v.001c-.807 0-3.356-2.828-10.52-1.36-.189.049-.436.126-.576.126-.915 0-1.09-1.369-.106-1.578 3.963-.875 8.013-.798 11.467 1.268.824.526.474 1.543-.265 1.543zm1.303-3.173c-.113-.03-.08.069-.597-.203-3.025-1.79-7.533-2.512-11.545-1.423-.232.063-.358.126-.576.126-1.071 0-1.355-1.611-.188-1.94 4.716-1.325 9.775-.552 13.297 1.543.392.232.547.533.547.953-.005.522-.411.944-.938.944zm-13.627-7.485c4.523-1.324 11.368-.906 15.624 1.578 1.091.629.662 2.22-.498 2.22l-.001-.001c-.252 0-.407-.063-.625-.189-3.443-2.056-9.604-2.549-13.59-1.436-.175.048-.393.125-.625.125-.639 0-1.127-.499-1.127-1.142 0-.657.407-1.029.842-1.155z"
|
||||
/>
|
||||
</svg>
|
||||
Spotify Features
|
||||
</h3>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Spotify clientID</p>
|
||||
<input type="text" v-model="spotifyFeatures.clientId" />
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Spotify Client Secret</p>
|
||||
<input type="password" v-model="spotifyFeatures.clientSecret" />
|
||||
</div>
|
||||
|
||||
<div class="input_group">
|
||||
<p class="input_group_text">Spotify username</p>
|
||||
<input type="text" v-model="spotifyUser" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button @click="resetSettings">Reset to Default</button>
|
||||
<button @click="saveSettings">Save</button>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { toast } from '@/js/toasts.js'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import EventBus from '@/js/EventBus'
|
||||
|
||||
export default {
|
||||
name: 'the-settings-tab',
|
||||
data: () => ({
|
||||
settings: { tags: {} },
|
||||
lastSettings: {},
|
||||
spotifyFeatures: {},
|
||||
lastCredentials: {},
|
||||
defaultSettings: {},
|
||||
lastUser: '',
|
||||
spotifyUser: '',
|
||||
slimDownloads: false,
|
||||
previewVolume: window.vol,
|
||||
accountNum: 0,
|
||||
accounts: []
|
||||
}),
|
||||
computed: {
|
||||
changeSlimDownloads: {
|
||||
get() {
|
||||
return this.slimDownloads
|
||||
},
|
||||
set(wantSlimDownloads) {
|
||||
this.slimDownloads = wantSlimDownloads
|
||||
document.getElementById('download_list').classList.toggle('slim', wantSlimDownloads)
|
||||
localStorage.setItem('slimDownloads', wantSlimDownloads)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
revertSettings() {
|
||||
this.settings = { ...this.lastSettings }
|
||||
},
|
||||
revertCredentials() {
|
||||
this.spotifyCredentials = { ...this.lastCredentials }
|
||||
this.spotifyUser = (' ' + this.lastUser).slice(1)
|
||||
},
|
||||
copyARLtoClipboard() {
|
||||
let copyText = this.$refs.loginInput
|
||||
|
||||
copyText.setAttribute('type', 'text')
|
||||
copyText.select()
|
||||
copyText.setSelectionRange(0, 99999)
|
||||
document.execCommand('copy')
|
||||
copyText.setAttribute('type', 'password')
|
||||
|
||||
toast('ARL copied to clipboard', 'assignment')
|
||||
},
|
||||
updateMaxVolume() {
|
||||
localStorage.setItem('previewVolume', this.previewVolume.preview_max_volume)
|
||||
},
|
||||
saveSettings() {
|
||||
this.lastSettings = { ...this.settings }
|
||||
this.lastCredentials = { ...this.spotifyFeatures }
|
||||
let changed = false
|
||||
if (this.lastUser != this.spotifyUser) {
|
||||
// force cloning without linking
|
||||
this.lastUser = (' ' + this.spotifyUser).slice(1)
|
||||
localStorage.setItem('spotifyUser', this.lastUser)
|
||||
changed = true
|
||||
}
|
||||
|
||||
socket.emit('saveSettings', this.lastSettings, this.lastCredentials, changed ? this.lastUser : false)
|
||||
},
|
||||
loadSettings(settings, spotifyCredentials, defaults = null) {
|
||||
if (defaults) {
|
||||
this.defaultSettings = { ...defaults }
|
||||
}
|
||||
|
||||
this.lastSettings = { ...settings }
|
||||
this.lastCredentials = { ...spotifyCredentials }
|
||||
this.settings = settings
|
||||
this.spotifyFeatures = spotifyCredentials
|
||||
},
|
||||
login() {
|
||||
let arl = this.$refs.loginInput.value.trim()
|
||||
if (arl != '' && arl != localStorage.getItem('arl')) {
|
||||
socket.emit('login', arl, true, this.accountNum)
|
||||
}
|
||||
},
|
||||
changeAccount() {
|
||||
socket.emit('changeAccount', this.accountNum)
|
||||
},
|
||||
accountChanged(user, accountNum) {
|
||||
this.$refs.username.innerText = user.name
|
||||
this.$refs.userpicture.src = `https://e-cdns-images.dzcdn.net/images/user/${user.picture}/125x125-000000-80-0-0.jpg`
|
||||
this.accountNum = accountNum
|
||||
localStorage.setItem('accountNum', this.accountNum)
|
||||
},
|
||||
initAccounts(accounts) {
|
||||
this.accounts = accounts
|
||||
},
|
||||
logout() {
|
||||
socket.emit('logout')
|
||||
},
|
||||
initSettings(settings, credentials, defaults) {
|
||||
this.loadSettings(settings, credentials, defaults)
|
||||
toast('Settings loaded!', 'settings')
|
||||
},
|
||||
updateSettings(settings, credentials) {
|
||||
this.loadSettings(settings, credentials)
|
||||
toast('Settings updated!', 'settings')
|
||||
},
|
||||
resetSettings() {
|
||||
this.settings = { ...this.defaultSettings }
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
EventBus.$on('settingsTab:revertSettings', this.revertSettings)
|
||||
EventBus.$on('settingsTab:revertCredentials', this.revertCredentials)
|
||||
|
||||
this.$refs.loggedInInfo.classList.add('hide')
|
||||
|
||||
if (localStorage.getItem('arl')) {
|
||||
this.$refs.loginInput.value = localStorage.getItem('arl').trim()
|
||||
}
|
||||
if (localStorage.getItem('accountNum')) {
|
||||
this.accountNum = localStorage.getItem('accountNum')
|
||||
}
|
||||
|
||||
let spotifyUser = localStorage.getItem('spotifyUser')
|
||||
|
||||
if (spotifyUser) {
|
||||
this.lastUser = spotifyUser
|
||||
this.spotifyUser = spotifyUser
|
||||
socket.emit('update_userSpotifyPlaylists', spotifyUser)
|
||||
}
|
||||
|
||||
this.changeSlimDownloads = 'true' === localStorage.getItem('slimDownloads')
|
||||
|
||||
let volume = parseInt(localStorage.getItem('previewVolume'))
|
||||
if (isNaN(volume)) {
|
||||
volume = 80
|
||||
localStorage.setItem('previewVolume', volume)
|
||||
}
|
||||
window.vol.preview_max_volume = volume
|
||||
|
||||
socket.on('init_settings', this.initSettings)
|
||||
socket.on('updateSettings', this.updateSettings)
|
||||
socket.on('accountChanged', this.accountChanged)
|
||||
socket.on('familyAccounts', this.initAccounts)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
53
src/js/components/TheSidebar.vue
Normal file
53
src/js/components/TheSidebar.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<aside id="sidebar" role="navigation">
|
||||
<span id="main_home_tablink" class="main_tablinks" role="link" aria-label="home">
|
||||
<i class="material-icons side_icon">home</i>
|
||||
<span class="main_tablinks_text">Home</span>
|
||||
</span>
|
||||
<span id="main_search_tablink" class="main_tablinks" role="link" aria-label="search">
|
||||
<i class="material-icons side_icon">search</i>
|
||||
<span class="main_tablinks_text">Search</span>
|
||||
</span>
|
||||
<span id="main_charts_tablink" class="main_tablinks" role="link" aria-label="charts">
|
||||
<i class="material-icons side_icon">bubble_chart</i>
|
||||
<span class="main_tablinks_text">Charts</span>
|
||||
</span>
|
||||
<span id="main_favorites_tablink" class="main_tablinks" role="link" aria-label="favorites">
|
||||
<i class="material-icons side_icon">album</i>
|
||||
<span class="main_tablinks_text">Favorites</span>
|
||||
</span>
|
||||
<span id="main_analyzer_tablink" class="main_tablinks" role="link" aria-label="link analyzer">
|
||||
<i class="material-icons side_icon">link</i>
|
||||
<span class="main_tablinks_text">Link Analyzer</span>
|
||||
</span>
|
||||
<span id="main_settings_tablink" class="main_tablinks" role="link" aria-label="settings">
|
||||
<i class="material-icons side_icon">settings</i>
|
||||
<span class="main_tablinks_text">Settings</span>
|
||||
</span>
|
||||
<span id="main_about_tablink" class="main_tablinks" role="link" aria-label="info">
|
||||
<i class="material-icons side_icon">info</i>
|
||||
<span class="main_tablinks_text">About</span>
|
||||
</span>
|
||||
<span id="theme_selector" class="main_tablinks" role="link" aria-label="theme selector">
|
||||
<i class="material-icons side_icon side_icon--theme">palette</i>
|
||||
<div id="theme_togglers">
|
||||
<div class="theme_toggler" data-theme-variant="purple"></div>
|
||||
<div class="theme_toggler" data-theme-variant="dark"></div>
|
||||
<div class="theme_toggler theme_toggler--active" data-theme-variant="light"></div>
|
||||
</div>
|
||||
</span>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'the-sidebar',
|
||||
// Without this empty data rollup watcher throws an error
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
301
src/js/components/TracklistTab.vue
Normal file
301
src/js/components/TracklistTab.vue
Normal file
@ -0,0 +1,301 @@
|
||||
<template>
|
||||
<div id="tracklist_tab" class="main_tabcontent fixed_footer image_header">
|
||||
<header
|
||||
:style="{
|
||||
'background-image':
|
||||
'linear-gradient(to bottom, transparent 0%, var(--main-background) 100%), url(\'' + image + '\')'
|
||||
}"
|
||||
>
|
||||
<h1 class="inline-flex">
|
||||
{{ title }} <i v-if="explicit" class="material-icons explicit_icon explicit_icon--right">explicit</i>
|
||||
</h1>
|
||||
<h2 class="inline-flex">
|
||||
<span v-if="metadata">{{ metadata }}</span
|
||||
><span class="right" v-if="release_date">{{ release_date }}</span>
|
||||
</h2>
|
||||
</header>
|
||||
|
||||
<table class="table table--tracklist">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<i class="material-icons">music_note</i>
|
||||
</th>
|
||||
<th>#</th>
|
||||
<th>Song</th>
|
||||
<th>Artist</th>
|
||||
<th v-if="type == 'Playlist'">Album</th>
|
||||
<th>
|
||||
<i class="material-icons">timer</i>
|
||||
</th>
|
||||
<th class="table__icon table__cell--center clickable">
|
||||
<input @click="toggleAll" class="selectAll" type="checkbox" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-if="type !== 'Spotify Playlist'">
|
||||
<template v-for="track in body">
|
||||
<tr v-if="track.type == 'track'">
|
||||
<td class="table__cell--x-small table__cell--center">
|
||||
<div class="table__cell-content table__cell-content--vertical-center">
|
||||
<i
|
||||
class="material-icons"
|
||||
:class="{ preview_playlist_controls: track.preview, disabled: !track.preview }"
|
||||
v-on="{ click: track.preview ? playPausePreview : false }"
|
||||
:data-preview="track.preview"
|
||||
>
|
||||
play_arrow
|
||||
</i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="table__cell--small table__cell--center track_position">
|
||||
{{ type === 'Album' ? track.track_position : body.indexOf(track) + 1 }}
|
||||
</td>
|
||||
<td class="table__cell--large table__cell--with-icon">
|
||||
<div class="table__cell-content table__cell-content--vertical-center">
|
||||
<i v-if="track.explicit_lyrics" class="material-icons explicit_icon">
|
||||
explicit
|
||||
</i>
|
||||
{{
|
||||
track.title +
|
||||
(track.title_version && track.title.indexOf(track.title_version) == -1
|
||||
? ' ' + track.title_version
|
||||
: '')
|
||||
}}
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--medium table__cell--center clickable"
|
||||
@click="artistView"
|
||||
:data-id="track.artist.id"
|
||||
>
|
||||
{{ track.artist.name }}
|
||||
</td>
|
||||
<td
|
||||
v-if="type == 'Playlist'"
|
||||
class="table__cell--medium table__cell--center clickable"
|
||||
@click="albumView"
|
||||
:data-id="track.album.id"
|
||||
>
|
||||
{{ track.album.title }}
|
||||
</td>
|
||||
<td
|
||||
class="table__cell--center"
|
||||
:class="{ 'table__cell--small': type === 'Album', 'table__cell--x-small': type === 'Playlist' }"
|
||||
>
|
||||
{{ convertDuration(track.duration) }}
|
||||
</td>
|
||||
<td class="table__icon table__cell--center">
|
||||
<input class="clickable" type="checkbox" v-model="track.selected" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-else-if="track.type == 'disc_separator'" class="table__row-no-highlight" style="opacity: 0.54;">
|
||||
<td>
|
||||
<div class="table__cell-content table__cell-content--vertical-center" style="opacity: 0.54;">
|
||||
<i class="material-icons">album</i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="table__cell--center">
|
||||
{{ track.number }}
|
||||
</td>
|
||||
<td colspan="4"></td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<tr v-for="(track, i) in body">
|
||||
<td>
|
||||
<i
|
||||
v-if="track.preview_url"
|
||||
@click="playPausePreview"
|
||||
:class="'material-icons' + (track.preview_url ? ' preview_playlist_controls' : '')"
|
||||
:data-preview="track.preview_url"
|
||||
>play_arrow</i
|
||||
>
|
||||
<i v-else class="material-icons disabled">play_arrow</i>
|
||||
</td>
|
||||
<td>{{ i + 1 }}</td>
|
||||
<td class="inline-flex">
|
||||
<i v-if="track.explicit" class="material-icons explicit_icon">explicit</i>
|
||||
{{ track.name }}
|
||||
</td>
|
||||
<td>{{ track.artists[0].name }}</td>
|
||||
<td>{{ track.album.name }}</td>
|
||||
<td>{{ convertDuration(Math.floor(track.duration_ms / 1000)) }}</td>
|
||||
<td><input class="clickable" type="checkbox" v-model="track.selected" /></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<span v-if="label" style="opacity: 0.40;margin-top: 8px;display: inline-block;font-size: 13px;">{{ label }}</span>
|
||||
<footer>
|
||||
<button @contextmenu.prevent="openQualityModal" @click.stop="addToQueue" :data-link="link">
|
||||
Download {{ type }}
|
||||
</button>
|
||||
<button
|
||||
class="with_icon"
|
||||
@contextmenu.prevent="openQualityModal"
|
||||
@click.stop="addToQueue"
|
||||
:data-link="selectedLinks()"
|
||||
>
|
||||
Download selection<i class="material-icons">file_download</i>
|
||||
</button>
|
||||
<button class="back-button">Back</button>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
import EventBus from '@/js/EventBus'
|
||||
|
||||
export default {
|
||||
name: 'tracklist-tab',
|
||||
data: () => ({
|
||||
title: '',
|
||||
metadata: '',
|
||||
release_date: '',
|
||||
label: '',
|
||||
explicit: false,
|
||||
image: '',
|
||||
type: '',
|
||||
link: '',
|
||||
body: []
|
||||
}),
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playPausePreview: TrackPreview.playPausePreview,
|
||||
reset() {
|
||||
console.log('tracklist tab reset')
|
||||
this.title = 'Loading...'
|
||||
this.image = ''
|
||||
this.metadata = ''
|
||||
this.label = ''
|
||||
this.release_date = ''
|
||||
this.explicit = false
|
||||
this.type = ''
|
||||
this.body = []
|
||||
},
|
||||
addToQueue(e) {
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
toggleAll(e) {
|
||||
this.body.forEach(item => {
|
||||
if (item.type == 'track') {
|
||||
item.selected = e.currentTarget.checked
|
||||
}
|
||||
})
|
||||
},
|
||||
selectedLinks() {
|
||||
var selected = []
|
||||
if (this.body) {
|
||||
this.body.forEach(item => {
|
||||
if (item.type == 'track' && item.selected)
|
||||
selected.push(this.type == 'Spotify Playlist' ? item.uri : item.link)
|
||||
})
|
||||
}
|
||||
return selected.join(';')
|
||||
},
|
||||
convertDuration: Utils.convertDuration,
|
||||
showAlbum(data) {
|
||||
const {
|
||||
id: albumID,
|
||||
title: albumTitle,
|
||||
explicit_lyrics,
|
||||
label: albumLabel,
|
||||
artist: { name: artistName },
|
||||
tracks: albumTracks,
|
||||
tracks: { length: numberOfTracks },
|
||||
release_date,
|
||||
cover_xl
|
||||
} = data
|
||||
|
||||
this.type = 'Album'
|
||||
this.link = `https://www.deezer.com/album/${albumID}`
|
||||
this.title = albumTitle
|
||||
this.explicit = explicit_lyrics
|
||||
this.label = albumLabel
|
||||
this.metadata = `${artistName} • ${numberOfTracks} songs`
|
||||
this.release_date = release_date.substring(0, 10)
|
||||
this.image = cover_xl
|
||||
|
||||
if (isEmpty(albumTracks)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = albumTracks
|
||||
}
|
||||
},
|
||||
showPlaylist(data) {
|
||||
const {
|
||||
id: playlistID,
|
||||
title: playlistTitle,
|
||||
picture_xl: playlistCover,
|
||||
creation_date,
|
||||
creator: { name: creatorName },
|
||||
tracks: playlistTracks,
|
||||
tracks: { length: numberOfTracks }
|
||||
} = data
|
||||
|
||||
this.type = 'Playlist'
|
||||
this.link = `https://www.deezer.com/playlist/${playlistID}`
|
||||
this.title = playlistTitle
|
||||
this.image = playlistCover
|
||||
this.release_date = creation_date.substring(0, 10)
|
||||
this.metadata = `by ${creatorName} • ${numberOfTracks} songs`
|
||||
|
||||
if (isEmpty(playlistTracks)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = playlistTracks
|
||||
}
|
||||
},
|
||||
showSpotifyPlaylist(data) {
|
||||
const {
|
||||
uri: playlistURI,
|
||||
name: playlistName,
|
||||
images,
|
||||
images: { length: numberOfImages },
|
||||
owner: { display_name: ownerName },
|
||||
tracks: playlistTracks,
|
||||
tracks: { length: numberOfTracks }
|
||||
} = data
|
||||
|
||||
this.type = 'Spotify Playlist'
|
||||
this.link = playlistURI
|
||||
this.title = playlistName
|
||||
this.image = numberOfImages
|
||||
? images[0].url
|
||||
: 'https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/1000x1000-000000-80-0-0.jpg'
|
||||
this.release_date = ''
|
||||
this.metadata = `by ${ownerName} • ${numberOfTracks} songs`
|
||||
|
||||
if (isEmpty(playlistTracks)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = playlistTracks
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
EventBus.$on('tracklistTab:reset', this.reset)
|
||||
|
||||
socket.on('show_album', this.showAlbum)
|
||||
socket.on('show_playlist', this.showPlaylist)
|
||||
socket.on('show_spotifyplaylist', this.showSpotifyPlaylist)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
@ -1,97 +0,0 @@
|
||||
import { isEmpty, orderBy } from 'lodash-es'
|
||||
import Vue from 'vue'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
|
||||
const ArtistTab = new Vue({
|
||||
data() {
|
||||
return {
|
||||
currentTab: '',
|
||||
sortKey: 'release_date',
|
||||
sortOrder: 'desc',
|
||||
title: '',
|
||||
image: '',
|
||||
type: '',
|
||||
link: '',
|
||||
head: null,
|
||||
body: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
albumView: showView.bind(null, 'album'),
|
||||
reset() {
|
||||
this.title = 'Loading...'
|
||||
this.image = ''
|
||||
this.type = ''
|
||||
this.currentTab = ''
|
||||
this.sortKey = 'release_date'
|
||||
this.sortOrder = 'desc'
|
||||
this.link = ''
|
||||
this.head = []
|
||||
this.body = null
|
||||
},
|
||||
addToQueue(e) {
|
||||
e.stopPropagation()
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
sortBy(key) {
|
||||
if (key == this.sortKey) {
|
||||
this.sortOrder = this.sortOrder == 'asc' ? 'desc' : 'asc'
|
||||
} else {
|
||||
this.sortKey = key
|
||||
this.sortOrder = 'asc'
|
||||
}
|
||||
},
|
||||
changeTab(tab) {
|
||||
this.currentTab = tab
|
||||
},
|
||||
getCurrentTab() {
|
||||
return this.currentTab
|
||||
},
|
||||
checkNewRelease(date) {
|
||||
let g1 = new Date()
|
||||
let g2 = new Date(date)
|
||||
g2.setDate(g2.getDate() + 3)
|
||||
g1.setHours(0, 0, 0, 0)
|
||||
|
||||
return g1.getTime() <= g2.getTime()
|
||||
},
|
||||
showArtist(data) {
|
||||
const { name, picture_xl, id, releases } = data
|
||||
|
||||
this.title = name
|
||||
this.image = picture_xl
|
||||
this.type = 'Artist'
|
||||
this.link = `https://www.deezer.com/artist/${id}`
|
||||
if (this.currentTab === '') this.currentTab = Object.keys(releases)[0]
|
||||
this.sortKey = 'release_date'
|
||||
this.sortOrder = 'desc'
|
||||
this.head = [
|
||||
{ title: 'Title', sortKey: 'title' },
|
||||
{ title: 'Release Date', sortKey: 'release_date' },
|
||||
{ title: '', width: '32px' }
|
||||
]
|
||||
if (isEmpty(releases)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = releases
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showTable() {
|
||||
if (this.body) return orderBy(this.body[this.currentTab], this.sortKey, this.sortOrder)
|
||||
else return []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('show_artist', this.showArtist)
|
||||
}
|
||||
}).$mount('#artist_tab')
|
||||
|
||||
export default ArtistTab
|
@ -1,82 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
|
||||
const ChartsTab = new Vue({
|
||||
data() {
|
||||
return {
|
||||
country: '',
|
||||
id: 0,
|
||||
countries: [],
|
||||
chart: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playPausePreview: TrackPreview.playPausePreview,
|
||||
previewMouseEnter: TrackPreview.previewMouseEnter,
|
||||
previewMouseLeave: TrackPreview.previewMouseLeave,
|
||||
convertDuration: Utils.convertDuration,
|
||||
addToQueue(e) {
|
||||
e.stopPropagation()
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
getTrackList(event) {
|
||||
document.getElementById('content').scrollTo(0, 0)
|
||||
|
||||
const {
|
||||
currentTarget: {
|
||||
dataset: { title }
|
||||
},
|
||||
currentTarget: {
|
||||
dataset: { id }
|
||||
}
|
||||
} = event
|
||||
|
||||
this.country = title
|
||||
localStorage.setItem('chart', this.country)
|
||||
this.id = id
|
||||
socket.emit('getChartTracks', this.id)
|
||||
},
|
||||
setTracklist(data) {
|
||||
this.chart = data
|
||||
},
|
||||
changeCountry() {
|
||||
this.country = ''
|
||||
this.id = 0
|
||||
},
|
||||
initCharts(data) {
|
||||
this.countries = data
|
||||
this.country = localStorage.getItem('chart') || ''
|
||||
|
||||
if (!this.country) return
|
||||
|
||||
let i = 0
|
||||
for (; i < this.countries.length; i++) {
|
||||
if (this.countries[i].title == this.country) break
|
||||
}
|
||||
|
||||
if (i !== this.countries.length) {
|
||||
this.id = this.countries[i].id
|
||||
socket.emit('getChartTracks', this.id)
|
||||
} else {
|
||||
this.country = ''
|
||||
localStorage.setItem('chart', this.country)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('init_charts', this.initCharts)
|
||||
socket.on('setChartTracks', this.setTracklist)
|
||||
}
|
||||
}).$mount('#charts_tab')
|
||||
|
||||
export default ChartsTab
|
@ -1,20 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
const ErrorsTab = new Vue({
|
||||
data: () => ({
|
||||
title: '',
|
||||
errors: []
|
||||
}),
|
||||
methods: {
|
||||
reset(){
|
||||
this.title = ''
|
||||
this.errors = []
|
||||
},
|
||||
showErrors(data){
|
||||
this.title = data.artist+" - "+data.title
|
||||
this.errors = data.errors
|
||||
}
|
||||
}
|
||||
}).$mount('#errors_tab')
|
||||
|
||||
export default ErrorsTab
|
@ -1,91 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
import { toast } from '@/js/toasts'
|
||||
|
||||
const FavoritesTab = new Vue({
|
||||
data() {
|
||||
return {
|
||||
tracks: [],
|
||||
albums: [],
|
||||
artists: [],
|
||||
playlists: [],
|
||||
spotifyPlaylists: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playlistView: showView.bind(null, 'playlist'),
|
||||
spotifyPlaylistView: showView.bind(null, 'spotifyplaylist'),
|
||||
playPausePreview: TrackPreview.playPausePreview,
|
||||
previewMouseEnter: TrackPreview.previewMouseEnter,
|
||||
previewMouseLeave: TrackPreview.previewMouseLeave,
|
||||
convertDuration: Utils.convertDuration,
|
||||
addToQueue(e) {
|
||||
e.stopPropagation()
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
updated_userSpotifyPlaylists(data) {
|
||||
this.spotifyPlaylists = data
|
||||
},
|
||||
updated_userPlaylists(data) {
|
||||
this.playlists = data
|
||||
},
|
||||
updated_userAlbums(data) {
|
||||
this.albums = data
|
||||
},
|
||||
updated_userArtist(data) {
|
||||
this.artists = data
|
||||
},
|
||||
updated_userTracks(data) {
|
||||
this.tracks = data
|
||||
},
|
||||
reloadTabs() {
|
||||
this.$refs.reloadButton.classList.add('spin')
|
||||
socket.emit('update_userFavorites')
|
||||
if (localStorage.getItem('spotifyUser'))
|
||||
socket.emit('update_userSpotifyPlaylists', localStorage.getItem('spotifyUser'))
|
||||
},
|
||||
updated_userFavorites(data) {
|
||||
const { tracks, albums, artists, playlists } = data
|
||||
this.tracks = tracks
|
||||
this.albums = albums
|
||||
this.artists = artists
|
||||
this.playlists = playlists
|
||||
|
||||
// Removing animation class only when the animation has completed an iteration
|
||||
// Prevents animation ugly stutter
|
||||
this.$refs.reloadButton.addEventListener(
|
||||
'animationiteration',
|
||||
() => {
|
||||
this.$refs.reloadButton.classList.remove('spin')
|
||||
toast('Refresh completed!', 'done', true)
|
||||
},
|
||||
{ once: true }
|
||||
)
|
||||
},
|
||||
initFavorites(data) {
|
||||
this.updated_userFavorites(data)
|
||||
document.getElementById('favorites_playlist_tab').click()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('init_favorites', this.initFavorites)
|
||||
socket.on('updated_userFavorites', this.updated_userFavorites)
|
||||
socket.on('updated_userSpotifyPlaylists', this.updated_userSpotifyPlaylists)
|
||||
socket.on('updated_userPlaylists', this.updated_userPlaylists)
|
||||
socket.on('updated_userAlbums', this.updated_userAlbums)
|
||||
socket.on('updated_userArtist', this.updated_userArtist)
|
||||
socket.on('updated_userTracks', this.updated_userTracks)
|
||||
}
|
||||
}).$mount('#favorites_tab')
|
||||
|
||||
export default FavoritesTab
|
@ -1,46 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
|
||||
const HomeTab = new Vue({
|
||||
data() {
|
||||
return {
|
||||
playlists: [],
|
||||
albums: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playlistView: showView.bind(null, 'playlist'),
|
||||
openSettings() {
|
||||
document.getElementById('main_settings_tablink').click()
|
||||
},
|
||||
addToQueue(e) {
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
initHome(data) {
|
||||
const {
|
||||
playlists: { data: playlistData },
|
||||
albums: { data: albumData }
|
||||
} = data
|
||||
|
||||
this.playlists = playlistData
|
||||
this.albums = albumData
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (localStorage.getItem('arl')) {
|
||||
this.$refs.notLogged.classList.add('hide')
|
||||
}
|
||||
|
||||
socket.on('init_home', this.initHome)
|
||||
}
|
||||
}).$mount('#home_tab')
|
||||
|
||||
export default HomeTab
|
@ -1,79 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
|
||||
const LinkAnalyzerTab = new Vue({
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
subtitle: '',
|
||||
image: '',
|
||||
data: {},
|
||||
type: '',
|
||||
link: '',
|
||||
id: '0',
|
||||
countries: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
convertDuration: Utils.convertDuration,
|
||||
reset() {
|
||||
this.title = 'Loading...'
|
||||
this.subtitle = ''
|
||||
this.image = ''
|
||||
this.data = {}
|
||||
this.type = ''
|
||||
this.link = ''
|
||||
this.countries = []
|
||||
},
|
||||
showTrack(data) {
|
||||
const {
|
||||
title,
|
||||
title_version,
|
||||
album: { cover_xl },
|
||||
link,
|
||||
available_countries,
|
||||
id
|
||||
} = data
|
||||
|
||||
this.title = title + (title_version && title.indexOf(title_version) == -1 ? ' ' + title_version : '')
|
||||
this.image = cover_xl
|
||||
this.type = 'track'
|
||||
this.link = link
|
||||
this.id = id
|
||||
|
||||
available_countries.forEach(cc => {
|
||||
let temp = []
|
||||
let chars = [...cc].map(c => c.charCodeAt() + 127397)
|
||||
temp.push(String.fromCodePoint(...chars))
|
||||
temp.push(Utils.COUNTRIES[cc])
|
||||
this.countries.push(temp)
|
||||
})
|
||||
|
||||
this.data = data
|
||||
},
|
||||
showAlbum(data) {
|
||||
const { title, cover_xl, link, id } = data
|
||||
|
||||
this.title = title
|
||||
this.image = cover_xl
|
||||
this.type = 'album'
|
||||
this.link = link
|
||||
this.data = data
|
||||
this.id = id
|
||||
},
|
||||
notSupported() {
|
||||
this.link = 'error'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('analyze_track', this.showTrack)
|
||||
socket.on('analyze_album', this.showAlbum)
|
||||
socket.on('analyze_notSupported', this.notSupported)
|
||||
}
|
||||
}).$mount('#analyzer_tab')
|
||||
|
||||
export default LinkAnalyzerTab
|
@ -5,8 +5,12 @@ import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
||||
|
||||
const MainSearch = new Vue({
|
||||
components: {
|
||||
BaseLoadingPlaceholder
|
||||
},
|
||||
data: {
|
||||
names: {
|
||||
TOP_RESULT: 'Top Result',
|
||||
|
@ -1,142 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import { toast } from '@/js/toasts.js'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import TestComponent from '@components/TestComponent.vue'
|
||||
|
||||
const SettingsTab = new Vue({
|
||||
components: {
|
||||
TestComponent
|
||||
},
|
||||
data: () => ({
|
||||
settings: { tags: {} },
|
||||
lastSettings: {},
|
||||
spotifyFeatures: {},
|
||||
lastCredentials: {},
|
||||
defaultSettings: {},
|
||||
lastUser: '',
|
||||
spotifyUser: '',
|
||||
slimDownloads: false,
|
||||
previewVolume: window.vol,
|
||||
accountNum: 0,
|
||||
accounts: []
|
||||
}),
|
||||
computed: {
|
||||
changeSlimDownloads: {
|
||||
get() {
|
||||
return this.slimDownloads
|
||||
},
|
||||
set(wantSlimDownloads) {
|
||||
this.slimDownloads = wantSlimDownloads
|
||||
document.getElementById('download_list').classList.toggle('slim', wantSlimDownloads)
|
||||
localStorage.setItem('slimDownloads', wantSlimDownloads)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
copyARLtoClipboard() {
|
||||
let copyText = this.$refs.loginInput
|
||||
|
||||
copyText.setAttribute('type', 'text')
|
||||
copyText.select()
|
||||
copyText.setSelectionRange(0, 99999)
|
||||
document.execCommand('copy')
|
||||
copyText.setAttribute('type', 'password')
|
||||
|
||||
toast('ARL copied to clipboard', 'assignment')
|
||||
},
|
||||
updateMaxVolume() {
|
||||
localStorage.setItem('previewVolume', this.previewVolume.preview_max_volume)
|
||||
},
|
||||
saveSettings() {
|
||||
this.lastSettings = { ...this.settings }
|
||||
this.lastCredentials = { ...this.spotifyFeatures }
|
||||
let changed = false
|
||||
if (this.lastUser != this.spotifyUser) {
|
||||
// force cloning without linking
|
||||
this.lastUser = (' ' + this.spotifyUser).slice(1)
|
||||
localStorage.setItem('spotifyUser', this.lastUser)
|
||||
changed = true
|
||||
}
|
||||
|
||||
socket.emit('saveSettings', this.lastSettings, this.lastCredentials, changed ? this.lastUser : false)
|
||||
},
|
||||
loadSettings(settings, spotifyCredentials, defaults = null) {
|
||||
if (defaults) {
|
||||
this.defaultSettings = { ...defaults }
|
||||
}
|
||||
|
||||
this.lastSettings = { ...settings }
|
||||
this.lastCredentials = { ...spotifyCredentials }
|
||||
this.settings = settings
|
||||
this.spotifyFeatures = spotifyCredentials
|
||||
},
|
||||
login() {
|
||||
let arl = this.$refs.loginInput.value.trim()
|
||||
if (arl != '' && arl != localStorage.getItem('arl')) {
|
||||
socket.emit('login', arl, true, this.accountNum)
|
||||
}
|
||||
},
|
||||
changeAccount() {
|
||||
socket.emit('changeAccount', this.accountNum)
|
||||
},
|
||||
accountChanged(user, accountNum) {
|
||||
this.$refs.username.innerText = user.name
|
||||
this.$refs.userpicture.src = `https://e-cdns-images.dzcdn.net/images/user/${
|
||||
user.picture
|
||||
}/125x125-000000-80-0-0.jpg`
|
||||
this.accountNum = accountNum
|
||||
localStorage.setItem('accountNum', this.accountNum)
|
||||
},
|
||||
initAccounts(accounts) {
|
||||
this.accounts = accounts
|
||||
},
|
||||
logout() {
|
||||
socket.emit('logout')
|
||||
},
|
||||
initSettings(settings, credentials, defaults) {
|
||||
this.loadSettings(settings, credentials, defaults)
|
||||
toast('Settings loaded!', 'settings')
|
||||
},
|
||||
updateSettings(settings, credentials) {
|
||||
this.loadSettings(settings, credentials)
|
||||
toast('Settings updated!', 'settings')
|
||||
},
|
||||
resetSettings() {
|
||||
this.settings = { ...this.defaultSettings }
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.loggedInInfo.classList.add('hide')
|
||||
|
||||
if (localStorage.getItem('arl')) {
|
||||
this.$refs.loginInput.value = localStorage.getItem('arl').trim()
|
||||
}
|
||||
if (localStorage.getItem('accountNum')) {
|
||||
this.accountNum = localStorage.getItem('accountNum')
|
||||
}
|
||||
|
||||
let spotifyUser = localStorage.getItem('spotifyUser')
|
||||
|
||||
if (spotifyUser) {
|
||||
this.lastUser = spotifyUser
|
||||
this.spotifyUser = spotifyUser
|
||||
socket.emit('update_userSpotifyPlaylists', spotifyUser)
|
||||
}
|
||||
|
||||
this.changeSlimDownloads = 'true' === localStorage.getItem('slimDownloads')
|
||||
|
||||
let volume = parseInt(localStorage.getItem('previewVolume'))
|
||||
if (isNaN(volume)) {
|
||||
volume = 80
|
||||
localStorage.setItem('previewVolume', volume)
|
||||
}
|
||||
window.vol.preview_max_volume = volume
|
||||
|
||||
socket.on('init_settings', this.initSettings)
|
||||
socket.on('updateSettings', this.updateSettings)
|
||||
socket.on('accountChanged', this.accountChanged)
|
||||
socket.on('familyAccounts', this.initAccounts)
|
||||
}
|
||||
}).$mount('#settings_tab')
|
||||
|
||||
export default SettingsTab
|
@ -1,146 +0,0 @@
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import Vue from 'vue'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import { showView } from '@/js/tabs.js'
|
||||
import Downloads from '@/js/downloads.js'
|
||||
import QualityModal from '@/js/quality-modal.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import Utils from '@/js/utils.js'
|
||||
|
||||
const TracklistTab = new Vue({
|
||||
data: () => ({
|
||||
title: '',
|
||||
metadata: '',
|
||||
release_date: '',
|
||||
label: '',
|
||||
explicit: false,
|
||||
image: '',
|
||||
type: '',
|
||||
link: '',
|
||||
body: []
|
||||
}),
|
||||
methods: {
|
||||
artistView: showView.bind(null, 'artist'),
|
||||
albumView: showView.bind(null, 'album'),
|
||||
playPausePreview: TrackPreview.playPausePreview,
|
||||
reset() {
|
||||
this.title = 'Loading...'
|
||||
this.image = ''
|
||||
this.metadata = ''
|
||||
this.label = ''
|
||||
this.release_date = ''
|
||||
this.explicit = false
|
||||
this.type = ''
|
||||
this.body = []
|
||||
},
|
||||
addToQueue(e) {
|
||||
Downloads.sendAddToQueue(e.currentTarget.dataset.link)
|
||||
},
|
||||
openQualityModal(e) {
|
||||
QualityModal.open(e.currentTarget.dataset.link)
|
||||
},
|
||||
toggleAll(e) {
|
||||
this.body.forEach(item => {
|
||||
if (item.type == 'track') {
|
||||
item.selected = e.currentTarget.checked
|
||||
}
|
||||
})
|
||||
},
|
||||
selectedLinks() {
|
||||
var selected = []
|
||||
if (this.body) {
|
||||
this.body.forEach(item => {
|
||||
if (item.type == 'track' && item.selected)
|
||||
selected.push(this.type == 'Spotify Playlist' ? item.uri : item.link)
|
||||
})
|
||||
}
|
||||
return selected.join(';')
|
||||
},
|
||||
convertDuration: Utils.convertDuration,
|
||||
showAlbum(data) {
|
||||
const {
|
||||
id: albumID,
|
||||
title: albumTitle,
|
||||
explicit_lyrics,
|
||||
label: albumLabel,
|
||||
artist: { name: artistName },
|
||||
tracks: albumTracks,
|
||||
tracks: { length: numberOfTracks },
|
||||
release_date,
|
||||
cover_xl
|
||||
} = data
|
||||
|
||||
this.type = 'Album'
|
||||
this.link = `https://www.deezer.com/album/${albumID}`
|
||||
this.title = albumTitle
|
||||
this.explicit = explicit_lyrics
|
||||
this.label = albumLabel
|
||||
this.metadata = `${artistName} • ${numberOfTracks} songs`
|
||||
this.release_date = release_date.substring(0, 10)
|
||||
this.image = cover_xl
|
||||
|
||||
if (isEmpty(albumTracks)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = albumTracks
|
||||
}
|
||||
},
|
||||
showPlaylist(data) {
|
||||
const {
|
||||
id: playlistID,
|
||||
title: playlistTitle,
|
||||
picture_xl: playlistCover,
|
||||
creation_date,
|
||||
creator: { name: creatorName },
|
||||
tracks: playlistTracks,
|
||||
tracks: { length: numberOfTracks }
|
||||
} = data
|
||||
|
||||
this.type = 'Playlist'
|
||||
this.link = `https://www.deezer.com/playlist/${playlistID}`
|
||||
this.title = playlistTitle
|
||||
this.image = playlistCover
|
||||
this.release_date = creation_date.substring(0, 10)
|
||||
this.metadata = `by ${creatorName} • ${numberOfTracks} songs`
|
||||
|
||||
if (isEmpty(playlistTracks)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = playlistTracks
|
||||
}
|
||||
},
|
||||
showSpotifyPlaylist(data) {
|
||||
const {
|
||||
uri: playlistURI,
|
||||
name: playlistName,
|
||||
images,
|
||||
images: { length: numberOfImages },
|
||||
owner: { display_name: ownerName },
|
||||
tracks: playlistTracks,
|
||||
tracks: { length: numberOfTracks }
|
||||
} = data
|
||||
|
||||
this.type = 'Spotify Playlist'
|
||||
this.link = playlistURI
|
||||
this.title = playlistName
|
||||
this.image = numberOfImages
|
||||
? images[0].url
|
||||
: 'https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/1000x1000-000000-80-0-0.jpg'
|
||||
this.release_date = ''
|
||||
this.metadata = `by ${ownerName} • ${numberOfTracks} songs`
|
||||
|
||||
if (isEmpty(playlistTracks)) {
|
||||
this.body = null
|
||||
} else {
|
||||
this.body = playlistTracks
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
socket.on('show_album', this.showAlbum)
|
||||
socket.on('show_playlist', this.showPlaylist)
|
||||
socket.on('show_spotifyplaylist', this.showSpotifyPlaylist)
|
||||
}
|
||||
}).$mount('#tracklist_tab')
|
||||
|
||||
export default TracklistTab
|
@ -1,11 +1,7 @@
|
||||
import ArtistTab from '@components/artist-tab.js'
|
||||
import TracklistTab from '@components/tracklist-tab.js'
|
||||
import LinkAnalyzerTab from '@components/link-analyzer-tab.js'
|
||||
import ErrorsTab from '@components/errors-tab.js'
|
||||
import SettingsTab from '@components/settings-tab.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import MainSearch from '@components/main-search.js'
|
||||
import { socket } from '@/js/socket.js'
|
||||
import TrackPreview from '@/js/track-preview.js'
|
||||
import EventBus from '@/js/EventBus'
|
||||
|
||||
/* ===== Globals ====== */
|
||||
window.search_selected = ''
|
||||
@ -27,12 +23,12 @@ export function showView(viewType, event) {
|
||||
|
||||
switch (viewType) {
|
||||
case 'artist':
|
||||
ArtistTab.reset()
|
||||
EventBus.$emit('artistTab:reset')
|
||||
break
|
||||
case 'album':
|
||||
case 'playlist':
|
||||
case 'spotifyplaylist':
|
||||
TracklistTab.reset()
|
||||
EventBus.$emit('tracklistTab:reset')
|
||||
break
|
||||
|
||||
default:
|
||||
@ -44,12 +40,18 @@ export function showView(viewType, event) {
|
||||
}
|
||||
|
||||
export function showErrors(event) {
|
||||
ErrorsTab.showErrors(event.data.item)
|
||||
EventBus.$emit('showErrors', event.data.item)
|
||||
changeTab(event.target, 'main', 'errors_tab')
|
||||
}
|
||||
|
||||
export function updateSelected(newSelected) {
|
||||
currentStack.selected = newSelected
|
||||
}
|
||||
|
||||
window.test = showErrors
|
||||
|
||||
function analyzeLink(link) {
|
||||
LinkAnalyzerTab.reset()
|
||||
EventBus.$emit('linkAnalyzerTab:reset')
|
||||
socket.emit('analyzeLink', link)
|
||||
}
|
||||
|
||||
@ -211,9 +213,8 @@ function changeTab(sidebarEl, section, tabName) {
|
||||
}
|
||||
|
||||
if (tabName == 'settings_tab' && main_selected != 'settings_tab') {
|
||||
SettingsTab.settings = { ...SettingsTab.lastSettings }
|
||||
SettingsTab.spotifyCredentials = { ...SettingsTab.lastCredentials }
|
||||
SettingsTab.spotifyUser = (' ' + SettingsTab.lastUser).slice(1)
|
||||
EventBus.$emit('settingsTab:revertSettings')
|
||||
EventBus.$emit('settingsTab:revertCredentials')
|
||||
}
|
||||
|
||||
document.getElementById(tabName).style.display = 'block'
|
||||
@ -243,7 +244,7 @@ function showTab(type, id, back = false) {
|
||||
windows_stack.push({ tab: main_selected })
|
||||
} else if (!back) {
|
||||
if (currentStack.type === 'artist') {
|
||||
currentStack.selected = ArtistTab.getCurrentTab()
|
||||
EventBus.$emit('artistTab:updateSelected')
|
||||
}
|
||||
|
||||
windows_stack.push(currentStack)
|
||||
@ -271,11 +272,15 @@ function backTab() {
|
||||
let { type, id } = data
|
||||
|
||||
if (type === 'artist') {
|
||||
ArtistTab.reset()
|
||||
if (data.selected) ArtistTab.changeTab(data.selected)
|
||||
} else {
|
||||
TracklistTab.reset()
|
||||
EventBus.$emit('artistTab:reset')
|
||||
|
||||
if (data.selected) {
|
||||
EventBus.$emit('artistTab:changeTab', data.selected)
|
||||
}
|
||||
} else {
|
||||
EventBus.$emit('tracklistTab:reset')
|
||||
}
|
||||
|
||||
socket.emit('getTracklist', { type, id })
|
||||
showTab(type, id, true)
|
||||
}
|
||||
|
@ -15,14 +15,14 @@ function init() {
|
||||
preview_track.volume = 1
|
||||
|
||||
// start playing when track loaded
|
||||
preview_track.addEventListener('canplay', function () {
|
||||
preview_track.addEventListener('canplay', function() {
|
||||
preview_track.play()
|
||||
preview_stopped = false
|
||||
$(preview_track).animate({ volume: vol.preview_max_volume / 100 }, 500)
|
||||
})
|
||||
|
||||
// auto fadeout when at the end of the song
|
||||
preview_track.addEventListener('timeupdate', function () {
|
||||
preview_track.addEventListener('timeupdate', function() {
|
||||
if (preview_track.currentTime > preview_track.duration - 1) {
|
||||
$(preview_track).animate({ volume: 0 }, 800)
|
||||
preview_stopped = true
|
||||
@ -37,7 +37,7 @@ function init() {
|
||||
// on modal closing
|
||||
function stopStackedTabsPreview() {
|
||||
if (
|
||||
$('.preview_playlist_controls').filter(function () {
|
||||
$('.preview_playlist_controls').filter(function() {
|
||||
return $(this).attr('playing')
|
||||
}).length > 0
|
||||
) {
|
||||
@ -56,7 +56,15 @@ function previewMouseEnter(e) {
|
||||
function previewMouseLeave(event) {
|
||||
const { currentTarget: obj } = event
|
||||
|
||||
if (($(obj).parent().attr('playing') && preview_stopped) || !$(obj).parent().attr('playing')) {
|
||||
if (
|
||||
($(obj)
|
||||
.parent()
|
||||
.attr('playing') &&
|
||||
preview_stopped) ||
|
||||
!$(obj)
|
||||
.parent()
|
||||
.attr('playing')
|
||||
) {
|
||||
$(obj).css({ opacity: 0 }, 200)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user