Squashed merge from refactor/code-cleanup to main

This commit is contained in:
Roberto Tonino 2021-07-17 14:28:29 +02:00
parent b677f422a2
commit 76b9185127
49 changed files with 2086 additions and 2118 deletions

View File

@ -14,3 +14,4 @@ rules:
no-unused-vars: off no-unused-vars: off
no-console: off no-console: off
camelcase: off camelcase: off
vue/no-v-html: off

View File

@ -1,12 +0,0 @@
{
"useTabs": true,
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"bracketSpacing": true,
"trailingComma": "none",
"printWidth": 120,
"arrowParens": "avoid",
"vueIndentScriptAndStyle": false,
"endOfLine": "lf"
}

10
.prettierrc.yml Normal file
View File

@ -0,0 +1,10 @@
---
useTabs: true
tabWidth: 2
semi: false
singleQuote: true
bracketSpacing: true
trailingComma: none
printWidth: 120
arrowParens: avoid
vueIndentScriptAndStyle: false

View File

@ -4,13 +4,11 @@
"scripts": { "scripts": {
"clean": "rimraf public/js/bundle.js public/js/bundle.temp.js public/js/bundle.js.map", "clean": "rimraf public/js/bundle.js public/js/bundle.temp.js public/js/bundle.js.map",
"clean-temp": "rimraf public/js/bundle.temp.js", "clean-temp": "rimraf public/js/bundle.temp.js",
"serve": "python ../server.py", "serve": "yarn --cwd ../server start",
"serve:gui": "python ../deemix-pyweb.py --dev",
"build:js": "rollup -c", "build:js": "rollup -c",
"watch:js": "rollup -c -w", "watch:js": "rollup -c -w",
"minify": "esbuild public/js/bundle.temp.js --outfile=public/js/bundle.js --minify", "minify": "esbuild public/js/bundle.temp.js --outfile=public/js/bundle.js --minify",
"dev": "npm-run-all --parallel serve watch:js", "dev": "npm-run-all --parallel watch:js",
"dev:gui": "npm-run-all --parallel serve:gui watch:js",
"build": "npm-run-all --sequential clean build:js minify clean-temp", "build": "npm-run-all --sequential clean build:js minify clean-temp",
"lint": "eslint src/**/*.{js,vue} --fix", "lint": "eslint src/**/*.{js,vue} --fix",
"lint-tests": "eslint src/**/*.js --fix", "lint-tests": "eslint src/**/*.js --fix",

File diff suppressed because one or more lines are too long

View File

@ -26,18 +26,6 @@
</div> </div>
</template> </template>
<style>
.app-container {
display: flex;
}
.content-container {
width: 100%;
display: flex;
flex-direction: column;
}
</style>
<script> <script>
import { socket } from '@/utils/socket' import { socket } from '@/utils/socket'
@ -78,3 +66,15 @@ export default {
} }
} }
</script> </script>
<style>
.app-container {
display: flex;
}
.content-container {
width: 100%;
display: flex;
flex-direction: column;
}
</style>

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-ar"
id="flag-icon-css-ar" viewBox="0 0 640 480"
viewBox="0 0 640 480" version="1.1">
version="1.1">
<metadata <metadata
id="metadata1678"> id="metadata1678">
<rdf:RDF> <rdf:RDF>

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg8" version="1.1" viewBox="0 0 26.458333 26.458334" height="100" width="100"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg8" version="1.1"
viewBox="0 0 26.458333 26.458334" height="100" width="100">
<defs id="defs2"> <defs id="defs2">
<linearGradient id="linearGradient3062"> <linearGradient id="linearGradient3062">
<stop id="stop3058" offset="0" style="stop-color:#007aff;stop-opacity:1"/> <stop id="stop3058" offset="0" style="stop-color:#007aff;stop-opacity:1"/>
@ -208,7 +209,7 @@
</filter> </filter>
</defs> </defs>
<metadata id="metadata5"> <metadata id="metadata5">
</metadata> </metadata>
<g style="display:inline" id="layer2"> <g style="display:inline" id="layer2">
<circle r="10.583333" cy="13.229166" cx="13.229166" id="path2775" style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:0.881856;stroke-linecap:round;stroke-linejoin:round"/> <circle r="10.583333" cy="13.229166" cx="13.229166" id="path2775" style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:0.881856;stroke-linecap:round;stroke-linejoin:round"/>

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1"?> <?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512.001 512.001" style="enable-background:new 0 0 512.001 512.001;" xml:space="preserve"> viewBox="0 0 512.001 512.001" style="enable-background:new 0 0 512.001 512.001;" xml:space="preserve">
<path style="fill:#03A9F4;" d="M425.457,117.739c-3.121-1.838-6.961-1.966-10.197-0.341c-3.231,1.629-5.416,4.786-5.803,8.384 <path style="fill:#03A9F4;" d="M425.457,117.739c-3.121-1.838-6.961-1.966-10.197-0.341c-3.231,1.629-5.416,4.786-5.803,8.384
c-0.384,3.499-0.981,6.997-1.728,10.667c-20.885,94.784-62.827,140.885-128.256,140.885h-96c-5.062,0.009-9.42,3.574-10.432,8.533 c-0.384,3.499-0.981,6.997-1.728,10.667c-20.885,94.784-62.827,140.885-128.256,140.885h-96c-5.062,0.009-9.42,3.574-10.432,8.533
l-32,149.995l-5.717,38.187c-3.287,17.365,8.125,34.107,25.489,37.394c1.915,0.362,3.858,0.549,5.807,0.558h64.213 l-32,149.995l-5.717,38.187c-3.287,17.365,8.125,34.107,25.489,37.394c1.915,0.362,3.858,0.549,5.807,0.558h64.213

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -27,6 +27,41 @@
</main> </main>
</template> </template>
<script>
import { debounce } from '@/utils/utils'
import BackButton from '@components/globals/BackButton.vue'
export default {
components: {
BackButton
},
data: () => ({
performScrolledSearch: false
}),
computed: {
showBackButton() {
return ['Tracklist', 'Artist', 'Album', 'Playlist', 'Spotify Playlist'].includes(this.$route.name)
}
},
mounted() {
this.$router.beforeEach((_, __, next) => {
this.$refs.content.scrollTo(0, 0)
next()
})
},
methods: {
handleContentScroll: debounce(async function () {
if (this.$refs.content.scrollTop + this.$refs.content.clientHeight < this.$refs.content.scrollHeight) return
this.performScrolledSearch = true
await this.$nextTick()
this.performScrolledSearch = false
}, 100)
}
}
</script>
<style lang="scss"> <style lang="scss">
#container { #container {
--container-width: 95%; --container-width: 95%;
@ -69,38 +104,3 @@ main::-webkit-scrollbar-thumb {
padding: 0px 2px; padding: 0px 2px;
} }
</style> </style>
<script>
import { debounce } from '@/utils/utils'
import BackButton from '@components/globals/BackButton.vue'
export default {
components: {
BackButton
},
data: () => ({
performScrolledSearch: false
}),
computed: {
showBackButton() {
return ['Tracklist', 'Artist', 'Album', 'Playlist', 'Spotify Playlist'].includes(this.$route.name)
}
},
mounted() {
this.$router.beforeEach((to, from, next) => {
this.$refs.content.scrollTo(0, 0)
next()
})
},
methods: {
handleContentScroll: debounce(async function () {
if (this.$refs.content.scrollTop + this.$refs.content.clientHeight < this.$refs.content.scrollHeight) return
this.performScrolledSearch = true
await this.$nextTick()
this.performScrolledSearch = false
}, 100)
}
}
</script>

