Merge pull request 'update' (#2) from RemixDev/deemix-webui:main into main
Reviewed-on: https://codeberg.org/wolfwork/deemix-webui/pulls/2
This commit is contained in:
commit
bf9706c2c1
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"css": {
|
|
||||||
"allowed_file_extensions": [
|
|
||||||
"css",
|
|
||||||
"scss",
|
|
||||||
"sass",
|
|
||||||
"less"
|
|
||||||
],
|
|
||||||
"end_with_newline": true,
|
|
||||||
"indent_char": " ",
|
|
||||||
"indent_size": 2,
|
|
||||||
"indent_with_tabs": true,
|
|
||||||
"newline_between_rules": true,
|
|
||||||
"selector_separator": " ",
|
|
||||||
"selector_separator_newline": false,
|
|
||||||
"preserve_newlines": true,
|
|
||||||
"max_preserve_newlines": 3
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,15 @@ You can find more informations about deemix at https://deemix.app/
|
|||||||
- [deemix-pyweb](https://codeberg.org/RemixDev/deemix-pyweb)
|
- [deemix-pyweb](https://codeberg.org/RemixDev/deemix-pyweb)
|
||||||
- [deemix-tools](https://codeberg.org/RemixDev/deemix-tools)
|
- [deemix-tools](https://codeberg.org/RemixDev/deemix-tools)
|
||||||
|
|
||||||
|
# "Hidden" features
|
||||||
|
|
||||||
|
- `CTRL+SHIFT+Backspace` deletes all the search bar content
|
||||||
|
- `CTRL+F` focuses the search bar
|
||||||
|
- `CTRL+B` toggles the download bar
|
||||||
|
- `ALT+Left` goes back to the previous page, if present (like would happen in the browser)
|
||||||
|
- `ALT+Right` goes forward to the next page, if present (like would happen in the browser)
|
||||||
|
- Custom context menu: on certain elements, like download buttons or album covers, when opening the context menu, a custom one with more options will appear instead of the default one
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -796,6 +796,11 @@
|
|||||||
"pinkie-promise": "^2.0.0"
|
"pinkie-promise": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flag-icon-css": {
|
||||||
|
"version": "3.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/flag-icon-css/-/flag-icon-css-3.5.0.tgz",
|
||||||
|
"integrity": "sha512-pgJnJLrtb0tcDgU1fzGaQXmR8h++nXvILJ+r5SmOXaaL/2pocunQo2a8TAXhjQnBpRLPtZ1KCz/TYpqeNuE2ew=="
|
||||||
|
},
|
||||||
"forever-agent": {
|
"forever-agent": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"build": "npm-run-all --sequential clean build:js build:styles"
|
"build": "npm-run-all --sequential clean build:js build:styles"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"flag-icon-css": "^3.5.0",
|
||||||
"lodash-es": "^4.17.15",
|
"lodash-es": "^4.17.15",
|
||||||
"svg-country-flags": "^1.2.7",
|
"svg-country-flags": "^1.2.7",
|
||||||
"toastify-js": "^1.8.0",
|
"toastify-js": "^1.8.0",
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -31,10 +31,6 @@ export default {
|
|||||||
find: '@',
|
find: '@',
|
||||||
replacement: __dirname + '/src'
|
replacement: __dirname + '/src'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
find: '@js',
|
|
||||||
replacement: __dirname + '/src/js'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
find: '@components',
|
find: '@components',
|
||||||
replacement: __dirname + '/src/components'
|
replacement: __dirname + '/src/components'
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<TheSearchBar />
|
<TheSearchBar />
|
||||||
<TheMiddleSection />
|
<TheContent />
|
||||||
</div>
|
</div>
|
||||||
<TheDownloadTab class="downlaods" />
|
<TheDownloadBar />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BaseLoadingPlaceholder id="start_app_placeholder" text="Connecting to the server..." />
|
<BaseLoadingPlaceholder id="start_app_placeholder" text="Connecting to the server..." />
|
||||||
@ -30,32 +30,30 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-left: 48px;
|
margin-left: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.downlaods {
|
|
||||||
flex-basis: 32px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import TheDownloadBar from '@components/downloads/TheDownloadBar.vue'
|
||||||
|
|
||||||
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
|
import TheContextMenu from '@components/globals/TheContextMenu.vue'
|
||||||
|
import TheTrackPreview from '@components/globals/TheTrackPreview.vue'
|
||||||
|
import TheQualityModal from '@components/globals/TheQualityModal.vue'
|
||||||
|
|
||||||
import TheSidebar from '@components/TheSidebar.vue'
|
import TheSidebar from '@components/TheSidebar.vue'
|
||||||
import TheMiddleSection from '@components/TheMiddleSection.vue'
|
|
||||||
import TheTrackPreview from '@components/TheTrackPreview.vue'
|
|
||||||
import TheQualityModal from '@components/TheQualityModal.vue'
|
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
|
||||||
import TheContextMenu from '@components/TheContextMenu.vue'
|
|
||||||
import TheDownloadTab from '@components/TheDownloadTab.vue'
|
|
||||||
import TheSearchBar from '@components/TheSearchBar.vue'
|
import TheSearchBar from '@components/TheSearchBar.vue'
|
||||||
|
import TheContent from '@components/TheContent.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
TheSidebar,
|
TheSidebar,
|
||||||
TheSearchBar,
|
TheSearchBar,
|
||||||
TheMiddleSection,
|
TheDownloadBar,
|
||||||
TheDownloadTab,
|
|
||||||
TheTrackPreview,
|
TheTrackPreview,
|
||||||
TheQualityModal,
|
TheQualityModal,
|
||||||
BaseLoadingPlaceholder,
|
BaseLoadingPlaceholder,
|
||||||
TheContextMenu
|
TheContextMenu,
|
||||||
|
TheContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
66
src/app.js
66
src/app.js
@ -5,27 +5,18 @@ window.vol = {
|
|||||||
preview_max_volume: 100
|
preview_max_volume: 100
|
||||||
}
|
}
|
||||||
|
|
||||||
import App from '@components/App.vue'
|
import App from '@/App.vue'
|
||||||
import i18n from '@/plugins/i18n'
|
import i18n from '@/plugins/i18n'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { toast } from '@/utils/toasts'
|
import { toast } from '@/utils/toasts'
|
||||||
import { init as initTabs } from '@js/tabs.js'
|
|
||||||
|
|
||||||
import { isValidURL } from '@/utils/utils'
|
import { isValidURL } from '@/utils/utils'
|
||||||
import Downloads from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import EventBus from '@/utils/EventBus.js'
|
|
||||||
|
|
||||||
/* ===== App initialization ===== */
|
/* ===== App initialization ===== */
|
||||||
|
|
||||||
function startApp() {
|
function startApp() {
|
||||||
mountApp()
|
|
||||||
initTabs()
|
|
||||||
}
|
|
||||||
|
|
||||||
function mountApp() {
|
|
||||||
new Vue({
|
new Vue({
|
||||||
store,
|
store,
|
||||||
router,
|
router,
|
||||||
@ -36,6 +27,7 @@ function mountApp() {
|
|||||||
|
|
||||||
function initClient() {
|
function initClient() {
|
||||||
store.dispatch('setClientMode', true)
|
store.dispatch('setClientMode', true)
|
||||||
|
setClientModeKeyBindings()
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', startApp)
|
document.addEventListener('DOMContentLoaded', startApp)
|
||||||
@ -44,24 +36,40 @@ window.addEventListener('pywebviewready', initClient)
|
|||||||
/* ===== Global shortcuts ===== */
|
/* ===== Global shortcuts ===== */
|
||||||
|
|
||||||
document.addEventListener('paste', pasteEvent => {
|
document.addEventListener('paste', pasteEvent => {
|
||||||
let pasteText = pasteEvent.clipboardData.getData('Text')
|
if (pasteEvent.target.localName === 'input') return
|
||||||
|
|
||||||
if (pasteEvent.target.localName != 'input') {
|
let pastedText = pasteEvent.clipboardData.getData('Text')
|
||||||
if (isValidURL(pasteText)) {
|
|
||||||
if (window.main_selected === 'analyzer_tab') {
|
if (isValidURL(pastedText)) {
|
||||||
EventBus.$emit('linkAnalyzerTab:reset')
|
if (router.currentRoute.name === 'Link Analyzer') {
|
||||||
socket.emit('analyzeLink', pasteText)
|
socket.emit('analyzeLink', pastedText)
|
||||||
} else {
|
|
||||||
Downloads.sendAddToQueue(pasteText)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let searchbar = document.querySelector('#searchbar')
|
sendAddToQueue(pastedText)
|
||||||
searchbar.select()
|
|
||||||
searchbar.setSelectionRange(0, 99999)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let searchbar = document.querySelector('#searchbar')
|
||||||
|
searchbar.select()
|
||||||
|
searchbar.setSelectionRange(0, 99999)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up key bindings that already work in the browser (server mode)
|
||||||
|
*/
|
||||||
|
function setClientModeKeyBindings() {
|
||||||
|
document.addEventListener('keyup', keyEvent => {
|
||||||
|
// ALT + left
|
||||||
|
if (keyEvent.altKey && keyEvent.key === 'ArrowLeft') {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALT + right
|
||||||
|
if (keyEvent.altKey && keyEvent.key === 'ArrowRight') {
|
||||||
|
router.forward()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Socketio listeners ===== */
|
/* ===== Socketio listeners ===== */
|
||||||
|
|
||||||
// Debug messages for socketio
|
// Debug messages for socketio
|
||||||
@ -113,11 +121,13 @@ socket.on('logged_in', function(data) {
|
|||||||
break
|
break
|
||||||
case -1:
|
case -1:
|
||||||
toast(i18n.t('toasts.deezerNotAvailable'), 'close', true, 'login-toast')
|
toast(i18n.t('toasts.deezerNotAvailable'), 'close', true, 'login-toast')
|
||||||
$('#open_login_prompt').show()
|
return
|
||||||
document.getElementById('logged_in_info').classList.add('hide')
|
// TODO
|
||||||
$('#settings_username').text('Not Logged')
|
// $('#open_login_prompt').show()
|
||||||
$('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`)
|
// document.getElementById('logged_in_info').classList.add('hide')
|
||||||
document.getElementById('home_not_logged_in').classList.remove('hide')
|
// $('#settings_username').text('Not Logged')
|
||||||
|
// $('#settings_picture').attr('src', `https://e-cdns-images.dzcdn.net/images/user/125x125-000000-80-0-0.jpg`)
|
||||||
|
// document.getElementById('home_not_logged_in').classList.remove('hide')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="content" @scroll="$route.name === 'Search' ? handleContentScroll($event) : null" ref="content">
|
<main
|
||||||
|
id="content"
|
||||||
|
@scroll="$route.name === 'Search' ? handleContentScroll($event) : null"
|
||||||
|
ref="content"
|
||||||
|
aria-label="main content"
|
||||||
|
>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<BaseLoadingPlaceholder id="search_placeholder" text="Searching..." :hidden="!loading" />
|
<BaseLoadingPlaceholder id="search_placeholder" text="Searching..." :hidden="!loading" />
|
||||||
|
|
||||||
@ -21,7 +26,7 @@
|
|||||||
exclude=""
|
exclude=""
|
||||||
></router-view>
|
></router-view>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -31,8 +36,9 @@
|
|||||||
width: var(--container-width);
|
width: var(--container-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
#content {
|
main {
|
||||||
background-color: var(--main-background);
|
background-color: var(--main-background);
|
||||||
|
padding-right: 5px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - 93px);
|
height: calc(100vh - 93px);
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@ -57,8 +63,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { debounce } from '@/utils/utils'
|
import { debounce } from '@/utils/utils'
|
||||||
import EventBus from '@/utils/EventBus.js'
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -72,6 +77,11 @@ export default {
|
|||||||
this.$root.$on('updateSearchLoadingState', loading => {
|
this.$root.$on('updateSearchLoadingState', loading => {
|
||||||
this.loading = loading
|
this.loading = loading
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.$router.beforeEach((to, from, next) => {
|
||||||
|
this.$refs.content.scrollTo(0, 0)
|
||||||
|
next()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleContentScroll: debounce(async function () {
|
handleContentScroll: debounce(async function () {
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
<template>
|
|
||||||
<main id="main_content">
|
|
||||||
<TheContent />
|
|
||||||
<!-- <BaseLoadingPlaceholder id="search_placeholder" text="Searching..." :hidden="true" /> -->
|
|
||||||
</main>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
#main_content {
|
|
||||||
background-color: var(--main-background);
|
|
||||||
min-width: 10px;
|
|
||||||
// margin-left: 48px; // $sidebar-width
|
|
||||||
// width: calc(100% - #{$sidebar-width});
|
|
||||||
// flex: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import TheContent from '@components/TheContent.vue'
|
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
TheContent,
|
|
||||||
BaseLoadingPlaceholder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<header id="search">
|
<header id="search" aria-label="searchbar">
|
||||||
<div class="search__icon">
|
<div class="search__icon">
|
||||||
<i class="material-icons">search</i>
|
<i class="material-icons">search</i>
|
||||||
</div>
|
</div>
|
||||||
@ -19,11 +19,66 @@
|
|||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$icon-dimension: 2rem;
|
||||||
|
$searchbar-height: 45px;
|
||||||
|
|
||||||
|
#search {
|
||||||
|
background-color: var(--secondary-background);
|
||||||
|
padding: 0 1em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: border 200ms ease-in-out;
|
||||||
|
border-radius: 15px;
|
||||||
|
margin: 10px 10px 20px 10px;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border: 1px solid var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search__icon {
|
||||||
|
width: $icon-dimension;
|
||||||
|
height: $icon-dimension;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: $icon-dimension;
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchbar {
|
||||||
|
height: $searchbar-height;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
border: 0px;
|
||||||
|
border-radius: 0px;
|
||||||
|
background-color: var(--secondary-background);
|
||||||
|
color: var(--foreground);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-weight: 300;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing Chrome autofill color
|
||||||
|
&:-webkit-autofill,
|
||||||
|
&:-webkit-autofill:hover,
|
||||||
|
&:-webkit-autofill:focus,
|
||||||
|
&:-webkit-autofill:active {
|
||||||
|
-webkit-box-shadow: 0 0 0 $searchbar-height var(--secondary-background) inset !important;
|
||||||
|
box-shadow: 0 0 0 $searchbar-height var(--secondary-background) inset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { isValidURL } from '@/utils/utils'
|
import { isValidURL } from '@/utils/utils'
|
||||||
import Downloads from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
|
import EventBus from '@/utils/EventBus'
|
||||||
import EventBus from '@/utils/EventBus.js'
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -32,12 +87,27 @@ export default {
|
|||||||
lastTextSearch: ''
|
lastTextSearch: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
created() {
|
||||||
document.addEventListener('keyup', keyEvent => {
|
const focusSearchBar = keyEvent => {
|
||||||
if (!(keyEvent.key == 'Backspace' && keyEvent.ctrlKey)) return
|
if (keyEvent.keyCode === 70 && keyEvent.ctrlKey) {
|
||||||
|
keyEvent.preventDefault()
|
||||||
|
this.$refs.searchbar.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteSearchBarContent = keyEvent => {
|
||||||
|
if (!(keyEvent.key == 'Backspace' && keyEvent.ctrlKey && keyEvent.shiftKey)) return
|
||||||
|
|
||||||
this.$refs.searchbar.value = ''
|
this.$refs.searchbar.value = ''
|
||||||
this.$refs.searchbar.focus()
|
this.$refs.searchbar.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', focusSearchBar)
|
||||||
|
document.addEventListener('keyup', deleteSearchBarContent)
|
||||||
|
|
||||||
|
this.$on('hook:destroyed', () => {
|
||||||
|
document.removeEventListener('keydown', focusSearchBar)
|
||||||
|
document.removeEventListener('keyup', deleteSearchBarContent)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -71,11 +141,14 @@ export default {
|
|||||||
socket.emit('analyzeLink', term)
|
socket.emit('analyzeLink', term)
|
||||||
} else {
|
} else {
|
||||||
// ? Open downloads tab ?
|
// ? Open downloads tab ?
|
||||||
Downloads.sendAddToQueue(term)
|
sendAddToQueue(term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isShowingSearch && sameAsLastSearch) return
|
if (isShowingSearch && sameAsLastSearch) {
|
||||||
|
this.$root.$emit('mainSearch:updateResults', term)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!isShowingSearch) {
|
if (!isShowingSearch) {
|
||||||
await this.$router.push({
|
await this.$router.push({
|
||||||
@ -88,12 +161,11 @@ export default {
|
|||||||
this.lastTextSearch = term
|
this.lastTextSearch = term
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$root.$emit('mainSearch:showNewResults', term, window.main_selected)
|
this.$root.$emit('mainSearch:showNewResults', term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<aside id="sidebar" role="navigation">
|
<aside id="sidebar" role="navigation" aria-label="sidebar">
|
||||||
<router-link
|
<router-link
|
||||||
v-for="link in links"
|
v-for="link in links"
|
||||||
:key="link.id"
|
:key="link.id"
|
||||||
tag="span"
|
tag="a"
|
||||||
class="main_tablinks"
|
class="main_tablinks"
|
||||||
role="link"
|
|
||||||
:id="link.id"
|
:id="link.id"
|
||||||
:class="{ active: activeTablink === link.name }"
|
:class="{ active: activeTablink === link.name }"
|
||||||
:aria-label="link.ariaLabel"
|
:aria-label="link.ariaLabel"
|
||||||
@ -13,7 +12,7 @@
|
|||||||
@click.native="activeTablink = link.name"
|
@click.native="activeTablink = link.name"
|
||||||
>
|
>
|
||||||
<i class="material-icons side_icon">{{ link.icon }}</i>
|
<i class="material-icons side_icon">{{ link.icon }}</i>
|
||||||
<span class="main_tablinks_text">{{ link.label }}</span>
|
<span class="main_tablinks_text">{{ $t(link.label) }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<span id="theme_selector" class="main_tablinks" role="link" aria-label="theme selector">
|
<span id="theme_selector" class="main_tablinks" role="link" aria-label="theme selector">
|
||||||
@ -67,9 +66,6 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
const $t = this.$t.bind(this)
|
|
||||||
const $tc = this.$tc.bind(this)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appOnline: null,
|
appOnline: null,
|
||||||
activeTheme: 'light',
|
activeTheme: 'light',
|
||||||
@ -82,7 +78,7 @@ export default {
|
|||||||
ariaLabel: 'home',
|
ariaLabel: 'home',
|
||||||
routerName: 'Home',
|
routerName: 'Home',
|
||||||
icon: 'home',
|
icon: 'home',
|
||||||
label: $t('sidebar.home')
|
label: 'sidebar.home'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'main_search_tablink',
|
id: 'main_search_tablink',
|
||||||
@ -90,7 +86,7 @@ export default {
|
|||||||
ariaLabel: 'search',
|
ariaLabel: 'search',
|
||||||
routerName: 'Search',
|
routerName: 'Search',
|
||||||
icon: 'search',
|
icon: 'search',
|
||||||
label: $t('sidebar.search')
|
label: 'sidebar.search'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'main_charts_tablink',
|
id: 'main_charts_tablink',
|
||||||
@ -98,7 +94,7 @@ export default {
|
|||||||
ariaLabel: 'charts',
|
ariaLabel: 'charts',
|
||||||
routerName: 'Charts',
|
routerName: 'Charts',
|
||||||
icon: 'show_chart',
|
icon: 'show_chart',
|
||||||
label: $t('sidebar.charts')
|
label: 'sidebar.charts'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'main_favorites_tablink',
|
id: 'main_favorites_tablink',
|
||||||
@ -106,7 +102,7 @@ export default {
|
|||||||
ariaLabel: 'favorites',
|
ariaLabel: 'favorites',
|
||||||
routerName: 'Favorites',
|
routerName: 'Favorites',
|
||||||
icon: 'star',
|
icon: 'star',
|
||||||
label: $t('sidebar.favorites')
|
label: 'sidebar.favorites'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'main_analyzer_tablink',
|
id: 'main_analyzer_tablink',
|
||||||
@ -114,7 +110,7 @@ export default {
|
|||||||
ariaLabel: 'link analyzer',
|
ariaLabel: 'link analyzer',
|
||||||
routerName: 'Link Analyzer',
|
routerName: 'Link Analyzer',
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
label: $t('sidebar.linkAnalyzer')
|
label: 'sidebar.linkAnalyzer'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'main_settings_tablink',
|
id: 'main_settings_tablink',
|
||||||
@ -122,7 +118,7 @@ export default {
|
|||||||
ariaLabel: 'settings',
|
ariaLabel: 'settings',
|
||||||
routerName: 'Settings',
|
routerName: 'Settings',
|
||||||
icon: 'settings',
|
icon: 'settings',
|
||||||
label: $t('sidebar.settings')
|
label: 'sidebar.settings'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'main_about_tablink',
|
id: 'main_about_tablink',
|
||||||
@ -130,7 +126,7 @@ export default {
|
|||||||
ariaLabel: 'info',
|
ariaLabel: 'info',
|
||||||
routerName: 'About',
|
routerName: 'About',
|
||||||
icon: 'info',
|
icon: 'info',
|
||||||
label: $t('sidebar.about')
|
label: 'sidebar.about'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
@transitionend="$refs.container.style.transition = ''"
|
@transitionend="$refs.container.style.transition = ''"
|
||||||
ref="container"
|
ref="container"
|
||||||
:data-label="$t('downloads')"
|
:data-label="$t('downloads')"
|
||||||
|
aria-label="downloads"
|
||||||
>
|
>
|
||||||
<div id="download_tab_drag_handler" @mousedown.prevent="startDrag" ref="dragHandler"></div>
|
<div id="download_tab_drag_handler" @mousedown.prevent="startDrag" ref="dragHandler"></div>
|
||||||
<i
|
<i
|
||||||
@ -16,7 +17,6 @@
|
|||||||
></i>
|
></i>
|
||||||
<div id="queue_buttons">
|
<div id="queue_buttons">
|
||||||
<i
|
<i
|
||||||
id="open_downloads_folder"
|
|
||||||
v-if="clientMode"
|
v-if="clientMode"
|
||||||
class="material-icons download_bar_icon"
|
class="material-icons download_bar_icon"
|
||||||
:title="$t('globals.open_downloads_folder')"
|
:title="$t('globals.open_downloads_folder')"
|
||||||
@ -24,20 +24,10 @@
|
|||||||
>
|
>
|
||||||
folder_open
|
folder_open
|
||||||
</i>
|
</i>
|
||||||
<i
|
<i class="material-icons download_bar_icon" @click="cleanQueue" :title="$t('globals.clean_queue_hint')">
|
||||||
id="clean_queue"
|
|
||||||
class="material-icons download_bar_icon"
|
|
||||||
@click="cleanQueue"
|
|
||||||
:title="$t('globals.clean_queue_hint')"
|
|
||||||
>
|
|
||||||
clear_all
|
clear_all
|
||||||
</i>
|
</i>
|
||||||
<i
|
<i class="material-icons download_bar_icon" @click="cancelQueue" :title="$t('globals.cancel_queue_hint')">
|
||||||
id="cancel_queue"
|
|
||||||
class="material-icons download_bar_icon"
|
|
||||||
@click="cancelQueue"
|
|
||||||
:title="$t('globals.cancel_queue_hint')"
|
|
||||||
>
|
|
||||||
delete_sweep
|
delete_sweep
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -87,6 +77,19 @@ export default {
|
|||||||
clientMode: 'getClientMode'
|
clientMode: 'getClientMode'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
const checkIfToggleBar = keyEvent => {
|
||||||
|
if (!(keyEvent.ctrlKey && keyEvent.key === 'b')) return
|
||||||
|
|
||||||
|
this.toggleDownloadTab()
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keyup', checkIfToggleBar)
|
||||||
|
|
||||||
|
this.$on('hook:destroyed', () => {
|
||||||
|
document.removeEventListener('keyup', checkIfToggleBar)
|
||||||
|
})
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
socket.on('startDownload', this.startDownload)
|
socket.on('startDownload', this.startDownload)
|
||||||
socket.on('startConversion', this.startConversion)
|
socket.on('startConversion', this.startConversion)
|
||||||
@ -263,7 +266,7 @@ export default {
|
|||||||
|
|
||||||
this.queueComplete = []
|
this.queueComplete = []
|
||||||
},
|
},
|
||||||
toggleDownloadTab(clickEvent) {
|
toggleDownloadTab() {
|
||||||
this.setTabWidth()
|
this.setTabWidth()
|
||||||
|
|
||||||
this.$refs.container.style.transition = 'all 250ms ease-in-out'
|
this.$refs.container.style.transition = 'all 250ms ease-in-out'
|
||||||
@ -337,4 +340,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -13,9 +13,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Downloads from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import downloadQualities from '@js/qualities'
|
|
||||||
import { generatePath, copyToClipboard } from '@/utils/utils'
|
import { generatePath, copyToClipboard } from '@/utils/utils'
|
||||||
|
import { downloadQualities } from '@/data/qualities'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@ -95,10 +95,10 @@ export default {
|
|||||||
|
|
||||||
downloadQualities.forEach((quality, index) => {
|
downloadQualities.forEach((quality, index) => {
|
||||||
options[quality.objName] = {
|
options[quality.objName] = {
|
||||||
label: `${this.$t('globals.download', {thing: quality.label})}`,
|
label: `${this.$t('globals.download', { thing: quality.label })}`,
|
||||||
show: false,
|
show: false,
|
||||||
position: nextValuePosition + index,
|
position: nextValuePosition + index,
|
||||||
action: this.tryToDownloadTrack.bind(null, quality.value)
|
action: sendAddToQueue.bind(null, this.deezerHref, quality.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -123,7 +123,6 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showMenu(contextMenuEvent) {
|
showMenu(contextMenuEvent) {
|
||||||
// contextMenuEvent.preventDefault()
|
|
||||||
const { pageX, pageY, target: elementClicked } = contextMenuEvent
|
const { pageX, pageY, target: elementClicked } = contextMenuEvent
|
||||||
const path = generatePath(elementClicked)
|
const path = generatePath(elementClicked)
|
||||||
let deezerLink = null
|
let deezerLink = null
|
||||||
@ -213,9 +212,6 @@ export default {
|
|||||||
downloadQualities.forEach(quality => {
|
downloadQualities.forEach(quality => {
|
||||||
this.options[quality.objName].show = true
|
this.options[quality.objName].show = true
|
||||||
})
|
})
|
||||||
},
|
|
||||||
tryToDownloadTrack(qualityValue) {
|
|
||||||
Downloads.sendAddToQueue(this.deezerHref, qualityValue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -47,7 +47,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="release in showTable" :key="release.id">
|
<tr v-for="release in showTable" :key="release.id">
|
||||||
<td class="inline-flex clickable" @click="albumView" :data-id="release.id">
|
<router-link tag="td" class="inline-flex clickable" :to="{ name: 'Album', params: { id: release.id } }">
|
||||||
<img
|
<img
|
||||||
class="rounded coverart"
|
class="rounded coverart"
|
||||||
:src="release.cover_small"
|
:src="release.cover_small"
|
||||||
@ -58,7 +58,7 @@
|
|||||||
<i v-if="checkNewRelease(release.release_date)" class="material-icons" style="color: #ff7300">
|
<i v-if="checkNewRelease(release.release_date)" class="material-icons" style="color: #ff7300">
|
||||||
fiber_new
|
fiber_new
|
||||||
</i>
|
</i>
|
||||||
</td>
|
</router-link>
|
||||||
<td>{{ release.release_date }}</td>
|
<td>{{ release.release_date }}</td>
|
||||||
<td>{{ release.nb_song }}</td>
|
<td>{{ release.nb_song }}</td>
|
||||||
<td @click.stop="addToQueue" :data-link="release.link" class="clickable">
|
<td @click.stop="addToQueue" :data-link="release.link" class="clickable">
|
||||||
@ -69,7 +69,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<button class="back-button" @click="backTab">{{ $t('globals.back') }}</button>
|
<button class="back-button" @click="$router.back()">{{ $t('globals.back') }}</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -78,7 +78,6 @@
|
|||||||
import { isEmpty, orderBy } from 'lodash-es'
|
import { isEmpty, orderBy } from 'lodash-es'
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import Downloads from '@/utils/downloads'
|
import Downloads from '@/utils/downloads'
|
||||||
import { showView, backTab } from '@js/tabs'
|
|
||||||
import EventBus from '@/utils/EventBus'
|
import EventBus from '@/utils/EventBus'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -97,8 +96,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
backTab,
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
reset() {
|
reset() {
|
||||||
this.title = 'Loading...'
|
this.title = 'Loading...'
|
||||||
this.image = ''
|
this.image = ''
|
||||||
@ -125,11 +122,8 @@ export default {
|
|||||||
changeTab(tab) {
|
changeTab(tab) {
|
||||||
this.currentTab = tab
|
this.currentTab = tab
|
||||||
},
|
},
|
||||||
getCurrentTab() {
|
|
||||||
return this.currentTab
|
|
||||||
},
|
|
||||||
updateSelected() {
|
updateSelected() {
|
||||||
window.currentStack.selected = this.currentTab
|
// Last tab opened logic
|
||||||
},
|
},
|
||||||
checkNewRelease(date) {
|
checkNewRelease(date) {
|
||||||
let g1 = new Date()
|
let g1 = new Date()
|
@ -71,20 +71,20 @@
|
|||||||
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
|
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
|
||||||
}}
|
}}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<router-link
|
||||||
class="table__cell--medium table__cell--center breakline clickable"
|
tag="td"
|
||||||
@click="artistView"
|
class="table__cell table__cell--medium table__cell--center breakline clickable"
|
||||||
:data-id="track.artist.id"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</td>
|
</router-link>
|
||||||
<td
|
<router-link
|
||||||
|
tag="td"
|
||||||
class="table__cell--medium table__cell--center breakline clickable"
|
class="table__cell--medium table__cell--center breakline clickable"
|
||||||
@click="albumView"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
:data-id="track.album.id"
|
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</td>
|
</router-link>
|
||||||
<td class="table__cell--small table__cell--center">
|
<td class="table__cell--small table__cell--center">
|
||||||
{{ convertDuration(track.duration) }}
|
{{ convertDuration(track.duration) }}
|
||||||
</td>
|
</td>
|
||||||
@ -107,7 +107,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { showView } from '@js/tabs.js'
|
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
|
|
||||||
@ -136,8 +135,6 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
convertDuration,
|
convertDuration,
|
||||||
artistView: showView.bind(null, 'artist'),
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
playPausePreview(e) {
|
playPausePreview(e) {
|
||||||
EventBus.$emit('trackPreview:playPausePreview', e)
|
EventBus.$emit('trackPreview:playPausePreview', e)
|
||||||
},
|
},
|
@ -29,46 +29,25 @@
|
|||||||
<h1>{{ $t('favorites.noPlaylists') }}</h1>
|
<h1>{{ $t('favorites.noPlaylists') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release_grid" v-if="playlists.length > 0 || spotifyPlaylists > 0">
|
<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">
|
<router-link
|
||||||
<div class="cover_container">
|
tag="div"
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
v-for="release in playlists"
|
||||||
<div
|
:key="release.id"
|
||||||
role="button"
|
|
||||||
aria-label="download"
|
|
||||||
@click.stop="addToQueue"
|
|
||||||
:data-link="release.link"
|
|
||||||
class="download_overlay"
|
|
||||||
>
|
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
|
||||||
<p class="secondary-text">
|
|
||||||
{{
|
|
||||||
`${$t('globals.by', { artist: release.creator.name })} - ${$tc(
|
|
||||||
'globals.listTabs.trackN',
|
|
||||||
release.nb_tracks
|
|
||||||
)}`
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="release in spotifyPlaylists"
|
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click="spotifyPlaylistView"
|
:to="{ name: 'Playlist', params: { id: release.id } }"
|
||||||
:data-id="release.id"
|
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="addToQueue"
|
@click.stop="addToQueue"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
<p class="secondary-text">
|
<p class="secondary-text">
|
||||||
@ -79,7 +58,37 @@
|
|||||||
)}`
|
)}`
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</router-link>
|
||||||
|
<router-link
|
||||||
|
tag="div"
|
||||||
|
v-for="release in spotifyPlaylists"
|
||||||
|
:key="release.id"
|
||||||
|
class="release clickable"
|
||||||
|
:to="{ name: 'Spotify Playlist', params: { id: release.id } }"
|
||||||
|
>
|
||||||
|
<div class="cover_container">
|
||||||
|
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||||
|
<button
|
||||||
|
role="button"
|
||||||
|
aria-label="download"
|
||||||
|
@click.stop="addToQueue"
|
||||||
|
:data-link="release.link"
|
||||||
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
|
<p class="secondary-text">
|
||||||
|
{{
|
||||||
|
`${$t('globals.by', { artist: release.creator.name })} - ${$tc(
|
||||||
|
'globals.listTabs.trackN',
|
||||||
|
release.nb_tracks
|
||||||
|
)}`
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -88,22 +97,29 @@
|
|||||||
<h1>{{ $t('favorites.noAlbums') }}</h1>
|
<h1>{{ $t('favorites.noAlbums') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release_grid" v-if="albums.length > 0">
|
<div class="release_grid" v-if="albums.length > 0">
|
||||||
<div v-for="release in albums" class="release clickable" @click="albumView" :data-id="release.id">
|
<router-link
|
||||||
|
tag="div"
|
||||||
|
class="release clickable"
|
||||||
|
v-for="release in albums"
|
||||||
|
:key="release.id"
|
||||||
|
:to="{ name: 'Album', params: { id: release.id } }"
|
||||||
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="addToQueue"
|
@click.stop="addToQueue"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -112,21 +128,28 @@
|
|||||||
<h1>{{ $t('favorites.noArtists') }}</h1>
|
<h1>{{ $t('favorites.noArtists') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release_grid" v-if="artists.length > 0">
|
<div class="release_grid" v-if="artists.length > 0">
|
||||||
<div v-for="release in artists" class="release clickable" @click="artistView" :data-id="release.id">
|
<router-link
|
||||||
|
tag="div"
|
||||||
|
class="release clickable"
|
||||||
|
v-for="release in artists"
|
||||||
|
:key="release.id"
|
||||||
|
:to="{ name: 'Artist', params: { id: release.id } }"
|
||||||
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="circle coverart" :src="release.picture_medium" />
|
<img aria-hidden="true" class="circle coverart" :src="release.picture_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="addToQueue"
|
@click.stop="addToQueue"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.name }}</p>
|
<p class="primary-text">{{ release.name }}</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -165,20 +188,20 @@
|
|||||||
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
|
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
|
||||||
}}
|
}}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<router-link
|
||||||
class="table__cell--medium table__cell--center breakline clickable"
|
tag="td"
|
||||||
@click="artistView"
|
class="table__cell table__cell--medium table__cell--center breakline clickable"
|
||||||
:data-id="track.artist.id"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</td>
|
</router-link>
|
||||||
<td
|
<router-link
|
||||||
|
tag="td"
|
||||||
class="table__cell--medium table__cell--center breakline clickable"
|
class="table__cell--medium table__cell--center breakline clickable"
|
||||||
@click="albumView"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
:data-id="track.album.id"
|
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</td>
|
</router-link>
|
||||||
<td class="table__cell--small">
|
<td class="table__cell--small">
|
||||||
{{ convertDuration(track.duration) }}
|
{{ convertDuration(track.duration) }}
|
||||||
</td>
|
</td>
|
||||||
@ -210,8 +233,6 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { showView } from '@js/tabs'
|
|
||||||
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
@ -257,10 +278,6 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
artistView: showView.bind(null, 'artist'),
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
playlistView: showView.bind(null, 'playlist'),
|
|
||||||
spotifyPlaylistView: showView.bind(null, 'spotifyplaylist'),
|
|
||||||
playPausePreview(e) {
|
playPausePreview(e) {
|
||||||
EventBus.$emit('trackPreview:playPausePreview', e)
|
EventBus.$emit('trackPreview:playPausePreview', e)
|
||||||
},
|
},
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
<section class="home_section" ref="notLogged" v-if="!isLoggedIn">
|
<section class="home_section" ref="notLogged" v-if="!isLoggedIn">
|
||||||
<p id="home_not_logged_text">{{ $t('home.needTologin') }}</p>
|
<p id="home_not_logged_text">{{ $t('home.needTologin') }}</p>
|
||||||
<!-- <button type="button" name="button" @click="openSettings">{{ $t('home.openSettings') }}</button> -->
|
|
||||||
<router-link tag="button" name="button" :to="{ name: 'Settings' }">
|
<router-link tag="button" name="button" :to="{ name: 'Settings' }">
|
||||||
{{ $t('home.openSettings') }}
|
{{ $t('home.openSettings') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -13,24 +12,27 @@
|
|||||||
<section v-if="playlists.length" class="home_section">
|
<section v-if="playlists.length" class="home_section">
|
||||||
<h3 class="section_heading">{{ $t('home.sections.popularPlaylists') }}</h3>
|
<h3 class="section_heading">{{ $t('home.sections.popularPlaylists') }}</h3>
|
||||||
<div class="release_grid">
|
<div class="release_grid">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in playlists"
|
v-for="release in playlists"
|
||||||
:key="release.id"
|
:key="release.id"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click="playlistView"
|
:to="{ name: 'Playlist', params: { id: release.id } }"
|
||||||
:data-id="release.id"
|
@keyup.enter.native="$router.push({ name: 'Playlist', params: { id: release.id } })"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="addToQueue"
|
@click.stop="addToQueue"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
<p class="secondary-text">
|
<p class="secondary-text">
|
||||||
@ -41,35 +43,39 @@
|
|||||||
)}`
|
)}`
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section v-if="albums.length" class="home_section">
|
<section v-if="albums.length" class="home_section">
|
||||||
<h3 class="section_heading">{{ $t('home.sections.popularAlbums') }}</h3>
|
<h3 class="section_heading">{{ $t('home.sections.popularAlbums') }}</h3>
|
||||||
<div class="release_grid">
|
<div class="release_grid">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in albums"
|
v-for="release in albums"
|
||||||
:key="release.id"
|
:key="release.id"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click="albumView"
|
:to="{ name: 'Album', params: { id: release.id } }"
|
||||||
|
@keyup.enter.native="$router.push({ name: 'Album', params: { id: release.id } })"
|
||||||
:data-id="release.id"
|
:data-id="release.id"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="addToQueue"
|
@click.stop="addToQueue"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -78,7 +84,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
import { showView } from '@js/tabs'
|
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import { getHomeData } from '@/data/home'
|
import { getHomeData } from '@/data/home'
|
||||||
|
|
||||||
@ -95,15 +100,9 @@ export default {
|
|||||||
this.initHome(homeData)
|
this.initHome(homeData)
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['isLoggedIn']),
|
...mapGetters(['isLoggedIn'])
|
||||||
needToWait() {
|
|
||||||
return this.getHomeData.albums.data.length === 0 && this.getHomeData.playlists.data.length === 0
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
artistView: showView.bind(null, 'artist'),
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
playlistView: showView.bind(null, 'playlist'),
|
|
||||||
addToQueue(e) {
|
addToQueue(e) {
|
||||||
sendAddToQueue(e.currentTarget.dataset.link)
|
sendAddToQueue(e.currentTarget.dataset.link)
|
||||||
},
|
},
|
@ -25,24 +25,39 @@
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
<h2 v-if="type == 'track'">
|
<h2 v-if="type === 'track'">
|
||||||
<i18n path="globals.by" tag="span">
|
<i18n path="globals.by" tag="span">
|
||||||
<span place="artist" class="clickable" @click="artistView" :data-id="data.artist.id">{{
|
<router-link
|
||||||
data.artist.name
|
tag="span"
|
||||||
}}</span>
|
place="artist"
|
||||||
|
class="clickable"
|
||||||
|
:to="{ name: 'Artist', params: { id: data.artist.id } }"
|
||||||
|
>
|
||||||
|
{{ data.artist.name }}
|
||||||
|
</router-link>
|
||||||
</i18n>
|
</i18n>
|
||||||
•
|
•
|
||||||
<i18n path="globals.in" tag="span">
|
<i18n path="globals.in" tag="span">
|
||||||
<span place="album" class="clickable" @click="albumView" :data-id="data.album.id">{{
|
<router-link
|
||||||
data.album.title
|
tag="span"
|
||||||
}}</span>
|
place="album"
|
||||||
|
class="clickable"
|
||||||
|
:to="{ name: 'Album', params: { id: data.album.id } }"
|
||||||
|
>
|
||||||
|
{{ data.album.title }}
|
||||||
|
</router-link>
|
||||||
</i18n>
|
</i18n>
|
||||||
</h2>
|
</h2>
|
||||||
<h2 v-else-if="type == 'album'">
|
<h2 v-else-if="type === 'album'">
|
||||||
<i18n path="globals.by" tag="span">
|
<i18n path="globals.by" tag="span">
|
||||||
<span place="artist" class="clickable" @click="artistView" :data-id="data.artist.id">{{
|
<router-link
|
||||||
data.artist.name
|
tag="span"
|
||||||
}}</span>
|
place="artist"
|
||||||
|
class="clickable"
|
||||||
|
:to="{ name: 'Artist', params: { id: data.artist.id } }"
|
||||||
|
>
|
||||||
|
{{ data.artist.name }}
|
||||||
|
</router-link>
|
||||||
</i18n>
|
</i18n>
|
||||||
{{ ` • ${$tc('globals.listTabs.trackN', data.nb_tracks)}` }}
|
{{ ` • ${$tc('globals.listTabs.trackN', data.nb_tracks)}` }}
|
||||||
</h2>
|
</h2>
|
||||||
@ -106,7 +121,9 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div v-if="type == 'album'">
|
<div v-if="type == 'album'">
|
||||||
<button @click="albumView" :data-id="id">{{ $t('linkAnalyzer.table.tracklist') }}</button>
|
<router-link tag="button" :to="{ name: 'Album', params: { id } }">
|
||||||
|
{{ $t('linkAnalyzer.table.tracklist') }}
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="countries.length">
|
<div v-if="countries.length">
|
||||||
<p v-for="country in countries">{{ country[0] }} - {{ country[1] }}</p>
|
<p v-for="country in countries">{{ country[0] }} - {{ country[1] }}</p>
|
||||||
@ -117,7 +134,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { showView } from '@js/tabs'
|
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
import { COUNTRIES } from '@/utils/countries'
|
import { COUNTRIES } from '@/utils/countries'
|
||||||
import EventBus from '@/utils/EventBus'
|
import EventBus from '@/utils/EventBus'
|
||||||
@ -137,8 +153,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
artistView: showView.bind(null, 'artist'),
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
convertDuration,
|
convertDuration,
|
||||||
reset() {
|
reset() {
|
||||||
this.title = 'Loading...'
|
this.title = 'Loading...'
|
@ -23,9 +23,6 @@
|
|||||||
:is="currentTab.component"
|
:is="currentTab.component"
|
||||||
:results="results"
|
:results="results"
|
||||||
@add-to-queue="addToQueue"
|
@add-to-queue="addToQueue"
|
||||||
@artist-view="artistView"
|
|
||||||
@album-view="albumView"
|
|
||||||
@playlist-view="playlistView"
|
|
||||||
@change-search-tab="changeSearchTab"
|
@change-search-tab="changeSearchTab"
|
||||||
></component>
|
></component>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
@ -34,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
import ResultsAll from '@components/search/ResultsAll.vue'
|
import ResultsAll from '@components/search/ResultsAll.vue'
|
||||||
import ResultsAlbums from '@components/search/ResultsAlbums.vue'
|
import ResultsAlbums from '@components/search/ResultsAlbums.vue'
|
||||||
import ResultsArtists from '@components/search/ResultsArtists.vue'
|
import ResultsArtists from '@components/search/ResultsArtists.vue'
|
||||||
@ -42,7 +39,6 @@ import ResultsPlaylists from '@components/search/ResultsPlaylists.vue'
|
|||||||
import ResultsTracks from '@components/search/ResultsTracks.vue'
|
import ResultsTracks from '@components/search/ResultsTracks.vue'
|
||||||
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { showView } from '@js/tabs'
|
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import { numberWithDots, convertDuration } from '@/utils/utils'
|
import { numberWithDots, convertDuration } from '@/utils/utils'
|
||||||
import EventBus from '@/utils/EventBus'
|
import EventBus from '@/utils/EventBus'
|
||||||
@ -156,14 +152,12 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
EventBus.$on('mainSearch:checkLoadMoreContent', this.checkLoadMoreContent)
|
EventBus.$on('mainSearch:checkLoadMoreContent', this.checkLoadMoreContent)
|
||||||
this.$root.$on('mainSearch:showNewResults', this.checkIfShowNewResults)
|
this.$root.$on('mainSearch:showNewResults', this.checkIfShowNewResults)
|
||||||
|
this.$root.$on('mainSearch:updateResults', this.checkIfUpdateResults)
|
||||||
|
|
||||||
socket.on('mainSearch', this.handleMainSearch)
|
socket.on('mainSearch', this.handleMainSearch)
|
||||||
socket.on('search', this.handleSearch)
|
socket.on('search', this.handleSearch)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
artistView: showView.bind(null, 'artist'),
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
playlistView: showView.bind(null, 'playlist'),
|
|
||||||
changeSearchTab(sectionName) {
|
changeSearchTab(sectionName) {
|
||||||
sectionName = sectionName.toLowerCase()
|
sectionName = sectionName.toLowerCase()
|
||||||
|
|
||||||
@ -180,12 +174,21 @@ export default {
|
|||||||
this.currentTab = newTab
|
this.currentTab = newTab
|
||||||
},
|
},
|
||||||
checkIfShowNewResults(term, mainSelected) {
|
checkIfShowNewResults(term, mainSelected) {
|
||||||
let needToPerformNewSearch = term !== this.results.query || mainSelected == 'search_tab'
|
let needToPerformNewSearch = term !== this.results.query /* || mainSelected == 'search_tab' */
|
||||||
|
|
||||||
if (needToPerformNewSearch) {
|
if (needToPerformNewSearch) {
|
||||||
this.showNewResults(term)
|
this.showNewResults(term)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
checkIfUpdateResults(term) {
|
||||||
|
let needToUpdateSearch = term === this.results.query && this.currentTab.searchType !== 'all'
|
||||||
|
|
||||||
|
if (needToUpdateSearch) {
|
||||||
|
let resetObj = { data: [], next: 0, total: 0, loaded: false }
|
||||||
|
this.results[this.currentTab.searchType + 'Tab'] = { ...resetObj }
|
||||||
|
this.search(this.currentTab.searchType)
|
||||||
|
}
|
||||||
|
},
|
||||||
showNewResults(term) {
|
showNewResults(term) {
|
||||||
socket.emit('mainSearch', { term })
|
socket.emit('mainSearch', { term })
|
||||||
|
|
@ -56,6 +56,7 @@
|
|||||||
:class="{ 'locale-flag--current': currentLocale === locale }"
|
:class="{ 'locale-flag--current': currentLocale === locale }"
|
||||||
@click="changeLocale(locale)"
|
@click="changeLocale(locale)"
|
||||||
v-html="flags[locale]"
|
v-html="flags[locale]"
|
||||||
|
:title="locale"
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -187,7 +188,7 @@
|
|||||||
|
|
||||||
<div class="input_group">
|
<div class="input_group">
|
||||||
<p class="input_group_text">{{ $t('settings.downloads.queueConcurrency') }}</p>
|
<p class="input_group_text">{{ $t('settings.downloads.queueConcurrency') }}</p>
|
||||||
<input type="number" v-model.number="settings.queueConcurrency" />
|
<input type="number" min="1" v-model.number="settings.queueConcurrency" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input_group">
|
<div class="input_group">
|
||||||
@ -643,8 +644,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 40px;
|
width: 40px !important;
|
||||||
height: 40px;
|
height: 40px !important;
|
||||||
filter: brightness(0.5);
|
filter: brightness(0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -653,19 +654,18 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapActions, mapGetters } from 'vuex'
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
import { getSettingsData } from '@/data/settings'
|
||||||
|
|
||||||
import { toast } from '@/utils/toasts'
|
import { toast } from '@/utils/toasts'
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import EventBus from '@/utils/EventBus'
|
import { flags } from '@/utils/flags'
|
||||||
import flags from '@/utils/flags'
|
|
||||||
|
|
||||||
import { getSettingsData } from '@/data/settings'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
flags,
|
flags,
|
||||||
currentLocale: 'en',
|
currentLocale: this.$i18n.locale,
|
||||||
locales: [],
|
locales: this.$i18n.availableLocales,
|
||||||
settings: {
|
settings: {
|
||||||
tags: {}
|
tags: {}
|
||||||
},
|
},
|
||||||
@ -679,7 +679,6 @@ export default {
|
|||||||
previewVolume: window.vol,
|
previewVolume: window.vol,
|
||||||
accountNum: 0,
|
accountNum: 0,
|
||||||
accounts: []
|
accounts: []
|
||||||
// clientMode: window.clientMode
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -708,23 +707,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.locales = this.$i18n.availableLocales
|
|
||||||
|
|
||||||
const { settingsData, defaultSettingsData, spotifyCredentials } = await getSettingsData()
|
const { settingsData, defaultSettingsData, spotifyCredentials } = await getSettingsData()
|
||||||
|
|
||||||
this.defaultSettings = defaultSettingsData
|
this.defaultSettings = defaultSettingsData
|
||||||
this.initSettings(settingsData, spotifyCredentials)
|
this.initSettings(settingsData, spotifyCredentials)
|
||||||
|
|
||||||
// this.revertSettings()
|
|
||||||
// this.revertCredentials()
|
|
||||||
|
|
||||||
let storedLocale = localStorage.getItem('locale')
|
|
||||||
|
|
||||||
if (storedLocale) {
|
|
||||||
this.$i18n.locale = storedLocale
|
|
||||||
this.currentLocale = storedLocale
|
|
||||||
}
|
|
||||||
|
|
||||||
let storedAccountNum = localStorage.getItem('accountNum')
|
let storedAccountNum = localStorage.getItem('accountNum')
|
||||||
|
|
||||||
if (storedAccountNum) {
|
if (storedAccountNum) {
|
||||||
@ -823,6 +810,11 @@ export default {
|
|||||||
this.lastCredentials = JSON.parse(JSON.stringify(credentials))
|
this.lastCredentials = JSON.parse(JSON.stringify(credentials))
|
||||||
this.spotifyFeatures = JSON.parse(JSON.stringify(credentials))
|
this.spotifyFeatures = JSON.parse(JSON.stringify(credentials))
|
||||||
},
|
},
|
||||||
|
loggedInViaDeezer(arl) {
|
||||||
|
this.dispatchARL({ arl })
|
||||||
|
socket.emit('login', arl, true, this.accountNum)
|
||||||
|
// this.login()
|
||||||
|
},
|
||||||
login() {
|
login() {
|
||||||
let newArl = this.$refs.loginInput.value.trim()
|
let newArl = this.$refs.loginInput.value.trim()
|
||||||
|
|
||||||
@ -833,10 +825,6 @@ export default {
|
|||||||
appLogin(e) {
|
appLogin(e) {
|
||||||
socket.emit('applogin')
|
socket.emit('applogin')
|
||||||
},
|
},
|
||||||
loggedInViaDeezer(arl) {
|
|
||||||
this.dispatchARL({ arl })
|
|
||||||
this.login()
|
|
||||||
},
|
|
||||||
changeAccount() {
|
changeAccount() {
|
||||||
socket.emit('changeAccount', this.accountNum)
|
socket.emit('changeAccount', this.accountNum)
|
||||||
},
|
},
|
@ -64,21 +64,21 @@
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td
|
<router-link
|
||||||
|
tag="td"
|
||||||
class="table__cell--medium table__cell--center clickable"
|
class="table__cell--medium table__cell--center clickable"
|
||||||
@click="artistView"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
:data-id="track.artist.id"
|
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</td>
|
</router-link>
|
||||||
<td
|
<router-link
|
||||||
v-if="type == 'playlist'"
|
tag="td"
|
||||||
|
v-if="type === 'playlist'"
|
||||||
class="table__cell--medium table__cell--center clickable"
|
class="table__cell--medium table__cell--center clickable"
|
||||||
@click="albumView"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
:data-id="track.album.id"
|
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</td>
|
</router-link>
|
||||||
<td
|
<td
|
||||||
class="table__cell--center"
|
class="table__cell--center"
|
||||||
:class="{ 'table__cell--small': type === 'album', 'table__cell--x-small': type === 'playlist' }"
|
:class="{ 'table__cell--small': type === 'album', 'table__cell--x-small': type === 'playlist' }"
|
||||||
@ -137,7 +137,7 @@
|
|||||||
<button class="with_icon" @click.stop="addToQueue" :data-link="selectedLinks()">
|
<button class="with_icon" @click.stop="addToQueue" :data-link="selectedLinks()">
|
||||||
{{ $t('tracklist.downloadSelection') }}<i class="material-icons">file_download</i>
|
{{ $t('tracklist.downloadSelection') }}<i class="material-icons">file_download</i>
|
||||||
</button>
|
</button>
|
||||||
<button class="back-button" @click="backTab">{{ $t('globals.back') }}</button>
|
<button class="back-button" @click="$router.back()">{{ $t('globals.back') }}</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -145,28 +145,25 @@
|
|||||||
<script>
|
<script>
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { showView, backTab } from '@js/tabs.js'
|
|
||||||
import Downloads from '@/utils/downloads'
|
import Downloads from '@/utils/downloads'
|
||||||
import Utils from '@/utils/utils'
|
import Utils from '@/utils/utils'
|
||||||
import EventBus from '@/utils/EventBus'
|
import EventBus from '@/utils/EventBus'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'tracklist-tab',
|
data() {
|
||||||
data: () => ({
|
return {
|
||||||
title: '',
|
title: '',
|
||||||
metadata: '',
|
metadata: '',
|
||||||
release_date: '',
|
release_date: '',
|
||||||
label: '',
|
label: '',
|
||||||
explicit: false,
|
explicit: false,
|
||||||
image: '',
|
image: '',
|
||||||
type: 'empty',
|
type: 'empty',
|
||||||
link: '',
|
link: '',
|
||||||
body: []
|
body: []
|
||||||
}),
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
backTab,
|
|
||||||
artistView: showView.bind(null, 'artist'),
|
|
||||||
albumView: showView.bind(null, 'album'),
|
|
||||||
playPausePreview(e) {
|
playPausePreview(e) {
|
||||||
EventBus.$emit('trackPreview:playPausePreview', e)
|
EventBus.$emit('trackPreview:playPausePreview', e)
|
||||||
},
|
},
|
@ -5,23 +5,25 @@
|
|||||||
<h1>{{ $t('search.noResultsAlbum') }}</h1>
|
<h1>{{ $t('search.noResultsAlbum') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release_grid" v-if="results.albumTab.data.length > 0">
|
<div class="release_grid" v-if="results.albumTab.data.length > 0">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in results.albumTab.data"
|
v-for="release in results.albumTab.data"
|
||||||
|
:key="release.id"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click.stop="$emit('album-view', $event)"
|
:to="{ name: 'Album', params: { id: release.id } }"
|
||||||
:data-id="release.id"
|
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
<img aria-hidden="true" class="rounded coverart" :src="release.cover_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text inline-flex">
|
<p class="primary-text inline-flex">
|
||||||
<i v-if="release.explicit_lyrics" class="material-icons explicit_icon">explicit</i>
|
<i v-if="release.explicit_lyrics" class="material-icons explicit_icon">explicit</i>
|
||||||
@ -34,13 +36,13 @@
|
|||||||
$tc('globals.listTabs.trackN', release.nb_tracks)
|
$tc('globals.listTabs.trackN', release.nb_tracks)
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['results'],
|
props: ['results'],
|
||||||
@ -48,4 +50,4 @@ export default {
|
|||||||
BaseLoadingPlaceholder
|
BaseLoadingPlaceholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
{{ $tc(`globals.listTabs.${section.toLowerCase()}`, 2) }}
|
{{ $tc(`globals.listTabs.${section.toLowerCase()}`, 2) }}
|
||||||
</h2>
|
</h2>
|
||||||
<!-- Top result -->
|
<!-- Top result -->
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-if="section == 'TOP_RESULT'"
|
v-if="section == 'TOP_RESULT'"
|
||||||
class="top_result clickable"
|
class="top_result clickable"
|
||||||
@click.stop="$emit(`${topResultType}-view`, $event)"
|
:to="{ name: upperCaseFirstLowerCaseRest(topResultType), params: { id: results.allTab.TOP_RESULT[0].id } }"
|
||||||
:data-id="results.allTab.TOP_RESULT[0].id"
|
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img
|
<img
|
||||||
@ -27,34 +27,29 @@
|
|||||||
:src="results.allTab.TOP_RESULT[0].picture"
|
:src="results.allTab.TOP_RESULT[0].picture"
|
||||||
:class="(results.allTab.TOP_RESULT[0].type == 'artist' ? 'circle' : 'rounded') + ' coverart'"
|
:class="(results.allTab.TOP_RESULT[0].type == 'artist' ? 'circle' : 'rounded') + ' coverart'"
|
||||||
/>
|
/>
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="results.allTab.TOP_RESULT[0].link"
|
:data-link="results.allTab.TOP_RESULT[0].link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="info_box">
|
<div class="info_box">
|
||||||
<p class="primary-text">{{ results.allTab.TOP_RESULT[0].title }}</p>
|
<p class="primary-text">{{ results.allTab.TOP_RESULT[0].title }}</p>
|
||||||
<p class="secondary-text">
|
<p class="secondary-text">
|
||||||
{{
|
{{ fansNumber }}
|
||||||
results.allTab.TOP_RESULT[0].type == 'artist'
|
|
||||||
? $t('search.fans', { n: $n(results.allTab.TOP_RESULT[0].nb_fan) })
|
|
||||||
: $t('globals.by', { artist: results.allTab.TOP_RESULT[0].artist }) +
|
|
||||||
' - ' +
|
|
||||||
$tc('globals.listTabs.trackN', results.allTab.TOP_RESULT[0].nb_song)
|
|
||||||
}}
|
|
||||||
</p>
|
</p>
|
||||||
<span class="tag">{{ $tc(`globals.listTabs.${results.allTab.TOP_RESULT[0].type}`, 1) }}</span>
|
<span class="tag">{{ $tc(`globals.listTabs.${results.allTab.TOP_RESULT[0].type}`, 1) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</router-link>
|
||||||
<div v-else-if="section == 'TRACK'">
|
<div v-else-if="section == 'TRACK'">
|
||||||
<table class="table table--tracks">
|
<table class="table table--tracks">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="track in results.allTab.TRACK.data.slice(0, 6)">
|
<tr v-for="track in results.allTab.TRACK.data.slice(0, 6)" :key="track.SNG_ID">
|
||||||
<td class="table__icon" aria-hidden="true">
|
<td class="table__icon" aria-hidden="true">
|
||||||
<img
|
<img
|
||||||
class="rounded coverart"
|
class="rounded coverart"
|
||||||
@ -70,23 +65,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="table__cell table__cell--medium table__cell--center breakline">
|
<td class="table__cell table__cell--medium table__cell--center breakline">
|
||||||
<span
|
<router-link
|
||||||
class="clickable"
|
tag="span"
|
||||||
@click.stop="$emit('artist-view', $event)"
|
|
||||||
:data-id="artist.ART_ID"
|
|
||||||
v-for="artist in track.ARTISTS"
|
v-for="artist in track.ARTISTS"
|
||||||
:key="artist.ART_ID"
|
:key="artist.ART_ID"
|
||||||
|
class="clickable"
|
||||||
|
:to="{
|
||||||
|
name: 'Artist',
|
||||||
|
params: { id: artist.ART_ID }
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
{{ artist.ART_NAME }}
|
{{ artist.ART_NAME }}
|
||||||
</span>
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
<td
|
<router-link
|
||||||
|
tag="td"
|
||||||
class="table__cell--medium table__cell--center breakline clickable"
|
class="table__cell--medium table__cell--center breakline clickable"
|
||||||
@click.stop="$emit('album-view', $event)"
|
:to="{ name: 'Album', params: { id: track.ALB_ID } }"
|
||||||
:data-id="track.ALB_ID"
|
|
||||||
>
|
>
|
||||||
{{ track.ALB_TITLE }}
|
{{ track.ALB_TITLE }}
|
||||||
</td>
|
</router-link>
|
||||||
<td class="table__cell table__cell--center">
|
<td class="table__cell table__cell--center">
|
||||||
{{ convertDuration(track.DURATION) }}
|
{{ convertDuration(track.DURATION) }}
|
||||||
</td>
|
</td>
|
||||||
@ -104,11 +102,12 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="section == 'ARTIST'" class="release_grid firstrow_only">
|
<div v-else-if="section == 'ARTIST'" class="release_grid firstrow_only">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in results.allTab.ARTIST.data.slice(0, 10)"
|
v-for="release in results.allTab.ARTIST.data.slice(0, 10)"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click.stop="$emit('artist-view', $event)"
|
:key="release.ART_ID"
|
||||||
:data-id="release.ART_ID"
|
:to="{ name: 'Artist', params: { id: release.ART_ID } }"
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img
|
<img
|
||||||
@ -118,26 +117,28 @@
|
|||||||
'https://e-cdns-images.dzcdn.net/images/artist/' + release.ART_PICTURE + '/156x156-000000-80-0-0.jpg'
|
'https://e-cdns-images.dzcdn.net/images/artist/' + release.ART_PICTURE + '/156x156-000000-80-0-0.jpg'
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="'https://deezer.com/artist/' + release.ART_ID"
|
:data-link="'https://deezer.com/artist/' + release.ART_ID"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.ART_NAME }}</p>
|
<p class="primary-text">{{ release.ART_NAME }}</p>
|
||||||
<p class="secondary-text">{{ $t('search.fans', { n: $n(release.NB_FAN) }) }}</p>
|
<p class="secondary-text">{{ $t('search.fans', { n: $n(release.NB_FAN) }) }}</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="section == 'ALBUM'" class="release_grid firstrow_only">
|
<div v-else-if="section == 'ALBUM'" class="release_grid firstrow_only">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in results.allTab.ALBUM.data.slice(0, 10)"
|
v-for="release in results.allTab.ALBUM.data.slice(0, 10)"
|
||||||
|
:key="release.ALB_ID"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click.stop="$emit('album-view', $event)"
|
:to="{ name: 'Album', params: { id: release.ALB_ID } }"
|
||||||
:data-id="release.ALB_ID"
|
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img
|
<img
|
||||||
@ -147,15 +148,16 @@
|
|||||||
'https://e-cdns-images.dzcdn.net/images/cover/' + release.ALB_PICTURE + '/156x156-000000-80-0-0.jpg'
|
'https://e-cdns-images.dzcdn.net/images/cover/' + release.ALB_PICTURE + '/156x156-000000-80-0-0.jpg'
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="'https://deezer.com/album/' + release.ALB_ID"
|
:data-link="'https://deezer.com/album/' + release.ALB_ID"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text inline-flex">
|
<p class="primary-text inline-flex">
|
||||||
<i
|
<i
|
||||||
@ -168,14 +170,15 @@
|
|||||||
<p class="secondary-text">
|
<p class="secondary-text">
|
||||||
{{ release.ART_NAME + ' - ' + $tc('globals.listTabs.trackN', release.NUMBER_TRACK) }}
|
{{ release.ART_NAME + ' - ' + $tc('globals.listTabs.trackN', release.NUMBER_TRACK) }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="section == 'PLAYLIST'" class="release_grid firstrow_only">
|
<div v-else-if="section == 'PLAYLIST'" class="release_grid firstrow_only">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in results.allTab.PLAYLIST.data.slice(0, 10)"
|
v-for="release in results.allTab.PLAYLIST.data.slice(0, 10)"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click.stop="$emit('playlist-view', $event)"
|
:key="release.PLAYLIST_ID"
|
||||||
:data-id="release.PLAYLIST_ID"
|
:to="{ name: 'Playlist', params: { id: release.PLAYLIST_ID } }"
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img
|
<img
|
||||||
@ -189,19 +192,20 @@
|
|||||||
'/156x156-000000-80-0-0.jpg'
|
'/156x156-000000-80-0-0.jpg'
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="'https://deezer.com/playlist/' + release.PLAYLIST_ID"
|
:data-link="'https://deezer.com/playlist/' + release.PLAYLIST_ID"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.TITLE }}</p>
|
<p class="primary-text">{{ release.TITLE }}</p>
|
||||||
<p class="secondary-text">{{ $tc('globals.listTabs.trackN', release.NB_SONG) }}</p>
|
<p class="secondary-text">{{ $tc('globals.listTabs.trackN', release.NB_SONG) }}</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@ -212,6 +216,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
|
import { upperCaseFirstLowerCaseRest } from '@/utils/texts'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['results'],
|
props: ['results'],
|
||||||
@ -225,10 +230,26 @@ export default {
|
|||||||
? this.results.allTab[section].length == 0
|
? this.results.allTab[section].length == 0
|
||||||
: this.results.allTab[section].data.length == 0
|
: this.results.allTab[section].data.length == 0
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
fansNumber() {
|
||||||
|
let number
|
||||||
|
|
||||||
|
try {
|
||||||
|
number = this.$n(this.results.allTab.TOP_RESULT[0].nb_fan)
|
||||||
|
} catch (error) {
|
||||||
|
number = this.$n(this.results.allTab.TOP_RESULT[0].nb_fan, { locale: 'en' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.results.allTab.TOP_RESULT[0].type == 'artist'
|
||||||
|
? this.$t('search.fans', { n: number })
|
||||||
|
: this.$t('globals.by', { artist: this.results.allTab.TOP_RESULT[0].artist }) +
|
||||||
|
' - ' +
|
||||||
|
this.$tc('globals.listTabs.trackN', this.results.allTab.TOP_RESULT[0].nb_song)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
convertDuration
|
convertDuration,
|
||||||
|
upperCaseFirstLowerCaseRest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,37 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="artist_search" class="search_tabcontent">
|
<div id="artist_search" class="search_tabcontent">
|
||||||
<base-loading-placeholder v-if="!results.artistTab.loaded"></base-loading-placeholder>
|
<BaseLoadingPlaceholder v-if="!results.artistTab.loaded"></BaseLoadingPlaceholder>
|
||||||
<div v-else-if="results.artistTab.data.length == 0">
|
<div v-else-if="results.artistTab.data.length == 0">
|
||||||
<h1>{{ $t('search.noResultsArtist') }}</h1>
|
<h1>{{ $t('search.noResultsArtist') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release_grid" v-if="results.artistTab.data.length > 0">
|
<div class="release_grid" v-if="results.artistTab.data.length > 0">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in results.artistTab.data"
|
v-for="release in results.artistTab.data"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click.stop="$emit('artist-view', $event)"
|
:key="release.id"
|
||||||
:data-id="release.id"
|
:to="{ name: 'Artist', params: { id: release.id } }"
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="circle coverart" :src="release.picture_medium" />
|
<img aria-hidden="true" class="circle coverart" :src="release.picture_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.name }}</p>
|
<p class="primary-text">{{ release.name }}</p>
|
||||||
<p class="secondary-text">{{ $tc('globals.listTabs.releaseN', release.nb_album) }}</p>
|
<p class="secondary-text">{{ $tc('globals.listTabs.releaseN', release.nb_album) }}</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['results'],
|
props: ['results'],
|
||||||
@ -39,4 +41,4 @@ export default {
|
|||||||
BaseLoadingPlaceholder
|
BaseLoadingPlaceholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -5,23 +5,25 @@
|
|||||||
<h1>{{ $t('search.noResultsPlaylist') }}</h1>
|
<h1>{{ $t('search.noResultsPlaylist') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="release_grid" v-if="results.playlistTab.data.length > 0">
|
<div class="release_grid" v-if="results.playlistTab.data.length > 0">
|
||||||
<div
|
<router-link
|
||||||
|
tag="div"
|
||||||
v-for="release in results.playlistTab.data"
|
v-for="release in results.playlistTab.data"
|
||||||
class="release clickable"
|
class="release clickable"
|
||||||
@click.stop="$emit('playlist-view', $event)"
|
:key="release.id"
|
||||||
:data-id="release.id"
|
:to="{ name: 'Playlist', params: { id: release.id } }"
|
||||||
>
|
>
|
||||||
<div class="cover_container">
|
<div class="cover_container">
|
||||||
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
<img aria-hidden="true" class="rounded coverart" :src="release.picture_medium" />
|
||||||
<div
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="download"
|
aria-label="download"
|
||||||
@click.stop="$emit('add-to-queue', $event)"
|
@click.stop="$emit('add-to-queue', $event)"
|
||||||
:data-link="release.link"
|
:data-link="release.link"
|
||||||
class="download_overlay"
|
class="download_overlay"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
<i class="material-icons" :title="$t('globals.download_hint')">get_app</i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="primary-text">{{ release.title }}</p>
|
<p class="primary-text">{{ release.title }}</p>
|
||||||
<p class="secondary-text">
|
<p class="secondary-text">
|
||||||
@ -29,13 +31,13 @@
|
|||||||
`${$t('globals.by', { artist: release.user.name })} - ${$tc('globals.listTabs.trackN', release.nb_tracks)}`
|
`${$t('globals.by', { artist: release.user.name })} - ${$tc('globals.listTabs.trackN', release.nb_tracks)}`
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['results'],
|
props: ['results'],
|
||||||
@ -43,4 +45,4 @@ export default {
|
|||||||
BaseLoadingPlaceholder
|
BaseLoadingPlaceholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -46,20 +46,20 @@
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td
|
<router-link
|
||||||
|
tag="td"
|
||||||
class="table__cell table__cell--medium table__cell--center breakline clickable"
|
class="table__cell table__cell--medium table__cell--center breakline clickable"
|
||||||
@click.stop="artistView"
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
||||||
:data-id="track.artist.id"
|
|
||||||
>
|
>
|
||||||
{{ track.artist.name }}
|
{{ track.artist.name }}
|
||||||
</td>
|
</router-link>
|
||||||
<td
|
<router-link
|
||||||
|
tag="td"
|
||||||
class="table__cell table__cell--medium table__cell--center breakline clickable"
|
class="table__cell table__cell--medium table__cell--center breakline clickable"
|
||||||
@click.stop="albumView"
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
||||||
:data-id="track.album.id"
|
|
||||||
>
|
>
|
||||||
{{ track.album.title }}
|
{{ track.album.title }}
|
||||||
</td>
|
</router-link>
|
||||||
<td class="table__cell table__cell--small table__cell--center">
|
<td class="table__cell table__cell--small table__cell--center">
|
||||||
{{ convertDuration(track.duration) }}
|
{{ convertDuration(track.duration) }}
|
||||||
</td>
|
</td>
|
||||||
@ -79,9 +79,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseLoadingPlaceholder from '@components/BaseLoadingPlaceholder.vue'
|
import BaseLoadingPlaceholder from '@components/globals/BaseLoadingPlaceholder.vue'
|
||||||
|
|
||||||
import EventBus from '@/utils/EventBus.js'
|
import EventBus from '@/utils/EventBus'
|
||||||
import { convertDuration } from '@/utils/utils'
|
import { convertDuration } from '@/utils/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -91,15 +91,6 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
convertDuration,
|
convertDuration,
|
||||||
artistView(event) {
|
|
||||||
this.$emit('artist-view', event)
|
|
||||||
},
|
|
||||||
albumView(event) {
|
|
||||||
this.$emit('album-view', event)
|
|
||||||
},
|
|
||||||
playlistView(event) {
|
|
||||||
this.$emit('playlist-view', event)
|
|
||||||
},
|
|
||||||
playPausePreview(e) {
|
playPausePreview(e) {
|
||||||
EventBus.$emit('trackPreview:playPausePreview', e)
|
EventBus.$emit('trackPreview:playPausePreview', e)
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export default [
|
export const downloadQualities = [
|
||||||
{
|
{
|
||||||
objName: 'flac',
|
objName: 'flac',
|
||||||
label: 'FLAC',
|
label: 'FLAC',
|
@ -1,93 +0,0 @@
|
|||||||
import EventBus from '@/utils/EventBus'
|
|
||||||
import router from '@/router'
|
|
||||||
|
|
||||||
/* ===== Globals ====== */
|
|
||||||
window.search_selected = ''
|
|
||||||
window.main_selected = ''
|
|
||||||
window.windows_stack = []
|
|
||||||
window.currentStack = {}
|
|
||||||
|
|
||||||
// Used only in errors tab
|
|
||||||
export function changeTab(sidebarEl, section, tabName) {
|
|
||||||
window.windows_stack = []
|
|
||||||
window.currentStack = {}
|
|
||||||
|
|
||||||
// * Only in section search
|
|
||||||
updateTabLink(section)
|
|
||||||
|
|
||||||
// * Only when clicking the settings icon in the sidebar
|
|
||||||
// resetSettings(tabName)
|
|
||||||
|
|
||||||
// * Only in section search
|
|
||||||
setSelectedTab(section, tabName)
|
|
||||||
|
|
||||||
// * Only if window.main_selected === 'search_tab'
|
|
||||||
checkNeedToLoadMoreContent()
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSelectedTab(section, tabName) {
|
|
||||||
if (section === 'main') {
|
|
||||||
window.main_selected = tabName
|
|
||||||
} else if (section === 'search') {
|
|
||||||
window.search_selected = tabName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkNeedToLoadMoreContent() {
|
|
||||||
// * Check if you need to load more content in the search tab
|
|
||||||
// * Happens when the user changes the tab in the main search
|
|
||||||
if (
|
|
||||||
window.main_selected === 'search_tab' &&
|
|
||||||
['track_search', 'album_search', 'artist_search', 'playlist_search'].indexOf(window.search_selected) !== -1
|
|
||||||
) {
|
|
||||||
EventBus.$emit('mainSearch:checkLoadMoreContent', window.search_selected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetSettings(tabName) {
|
|
||||||
if (tabName === 'settings_tab' && window.main_selected !== 'settings_tab') {
|
|
||||||
EventBus.$emit('settingsTab:revertSettings')
|
|
||||||
EventBus.$emit('settingsTab:revertCredentials')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTabLink(section) {
|
|
||||||
// * Tabs inside the actual tab (like albums, tracks, playlists...)
|
|
||||||
// * or sidebar links
|
|
||||||
if (section == 'main') return
|
|
||||||
|
|
||||||
const tabLinks = document.getElementsByClassName(`${section}_tablinks`)
|
|
||||||
|
|
||||||
for (let i = 0; i < tabLinks.length; i++) {
|
|
||||||
tabLinks[i].classList.remove('active')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showView(viewType, event) {
|
|
||||||
const {
|
|
||||||
currentTarget: {
|
|
||||||
dataset: { id }
|
|
||||||
}
|
|
||||||
} = event
|
|
||||||
const isArtist = viewType === 'artist'
|
|
||||||
const name = isArtist ? 'Artist' : 'Tracklist'
|
|
||||||
const params = isArtist ? { id } : { type: viewType, id }
|
|
||||||
|
|
||||||
router.push({
|
|
||||||
name,
|
|
||||||
params
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Goes back to the previous tab according to the global window stack.
|
|
||||||
*/
|
|
||||||
export function backTab() {
|
|
||||||
// ! Need to implement the memory of the opened artist tab
|
|
||||||
router.back()
|
|
||||||
}
|
|
||||||
|
|
||||||
export function init() {
|
|
||||||
// Open default tab
|
|
||||||
changeTab(document.getElementById('main_home_tablink'), 'main', 'home_tab')
|
|
||||||
}
|
|
@ -4,7 +4,6 @@
|
|||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./*"],
|
"@/*": ["./*"],
|
||||||
"@js/*": ["./js/*"],
|
|
||||||
"@components/*": ["./components/*"]
|
"@components/*": ["./components/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -105,7 +105,8 @@ const en = {
|
|||||||
no360RA: 'Track is not available in Reality Audio 360.',
|
no360RA: 'Track is not available in Reality Audio 360.',
|
||||||
notAvailable: "Track not available on Deezer's servers!",
|
notAvailable: "Track not available on Deezer's servers!",
|
||||||
notAvailableNoAlternative: "Track not available on Deezer's servers and no alternative found!",
|
notAvailableNoAlternative: "Track not available on Deezer's servers and no alternative found!",
|
||||||
noSpaceLeft: "No space left on the device!"
|
noSpaceLeft: "No space left on the device!",
|
||||||
|
albumDoesntExists: "Track's album doesn't exist, failed to gather info"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
favorites: {
|
favorites: {
|
||||||
|
@ -105,7 +105,8 @@ const fr = {
|
|||||||
no360RA: 'La piste est indisponible au format Reality Audio 360.',
|
no360RA: 'La piste est indisponible au format Reality Audio 360.',
|
||||||
notAvailable: 'La piste est indisponible sur les serveurs de Deezer !',
|
notAvailable: 'La piste est indisponible sur les serveurs de Deezer !',
|
||||||
notAvailableNoAlternative: "La piste est indisponible sur les serveurs de Deezer et aucune alternative n'a été trouvée !",
|
notAvailableNoAlternative: "La piste est indisponible sur les serveurs de Deezer et aucune alternative n'a été trouvée !",
|
||||||
noSpaceLeft: "L'espace disponible sur cet appareil est insuffisant !"
|
noSpaceLeft: "L'espace disponible sur cet appareil est insuffisant !",
|
||||||
|
albumDoesntExists: "Aucun album n'existe pour cette piste, impossible de collecter les informations nécessaires"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
favorites: {
|
favorites: {
|
||||||
|
33
src/lang/index.js
Normal file
33
src/lang/index.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import it from '@/lang/it'
|
||||||
|
import en from '@/lang/en'
|
||||||
|
import es from '@/lang/es'
|
||||||
|
import de from '@/lang/de'
|
||||||
|
import fr from '@/lang/fr'
|
||||||
|
import id from '@/lang/id'
|
||||||
|
import pt from '@/lang/pt-pt'
|
||||||
|
import pt_br from '@/lang/pt-br'
|
||||||
|
import ru from '@/lang/ru'
|
||||||
|
import tr from '@/lang/tr'
|
||||||
|
import vn from '@/lang/vn'
|
||||||
|
import hr from '@/lang/hr'
|
||||||
|
import ar from '@/lang/ar'
|
||||||
|
import ko from '@/lang/ko'
|
||||||
|
import ph from '@/lang/ph'
|
||||||
|
|
||||||
|
export const locales = {
|
||||||
|
it,
|
||||||
|
en,
|
||||||
|
es,
|
||||||
|
de,
|
||||||
|
fr,
|
||||||
|
id,
|
||||||
|
pt,
|
||||||
|
pt_br,
|
||||||
|
ru,
|
||||||
|
tr,
|
||||||
|
vn,
|
||||||
|
hr,
|
||||||
|
ar,
|
||||||
|
ko,
|
||||||
|
ph
|
||||||
|
}
|
@ -108,7 +108,8 @@ const it = {
|
|||||||
no360RA: 'Brano non disponibile in Reality Audio 360.',
|
no360RA: 'Brano non disponibile in Reality Audio 360.',
|
||||||
notAvailable: 'Brano non presente sui server di Deezer!',
|
notAvailable: 'Brano non presente sui server di Deezer!',
|
||||||
notAvailableNoAlternative: 'Brano non presente sui server di Deezer e nessuna alternativa trovata!',
|
notAvailableNoAlternative: 'Brano non presente sui server di Deezer e nessuna alternativa trovata!',
|
||||||
noSpaceLeft: "Spazio su disco esaurito!"
|
noSpaceLeft: "Spazio su disco esaurito!",
|
||||||
|
albumDoesntExists: "Il brano non ha nessun album, impossibile ottenere informazioni"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
favorites: {
|
favorites: {
|
||||||
|
@ -97,7 +97,7 @@ const ko = {
|
|||||||
wrongBitrateNoAlternative: '요구하는 비트레이트를 찾을 수 없을 뿐더러 대체할 것을 찾지 못했습니다!',
|
wrongBitrateNoAlternative: '요구하는 비트레이트를 찾을 수 없을 뿐더러 대체할 것을 찾지 못했습니다!',
|
||||||
no360RA: '해당 트랙은 360 리얼리티 오디오에 존재하지 않습니다.',
|
no360RA: '해당 트랙은 360 리얼리티 오디오에 존재하지 않습니다.',
|
||||||
notAvailable: "해당 트랙은 Deezer 서버에 존재하지 않습니다!",
|
notAvailable: "해당 트랙은 Deezer 서버에 존재하지 않습니다!",
|
||||||
notAvailableNoAlternative: "해당 트랙은 Deezer 서버에 존재하지 않을 뿐더러 대체할 것을 찾지 못했습니다!"
|
notAvailableNoAlternative: "해당 트랙은 Deezer 서버에 존재하지 않을 뿐더러 대체할 것을 찾지 못했습니다!",
|
||||||
noSpaceLeft: "장치에 여유 공간이 없습니다!"
|
noSpaceLeft: "장치에 여유 공간이 없습니다!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -168,7 +168,7 @@ const ko = {
|
|||||||
finishAddingArtist: '{artist} 앨범이 대기열에 추가되었습니다',
|
finishAddingArtist: '{artist} 앨범이 대기열에 추가되었습니다',
|
||||||
startConvertingSpotifyPlaylist: '스포티파이 트랙을 Deezer 트랙으로 전환 중입니다',
|
startConvertingSpotifyPlaylist: '스포티파이 트랙을 Deezer 트랙으로 전환 중입니다',
|
||||||
finishConvertingSpotifyPlaylist: '스프토파이 재생 목록이 전환되었습니다',
|
finishConvertingSpotifyPlaylist: '스프토파이 재생 목록이 전환되었습니다',
|
||||||
loginNeededToDownload: '트랙을 다운로드하려면 로그인이 필요합니다!'
|
loginNeededToDownload: '트랙을 다운로드하려면 로그인이 필요합니다!',
|
||||||
deezerNotAvailable: 'Deezer 사이트는 현재 귀하의 국가에서 사용이 불가능합니다. VPN을 사용하세요.'
|
deezerNotAvailable: 'Deezer 사이트는 현재 귀하의 국가에서 사용이 불가능합니다. VPN을 사용하세요.'
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
@ -181,8 +181,8 @@ const ko = {
|
|||||||
question: 'ARL을 어떻게 확인합니까?',
|
question: 'ARL을 어떻게 확인합니까?',
|
||||||
update: 'ARL 업데이트'
|
update: 'ARL 업데이트'
|
||||||
},
|
},
|
||||||
logout: '로그아웃'
|
logout: '로그아웃',
|
||||||
question: '스포티파이 기능들을 쓰려면 어떻게 해야합니까?
|
question: '스포티파이 기능들을 쓰려면 어떻게 해야합니까?'
|
||||||
},
|
},
|
||||||
appearance: {
|
appearance: {
|
||||||
title: '외관',
|
title: '외관',
|
||||||
@ -258,7 +258,7 @@ const ko = {
|
|||||||
jpegImageQuality: 'JPEG 이미지 품질',
|
jpegImageQuality: 'JPEG 이미지 품질',
|
||||||
embeddedArtworkPNG: '포함된 그림의 형식을 PNG로 저장합니다',
|
embeddedArtworkPNG: '포함된 그림의 형식을 PNG로 저장합니다',
|
||||||
embeddedPNGWarning: 'PNG는 Deezer에서 공식적으로 지원하지 않기 때문에 버그가 있을 수 있습니다',
|
embeddedPNGWarning: 'PNG는 Deezer에서 공식적으로 지원하지 않기 때문에 버그가 있을 수 있습니다',
|
||||||
imageSizeWarning: 'x1200 크기를 초과해서는 Deezer에서 공식적으로 사용되지 않기 때문에 문제가 생길 수 있습니다'
|
imageSizeWarning: 'x1200 크기를 초과해서는 Deezer에서 공식적으로 사용되지 않기 때문에 문제가 생길 수 있습니다',
|
||||||
coverDescriptionUTF8: '커버 설명을 UTF8 포맷을 이용해 저장합니다 (iTunes 커버 오류 해결)'
|
coverDescriptionUTF8: '커버 설명을 UTF8 포맷을 이용해 저장합니다 (iTunes 커버 오류 해결)'
|
||||||
},
|
},
|
||||||
tags: {
|
tags: {
|
||||||
|
371
src/lang/ph.js
Normal file
371
src/lang/ph.js
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
const ph = {
|
||||||
|
globals: {
|
||||||
|
welcome: 'Welcome sa deemix',
|
||||||
|
back: 'bumalik',
|
||||||
|
loading: 'kumakarga',
|
||||||
|
download: 'I-download {thing}',
|
||||||
|
by: 'ayon sa {artist}',
|
||||||
|
in: 'sa {album}',
|
||||||
|
download_hint: 'I-download',
|
||||||
|
play_hint: 'I-play',
|
||||||
|
toggle_download_tab_hint: 'Palakihin/Paliitan',
|
||||||
|
clean_queue_hint: 'Natapos na ang Pag-alis',
|
||||||
|
cancel_queue_hint: 'Ikansel Lahat',
|
||||||
|
open_downloads_folder: 'Buksan ang Polder ng Download',
|
||||||
|
cut: 'i-cut',
|
||||||
|
copy: 'kopyahin',
|
||||||
|
copyLink: 'kopyahin ang link',
|
||||||
|
copyImageLink: 'kopyahin ang imahe sa link',
|
||||||
|
copyDeezerLink: 'kopyahin ang link ng deezer',
|
||||||
|
paste: 'idikit',
|
||||||
|
listTabs: {
|
||||||
|
empty: '',
|
||||||
|
all: 'lahat',
|
||||||
|
top_result: 'nangungunang resulta',
|
||||||
|
album: 'album | mga album',
|
||||||
|
artist: 'artist | mga artist',
|
||||||
|
single: 'single | mga single',
|
||||||
|
title: 'pamagat | mga pamagat',
|
||||||
|
track: 'track | mga track',
|
||||||
|
trackN: '0 mga track | {n} track | {n} mga track',
|
||||||
|
releaseN: '0 mga release | {n} release | {n} mga release',
|
||||||
|
playlist: 'playlist | mga playlist',
|
||||||
|
compile: 'pinagsama | mga pinagsama',
|
||||||
|
ep: 'ep | mga ep',
|
||||||
|
bundle: 'bundle | mga bundle',
|
||||||
|
more: 'Iba pang mga album',
|
||||||
|
featured: 'Ibinida sa',
|
||||||
|
spotifyPlaylist: 'playlist sa spotify | mga playlist sa spotify',
|
||||||
|
releaseDate: 'petsa ng paglabas',
|
||||||
|
error: 'error'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
about: {
|
||||||
|
updates: {
|
||||||
|
currentVersion: 'Kasalukuyang version',
|
||||||
|
versionNotAvailable: 'H/P',
|
||||||
|
updateAvailable: `Hindi mo ginagamit ang pinakabagong version: {version}`,
|
||||||
|
deemixVersion: 'deemix lib version'
|
||||||
|
},
|
||||||
|
titles: {
|
||||||
|
usefulLinks: 'Nakatutulong na mga Link',
|
||||||
|
bugReports: 'Report sa Bug',
|
||||||
|
contributing: 'Pagtulong',
|
||||||
|
donations: 'Mga donasiyon',
|
||||||
|
license: 'Lisensiya'
|
||||||
|
},
|
||||||
|
subtitles: {
|
||||||
|
bugReports: "Meron bang hindi gumagana sa deemix? Ipaalam mo sa amin!",
|
||||||
|
contributing: 'Gusto mo bang tumulong sa proyektong ito? Pwede mong gawin iyan sa maraming paraan!',
|
||||||
|
donations: 'Gusto mo bang tumulong sa pamamagitan ng pera? Pwede kang magbigay ng donasiyon!'
|
||||||
|
},
|
||||||
|
usesLibrary: 'Ang app na ito ay gumagamit ng library galing sa <strong>deemix</strong>, na kung saan ay pwede mong gamitin para gumawa ng sarili mong UI ng deemix.',
|
||||||
|
thanks: `Salamat kay <strong>rtonno</strong>, <strong>uhwot</strong> at <strong>lollilol</strong> sa pagtulong sa akin para sa proyektong ito at kay <strong>BasCurtiz</strong> at <strong>scarvimane</strong> sa paggawa ng icon.`,
|
||||||
|
upToDate: `Huwag magpapahuli sa mga update patungkol dito sa pamamagitan ng pagsali sa <a href="https://t.me/RemixDevNews" target="_blank">news channel</a> sa Telegram.`,
|
||||||
|
officialWebsite: 'Opisyal na Website',
|
||||||
|
officialRepo: 'Opisyal na Library Repository',
|
||||||
|
officialWebuiRepo: 'Opisyal na Repository ng WebUI',
|
||||||
|
officialSubreddit: 'Opisyal na Subreddit',
|
||||||
|
newsChannel: 'News Channel',
|
||||||
|
questions: `Kung may tanong ka o problema sa app, maghanap ka muna ng solusiyon sa <a href="https://www.reddit.com/r/deemix" target="_blank">subreddit</a>. Ngayon, kung wala ka talagang mahanap ay pwede kang mag-post patungkol sa iyong isyu doon sa subreddit.`,
|
||||||
|
beforeReporting: `Bago ka magreport ng bug, siguraduhing pinakabagong version ang ginagamit mo at ang ire-report mo ay talagang bug at hindi dahil sa pagkakamali mo lang ng paggamit.`,
|
||||||
|
beSure: `Siguraduhing nangyayari rin ang bug sa iba't ibang plataporma at tsaka <strong>HUWAG</strong> mo nang i-report ang bug kung ito ay naipa-alam na ng iba.`,
|
||||||
|
duplicateReports: 'Isasara namin ang mga magkaparehong report sa bug, kaya alamin mo muna.',
|
||||||
|
dontOpenIssues: `<strong>HUWAG</strong> kayong magbubukas ng isyu kung magtatanong lang kayo, meron tayong subreddit para diyan.`,
|
||||||
|
newUI: `Kung ikaw ay maraming alam sa python, subukan mong gumawa ng bagong UI gamit ng base library, o kaya ayusin ang mga bug sa library sa pamamagitan ng pag-pull ng request sa <a href="https://codeberg.org/RemixDev/deemix" target="_blank">repo</a>.`,
|
||||||
|
acceptFeatures: `Tumatangggap din ako ng mga feature, basta hindi komplikado, dahil diretso ko itong nilalagay sa app at hindi sa library.`,
|
||||||
|
otherLanguages: `Kung ikaw ay maraming alam sa ibang programming language, maaari mo ring subukan i-port ang deemix sa iba't ibang programming language!`,
|
||||||
|
understandingCode: `Kailangan mo ba ng tulong para maintindihan ang code? Bisitahin si RemixDev sa Telegram o sa Reddit.`,
|
||||||
|
contributeWebUI: `Kung may alam ka sa Vue.js (JavaScript), HTML o kaya CSS, maaari kang sumali at tumulong dito sa <a href="https://codeberg.org/RemixDev/deemix-webui" target="_blank">WebUI</a>.`,
|
||||||
|
itsFree: `Lagi mong tandaang <strong>ang proyektong ito ay libre</strong> at <strong>suportuhanmuna ang minamahal ninyong mga artist</strong> bago ang mga developer.`,
|
||||||
|
notObligated: `Huwag mong pilitin ang sarili para mag-donate, Naiintindihan ka namin!`,
|
||||||
|
lincensedUnder: `Ang aktibidad na ito ay lisensiyado sa
|
||||||
|
<a rel="license" href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GNU General Public License 3.0</a>.`
|
||||||
|
},
|
||||||
|
charts: {
|
||||||
|
title: 'Mga Chart',
|
||||||
|
changeCountry: 'Palitan ang Country',
|
||||||
|
download: 'I-download ang Chart'
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
title: 'Mga error sa {name}',
|
||||||
|
ids: {
|
||||||
|
invalidURL: 'Hindi makilala ang URL',
|
||||||
|
unsupportedURL: 'Hindi pa suportado ang URL',
|
||||||
|
ISRCnotOnDeezer: 'Ang Track ISRC ay hindi pwede sa Deezer',
|
||||||
|
notYourPrivatePlaylist: "Hindi pwedeng i-download ang mga pribadong playlist ng iba.",
|
||||||
|
spotifyDisabled: 'Hindi mo nai-set nang tama ang Spotify Features.',
|
||||||
|
trackNotOnDeezer: 'Hindi mahanap ang track sa Deezer!',
|
||||||
|
albumNotOnDeezer: 'Hindi mahanap ang album sa Deezer!',
|
||||||
|
notOnDeezer: 'Hindi available ang track sa Deezer!',
|
||||||
|
notEncoded: 'Hindi pa nae-encode ang track!',
|
||||||
|
notEncodedNoAlternative: 'Hindi pa nae-encode ang track at walang mahanap na iba!',
|
||||||
|
wrongBitrate: 'Hindi mahanap ang track sa gusto mong bitrate.',
|
||||||
|
wrongBitrateNoAlternative: 'Hindi mahanap ang track sa gusto mong bitrate at walang mahanap na iba!',
|
||||||
|
no360RA: 'Hindi pwede ang track para sa Reality Audio 360.',
|
||||||
|
notAvailable: "Walang available na track sa server ng Deezer!",
|
||||||
|
notAvailableNoAlternative: "Walang available na track sa server ng Deezer at walang mahanap na iba!",
|
||||||
|
noSpaceLeft: "Wala nang natitirang space sa iyong device!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
favorites: {
|
||||||
|
title: 'Mga Paborito',
|
||||||
|
noPlaylists: 'Walang makitang mga Playlist',
|
||||||
|
noAlbums: 'Walang makitang mga Paboritong Album',
|
||||||
|
noArtists: 'Walang makitang mga Paboritong Artist',
|
||||||
|
noTracks: 'Walang makitang mga Paboritong Track'
|
||||||
|
},
|
||||||
|
home: {
|
||||||
|
needTologin: 'Kailangan mong mag-log in sa iyong Deezer account bago ka makasimulang magdownload.',
|
||||||
|
openSettings: 'Buksan ang Mga Setting',
|
||||||
|
sections: {
|
||||||
|
popularPlaylists: 'Mga sikat na playlist',
|
||||||
|
popularAlbums: 'Pinakamaraming pinakikinggang mga album'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
linkAnalyzer: {
|
||||||
|
info: 'Pwede gamitin ang section na ito para sa iba pang impormasyon patungkol sa link na gusto mong i-download.',
|
||||||
|
useful: "Makatutulong ito kung meron kang gustong i-download na track na hindi available sa bansa mo at gusto mong malaman kung meron bang ganito kapag sa iba.",
|
||||||
|
linkNotSupported: 'Hindi pa suportado ang link',
|
||||||
|
linkNotSupportedYet: 'Mukhang hindi pa suportado itong link, iba na lang ang ilagay mo.',
|
||||||
|
table: {
|
||||||
|
id: 'ID',
|
||||||
|
isrc: 'ISRC',
|
||||||
|
upc: 'UPC',
|
||||||
|
duration: 'Haba',
|
||||||
|
diskNumber: 'Bilang ng Disk',
|
||||||
|
trackNumber: 'Bilang ng Track',
|
||||||
|
releaseDate: 'Petsa ng Release',
|
||||||
|
bpm: 'BPM',
|
||||||
|
label: 'Label',
|
||||||
|
recordType: 'Uri ng Rekord',
|
||||||
|
genres: 'Mga Genre',
|
||||||
|
tracklist: 'Listahan ng Track'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
startSearching: 'Simulang Maghanap!',
|
||||||
|
description: 'Pwede kang maghanap ng track, buong album, artist, playlist.... kahit ano! Pwede ka ring mag-paste dito ng link na galing sa Deezer',
|
||||||
|
fans: '{n} mga fan',
|
||||||
|
noResults: 'Walang resulta',
|
||||||
|
noResultsTrack: 'Walang mahanap na mga Track',
|
||||||
|
noResultsAlbum: 'Walang mahanap na mga Album',
|
||||||
|
noResultsArtist: 'Walang mahanap na mga Artist',
|
||||||
|
noResultsPlaylist: 'Walang mahanap na mga Playlist'
|
||||||
|
},
|
||||||
|
searchbar: 'Maghanap ka ng gusto mo (o mag-paste ka ng link)',
|
||||||
|
downloads: 'mga download',
|
||||||
|
toasts: {
|
||||||
|
restoringQueue: 'Binabalik ang download queue...',
|
||||||
|
queueRestored: 'Naibalik na ang download queue!',
|
||||||
|
addedToQueue: '{item} ay naidagdag sa queue',
|
||||||
|
addedMoreToQueue: '{n} naidagdag rin sa queue',
|
||||||
|
alreadyInQueue: '{item} ay meron na sa queue!',
|
||||||
|
finishDownload: '{item} ay natapos nang i-download.',
|
||||||
|
allDownloaded: 'Nadownload na lahat!',
|
||||||
|
refreshFavs: 'Narefresh na!',
|
||||||
|
loggingIn: 'Nagla-log in...',
|
||||||
|
loggedIn: 'Na-login na',
|
||||||
|
alreadyLogged: 'Nakalogin ka na',
|
||||||
|
loginFailed: "Hindi maka-log in",
|
||||||
|
loggedOut: 'Na-logout na',
|
||||||
|
cancellingCurrentItem: 'Kinakansel ang item.',
|
||||||
|
currentItemCancelled: 'Nakansel na ang item.',
|
||||||
|
startAddingArtist: 'Idinadagdag si {artist} sa queue ng mga album',
|
||||||
|
finishAddingArtist: 'Naidagdag na si {artist} sa queue ng mga album',
|
||||||
|
startConvertingSpotifyPlaylist: 'Kino-convert ang mga track sa spotify papuntang Deezer',
|
||||||
|
finishConvertingSpotifyPlaylist: 'Naconvert na ang playlist sa Spotify',
|
||||||
|
loginNeededToDownload: 'Kailangan mong mag-login para madownload ang mga track!',
|
||||||
|
deezerNotAvailable: 'Hindi available ang Deezer sa iyong bansa. Kailangan mong gumamit ng VPN.'
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
title: 'Mga Setting',
|
||||||
|
languages: 'Mga Wika',
|
||||||
|
login: {
|
||||||
|
title: 'Login',
|
||||||
|
loggedIn: 'Ikaw ay naka-login sa pangalang {username}',
|
||||||
|
arl: {
|
||||||
|
question: 'Paano ako makakuha ng sariling ARL?',
|
||||||
|
update: 'I-update ang ARL'
|
||||||
|
},
|
||||||
|
logout: 'Logout',
|
||||||
|
login: 'Mag-login gamit ng deezer.com'
|
||||||
|
},
|
||||||
|
appearance: {
|
||||||
|
title: 'Hitsura',
|
||||||
|
slimDownloadTab: 'Pinaliit na download tab'
|
||||||
|
},
|
||||||
|
downloadPath: {
|
||||||
|
title: 'Paglalagyan ng Download'
|
||||||
|
},
|
||||||
|
templates: {
|
||||||
|
title: 'Mga Template',
|
||||||
|
tracknameTemplate: 'Template sa pangalan ng Track',
|
||||||
|
albumTracknameTemplate: 'Template sa track ng Album',
|
||||||
|
playlistTracknameTemplate: 'Template sa track ng Playlist'
|
||||||
|
},
|
||||||
|
folders: {
|
||||||
|
title: 'Mga Folder',
|
||||||
|
createPlaylistFolder: 'Gumawa ng folder para sa mga playlist',
|
||||||
|
playlistNameTemplate: 'Template sa folder ng Playlist',
|
||||||
|
createArtistFolder: 'Gumawa ng folder para sa artist',
|
||||||
|
artistNameTemplate: 'Template sa folder ng Artist',
|
||||||
|
createAlbumFolder: 'Gumawa ng folder para sa album',
|
||||||
|
albumNameTemplate: 'Template sa folder ng Album',
|
||||||
|
createCDFolder: 'Gumawa ng folder para sa mga CD',
|
||||||
|
createStructurePlaylist: 'Gumawa ng istraktura ng folder para sa mga playlist',
|
||||||
|
createSingleFolder: 'Gumawa ng istraktura ng folder para sa mga single'
|
||||||
|
},
|
||||||
|
trackTitles: {
|
||||||
|
title: 'Pamagat sa mga track',
|
||||||
|
padTracks: 'Mga track ng Pad',
|
||||||
|
paddingSize: 'Patungan ang laki ng padding',
|
||||||
|
illegalCharacterReplacer: 'Pamalit sa ilegal na Karakter'
|
||||||
|
},
|
||||||
|
downloads: {
|
||||||
|
title: 'Mga Download',
|
||||||
|
queueConcurrency: 'Mga Kasabay na Download',
|
||||||
|
maxBitrate: {
|
||||||
|
title: 'Gustong Bitrate',
|
||||||
|
9: 'FLAC 1411kbps',
|
||||||
|
3: 'MP3 320kbps',
|
||||||
|
1: 'MP3 128kbps'
|
||||||
|
},
|
||||||
|
overwriteFile: {
|
||||||
|
title: 'Papatungan ko ba ang file?',
|
||||||
|
y: 'Oo, patungan mo ang file',
|
||||||
|
n: "Hindi, huwag mong patungan ang file",
|
||||||
|
t: 'Patungan mo lang ang mga tag',
|
||||||
|
b: 'Hindi, hayaan mo silang dalawa at lagyan mo lang ng numero sa kapareho niya',
|
||||||
|
e: "Hindi, at huwag mong tignan ang mga extension"
|
||||||
|
},
|
||||||
|
fallbackBitrate: 'Binabaang bitrate',
|
||||||
|
fallbackSearch: 'Maghanap para sa binabaan',
|
||||||
|
logErrors: 'Gumawa ng log file para sa mga error',
|
||||||
|
logSearched: 'Gumawa ng log file para sa mga hinanap na track',
|
||||||
|
createM3U8File: 'Gumawa ng file sa playlist',
|
||||||
|
syncedLyrics: 'Gumawa ng mga .lyr file (Mga Sync Lyric)',
|
||||||
|
playlistFilenameTemplate: 'Template sa pangalan ng Playlist file',
|
||||||
|
saveDownloadQueue: 'I-save ang download queue kapag isasara the app'
|
||||||
|
},
|
||||||
|
covers: {
|
||||||
|
title: 'Mga cover ng album',
|
||||||
|
saveArtwork: 'I-save ang mga Cover',
|
||||||
|
coverImageTemplate: 'Template ng pangalan ng cover',
|
||||||
|
saveArtworkArtist: 'I-save ang imahe ng artist',
|
||||||
|
artistImageTemplate: 'Template ng imahe ng artist',
|
||||||
|
localArtworkSize: 'Laki ng lokal na artwork',
|
||||||
|
embeddedArtworkSize: 'Laki ng Nakadikit na artwork',
|
||||||
|
localArtworkFormat: {
|
||||||
|
title: 'Anong gusto mong format para sa mga lokal na artwork?',
|
||||||
|
jpg: 'jpeg na imahe',
|
||||||
|
png: 'png na imahe',
|
||||||
|
both: 'Parehong jpeg at png'
|
||||||
|
},
|
||||||
|
jpegImageQuality: 'Kalidad ng JPEG na imahe',
|
||||||
|
embeddedArtworkPNG: 'I-save ang nakadikit na artwork bilang PNG',
|
||||||
|
embeddedPNGWarning: 'Ang mga PNG ay hindi opisyal na suportado ng Deezer at maaaring magkaroon ng bug',
|
||||||
|
imageSizeWarning: 'Lahat ng mas mataas sa x1200 ay hindi opisyal na ginagamit sa Deezer, at posibleng magkaroon ng isyu',
|
||||||
|
coverDescriptionUTF8: 'I-save ang deskripsyon ng cover gamit ng UTF8 (iTunes Cover Fix)'
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
head: 'Aling tag ang ise-save',
|
||||||
|
title: 'Pamagat',
|
||||||
|
artist: 'Artist',
|
||||||
|
album: 'Album',
|
||||||
|
cover: 'Cover',
|
||||||
|
trackNumber: 'Bilang ng Track',
|
||||||
|
trackTotal: 'Kabuuang Track',
|
||||||
|
discNumber: 'Bilang ng Disk',
|
||||||
|
discTotal: 'Kabuuang Disk',
|
||||||
|
albumArtist: 'Album Artist',
|
||||||
|
genre: 'Genre',
|
||||||
|
year: 'Taon',
|
||||||
|
date: 'Petsa',
|
||||||
|
explicit: 'Mga Explicit na Lyric',
|
||||||
|
isrc: 'ISRC',
|
||||||
|
length: 'Haba ng Track',
|
||||||
|
barcode: 'Barcode ng Album (UPC)',
|
||||||
|
bpm: 'BPM',
|
||||||
|
replayGain: 'Replay Gain',
|
||||||
|
label: 'Label ng Album',
|
||||||
|
lyrics: 'Unsynchronized na mga Lyric',
|
||||||
|
syncedLyrics: 'Synchronized na mga Lyric',
|
||||||
|
copyright: 'Karapatang Ari',
|
||||||
|
composer: 'Komposer',
|
||||||
|
involvedPeople: 'Mga Kasamang Tao'
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
title: 'Iba pa',
|
||||||
|
savePlaylistAsCompilation: 'I-save ang mga playlist bilang compilation',
|
||||||
|
useNullSeparator: 'Gumamit ng panghiwalay sa null',
|
||||||
|
saveID3v1: 'I-save rin ang ID3v1',
|
||||||
|
multiArtistSeparator: {
|
||||||
|
title: 'Anong gusto mo para maihanay mga artist?',
|
||||||
|
nothing: 'I-save lang ang pangunahing artist',
|
||||||
|
default: 'Gamit ng standard na specification',
|
||||||
|
andFeat: 'Gamit ng & at feat.',
|
||||||
|
using: 'Gamit ng "{separator}"'
|
||||||
|
},
|
||||||
|
singleAlbumArtist: 'I-save lang ang pangunahing album ng artist',
|
||||||
|
albumVariousArtists: 'Isama ang "Various Artists" sa mga Album Artist',
|
||||||
|
removeAlbumVersion: 'Tanggalin ang "Album Version" sa pamagat ng track',
|
||||||
|
removeDuplicateArtists: 'Tanggalin ang kombinasyon ng mga artist',
|
||||||
|
dateFormat: {
|
||||||
|
title: 'Format ng petsa para sa mga FLAC file',
|
||||||
|
year: 'YYYY',
|
||||||
|
month: 'MM',
|
||||||
|
day: 'DD'
|
||||||
|
},
|
||||||
|
featuredToTitle: {
|
||||||
|
title: 'Anong gagawin ko sa mga itinampok na artist',
|
||||||
|
0: 'Wala',
|
||||||
|
1: 'Tanggalin mo sila sa Pamagat',
|
||||||
|
3: 'Tanggalin mo sila sa Pamagat mismo at Pamagat ng Album',
|
||||||
|
2: 'Ilipat mo sila sa pamagat'
|
||||||
|
},
|
||||||
|
titleCasing: 'Pagleletra sa Pamagat',
|
||||||
|
artistCasing: 'Pagleletra sa Artist',
|
||||||
|
casing: {
|
||||||
|
nothing: 'Walang babaguhin',
|
||||||
|
lower: 'maliliit',
|
||||||
|
upper: 'MALALAKI',
|
||||||
|
start: 'Simula Ng Bawata Salita',
|
||||||
|
sentence: 'Kagaya ng pangungusap'
|
||||||
|
},
|
||||||
|
previewVolume: 'Volume ng Preview',
|
||||||
|
executeCommand: {
|
||||||
|
title: 'Mga gagawin pagkatapos ng download',
|
||||||
|
description: 'Hayaan lang na blangko kung wala'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
spotify: {
|
||||||
|
title: 'Spotify Features',
|
||||||
|
clientID: 'Spotify ClientID',
|
||||||
|
clientSecret: 'Spotify Client Secret',
|
||||||
|
username: 'Spotify Username',
|
||||||
|
question: 'Paano ma-enable ang Spotify Features?'
|
||||||
|
},
|
||||||
|
reset: 'Ibalik sa Dati',
|
||||||
|
save: 'I-save',
|
||||||
|
toasts: {
|
||||||
|
init: 'Ikinarga ang mga Setting!',
|
||||||
|
update: 'In-update ang mga Setting!',
|
||||||
|
ARLcopied: 'Kinopya ang ARL sa clipboard'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sidebar: {
|
||||||
|
home: 'tahanan',
|
||||||
|
search: 'maghanap',
|
||||||
|
charts: 'mga chart',
|
||||||
|
favorites: 'mga paborito',
|
||||||
|
linkAnalyzer: 'tagasuri ng link',
|
||||||
|
settings: 'mga setting',
|
||||||
|
about: 'tungkol sa'
|
||||||
|
},
|
||||||
|
tracklist: {
|
||||||
|
downloadSelection: 'Pagpipili ng download'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ph
|
@ -39,11 +39,12 @@
|
|||||||
license: 'Licença'
|
license: 'Licença'
|
||||||
},
|
},
|
||||||
subtitles: {
|
subtitles: {
|
||||||
bugReports: "Há algo não funcionando no deemix? Nos diga!",
|
bugReports: 'Há algo não funcionando no deemix? Nos diga!',
|
||||||
contributing: 'Você quer contribuir para este projeto? Você pode fazer isso de diferentes maneiras!',
|
contributing: 'Você quer contribuir para este projeto? Você pode fazer isso de diferentes maneiras!',
|
||||||
donations: 'Você quer contribuir monetariamente? Você pode fazer uma doação!'
|
donations: 'Você quer contribuir monetariamente? Você pode fazer uma doação!'
|
||||||
},
|
},
|
||||||
usesLibrary: 'Esse app usa a biblioteca do <strong>deemix</strong>, no qual você pode usar para criar sua própria UI para o deemix',
|
usesLibrary:
|
||||||
|
'Esse app usa a biblioteca do <strong>deemix</strong>, no qual você pode usar para criar sua própria UI para o deemix',
|
||||||
thanks: `Agradecimentos para <strong>rtonno</strong>, <strong>uhwot</strong> e <strong>lollilol</strong> por ajudar neste projeto, e para <strong>BasCurtiz</strong> e <strong>scarvimane</strong> por fazerem o ícone`,
|
thanks: `Agradecimentos para <strong>rtonno</strong>, <strong>uhwot</strong> e <strong>lollilol</strong> por ajudar neste projeto, e para <strong>BasCurtiz</strong> e <strong>scarvimane</strong> por fazerem o ícone`,
|
||||||
upToDate: `Para mais novidades siga o <a href="https://t.me/RemixDevNews" target="_blank">news channel</a> no Telegram.`,
|
upToDate: `Para mais novidades siga o <a href="https://t.me/RemixDevNews" target="_blank">news channel</a> no Telegram.`,
|
||||||
officialWebsite: 'Site Oficial',
|
officialWebsite: 'Site Oficial',
|
||||||
@ -79,7 +80,7 @@
|
|||||||
invalidURL: 'URL inválida',
|
invalidURL: 'URL inválida',
|
||||||
unsupportedURL: 'URL não suportada ainda',
|
unsupportedURL: 'URL não suportada ainda',
|
||||||
ISRCnotOnDeezer: 'Faixa ISRC não está disponível ainda no deezer',
|
ISRCnotOnDeezer: 'Faixa ISRC não está disponível ainda no deezer',
|
||||||
notYourPrivatePlaylist: "Você não pode baixar playlists privadas.",
|
notYourPrivatePlaylist: 'Você não pode baixar playlists privadas.',
|
||||||
spotifyDisabled: 'Os Recursos do Spotify não foram configurados corretamente.',
|
spotifyDisabled: 'Os Recursos do Spotify não foram configurados corretamente.',
|
||||||
trackNotOnDeezer: 'Faixa não encontrada no deezer!',
|
trackNotOnDeezer: 'Faixa não encontrada no deezer!',
|
||||||
albumNotOnDeezer: 'Album not found on deezer! Álbum não encontrado no deezer!',
|
albumNotOnDeezer: 'Album not found on deezer! Álbum não encontrado no deezer!',
|
||||||
@ -89,8 +90,8 @@
|
|||||||
wrongBitrate: 'Faixa não encontrada no bitrate desejado.',
|
wrongBitrate: 'Faixa não encontrada no bitrate desejado.',
|
||||||
wrongBitrateNoAlternative: 'Faixa não encontrada no bitrate desejado e nenhuma outra alternativa encontrada!',
|
wrongBitrateNoAlternative: 'Faixa não encontrada no bitrate desejado e nenhuma outra alternativa encontrada!',
|
||||||
no360RA: 'Faixa não disponível na qualidade Reality Audio 360.',
|
no360RA: 'Faixa não disponível na qualidade Reality Audio 360.',
|
||||||
notAvailable: "Faixa não disponível nos servidores do deezer!",
|
notAvailable: 'Faixa não disponível nos servidores do deezer!',
|
||||||
notAvailableNoAlternative: "Faixa não disponível nos servidores do deezer e nenhuma outra alternativa encontrada!"
|
notAvailableNoAlternative: 'Faixa não disponível nos servidores do deezer e nenhuma outra alternativa encontrada!'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
favorites: {
|
favorites: {
|
||||||
@ -111,7 +112,7 @@
|
|||||||
linkAnalyzer: {
|
linkAnalyzer: {
|
||||||
info: 'Você pode usar essa seção para encontrar mais informações sobre o link que você quer baixar.',
|
info: 'Você pode usar essa seção para encontrar mais informações sobre o link que você quer baixar.',
|
||||||
useful:
|
useful:
|
||||||
"Isso é útil se você está tentando baixar algumas faixas que não estão disponíveis no seu país, e quer saber onde elas estão disponíveis, por exemplo.",
|
'Isso é útil se você está tentando baixar algumas faixas que não estão disponíveis no seu país, e quer saber onde elas estão disponíveis, por exemplo.',
|
||||||
linkNotSupported: 'Esse link não é suportado ainda',
|
linkNotSupported: 'Esse link não é suportado ainda',
|
||||||
linkNotSupportedYet: 'Parece que esse link não é suportado ainda, tente analizar outro.',
|
linkNotSupportedYet: 'Parece que esse link não é suportado ainda, tente analizar outro.',
|
||||||
table: {
|
table: {
|
||||||
@ -151,7 +152,7 @@
|
|||||||
loggingIn: 'Logando',
|
loggingIn: 'Logando',
|
||||||
loggedIn: 'Logado',
|
loggedIn: 'Logado',
|
||||||
alreadyLogged: 'Você já está logado',
|
alreadyLogged: 'Você já está logado',
|
||||||
loginFailed: "Não foi possivel entrar",
|
loginFailed: 'Não foi possivel entrar',
|
||||||
loggedOut: 'Desconectando',
|
loggedOut: 'Desconectando',
|
||||||
cancellingCurrentItem: 'Cancelando item atual.',
|
cancellingCurrentItem: 'Cancelando item atual.',
|
||||||
currentItemCancelled: 'Item atual cancelado.',
|
currentItemCancelled: 'Item atual cancelado.',
|
||||||
@ -215,7 +216,7 @@
|
|||||||
overwriteFile: {
|
overwriteFile: {
|
||||||
title: 'Sobrescrever arquivos?',
|
title: 'Sobrescrever arquivos?',
|
||||||
y: 'Sim, sobrescrever arquivos',
|
y: 'Sim, sobrescrever arquivos',
|
||||||
n: "Não, não sobrescrever arquivos",
|
n: 'Não, não sobrescrever arquivos',
|
||||||
t: 'Sobrescrever apenas as tags'
|
t: 'Sobrescrever apenas as tags'
|
||||||
},
|
},
|
||||||
fallbackBitrate: 'Taxa de bits reserva',
|
fallbackBitrate: 'Taxa de bits reserva',
|
||||||
|
@ -1,54 +1,24 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import VueI18n from 'vue-i18n'
|
import VueI18n from 'vue-i18n'
|
||||||
|
|
||||||
// Languages
|
import { locales } from '@/lang/index'
|
||||||
import it from '@/lang/it'
|
|
||||||
import en from '@/lang/en'
|
|
||||||
import es from '@/lang/es'
|
|
||||||
import de from '@/lang/de'
|
|
||||||
import fr from '@/lang/fr'
|
|
||||||
import id from '@/lang/id'
|
|
||||||
import pt from '@/lang/pt-pt'
|
|
||||||
import pt_br from '@/lang/pt-br'
|
|
||||||
import ru from '@/lang/ru'
|
|
||||||
import tr from '@/lang/tr'
|
|
||||||
import vn from '@/lang/vn'
|
|
||||||
import hr from '@/lang/hr'
|
|
||||||
import ar from '@/lang/ar'
|
|
||||||
import ko from '@/lang/ko'
|
|
||||||
|
|
||||||
Vue.use(VueI18n)
|
Vue.use(VueI18n)
|
||||||
|
|
||||||
const DEFAULT_LANG = 'en'
|
const storedLocale = localStorage.getItem('locale')
|
||||||
|
const DEFAULT_LANG = storedLocale || 'en'
|
||||||
|
|
||||||
document.querySelector('html').setAttribute('lang', DEFAULT_LANG)
|
document.querySelector('html').setAttribute('lang', DEFAULT_LANG)
|
||||||
|
|
||||||
const locales = {
|
|
||||||
it,
|
|
||||||
en,
|
|
||||||
es,
|
|
||||||
de,
|
|
||||||
fr,
|
|
||||||
id,
|
|
||||||
pt,
|
|
||||||
pt_br,
|
|
||||||
ru,
|
|
||||||
tr,
|
|
||||||
vn,
|
|
||||||
hr,
|
|
||||||
ar,
|
|
||||||
ko
|
|
||||||
}
|
|
||||||
|
|
||||||
const i18n = new VueI18n({
|
const i18n = new VueI18n({
|
||||||
locale: DEFAULT_LANG,
|
locale: DEFAULT_LANG,
|
||||||
fallbackLocale: DEFAULT_LANG,
|
fallbackLocale: 'en',
|
||||||
messages: locales,
|
messages: locales,
|
||||||
pluralizationRules: {
|
pluralizationRules: {
|
||||||
/**
|
/**
|
||||||
* @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
|
* @param {number} choice A choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
|
||||||
* @param choicesLength {number} an overall amount of available choices
|
* @param {number} choicesLength An overall amount of available choices
|
||||||
* @returns a final choice index to select plural word by
|
* @returns A final choice index to select plural word by
|
||||||
*/
|
*/
|
||||||
ru: function(choice, choicesLength) {
|
ru: function(choice, choicesLength) {
|
||||||
var n = Math.abs(choice) % 100
|
var n = Math.abs(choice) % 100
|
||||||
|
@ -3,17 +3,17 @@ import VueRouter from 'vue-router'
|
|||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import EventBus from '@/utils/EventBus'
|
import EventBus from '@/utils/EventBus'
|
||||||
|
|
||||||
import ArtistTab from '@components/ArtistTab.vue'
|
// Pages
|
||||||
import TracklistTab from '@components/TracklistTab.vue'
|
import About from '@components/pages/About.vue'
|
||||||
|
import Artist from '@components/pages/Artist.vue'
|
||||||
import TheHomeTab from '@components/TheHomeTab.vue'
|
import Charts from '@components/pages/Charts.vue'
|
||||||
import TheChartsTab from '@components/TheChartsTab.vue'
|
import Errors from '@components/pages/Errors.vue'
|
||||||
import TheFavoritesTab from '@components/TheFavoritesTab.vue'
|
import Favorites from '@components/pages/Favorites.vue'
|
||||||
import TheErrorsTab from '@components/TheErrorsTab.vue'
|
import Home from '@components/pages/Home.vue'
|
||||||
import TheLinkAnalyzerTab from '@components/TheLinkAnalyzerTab.vue'
|
import LinkAnalyzer from '@components/pages/LinkAnalyzer.vue'
|
||||||
import TheAboutTab from '@components/TheAboutTab.vue'
|
import Search from '@components/pages/Search.vue'
|
||||||
import TheSettingsTab from '@components/TheSettingsTab.vue'
|
import Settings from '@components/pages/Settings.vue'
|
||||||
import TheMainSearch from '@components/TheMainSearch.vue'
|
import Tracklist from '@components/pages/Tracklist.vue'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: TheHomeTab,
|
component: Home,
|
||||||
meta: {
|
meta: {
|
||||||
notKeepAlive: true
|
notKeepAlive: true
|
||||||
}
|
}
|
||||||
@ -29,17 +29,32 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/tracklist/:type/:id',
|
path: '/tracklist/:type/:id',
|
||||||
name: 'Tracklist',
|
name: 'Tracklist',
|
||||||
component: TracklistTab
|
component: Tracklist
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/artist/:id',
|
path: '/artist/:id',
|
||||||
name: 'Artist',
|
name: 'Artist',
|
||||||
component: ArtistTab
|
component: Artist
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/album/:id',
|
||||||
|
name: 'Album',
|
||||||
|
component: Tracklist
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/tracklist/:id',
|
||||||
|
name: 'Playlist',
|
||||||
|
component: Tracklist
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/tracklist/:id',
|
||||||
|
name: 'Spotify Playlist',
|
||||||
|
component: Tracklist
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/charts',
|
path: '/charts',
|
||||||
name: 'Charts',
|
name: 'Charts',
|
||||||
component: TheChartsTab,
|
component: Charts,
|
||||||
meta: {
|
meta: {
|
||||||
notKeepAlive: true
|
notKeepAlive: true
|
||||||
}
|
}
|
||||||
@ -47,7 +62,7 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/favorites',
|
path: '/favorites',
|
||||||
name: 'Favorites',
|
name: 'Favorites',
|
||||||
component: TheFavoritesTab,
|
component: Favorites,
|
||||||
meta: {
|
meta: {
|
||||||
notKeepAlive: true
|
notKeepAlive: true
|
||||||
}
|
}
|
||||||
@ -55,32 +70,32 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/errors',
|
path: '/errors',
|
||||||
name: 'Errors',
|
name: 'Errors',
|
||||||
component: TheErrorsTab
|
component: Errors
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/link-analyzer',
|
path: '/link-analyzer',
|
||||||
name: 'Link Analyzer',
|
name: 'Link Analyzer',
|
||||||
component: TheLinkAnalyzerTab
|
component: LinkAnalyzer
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
name: 'About',
|
name: 'About',
|
||||||
component: TheAboutTab
|
component: About
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
name: 'Settings',
|
name: 'Settings',
|
||||||
component: TheSettingsTab
|
component: Settings
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/search',
|
path: '/search',
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
component: TheMainSearch
|
component: Search
|
||||||
},
|
},
|
||||||
// 404 client side
|
// 404 client side
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
component: TheHomeTab
|
component: Home
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -109,6 +124,24 @@ router.beforeEach((to, from, next) => {
|
|||||||
id: to.params.id
|
id: to.params.id
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'Album':
|
||||||
|
getTracklistParams = {
|
||||||
|
type: 'album',
|
||||||
|
id: to.params.id
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'Playlist':
|
||||||
|
getTracklistParams = {
|
||||||
|
type: 'playlist',
|
||||||
|
id: to.params.id
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'Spotify Playlist':
|
||||||
|
getTracklistParams = {
|
||||||
|
type: 'spotifyplaylist',
|
||||||
|
id: to.params.id
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -72,7 +72,9 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
RESET_LOGIN(state) {
|
RESET_LOGIN(state) {
|
||||||
// Needed for reactivity
|
// Needed for reactivity
|
||||||
|
let clientMode = state.clientMode
|
||||||
Object.assign(state, getDefaultState())
|
Object.assign(state, getDefaultState())
|
||||||
|
state.clientMode = clientMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,58 +1,9 @@
|
|||||||
/* Center section */
|
|
||||||
$icon-dimension: 2rem;
|
|
||||||
$searchbar-height: calc(2rem + 1em);
|
|
||||||
|
|
||||||
#search {
|
#search {
|
||||||
background-color: var(--secondary-background);
|
|
||||||
width: 100%;
|
|
||||||
padding: 0 1em;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
margin-right: 32px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
transition: border 200ms ease-in-out;
|
|
||||||
|
|
||||||
.search__icon {
|
.search__icon {
|
||||||
width: $icon-dimension;
|
|
||||||
height: $icon-dimension;
|
|
||||||
|
|
||||||
i {
|
i {
|
||||||
font-size: $icon-dimension;
|
|
||||||
color: var(--foreground);
|
|
||||||
|
|
||||||
@include remove-selection-background;
|
@include remove-selection-background;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus-within {
|
|
||||||
border: 1px solid var(--foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchbar {
|
|
||||||
height: $searchbar-height;
|
|
||||||
padding-left: 0.5em;
|
|
||||||
border: 0px;
|
|
||||||
border-radius: 0px;
|
|
||||||
background-color: var(--secondary-background);
|
|
||||||
color: var(--foreground);
|
|
||||||
font-size: 2rem;
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-weight: 300;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removing Chrome autofill color
|
|
||||||
&:-webkit-autofill,
|
|
||||||
&:-webkit-autofill:hover,
|
|
||||||
&:-webkit-autofill:focus,
|
|
||||||
&:-webkit-autofill:active {
|
|
||||||
-webkit-box-shadow: 0 0 0 $searchbar-height var(--secondary-background) inset !important;
|
|
||||||
box-shadow: 0 0 0 $searchbar-height var(--secondary-background) inset !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
|
@ -20,6 +20,8 @@ $sidebar-delay: 75ms;
|
|||||||
|
|
||||||
.main_tablinks {
|
.main_tablinks {
|
||||||
transition: all 500ms;
|
transition: all 500ms;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
|
@ -295,14 +295,22 @@ a {
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
background-color: #000000;
|
||||||
|
border-radius: 50%;
|
||||||
|
min-width: 32px;
|
||||||
|
padding: 0px;
|
||||||
|
height: 44px;
|
||||||
|
border: 0px;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
background-color: #000000;
|
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 50%;
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -312,6 +320,7 @@ a {
|
|||||||
|
|
||||||
.download_overlay {
|
.download_overlay {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
border: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ export async function adjustVolume(element, newVolume, { duration = 1000, easing
|
|||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const timer = setInterval(() => {
|
const timer = setInterval(() => {
|
||||||
element.volume = originalVolume + easing(tick / ticks) * delta
|
element.volume = originalVolume + easing(tick / ticks) * delta
|
||||||
// console.log(element.volume)
|
|
||||||
if (++tick === ticks) {
|
if (++tick === ticks) {
|
||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
resolve()
|
resolve()
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
import it from 'svg-country-flags/svg/it.svg'
|
import it from 'svg-country-flags/svg/it.svg'
|
||||||
import gb from 'svg-country-flags/svg/gb.svg'
|
import gb from 'svg-country-flags/svg/gb.svg'
|
||||||
import es from 'svg-country-flags/svg/es.svg'
|
import es from 'flag-icon-css/flags/4x3/es.svg'
|
||||||
import de from 'svg-country-flags/svg/de.svg'
|
import de from 'svg-country-flags/svg/de.svg'
|
||||||
import fr from 'svg-country-flags/svg/fr.svg'
|
import fr from 'svg-country-flags/svg/fr.svg'
|
||||||
import id from 'svg-country-flags/svg/id.svg'
|
import id from 'svg-country-flags/svg/id.svg'
|
||||||
import pt from 'svg-country-flags/svg/pt.svg'
|
import pt from 'flag-icon-css/flags/4x3/pt.svg'
|
||||||
import br from 'svg-country-flags/svg/br.svg'
|
import br from 'svg-country-flags/svg/br.svg'
|
||||||
import ru from 'svg-country-flags/svg/ru.svg'
|
import ru from 'svg-country-flags/svg/ru.svg'
|
||||||
import tr from 'svg-country-flags/svg/tr.svg'
|
import tr from 'svg-country-flags/svg/tr.svg'
|
||||||
import vn from 'svg-country-flags/svg/vn.svg'
|
import vn from 'svg-country-flags/svg/vn.svg'
|
||||||
import hr from 'svg-country-flags/svg/hr.svg'
|
import hr from 'flag-icon-css/flags/4x3/hr.svg'
|
||||||
import ar from '@/assets/ar.svg'
|
import ar from '@/assets/ar.svg'
|
||||||
import ko from 'svg-country-flags/svg/kr.svg'
|
import ko from 'flag-icon-css/flags/4x3/kr.svg'
|
||||||
|
import ph from 'flag-icon-css/flags/4x3/ph.svg'
|
||||||
|
|
||||||
export default {
|
export const flags = {
|
||||||
it,
|
it,
|
||||||
en: gb,
|
en: gb,
|
||||||
es,
|
es,
|
||||||
@ -27,5 +28,6 @@ export default {
|
|||||||
vn,
|
vn,
|
||||||
hr,
|
hr,
|
||||||
ar,
|
ar,
|
||||||
ko
|
ko,
|
||||||
|
ph
|
||||||
}
|
}
|
||||||
|
4
src/utils/texts.js
Normal file
4
src/utils/texts.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* @param {string} text
|
||||||
|
*/
|
||||||
|
export const upperCaseFirstLowerCaseRest = text => text.charAt(0).toUpperCase() + text.slice(1).toLowerCase()
|
Loading…
Reference in New Issue
Block a user