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?
|
## What's left to do?
|
||||||
|
|
||||||
|
- Use Vue as much as possible
|
||||||
|
- First step: Single File Components
|
||||||
- Completely remove jQuery dependency
|
- Completely remove jQuery dependency
|
||||||
- Make the UI look coherent
|
- Make the UI look coherent
|
||||||
- Style buttons
|
- 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 Vue from 'vue'
|
||||||
import '@components/LoadingPlaceholder.js'
|
|
||||||
|
|
||||||
// Vue views components
|
// Vue views components
|
||||||
import '@components/artist-tab.js'
|
import TheSidebar from '@components/TheSidebar.vue'
|
||||||
import '@components/charts-tab.js'
|
import ArtistTab from '@components/ArtistTab.vue'
|
||||||
import '@components/errors-tab.js'
|
import TheChartsTab from '@components/TheChartsTab.vue'
|
||||||
import '@components/favorites-tab.js'
|
import TheFavoritesTab from '@components/TheFavoritesTab.vue'
|
||||||
import '@components/home-tab.js'
|
import TheErrorsTab from '@components/TheErrorsTab.vue'
|
||||||
import '@components/link-analyzer-tab.js'
|
import TheHomeTab from '@components/TheHomeTab.vue'
|
||||||
import '@components/main-search.js'
|
import TheLinkAnalyzerTab from '@components/TheLinkAnalyzerTab.vue'
|
||||||
import '@components/settings-tab.js'
|
import TheAboutTab from '@components/TheAboutTab.vue'
|
||||||
import '@components/tracklist-tab.js'
|
|
||||||
|
|
||||||
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 $ from 'jquery'
|
||||||
import { socket } from '@/js/socket.js'
|
import { socket } from '@/js/socket.js'
|
||||||
@ -21,11 +24,11 @@ import Downloads from '@/js/downloads.js'
|
|||||||
import QualityModal from '@/js/quality-modal.js'
|
import QualityModal from '@/js/quality-modal.js'
|
||||||
import Tabs from '@/js/tabs.js'
|
import Tabs from '@/js/tabs.js'
|
||||||
import Search from '@/js/search.js'
|
import Search from '@/js/search.js'
|
||||||
import TrackPreview from '@/js/track-preview.js'
|
|
||||||
|
|
||||||
/* ===== App initialization ===== */
|
/* ===== App initialization ===== */
|
||||||
|
|
||||||
function startApp() {
|
function startApp() {
|
||||||
|
mountComponents()
|
||||||
setCurrentUserTheme()
|
setCurrentUserTheme()
|
||||||
|
|
||||||
Downloads.init()
|
Downloads.init()
|
||||||
@ -35,6 +38,23 @@ function startApp() {
|
|||||||
TrackPreview.init()
|
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() {
|
function initClient() {
|
||||||
window.clientMode = true
|
window.clientMode = true
|
||||||
document.querySelector(`#open_downloads_folder`).classList.remove('hide')
|
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 QualityModal from '@/js/quality-modal.js'
|
||||||
import TrackPreview from '@/js/track-preview.js'
|
import TrackPreview from '@/js/track-preview.js'
|
||||||
import Utils from '@/js/utils.js'
|
import Utils from '@/js/utils.js'
|
||||||
|
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
||||||
|
|
||||||
const MainSearch = new Vue({
|
const MainSearch = new Vue({
|
||||||
|
components: {
|
||||||
|
BaseLoadingPlaceholder
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
names: {
|
names: {
|
||||||
TOP_RESULT: 'Top Result',
|
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 TrackPreview from '@/js/track-preview.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 MainSearch from '@components/main-search.js'
|
import MainSearch from '@components/main-search.js'
|
||||||
import { socket } from '@/js/socket.js'
|
import { socket } from '@/js/socket.js'
|
||||||
import TrackPreview from '@/js/track-preview.js'
|
import EventBus from '@/js/EventBus'
|
||||||
|
|
||||||
/* ===== Globals ====== */
|
/* ===== Globals ====== */
|
||||||
window.search_selected = ''
|
window.search_selected = ''
|
||||||
@ -27,12 +23,12 @@ export function showView(viewType, event) {
|
|||||||
|
|
||||||
switch (viewType) {
|
switch (viewType) {
|
||||||
case 'artist':
|
case 'artist':
|
||||||
ArtistTab.reset()
|
EventBus.$emit('artistTab:reset')
|
||||||
break
|
break
|
||||||
case 'album':
|
case 'album':
|
||||||
case 'playlist':
|
case 'playlist':
|
||||||
case 'spotifyplaylist':
|
case 'spotifyplaylist':
|
||||||
TracklistTab.reset()
|
EventBus.$emit('tracklistTab:reset')
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -44,12 +40,18 @@ export function showView(viewType, event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function showErrors(event) {
|
export function showErrors(event) {
|
||||||
ErrorsTab.showErrors(event.data.item)
|
EventBus.$emit('showErrors', event.data.item)
|
||||||
changeTab(event.target, 'main', 'errors_tab')
|
changeTab(event.target, 'main', 'errors_tab')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateSelected(newSelected) {
|
||||||
|
currentStack.selected = newSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
window.test = showErrors
|
||||||
|
|
||||||
function analyzeLink(link) {
|
function analyzeLink(link) {
|
||||||
LinkAnalyzerTab.reset()
|
EventBus.$emit('linkAnalyzerTab:reset')
|
||||||
socket.emit('analyzeLink', link)
|
socket.emit('analyzeLink', link)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,9 +213,8 @@ function changeTab(sidebarEl, section, tabName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tabName == 'settings_tab' && main_selected != 'settings_tab') {
|
if (tabName == 'settings_tab' && main_selected != 'settings_tab') {
|
||||||
SettingsTab.settings = { ...SettingsTab.lastSettings }
|
EventBus.$emit('settingsTab:revertSettings')
|
||||||
SettingsTab.spotifyCredentials = { ...SettingsTab.lastCredentials }
|
EventBus.$emit('settingsTab:revertCredentials')
|
||||||
SettingsTab.spotifyUser = (' ' + SettingsTab.lastUser).slice(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById(tabName).style.display = 'block'
|
document.getElementById(tabName).style.display = 'block'
|
||||||
@ -243,7 +244,7 @@ function showTab(type, id, back = false) {
|
|||||||
windows_stack.push({ tab: main_selected })
|
windows_stack.push({ tab: main_selected })
|
||||||
} else if (!back) {
|
} else if (!back) {
|
||||||
if (currentStack.type === 'artist') {
|
if (currentStack.type === 'artist') {
|
||||||
currentStack.selected = ArtistTab.getCurrentTab()
|
EventBus.$emit('artistTab:updateSelected')
|
||||||
}
|
}
|
||||||
|
|
||||||
windows_stack.push(currentStack)
|
windows_stack.push(currentStack)
|
||||||
@ -271,11 +272,15 @@ function backTab() {
|
|||||||
let { type, id } = data
|
let { type, id } = data
|
||||||
|
|
||||||
if (type === 'artist') {
|
if (type === 'artist') {
|
||||||
ArtistTab.reset()
|
EventBus.$emit('artistTab:reset')
|
||||||
if (data.selected) ArtistTab.changeTab(data.selected)
|
|
||||||
|
if (data.selected) {
|
||||||
|
EventBus.$emit('artistTab:changeTab', data.selected)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
TracklistTab.reset()
|
EventBus.$emit('tracklistTab:reset')
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('getTracklist', { type, id })
|
socket.emit('getTracklist', { type, id })
|
||||||
showTab(type, id, true)
|
showTab(type, id, true)
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,14 @@ function init() {
|
|||||||
preview_track.volume = 1
|
preview_track.volume = 1
|
||||||
|
|
||||||
// start playing when track loaded
|
// start playing when track loaded
|
||||||
preview_track.addEventListener('canplay', function () {
|
preview_track.addEventListener('canplay', function() {
|
||||||
preview_track.play()
|
preview_track.play()
|
||||||
preview_stopped = false
|
preview_stopped = false
|
||||||
$(preview_track).animate({ volume: vol.preview_max_volume / 100 }, 500)
|
$(preview_track).animate({ volume: vol.preview_max_volume / 100 }, 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
// auto fadeout when at the end of the song
|
// 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) {
|
if (preview_track.currentTime > preview_track.duration - 1) {
|
||||||
$(preview_track).animate({ volume: 0 }, 800)
|
$(preview_track).animate({ volume: 0 }, 800)
|
||||||
preview_stopped = true
|
preview_stopped = true
|
||||||
@ -37,7 +37,7 @@ function init() {
|
|||||||
// on modal closing
|
// on modal closing
|
||||||
function stopStackedTabsPreview() {
|
function stopStackedTabsPreview() {
|
||||||
if (
|
if (
|
||||||
$('.preview_playlist_controls').filter(function () {
|
$('.preview_playlist_controls').filter(function() {
|
||||||
return $(this).attr('playing')
|
return $(this).attr('playing')
|
||||||
}).length > 0
|
}).length > 0
|
||||||
) {
|
) {
|
||||||
@ -56,7 +56,15 @@ function previewMouseEnter(e) {
|
|||||||
function previewMouseLeave(event) {
|
function previewMouseLeave(event) {
|
||||||
const { currentTarget: obj } = 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)
|
$(obj).css({ opacity: 0 }, 200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user