View File

@ -21,87 +21,10 @@
</header> </header>
</template> </template>
<style lang="scss">
$icon-dimension: 2rem;
$searchbar-height: 45px;
input[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
width: 28px;
height: 28px;
background-color: var(--foreground);
-webkit-mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='28' viewBox='0 0 24 24' width='28'%3E%%3Cpath fill='%23ffffff' d='M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z'/%3E3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='28' viewBox='0 0 24 24' width='28'%3E%%3Cpath fill='%23ffffff' d='M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z'/%3E3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
}
#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;
.search__icon {
width: $icon-dimension;
height: $icon-dimension;
i {
font-size: $icon-dimension;
color: var(--foreground);
&::selection {
background: none;
}
}
}
#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;
}
&::-webkit-search-cancel-button {
appearance: none;
width: 28px;
height: 28px;
background-color: var(--foreground);
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='28' viewBox='0 0 24 24' width='28'%3E%%3Cpath fill='%23ffffff' d='M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z'/%3E3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
}
// Removing Chrome autofill color
&:-webkit-autofill,
&:-webkit-autofill:hover,
&:-webkit-autofill:focus,
&:-webkit-autofill:active {
box-shadow: 0 0 0 $searchbar-height var(--secondary-background) inset !important;
}
}
&:focus-within {
border: 1px solid var(--foreground);
}
}
</style>
<script> <script>
import { defineComponent, ref } from '@vue/composition-api' import { defineComponent, ref } from '@vue/composition-api'
import { isValidURL } from '@/utils/utils' import { isValidURL } from '@/utils/utils'
import { sendAddToQueue } from '@/utils/downloads' import { sendAddToQueue } from '@/utils/downloads'
import { socket } from '@/utils/socket'
import { fetchData } from '@/utils/api' import { fetchData } from '@/utils/api'
import EventBus from '@/utils/EventBus' import EventBus from '@/utils/EventBus'
@ -120,7 +43,7 @@ export default defineComponent({
} }
const deleteSearchBarContent = keyEvent => { const deleteSearchBarContent = keyEvent => {
if (!(keyEvent.key == 'Backspace' && keyEvent.ctrlKey && keyEvent.shiftKey)) return 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()
@ -207,3 +130,79 @@ export default defineComponent({
} }
}) })
</script> </script>
<style lang="scss">
$icon-dimension: 2rem;
$searchbar-height: 45px;
input[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
width: 28px;
height: 28px;
background-color: var(--foreground);
-webkit-mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='28' viewBox='0 0 24 24' width='28'%3E%%3Cpath fill='%23ffffff' d='M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z'/%3E3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='28' viewBox='0 0 24 24' width='28'%3E%%3Cpath fill='%23ffffff' d='M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z'/%3E3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
}
#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;
.search__icon {
width: $icon-dimension;
height: $icon-dimension;
i {
font-size: $icon-dimension;
color: var(--foreground);
&::selection {
background: none;
}
}
}
#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;
}
&::-webkit-search-cancel-button {
appearance: none;
width: 28px;
height: 28px;
background-color: var(--foreground);
mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='28' viewBox='0 0 24 24' width='28'%3E%%3Cpath fill='%23ffffff' d='M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z'/%3E3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
}
// Removing Chrome autofill color
&:-webkit-autofill,
&:-webkit-autofill:hover,
&:-webkit-autofill:focus,
&:-webkit-autofill:active {
box-shadow: 0 0 0 $searchbar-height var(--secondary-background) inset !important;
}
}
&:focus-within {
border: 1px solid var(--foreground);
}
}
</style>

View File

@ -65,6 +65,45 @@
</aside> </aside>
</template> </template>
<script>
import { computed, defineComponent, reactive, toRefs } from '@vue/composition-api'
import { links } from '@/data/sidebar'
import { useTheme } from '@/use/theme'
import deemixIcon from '@/assets/deemix-icon.svg'
export default defineComponent({
setup(_, ctx) {
const state = reactive({
activeTablink: 'home',
links
})
const { THEMES, currentTheme } = useTheme()
/* === Add update notification near info === */
const updateAvailable = computed(() => ctx.root.$store.state.appInfo.updateAvailable)
ctx.root.$router.afterEach(to => {
const linkInSidebar = state.links.find(link => link.routerName === to.name)
if (!linkInSidebar) return
state.activeTablink = linkInSidebar.name
})
return {
...toRefs(state),
updateAvailable,
THEMES,
currentTheme,
isSlim: computed(() => ctx.root.$store.getters.getSlimSidebar),
deemixIcon
}
}
})
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
.deemix-icon-container { .deemix-icon-container {
display: grid; display: grid;
@ -108,42 +147,3 @@
} }
} }
</style> </style>
<script>
import { computed, defineComponent, reactive, toRefs } from '@vue/composition-api'
import { links } from '@/data/sidebar'
import { useTheme } from '@/use/theme'
import deemixIcon from '@/assets/deemix-icon.svg'
export default defineComponent({
setup(props, ctx) {
const state = reactive({
activeTablink: 'home',
links
})
const { THEMES, currentTheme } = useTheme()
/* === Add update notification near info === */
const updateAvailable = computed(() => ctx.root.$store.state.appInfo.updateAvailable)
ctx.root.$router.afterEach((to, from) => {
const linkInSidebar = state.links.find(link => link.routerName === to.name)
if (!linkInSidebar) return
state.activeTablink = linkInSidebar.name
})
return {
...toRefs(state),
updateAvailable,
THEMES,
currentTheme,
isSlim: computed(() => ctx.root.$store.getters.getSlimSidebar),
deemixIcon
}
}
})
</script>

View File

@ -41,184 +41,15 @@
</div> </div>
</template> </template>
<style lang="scss">
.download-object {
padding-bottom: 8px;
.download-info {
display: flex;
align-items: center;
img {
height: 75px;
flex-shrink: 0;
flex: 0 0 75px;
}
.download-line {
display: block;
}
.download-slim-separator {
display: none;
}
}
.download-info-data {
flex: 1 50%;
margin-left: 8px;
overflow: hidden;
}
.download-info-status {
flex: 1 15%;
margin-left: 8px;
width: 80px;
}
> .download-bar {
display: flex;
align-items: center;
height: 24px;
> .queue_icon {
cursor: default;
margin-left: 8px;
}
> .progress {
margin: 0px;
}
}
}
#download_list:not(.slim) .download-line {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
#download_list.slim {
> .download-object {
.download-info {
display: block;
img {
display: none;
}
.download-line {
display: inline-block;
}
.download-slim-separator {
display: inline-block;
}
}
.download-info-data {
width: calc(80% - 16px);
display: inline-block;
padding-left: 0px;
}
.download-info-status {
width: 20%;
display: inline-block; // ignored due to float
float: right;
}
}
}
.progress {
position: relative;
height: 4px;
display: block;
width: 100%;
background-color: var(--secondary-background);
border-radius: 2px;
margin: 0.5rem 0 1rem 0;
overflow: hidden;
.determinate {
position: absolute;
top: 0;
left: 0;
bottom: 0;
background-color: var(--primary-color);
transition: width 0.3s linear;
}
.converting {
background-color: var(--secondary-color);
transition: none !important;
}
.indeterminate {
background-color: var(--primary-color);
&::before {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
}
&::after {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation-delay: 1.15s;
}
}
}
@keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
</style>
<script> <script>
const possibleStates = ['converting', 'downloading', 'download finished', 'completed'] const possibleStates = ['converting', 'downloading', 'download finished', 'completed']
export default { export default {
props: { props: {
queueItem: Object queueItem: {
type: Object,
default: () => ({})
}
}, },
data() { data() {
return { return {
@ -321,3 +152,174 @@ export default {
} }
} }
</script> </script>
<style lang="scss">
.download-object {
padding-bottom: 8px;
.download-info {
display: flex;
align-items: center;
img {
height: 75px;
flex: 0 0 75px;
}
.download-line {
display: block;
}
.download-slim-separator {
display: none;
}
}
.download-info-data {
flex: 1 50%;
margin-left: 8px;
overflow: hidden;
}
.download-info-status {
flex: 1 15%;
margin-left: 8px;
width: 80px;
}
> .download-bar {
display: flex;
align-items: center;
height: 24px;
> .queue_icon {
cursor: default;
margin-left: 8px;
}
> .progress {
margin: 0;
}
}
}
#download_list:not(.slim) .download-line {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
#download_list.slim {
> .download-object {
.download-info {
display: block;
img {
display: none;
}
.download-line {
display: inline-block;
}
.download-slim-separator {
display: inline-block;
}
}
.download-info-data {
width: calc(80% - 16px);
display: inline-block;
padding-left: 0;
}
.download-info-status {
width: 20%;
display: inline-block; // ignored due to float
float: right;
}
}
}
.progress {
position: relative;
height: 4px;
display: block;
width: 100%;
background-color: var(--secondary-background);
border-radius: 2px;
margin: 0.5rem 0 1rem 0;
overflow: hidden;
.determinate {
position: absolute;
top: 0;
left: 0;
bottom: 0;
background-color: var(--primary-color);
transition: width 0.3s linear;
}
.converting {
background-color: var(--secondary-color);
transition: none !important;
}
.indeterminate {
background-color: var(--primary-color);
&::before {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
}
&::after {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation-delay: 1.15s;
}
}
}
@keyframes indeterminate {
0% {
left: -35%;
right: 100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
</style>

View File

@ -63,58 +63,6 @@
</section> </section>
</template> </template>
<style lang="scss" scoped>
#toggle_download_tab {
width: 25px;
height: 25px;
&::before {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
content: 'chevron_right';
}
}
#download_tab_container.tab-hidden {
#toggle_download_tab {
&::before {
content: 'chevron_left';
}
}
&::after {
content: attr(data-label);
display: flex;
align-items: center;
text-transform: capitalize;
writing-mode: vertical-rl;
line-height: 2rem;
}
}
#download_list {
height: calc(100% - 32px);
padding-left: 28px;
overflow-y: scroll;
&::-webkit-scrollbar {
width: 10px;
}
&::-webkit-scrollbar-track {
background: var(--panels-background);
}
&::-webkit-scrollbar-thumb {
background: var(--panels-scroll);
border-radius: 4px;
width: 6px;
padding: 0px 2px;
}
}
</style>
<script> <script>
import { mapActions, mapGetters } from 'vuex' import { mapActions, mapGetters } from 'vuex'
import QueueItem from '@components/downloads/QueueItem.vue' import QueueItem from '@components/downloads/QueueItem.vue'
@ -250,7 +198,7 @@ export default {
addToQueue(queueItem, current = false) { addToQueue(queueItem, current = false) {
if (Array.isArray(queueItem)) { if (Array.isArray(queueItem)) {
if (queueItem.length > 1) { if (queueItem.length > 1) {
queueItem.forEach((item, i) => { queueItem.forEach(item => {
item.silent = true item.silent = true
this.addToQueue(item) this.addToQueue(item)
}) })
@ -435,3 +383,55 @@ export default {
} }
} }
</script> </script>
<style lang="scss" scoped>
#toggle_download_tab {
width: 25px;
height: 25px;
&::before {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
content: 'chevron_right';
}
}
#download_tab_container.tab-hidden {
#toggle_download_tab {
&::before {
content: 'chevron_left';
}
}
&::after {
content: attr(data-label);
display: flex;
align-items: center;
text-transform: capitalize;
writing-mode: vertical-rl;
line-height: 2rem;
}
}
#download_list {
height: calc(100% - 32px);
padding-left: 28px;
overflow-y: scroll;
&::-webkit-scrollbar {
width: 10px;
}
&::-webkit-scrollbar-track {
background: var(--panels-background);
}
&::-webkit-scrollbar-thumb {
background: var(--panels-scroll);
border-radius: 4px;
width: 6px;
padding: 0px 2px;
}
}
</style>

View File

@ -10,17 +10,6 @@
</details> </details>
</template> </template>
<style>
details > summary::marker {
display: none;
}
details.with-arrow > summary::marker {
display: initial;
vertical-align: var(--arrow-v-align, super);
}
</style>
<script> <script>
export default { export default {
props: { props: {
@ -31,3 +20,14 @@ export default {
} }
} }
</script> </script>
<style>
details > summary::marker {
display: none;
}
details.with-arrow > summary::marker {
display: initial;
vertical-align: var(--arrow-v-align, super);
}
</style>

View File

@ -1,3 +1,4 @@
/* eslint-disable vue/one-component-per-file */
import { defineComponent } from '@vue/composition-api' import { defineComponent } from '@vue/composition-api'
// https://vuejs.org/v2/guide/render-function.html // https://vuejs.org/v2/guide/render-function.html

View File

@ -13,6 +13,22 @@
</div> </div>
</template> </template>
<script>
export default {
data() {
return {
titleText: 'Are you sure you want to reset settings to default?'
}
},
mounted() {
setTimeout(() => {
// this.$refs.wrapper.classList.add('bounceIn')
// this.$refs.body.classList.add('bounceIn')
}, 2000)
}
}
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
$body-padding: 2rem; $body-padding: 2rem;
$body-radius: 15px; $body-radius: 15px;
@ -68,19 +84,3 @@ $body-radius: 15px;
z-index: 1; z-index: 1;
} }
</style> </style>
<script>
export default {
data() {
return {
titleText: 'Are you sure you want to reset settings to default?'
}
},
mounted() {
setTimeout(() => {
// this.$refs.wrapper.classList.add('bounceIn')
// this.$refs.body.classList.add('bounceIn')
}, 2000)
}
}
</script>

View File

@ -20,6 +20,30 @@
</div> </div>
</template> </template>
<script>
export default {
inheritAttrs: false,
props: {
cover: {
type: String,
required: true
},
isRounded: {
type: Boolean,
required: false
},
isCircle: {
type: Boolean,
required: false
},
link: {
type: String,
required: true
}
}
}
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
.cover-container { .cover-container {
width: 156px; width: 156px;
@ -58,32 +82,8 @@
.download_overlay { .download_overlay {
opacity: 1; opacity: 1;
border: 0px; border: 0;
} }
} }
} }
</style> </style>
<script>
export default {
inheritAttrs: false,
props: {
cover: {
type: String,
reqired: true
},
isRounded: {
type: Boolean,
required: false
},
isCircle: {
type: Boolean,
required: false
},
link: {
type: String,
reqired: true
}
}
}
</script>

View File

@ -1,23 +1,23 @@
<template> <template>
<div id="deezer_not_available" class="hide"> <div id="deezer_not_available" class="hide">
<i class="material-icons">warning</i> {{ $t('toasts.deezerNotAvailable') }} <i class="material-icons">warning</i> {{ $t('toasts.deezerNotAvailable') }}
</div> </div>
</template> </template>
<style> <style>
#deezer_not_available { #deezer_not_available {
background-color: hsl(53, 98%, 47%); background-color: hsl(53, 98%, 47%);
color: rgba(0,0,0, .75); color: rgba(0, 0, 0, 0.75);
padding: 8px 12px; padding: 8px 12px;
margin: -10px 10px 0px; margin: -10px 10px 0px;
display: flex; display: flex;
border-radius: 8px; border-radius: 8px;
align-items: center; align-items: center;
} }
#deezer_not_available i { #deezer_not_available i {
margin-right: 8px; margin-right: 8px;
} }
#deezer_not_available.hide { #deezer_not_available.hide {
display: none !important; display: none !important;
} }
</style> </style>

View File

@ -80,7 +80,7 @@ export default {
position: 6, position: 6,
action: () => { action: () => {
// Paste does not always work // Paste does not always work
if (clipboard in navigator) { if ('clipboard' in navigator) {
navigator.clipboard.readText().then(text => { navigator.clipboard.readText().then(text => {
document.execCommand('insertText', undefined, text) document.execCommand('insertText', undefined, text)
}) })

View File

@ -22,43 +22,7 @@
</div> </div>
</div> </div>
</template> </template>
<style lang="scss">
.smallmodal {
position: fixed;
z-index: 1250;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: hsla(0, 0%, 0%, 0.4);
animation-duration: 0.3s;
}
.smallmodal-content {
--modal-content-width: 95%;
background-color: transparent;
margin: auto;
width: var(--modal-content-width);
position: relative;
top: 50%;
transform: translateY(-50%);
@media only screen and (min-width: 601px) {
--modal-content-width: 85%;
}
@media only screen and (min-width: 993px) {
--modal-content-width: 70%;
}
}
.smallmodal-content button {
width: 100%;
margin-bottom: 8px;
}
</style>
<script> <script>
import { sendAddToQueue } from '@/utils/downloads' import { sendAddToQueue } from '@/utils/downloads'
@ -99,3 +63,41 @@ export default {
} }
} }
</script> </script>
<style lang="scss">
.smallmodal {
position: fixed;
z-index: 1250;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: hsla(0, 0%, 0%, 0.4);
animation-duration: 0.3s;
}
.smallmodal-content {
--modal-content-width: 95%;
background-color: transparent;
margin: auto;
width: var(--modal-content-width);
position: relative;
top: 50%;
transform: translateY(-50%);
@media only screen and (min-width: 601px) {
--modal-content-width: 85%;
}
@media only screen and (min-width: 993px) {
--modal-content-width: 70%;
}
}
.smallmodal-content button {
width: 100%;
margin-bottom: 8px;
}
</style>

View File

@ -34,7 +34,7 @@ export default {
mounted() { mounted() {
this.$refs.preview.volume = 1 this.$refs.preview.volume = 1
this.$router.beforeEach((to, from, next) => { this.$router.beforeEach((_, __, next) => {
this.stopStackedTabsPreview() this.stopStackedTabsPreview()
next() next()
}) })
@ -86,7 +86,7 @@ export default {
const { currentTarget: obj } = e const { currentTarget: obj } = e
const icon = obj.tagName == 'I' ? obj : obj.querySelector('i') const icon = obj.tagName === 'I' ? obj : obj.querySelector('i')
if (obj.hasAttribute('playing')) { if (obj.hasAttribute('playing')) {
if (this.$refs.preview.paused) { if (this.$refs.preview.paused) {

View File

@ -144,6 +144,49 @@
</div> </div>
</template> </template>
<script>
import { computed, defineComponent, onMounted, reactive, toRefs } from '@vue/composition-api'
import { useOnline } from '@/use/online'
import paypal from '@/assets/paypal.svg'
import ethereum from '@/assets/ethereum.svg'
export default defineComponent({
setup(_, ctx) {
const state = reactive({
current: null,
latest: null,
updateAvailable: false,
deemixVersion: null
})
const { isOnline } = useOnline()
function initUpdate(appInfo) {
const { currentCommit, latestCommit, updateAvailable, deemixVersion } = appInfo
state.current = currentCommit
state.latest = latestCommit
state.updateAvailable = updateAvailable
state.deemixVersion = deemixVersion
}
const getAppInfo = computed(() => ctx.root.$store.getters.getAppInfo)
onMounted(() => {
initUpdate(getAppInfo.value)
})
return {
...toRefs(state),
paypal,
ethereum,
isOnline
}
}
})
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
li, li,
p, p,
@ -233,46 +276,3 @@ ul {
} }
} }
</style> </style>
<script>
import { computed, defineComponent, onMounted, reactive, toRefs } from '@vue/composition-api'
import { useOnline } from '@/use/online'
import paypal from '@/assets/paypal.svg'
import ethereum from '@/assets/ethereum.svg'
export default defineComponent({
setup(props, ctx) {
const state = reactive({
current: null,
latest: null,
updateAvailable: false,
deemixVersion: null
})
const { isOnline } = useOnline()
function initUpdate(appInfo) {
const { currentCommit, latestCommit, updateAvailable, deemixVersion } = appInfo
state.current = currentCommit
state.latest = latestCommit
state.updateAvailable = updateAvailable
state.deemixVersion = deemixVersion
}
const getAppInfo = computed(() => ctx.root.$store.getters.getAppInfo)
onMounted(() => {
initUpdate(getAppInfo.value)
})
return {
...toRefs(state),
paypal,
ethereum,
isOnline
}
}
})
</script>

View File

@ -87,7 +87,7 @@
</template> </template>
<script> <script>
import { defineComponent, ref, unref, reactive, computed, onMounted, toRefs, watch } from '@vue/composition-api' import { defineComponent, ref, unref, reactive, computed, toRefs } from '@vue/composition-api'
import { orderBy } from 'lodash-es' import { orderBy } from 'lodash-es'
import { BaseTabs, BaseTab } from '@components/globals/BaseTabs' import { BaseTabs, BaseTab } from '@components/globals/BaseTabs'
@ -102,7 +102,7 @@ export default defineComponent({
BaseTabs, BaseTabs,
BaseTab BaseTab
}, },
setup(props, ctx) { setup(_, ctx) {
const state = reactive({ const state = reactive({
currentTab: '', currentTab: '',
sortKey: 'releaseDate', sortKey: 'releaseDate',
@ -145,7 +145,7 @@ export default defineComponent({
let sortKey = state.sortKey let sortKey = state.sortKey
if (sortKey === 'releaseTracksNumber') { if (sortKey === 'releaseTracksNumber') {
sortKey = o => new Number(o.releaseTracksNumber) sortKey = o => Number(o.releaseTracksNumber)
} }
return orderBy(state.currentRelease, sortKey, state.sortOrder) return orderBy(state.currentRelease, sortKey, state.sortOrder)

View File

@ -26,7 +26,7 @@
</button> </button>
<table class="table table--charts"> <table class="table table--charts">
<tbody> <tbody>
<tr v-for="(track, pos) in chart" class="track_row"> <tr v-for="(track, pos) in chart" :key="pos" class="track_row">
<td :class="{ first: pos === 0 }" class="p-3 text-center cursor-default"> <td :class="{ first: pos === 0 }" class="p-3 text-center cursor-default">
{{ pos + 1 }} {{ pos + 1 }}
</td> </td>
@ -91,7 +91,6 @@ import { getChartsData, getChartTracks } from '@/data/charts'
import PreviewControls from '@components/globals/PreviewControls.vue' import PreviewControls from '@components/globals/PreviewControls.vue'
import { playPausePreview } from '@components/globals/TheTrackPreview.vue' import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
import { fetchData } from '@/utils/api'
export default { export default {
components: { components: {
@ -178,7 +177,7 @@ export default {
let i = 0 let i = 0
for (; i < this.countries.length; i++) { for (; i < this.countries.length; i++) {
if (this.countries[i].title == this.country) break if (this.countries[i].title === this.country) break
} }
if (i !== this.countries.length) { if (i !== this.countries.length) {

View File

@ -24,7 +24,7 @@
</button> </button>
<div v-show="activeTab === 'playlist'"> <div v-show="activeTab === 'playlist'">
<div v-if="playlists.length == 0"> <div v-if="playlists.length === 0">
<h1>{{ $t('favorites.noPlaylists') }}</h1> <h1>{{ $t('favorites.noPlaylists') }}</h1>
</div> </div>
<div v-if="playlists.length > 0 || spotifyPlaylists.length > 0" class="release-grid"> <div v-if="playlists.length > 0 || spotifyPlaylists.length > 0" class="release-grid">

View File

@ -75,14 +75,14 @@ export default {
albums: [] albums: []
} }
}, },
computed: {
...mapGetters(['isLoggedIn'])
},
async created() { async created() {
const homeData = await getHomeData() const homeData = await getHomeData()
this.initHome(homeData) this.initHome(homeData)
}, },
computed: {
...mapGetters(['isLoggedIn'])
},
methods: { methods: {
addToQueue(e) { addToQueue(e) {
sendAddToQueue(e.currentTarget.dataset.link) sendAddToQueue(e.currentTarget.dataset.link)

View File

@ -120,14 +120,14 @@
</tr> </tr>
</table> </table>
<div v-if="type == 'album'"> <div v-if="type === 'album'">
<router-link tag="button" class="btn btn-primary" name="button" :to="{ name: 'Album', params: { id } }"> <router-link tag="button" class="btn btn-primary" name="button" :to="{ name: 'Album', params: { id } }">
{{ $t('linkAnalyzer.table.tracklist') }} {{ $t('linkAnalyzer.table.tracklist') }}
</router-link> </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, i) in countries" :key="i">{{ country[0] }} - {{ country[1] }}</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -43,8 +43,6 @@ import ResultsArtists from '@components/search/ResultsArtists.vue'
import ResultsPlaylists from '@components/search/ResultsPlaylists.vue' import ResultsPlaylists from '@components/search/ResultsPlaylists.vue'
import ResultsTracks from '@components/search/ResultsTracks.vue' import ResultsTracks from '@components/search/ResultsTracks.vue'
import { BaseTabs, BaseTab } from '@components/globals/BaseTabs' import { BaseTabs, BaseTab } from '@components/globals/BaseTabs'
import { socket } from '@/utils/socket'
import { sendAddToQueue } from '@/utils/downloads' import { sendAddToQueue } from '@/utils/downloads'
import { numberWithDots, convertDuration } from '@/utils/utils' import { numberWithDots, convertDuration } from '@/utils/utils'
@ -52,7 +50,6 @@ import { formatSingleTrack, formatAlbums, formatArtist, formatPlaylist } from '@
import { standardizeData } from '@/data/standardize' import { standardizeData } from '@/data/standardize'
import { useMainSearch } from '@/use/main-search' import { useMainSearch } from '@/use/main-search'
import { useSearch } from '@/use/search' import { useSearch } from '@/use/search'
import { useLogs } from '@/use/logs'
const resetObj = { data: [], next: 0, total: 0, hasLoaded: false } const resetObj = { data: [], next: 0, total: 0, hasLoaded: false }
@ -70,7 +67,7 @@ export default defineComponent({
required: false required: false
} }
}, },
setup(props, ctx) { setup(_, ctx) {
const state = reactive({ const state = reactive({
currentTab: { currentTab: {
name: '', name: '',
@ -249,7 +246,7 @@ export default defineComponent({
this.scrolledSearch(needToSearch) this.scrolledSearch(needToSearch)
}, },
currentTab(newTab, old) { currentTab(newTab) {
if (this.isTabLoaded(newTab)) return if (this.isTabLoaded(newTab)) return
this.performSearch({ this.performSearch({

View File

@ -718,101 +718,6 @@
</div> </div>
</template> </template>
<style lang="scss" scoped>
#logged_in_info {
display: flex;
align-items: center;
flex-direction: column;
justify-content: space-evenly;
height: 250px;
}
.locale-flag {
justify-content: center;
cursor: pointer;
width: 60px;
&:not(:last-child) {
margin-right: 10px;
}
&.locale-flag--current {
::v-deep svg {
filter: brightness(1) !important;
}
}
&::v-deep svg {
width: 40px !important;
height: 40px !important;
filter: brightness(0.5);
}
}
.settings-group {
border-top-width: 1px;
border-color: hsl(0, 0%, 50%);
}
.settings-group__header {
display: inline-flex;
align-items: center;
padding-top: 2rem;
padding-bottom: 2rem;
font-size: 1.5rem;
i.material-icons {
margin-right: 1rem;
}
}
.settings-container {
display: flex;
&__half {
width: 50%;
}
&__third {
width: 33%;
&--only-checkbox {
display: flex;
align-items: start;
flex-direction: column;
justify-content: center;
}
}
&__half > *,
&__third > * {
margin-bottom: 1rem;
}
}
.with-checkbox {
display: flex;
align-items: center;
[type='checkbox'] {
cursor: pointer;
}
.checkbox-text {
margin-left: 10px;
cursor: pointer;
user-select: none;
}
}
/* Input group */
.input-group {
.input-group-text {
margin-bottom: 0.5rem;
}
}
</style>
<script> <script>
import { mapActions, mapGetters } from 'vuex' import { mapActions, mapGetters } from 'vuex'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
@ -1013,7 +918,7 @@ 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))
}, },
async loggedInViaDeezer(arl) { loggedInViaDeezer(arl) {
this.dispatchARL({ arl }) this.dispatchARL({ arl })
// this.login() // this.login()
// const res = await fetchData('login', { arl, force: true, child: this.accountNum }) // const res = await fetchData('login', { arl, force: true, child: this.accountNum })
@ -1043,7 +948,7 @@ export default {
toast(this.$t('toasts.deezerNotAvailable'), 'close', true, 'login-toast') toast(this.$t('toasts.deezerNotAvailable'), 'close', true, 'login-toast')
} }
}, },
async loginButton() { loginButton() {
const newArl = this.$refs.loginInput.value.trim() const newArl = this.$refs.loginInput.value.trim()
if (newArl && newArl !== this.arl) { if (newArl && newArl !== this.arl) {
@ -1117,3 +1022,98 @@ export default {
} }
} }
</script> </script>
<style lang="scss" scoped>
#logged_in_info {
display: flex;
align-items: center;
flex-direction: column;
justify-content: space-evenly;
height: 250px;
}
.locale-flag {
justify-content: center;
cursor: pointer;
width: 60px;
&:not(:last-child) {
margin-right: 10px;
}
&.locale-flag--current {
::v-deep svg {
filter: brightness(1) !important;
}
}
&::v-deep svg {
width: 40px !important;
height: 40px !important;
filter: brightness(0.5);
}
}
.settings-group {
border-top-width: 1px;
border-color: hsl(0, 0%, 50%);
}
.settings-group__header {
display: inline-flex;
align-items: center;
padding-top: 2rem;
padding-bottom: 2rem;
font-size: 1.5rem;
i.material-icons {
margin-right: 1rem;
}
}
.settings-container {
display: flex;
&__half {
width: 50%;
}
&__third {
width: 33%;
&--only-checkbox {
display: flex;
align-items: start;
flex-direction: column;
justify-content: center;
}
}
&__half > *,
&__third > * {
margin-bottom: 1rem;
}
}
.with-checkbox {
display: flex;
align-items: center;
[type='checkbox'] {
cursor: pointer;
}
.checkbox-text {
margin-left: 10px;
cursor: pointer;
user-select: none;
}
}
/* Input group */
.input-group {
.input-group-text {
margin-bottom: 0.5rem;
}
}
</style>

View File

@ -37,7 +37,7 @@
<tbody> <tbody>
<template v-if="type !== 'spotifyPlaylist'"> <template v-if="type !== 'spotifyPlaylist'">
<template v-for="(track, index) in body"> <template v-for="(track, index) in body">
<tr v-if="track.type == 'track'" @click="selectRow(index, track)"> <tr v-if="track.type === 'track'" @click="selectRow(index, track)">
<td class="table__cell--x-small table__cell--center"> <td class="table__cell--x-small table__cell--center">
<div class="table__cell-content table__cell-content--vertical-center"> <div class="table__cell-content table__cell-content--vertical-center">
<i <i
@ -152,7 +152,6 @@
<script> <script>
import { isEmpty } from 'lodash-es' import { isEmpty } from 'lodash-es'
import { socket } from '@/utils/socket'
import { sendAddToQueue } from '@/utils/downloads' import { sendAddToQueue } from '@/utils/downloads'
import Utils from '@/utils/utils' import Utils from '@/utils/utils'
import { playPausePreview } from '@components/globals/TheTrackPreview.vue' import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
@ -300,7 +299,7 @@ export default {
this.body = playlistTracks this.body = playlistTracks
} }
}, },
selectRow(index, track) { selectRow(_, track) {
track.selected = !track.selected track.selected = !track.selected
} }
} }

View File

@ -63,7 +63,7 @@ export default {
}, },
itemsToShow: { itemsToShow: {
type: Number, type: Number,
required: false default: 6
}, },
wantHeaders: { wantHeaders: {
type: Boolean, type: Boolean,

View File

@ -32,28 +32,24 @@
<ResultsTracks <ResultsTracks
v-else-if="section === 'TRACK'" v-else-if="section === 'TRACK'"
:view-info="standardizeData(viewInfo.TRACK, formatSingleTrack)" :view-info="standardizeData(viewInfo.TRACK, formatSingleTrack)"
:items-to-show="6"
@add-to-queue="$emit('add-to-queue', $event)" @add-to-queue="$emit('add-to-queue', $event)"
/> />
<ResultsAlbums <ResultsAlbums
v-else-if="section == 'ALBUM'" v-else-if="section === 'ALBUM'"
:view-info="standardizeData(viewInfo.ALBUM, formatAlbums)" :view-info="standardizeData(viewInfo.ALBUM, formatAlbums)"
:items-to-show="6"
@add-to-queue="$emit('add-to-queue', $event)" @add-to-queue="$emit('add-to-queue', $event)"
/> />
<ResultsPlaylists <ResultsPlaylists
v-else-if="section == 'PLAYLIST'" v-else-if="section === 'PLAYLIST'"
:view-info="standardizeData(viewInfo.PLAYLIST, formatPlaylist)" :view-info="standardizeData(viewInfo.PLAYLIST, formatPlaylist)"
:items-to-show="6"
@add-to-queue="$emit('add-to-queue', $event)" @add-to-queue="$emit('add-to-queue', $event)"
/> />
<ResultsArtists <ResultsArtists
v-else-if="section === 'ARTIST'" v-else-if="section === 'ARTIST'"
:view-info="standardizeData(viewInfo.ARTIST, formatArtist)" :view-info="standardizeData(viewInfo.ARTIST, formatArtist)"
:items-to-show="6"
@add-to-queue="$emit('add-to-queue', $event)" @add-to-queue="$emit('add-to-queue', $event)"
/> />
</template> </template>
@ -85,7 +81,7 @@ export default {
props: { props: {
viewInfo: { viewInfo: {
type: Object, type: Object,
required: false required: true
} }
}, },
computed: { computed: {

View File

@ -51,7 +51,7 @@ export default {
}, },
itemsToShow: { itemsToShow: {
type: Number, type: Number,
required: false default: 6
}, },
wantHeaders: { wantHeaders: {
type: Boolean, type: Boolean,

View File

@ -56,7 +56,7 @@ export default {
}, },
itemsToShow: { itemsToShow: {
type: Number, type: Number,
required: false default: 6
}, },
wantHeaders: { wantHeaders: {
type: Boolean, type: Boolean,

View File

@ -111,7 +111,7 @@ export default {
}, },
itemsToShow: { itemsToShow: {
type: Number, type: Number,
required: false default: 6
}, },
wantHeaders: { wantHeaders: {
type: Boolean, type: Boolean,

View File

@ -46,7 +46,7 @@ export default {
number = this.$n(this.$attrs.info.nb_fan, { locale: 'en' }) number = this.$n(this.$attrs.info.nb_fan, { locale: 'en' })
} }
return this.$attrs.info.type == 'artist' return this.$attrs.info.type === 'artist'
? this.$t('search.fans', { n: number }) ? this.$t('search.fans', { n: number })
: this.$t('globals.by', { artist: this.$attrs.info.artist }) + : this.$t('globals.by', { artist: this.$attrs.info.artist }) +
' - ' + ' - ' +

View File

@ -6,7 +6,8 @@
<div class="flex flex-wrap p-4 space-x-2 rounded-2xl bg-background-secondary"> <div class="flex flex-wrap p-4 space-x-2 rounded-2xl bg-background-secondary">
<span <span
v-for="templateVariable in templateVariables" v-for="(templateVariable, i) in templateVariables"
:key="i"
class="inline-block p-2 mt-2 tracking-wider rounded cursor-pointer bg-panels-bg first:ml-2 hover:shadow-outline" class="inline-block p-2 mt-2 tracking-wider rounded cursor-pointer bg-panels-bg first:ml-2 hover:shadow-outline"
@click="$emit('variable-click', templateVariable)" @click="$emit('variable-click', templateVariable)"
> >

View File

@ -4,17 +4,13 @@ let settingsData = {}
let defaultSettingsData = {} let defaultSettingsData = {}
let spotifyCredentials = {} let spotifyCredentials = {}
const cached = false
export async function getSettingsData() { export async function getSettingsData() {
if (!cached) { const data = await fetchData('getSettings')
const data = await fetchData('getSettings') const { settings, defaultSettings, spotifySettings } = data
const { settings, defaultSettings, spotifySettings } = data settingsData = settings
// cached = true defaultSettingsData = defaultSettings
settingsData = settings spotifyCredentials = spotifySettings || {}
defaultSettingsData = defaultSettings
spotifyCredentials = spotifySettings || {}
}
return { settingsData, defaultSettingsData, spotifyCredentials } return { settingsData, defaultSettingsData, spotifyCredentials }
} }

View File

@ -406,7 +406,7 @@ const fr = {
ARLcopied: 'ARL copié dans le presse-papier' ARLcopied: 'ARL copié dans le presse-papier'
}, },
logs: { logs: {
title: "Journaux (Logs)", title: 'Journaux (Logs)',
areLogsActive: 'Actifs' areLogsActive: 'Actifs'
} }
}, },
@ -417,7 +417,7 @@ const fr = {
favorites: 'favoris', favorites: 'favoris',
linkAnalyzer: 'analyseur de lien', linkAnalyzer: 'analyseur de lien',
settings: 'paramètres', settings: 'paramètres',
logs: "journaux (logs)", logs: 'journaux (logs)',
about: 'à propos' about: 'à propos'
}, },
tracklist: { tracklist: {

View File

@ -1,7 +1,7 @@
import Vue from 'vue' import Vue from 'vue'
import VueI18n from 'vue-i18n' import VueI18n from 'vue-i18n'
import { locales } from '@/lang/index' import { locales } from '@/lang'
Vue.use(VueI18n) Vue.use(VueI18n)
@ -20,7 +20,7 @@ const i18n = new VueI18n({
* @param {number} choicesLength 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(choice, choicesLength) { ru(choice /*, choicesLength */) {
const n = Math.abs(choice) % 100 const n = Math.abs(choice) % 100
const n1 = n % 10 const n1 = n % 10

View File

@ -127,12 +127,12 @@ const routes = [
const router = new VueRouter({ const router = new VueRouter({
mode: 'history', mode: 'history',
routes, routes,
scrollBehavior(to, from, savedPosition) { scrollBehavior() {
return { x: 0, y: 0 } return { x: 0, y: 0 }
} }
}) })
router.beforeEach((to, from, next) => { router.beforeEach((to, _, next) => {
switch (to.name) { switch (to.name) {
case 'Tracklist': { case 'Tracklist': {
// const getTracklistParams = { // const getTracklistParams = {

View File

@ -28,10 +28,9 @@ const mutations = {
SET_ERRORS(state, payload) { SET_ERRORS(state, payload) {
// The payload has useless data for the GUI, so only the needed data is saved in the store // The payload has useless data for the GUI, so only the needed data is saved in the store
for (const errorName in state) { for (const errorName in state) {
// eslint-disable-next-line no-prototype-builtins
if (state.hasOwnProperty(errorName)) { if (state.hasOwnProperty(errorName)) {
const error = payload[errorName] state[errorName] = payload[errorName]
state[errorName] = error
} }
} }
} }

View File

@ -34,7 +34,8 @@ const actions = {
commit('RESET_LOGIN') commit('RESET_LOGIN')
}, },
setARL({ commit }, payload) { setARL({ commit }, payload) {
let { arl, saveOnLocalStorage } = payload let { saveOnLocalStorage } = payload
const { arl } = payload
saveOnLocalStorage = typeof saveOnLocalStorage === 'undefined' ? true : saveOnLocalStorage saveOnLocalStorage = typeof saveOnLocalStorage === 'undefined' ? true : saveOnLocalStorage
@ -45,7 +46,8 @@ const actions = {
} }
}, },
setAccessToken({ commit }, payload) { setAccessToken({ commit }, payload) {
let { accessToken, saveOnLocalStorage } = payload let { saveOnLocalStorage } = payload
const { accessToken } = payload
saveOnLocalStorage = typeof saveOnLocalStorage === 'undefined' ? true : saveOnLocalStorage saveOnLocalStorage = typeof saveOnLocalStorage === 'undefined' ? true : saveOnLocalStorage

View File

@ -1,4 +1,4 @@
import { ref, watch } from '@vue/composition-api' import { ref } from '@vue/composition-api'
import { socket } from '@/utils/socket' import { socket } from '@/utils/socket'
const messages = ref([]) const messages = ref([])

View File

@ -1,5 +1,5 @@
// https://stackoverflow.com/questions/7451508/html5-audio-playback-with-fade-in-and-fade-out#answer-13149848 // https://stackoverflow.com/questions/7451508/html5-audio-playback-with-fade-in-and-fade-out#answer-13149848
export async function adjustVolume(element, newVolume, { duration = 1000, easing = swing, interval = 13 } = {}) { export function adjustVolume(element, newVolume, { duration = 1000, easing = swing, interval = 13 } = {}) {
const originalVolume = element.volume const originalVolume = element.volume
const delta = newVolume - originalVolume const delta = newVolume - originalVolume

View File

@ -31,7 +31,7 @@ export const toast = function (msg, icon = null, dismiss = true, id = null) {
const iconNode = document.createElement('span') const iconNode = document.createElement('span')
iconNode.classList.add('toast-icon') iconNode.classList.add('toast-icon')
if (icon == 'loading') { if (icon === 'loading') {
const loader = document.createElement('div') const loader = document.createElement('div')
loader.classList.add('circle-loader') loader.classList.add('circle-loader')
iconNode.appendChild(loader) iconNode.appendChild(loader)
@ -66,7 +66,7 @@ export const toast = function (msg, icon = null, dismiss = true, id = null) {
iconNode.classList.add('toast-icon') iconNode.classList.add('toast-icon')
if (icon == null) { if (icon == null) {
iconNode.appendChild(document.createTextNode('')) iconNode.appendChild(document.createTextNode(''))
} else if (icon == 'loading') { } else if (icon === 'loading') {
const loader = document.createElement('div') const loader = document.createElement('div')
loader.classList.add('circle-loader') loader.classList.add('circle-loader')
iconNode.appendChild(loader) iconNode.appendChild(loader)

View File

@ -47,14 +47,15 @@ export function isValidURL(text) {
* @since 0.0.0 * @since 0.0.0
*/ */
export function convertDuration(duration) { export function convertDuration(duration) {
const mm = Math.floor(duration / 60)
// Convert from seconds only to mm:ss format // Convert from seconds only to mm:ss format
let mm, ss let ss = duration - mm * 60 // Add leading zero if ss < 0
mm = Math.floor(duration / 60)
ss = duration - mm * 60
// Add leading zero if ss < 0
if (ss < 10) { if (ss < 10) {
ss = '0' + ss ss = '0' + ss
} }
return mm + ':' + ss return mm + ':' + ss
} }
@ -64,11 +65,13 @@ export function convertDuration(duration) {
* @since 0.0.0 * @since 0.0.0
*/ */
export function convertDurationSeparated(duration) { export function convertDurationSeparated(duration) {
let hh, mm, ss let mm = Math.floor(duration / 60)
mm = Math.floor(duration / 60)
hh = Math.floor(mm / 60) const hh = Math.floor(mm / 60)
ss = duration - mm * 60 const ss = duration - mm * 60
mm -= hh * 60 mm -= hh * 60
return [hh, mm, ss] return [hh, mm, ss]
} }

View File

@ -21,7 +21,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz"
integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q==
"@babel/core@7.14.3": "@babel/core@7.14.3", "@babel/core@^7.1.0", "@babel/core@^7.12.16", "@babel/core@^7.7.5":
version "7.14.3" version "7.14.3"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38"
integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==
@ -42,27 +42,6 @@
semver "^6.3.0" semver "^6.3.0"
source-map "^0.5.0" source-map "^0.5.0"
"@babel/core@^7.1.0", "@babel/core@^7.12.16", "@babel/core@^7.7.5":
version "7.14.3"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.14.3.tgz"
integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==
dependencies:
"@babel/code-frame" "^7.12.13"
"@babel/generator" "^7.14.3"
"@babel/helper-compilation-targets" "^7.13.16"
"@babel/helper-module-transforms" "^7.14.2"
"@babel/helpers" "^7.14.0"
"@babel/parser" "^7.14.3"
"@babel/template" "^7.12.13"
"@babel/traverse" "^7.14.2"
"@babel/types" "^7.14.2"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.1.2"
semver "^6.3.0"
source-map "^0.5.0"
"@babel/eslint-parser@^7.12.16": "@babel/eslint-parser@^7.12.16":
version "7.14.3" version "7.14.3"
resolved "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.14.3.tgz" resolved "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.14.3.tgz"