save-and-restore-progress-for-audio fix #10 #16
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"backend_de": "http://localhost:31204",
|
"backend_dev": "http://localhost:31204",
|
||||||
"backend_dev": "https://webplay.rocks",
|
"backend_de": "https://webplay.rocks",
|
||||||
"backend": "https://webplay.rocks"
|
"backend": "https://webplay.rocks"
|
||||||
}
|
}
|
@ -95,6 +95,14 @@ td.fillCell>* {
|
|||||||
color: var(--yellow);
|
color: var(--yellow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.keepPlaying {
|
||||||
|
z-index: 1;
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DIALOGS
|
DIALOGS
|
||||||
*/
|
*/
|
||||||
|
@ -1,26 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div id="player" class="flex-column" v-show="selectedTrack._id || selectedRadio._id">
|
||||||
id="player"
|
<input type="range" id="slider" min="0" max="100" step="0.1" v-model="selectedTrack.percent" @change="slideChanged" />
|
||||||
class="flex-column"
|
|
||||||
v-show="selectedTrack._id || selectedRadio._id"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="range"
|
|
||||||
id="slider"
|
|
||||||
min="0"
|
|
||||||
max="100"
|
|
||||||
step="0.1"
|
|
||||||
v-model="selectedTrack.percent"
|
|
||||||
@change="slideChanged"
|
|
||||||
/>
|
|
||||||
<div id="playerBar" class="flex-row">
|
<div id="playerBar" class="flex-row">
|
||||||
<div class="flex-row grow">
|
<div class="flex-row grow">
|
||||||
<img
|
<img class="cover pointer" :src="cover" :title="selectedTrack.parent.title" @click="gotoContainer" />
|
||||||
class="cover pointer"
|
|
||||||
:src="cover"
|
|
||||||
:title="selectedTrack.parent.title"
|
|
||||||
@click="gotoContainer"
|
|
||||||
/>
|
|
||||||
<div v-if="selectedTrack._id" class="flex-column">
|
<div v-if="selectedTrack._id" class="flex-column">
|
||||||
<b>{{ selectedTrack.title }}</b>
|
<b>{{ selectedTrack.title }}</b>
|
||||||
from
|
from
|
||||||
@ -28,21 +11,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="playerControls" class="flex-row center">
|
<div id="playerControls" class="flex-row center">
|
||||||
<button
|
<button @click="switchShuffle" title="Shuffle mode" v-if="selectedTrack._id">
|
||||||
@click="switchShuffle"
|
<img src="static/icons/media-shuffle-dark.svg" v-show="$store.getters['player/shuffle']" class="small" />
|
||||||
title="Shuffle mode"
|
<img src="static/icons/media-consecutive-dark.svg" v-show="$store.getters['player/shuffle'] == false" class="small" />
|
||||||
v-if="selectedTrack._id"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="static/icons/media-shuffle-dark.svg"
|
|
||||||
v-show="$store.getters['player/shuffle']"
|
|
||||||
class="small"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
src="static/icons/media-consecutive-dark.svg"
|
|
||||||
v-show="$store.getters['player/shuffle'] == false"
|
|
||||||
class="small"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
<button @click="prevTrack" title="Back" v-if="selectedTrack._id">
|
<button @click="prevTrack" title="Back" v-if="selectedTrack._id">
|
||||||
<awesome-icon icon="backward" />
|
<awesome-icon icon="backward" />
|
||||||
@ -54,46 +25,17 @@
|
|||||||
<button @click="nextTrack" title="Forward" v-if="selectedTrack._id">
|
<button @click="nextTrack" title="Forward" v-if="selectedTrack._id">
|
||||||
<awesome-icon icon="forward" />
|
<awesome-icon icon="forward" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button @click="switchRepeatType" title="Repeat mode" v-if="selectedTrack._id">
|
||||||
@click="switchRepeatType"
|
<img src="static/icons/media-repeat-dark.svg" class="small" v-show="$store.getters['player/repeatType'] == 'all'" />
|
||||||
title="Repeat mode"
|
<img src="static/icons/media-repeat-song-dark.svg" class="small" v-show="$store.getters['player/repeatType'] == 'one'" />
|
||||||
v-if="selectedTrack._id"
|
<img src="static/icons/media-no-repeat-dark.svg" class="small" v-show="$store.getters['player/repeatType'] == 'none'" />
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="static/icons/media-repeat-dark.svg"
|
|
||||||
class="small"
|
|
||||||
v-show="$store.getters['player/repeatType'] == 'all'"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
src="static/icons/media-repeat-song-dark.svg"
|
|
||||||
class="small"
|
|
||||||
v-show="$store.getters['player/repeatType'] == 'one'"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
src="static/icons/media-no-repeat-dark.svg"
|
|
||||||
class="small"
|
|
||||||
v-show="$store.getters['player/repeatType'] == 'none'"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="flex-row ma-right hideOnMobilePortrait grow right" v-show="selectedTrack.title">
|
||||||
class="flex-row ma-right hideOnMobilePortrait grow right"
|
|
||||||
v-show="selectedTrack.title"
|
|
||||||
>
|
|
||||||
{{ formatedP }} | {{ formatedD }}
|
{{ formatedP }} | {{ formatedD }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<audio
|
<audio preload="auto" ref="audioControl" type="audio/mpeg" @ended="nextTrack" @canplay="play" @playing="playing" @durationchange="durationChanged" @timeupdate="timeUpdate" src></audio>
|
||||||
preload="auto"
|
|
||||||
ref="audioControl"
|
|
||||||
type="audio/mpeg"
|
|
||||||
@ended="nextTrack"
|
|
||||||
@canplay="play"
|
|
||||||
@playing="playing"
|
|
||||||
@durationchange="durationChanged"
|
|
||||||
@timeupdate="timeUpdate"
|
|
||||||
src
|
|
||||||
></audio>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -105,7 +47,8 @@ export default {
|
|||||||
audio: {},
|
audio: {},
|
||||||
duration: 0,
|
duration: 0,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
interval: 0,
|
intervalProgress: 0,
|
||||||
|
intervalState: 0,
|
||||||
preConvert: false,
|
preConvert: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -121,21 +64,31 @@ export default {
|
|||||||
play() {
|
play() {
|
||||||
this.audio.play();
|
this.audio.play();
|
||||||
},
|
},
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
if (!this.audio.paused) {
|
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
}
|
|
||||||
|
window.clearInterval(this.intervalProgress);
|
||||||
|
window.clearInterval(this.intervalState);
|
||||||
|
|
||||||
|
this.pushState();
|
||||||
},
|
},
|
||||||
durationChanged() {
|
durationChanged() {
|
||||||
this.duration = this.audio.duration;
|
this.duration = this.audio.duration;
|
||||||
},
|
},
|
||||||
playing() {
|
playing() {
|
||||||
window.clearInterval(this.interval);
|
window.clearInterval(this.intervalProgress);
|
||||||
this.interval = setInterval(() => {
|
window.clearInterval(this.intervalState);
|
||||||
|
|
||||||
|
this.intervalProgress = setInterval(() => {
|
||||||
this.progress = this.audio.currentTime;
|
this.progress = this.audio.currentTime;
|
||||||
this.selectedTrack.percent = (100 / this.duration) * this.progress;
|
this.selectedTrack.percent = (100 / this.duration) * this.progress;
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
if (this.currentUser._id) {
|
||||||
|
this.intervalState = setInterval(() => {
|
||||||
|
this.pushState();
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
audioReset() {
|
audioReset() {
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
@ -156,6 +109,14 @@ export default {
|
|||||||
this.audio.play();
|
this.audio.play();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
skipToSecond(second) {
|
||||||
|
let was_paused = this.audio.paused;
|
||||||
|
this.audio.pause();
|
||||||
|
this.audio.currentTime = second;
|
||||||
|
if (!was_paused) {
|
||||||
|
this.audio.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
playRadio(radio) {
|
playRadio(radio) {
|
||||||
this.$store.commit("tracks/resetSelectedTrack");
|
this.$store.commit("tracks/resetSelectedTrack");
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
@ -184,8 +145,13 @@ export default {
|
|||||||
|
|
||||||
this.pushHistoryItem();
|
this.pushHistoryItem();
|
||||||
|
|
||||||
|
if (this.currentTrackParent.progress) {
|
||||||
|
this.skipToSecond(this.currentTrackParent.progress.progress);
|
||||||
|
this.currentTrackParent.progress = undefined;
|
||||||
|
} else {
|
||||||
// Try to fix SAFARI
|
// Try to fix SAFARI
|
||||||
this.audio.play();
|
this.audio.play();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pushHistoryItem() {
|
pushHistoryItem() {
|
||||||
if (!this.currentUser._id) {
|
if (!this.currentUser._id) {
|
||||||
@ -232,13 +198,20 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.audio.paused) {
|
if (!this.audio.paused) {
|
||||||
this.audio.pause();
|
this.pause();
|
||||||
} else if (this.audio.src != "") {
|
} else if (this.audio.src != "") {
|
||||||
this.audio.play();
|
this.audio.play();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reset() {
|
reset(item) {
|
||||||
window.clearInterval(this.interval);
|
let parentId = item.parent._id;
|
||||||
|
if (item.parent.parent && item.parent.parent.tracks) {
|
||||||
|
parentId = item.parent.parent._id;
|
||||||
|
}
|
||||||
|
this.$store.dispatch("user/resetProgress", parentId);
|
||||||
|
|
||||||
|
window.clearInterval(this.intervalProgress);
|
||||||
|
window.clearInterval(this.intervalState);
|
||||||
if (!this.audio.paused) {
|
if (!this.audio.paused) {
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
}
|
}
|
||||||
@ -299,6 +272,19 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$store.dispatch("user/savePlayerSettings");
|
this.$store.dispatch("user/savePlayerSettings");
|
||||||
},
|
},
|
||||||
|
pushState() {
|
||||||
|
if (!this.currentUser._id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.progress = this.audio.currentTime;
|
||||||
|
let item = {
|
||||||
|
id: this.selectedTrack._id,
|
||||||
|
parentId: this.currentTrackParent._id,
|
||||||
|
type: "track",
|
||||||
|
progress: Math.round(this.progress)
|
||||||
|
}
|
||||||
|
this.$store.dispatch("user/saveProgress", item);
|
||||||
|
},
|
||||||
timeUpdate(event) {
|
timeUpdate(event) {
|
||||||
let percent = (event.target.currentTime / event.target.duration) * 100;
|
let percent = (event.target.currentTime / event.target.duration) * 100;
|
||||||
if (percent > 10 && !this.preConvert) {
|
if (percent > 10 && !this.preConvert) {
|
||||||
@ -390,11 +376,11 @@ export default {
|
|||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedTrack(newVal) {
|
selectedTrack(newVal, oldVal) {
|
||||||
if (newVal._id) {
|
if (newVal._id) {
|
||||||
this.playTrack(newVal);
|
this.playTrack(newVal);
|
||||||
} else {
|
} else {
|
||||||
this.reset();
|
this.reset(oldVal);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -409,17 +395,21 @@ export default {
|
|||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
box-shadow: 0 0px 4px var(--shadow);
|
box-shadow: 0 0px 4px var(--shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
#player .cover {
|
#player .cover {
|
||||||
width: 52px;
|
width: 52px;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#playerBar {
|
#playerBar {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
max-height: 52px;
|
max-height: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#playerBar>div {
|
#playerBar>div {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#playerControls button {
|
#playerControls button {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
|
@ -1,25 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<DialogBase
|
<DialogBase ref="dialogWindow" :title="album_title" @canceled="closed" :showFooter="false" :disableXscroll="true" :disableYscroll="true">
|
||||||
ref="dialogWindow"
|
|
||||||
:title="album_title"
|
|
||||||
@canceled="closed"
|
|
||||||
:showFooter="false"
|
|
||||||
:disableXscroll="true"
|
|
||||||
:disableYscroll="true"
|
|
||||||
>
|
|
||||||
<div id="albumViewer" class="flex-row">
|
<div id="albumViewer" class="flex-row">
|
||||||
<div id="header" class="flex-column">
|
<div id="header" class="flex-column">
|
||||||
<div id="background" :style="coverBackground" />
|
<div id="background" :style="coverBackground" />
|
||||||
<div class="grow z1 center flex-column">
|
<div class="grow z1 center flex-column">
|
||||||
<img class="glow ma24" :src="cover" @dblclick="dblclick" />
|
<img class="glow ma24" :src="cover" @dblclick="dblclick" />
|
||||||
</div>
|
</div>
|
||||||
<awesome-icon
|
<awesome-icon icon="star" size="2x" class="favourite ma4" :class="{ active: isFavourite }" @click="toggleFavourite" title="Favourite" />
|
||||||
icon="star"
|
<awesome-icon icon="play" size="2x" class="keepPlaying ma4 primary-text" @click="playProgress" v-if="selectedAlbum.progress" title="Keep playing" />
|
||||||
size="2x"
|
|
||||||
class="favourite ma4"
|
|
||||||
:class="{ active: isFavourite }"
|
|
||||||
@click="toggleFavourite"
|
|
||||||
/>
|
|
||||||
<div id="stats" class="flex-row z1">
|
<div id="stats" class="flex-row z1">
|
||||||
<DropDown v-if="$store.getters['user/isAdministrator']">
|
<DropDown v-if="$store.getters['user/isAdministrator']">
|
||||||
<button class="flat center" :title="visibility_text">
|
<button class="flat center" :title="visibility_text">
|
||||||
@ -27,11 +15,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<template v-slot:dropdown-content>
|
<template v-slot:dropdown-content>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button v-for="(item, i) in $store.state.system.lists.visibility" :key="i" @click="setVisibility(item)">
|
||||||
v-for="(item, i) in $store.state.system.lists.visibility"
|
|
||||||
:key="i"
|
|
||||||
@click="setVisibility(item)"
|
|
||||||
>
|
|
||||||
<awesome-icon :icon="getVisibilityIcon(item)" />{{
|
<awesome-icon :icon="getVisibilityIcon(item)" />{{
|
||||||
getVisibilityText(item)
|
getVisibilityText(item)
|
||||||
}}
|
}}
|
||||||
@ -40,10 +24,7 @@
|
|||||||
<button v-if="!selectedAlbum.share._id" @click="shareEnable">
|
<button v-if="!selectedAlbum.share._id" @click="shareEnable">
|
||||||
<awesome-icon icon="share" />Share this album
|
<awesome-icon icon="share" />Share this album
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button v-if="selectedAlbum.share._id" @click="addShareUrlToClipboard">
|
||||||
v-if="selectedAlbum.share._id"
|
|
||||||
@click="addShareUrlToClipboard"
|
|
||||||
>
|
|
||||||
<awesome-icon icon="clipboard" />Copy url into clipboard
|
<awesome-icon icon="clipboard" />Copy url into clipboard
|
||||||
</button>
|
</button>
|
||||||
<button v-if="selectedAlbum.share._id" @click="shareDisable">
|
<button v-if="selectedAlbum.share._id" @click="shareDisable">
|
||||||
@ -61,8 +42,7 @@
|
|||||||
}}</b>
|
}}</b>
|
||||||
<br />
|
<br />
|
||||||
<span v-if="album_year">
|
<span v-if="album_year">
|
||||||
from year <b>{{ album_year }}</b> </span
|
from year <b>{{ album_year }}</b> </span><br />
|
||||||
><br />
|
|
||||||
<b>{{ album_tracks.length }}</b> Tracks with a duration of
|
<b>{{ album_tracks.length }}</b> Tracks with a duration of
|
||||||
<b>{{ album_duration }}</b>
|
<b>{{ album_duration }}</b>
|
||||||
</span>
|
</span>
|
||||||
@ -89,7 +69,6 @@
|
|||||||
</DropDown>
|
</DropDown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul id="trackList" class="tracks">
|
<ul id="trackList" class="tracks">
|
||||||
<li v-for="track in selectedAlbum.tracks" :key="track._id">
|
<li v-for="track in selectedAlbum.tracks" :key="track._id">
|
||||||
<TrackItem :track="track" :showCover="false" />
|
<TrackItem :track="track" :showCover="false" />
|
||||||
@ -156,6 +135,14 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
playProgress() {
|
||||||
|
let track = this.selectedAlbum.tracks.find(
|
||||||
|
(f) => f._id == this.selectedAlbum.progress.id
|
||||||
|
);
|
||||||
|
if (track) {
|
||||||
|
this.$store.dispatch("tracks/play", track);
|
||||||
|
}
|
||||||
|
},
|
||||||
closed() {
|
closed() {
|
||||||
if (
|
if (
|
||||||
(window.history.state.back &&
|
(window.history.state.back &&
|
||||||
@ -228,6 +215,10 @@ export default {
|
|||||||
shareDisable() {
|
shareDisable() {
|
||||||
this.$store.dispatch("albums/shareDisable", this.selectedAlbum);
|
this.$store.dispatch("albums/shareDisable", this.selectedAlbum);
|
||||||
},
|
},
|
||||||
|
loadUserProgress() {
|
||||||
|
if (this.selectedTrack.parent._id != this.selectedAlbum._id)
|
||||||
|
this.$store.dispatch("user/getProgress", this.selectedAlbum);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
@ -318,6 +309,7 @@ export default {
|
|||||||
this.$refs.dialogWindow.open();
|
this.$refs.dialogWindow.open();
|
||||||
window.addEventListener("keydown", this.keydownListener);
|
window.addEventListener("keydown", this.keydownListener);
|
||||||
}
|
}
|
||||||
|
this.loadUserProgress();
|
||||||
this.gotoTrack();
|
this.gotoTrack();
|
||||||
} else {
|
} else {
|
||||||
if (this.$refs.dialogWindow.visible) {
|
if (this.$refs.dialogWindow.visible) {
|
||||||
@ -339,14 +331,17 @@ export default {
|
|||||||
height: 366px;
|
height: 366px;
|
||||||
width: 640px;
|
width: 640px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header img {
|
#header img {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#stats {
|
#stats {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -357,10 +352,12 @@ export default {
|
|||||||
border-top: 1px solid #ffffff20;
|
border-top: 1px solid #ffffff20;
|
||||||
border-bottom: 1px solid #00000020;
|
border-bottom: 1px solid #00000020;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-activator button {
|
.dropdown-activator button {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#trackList {
|
#trackList {
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -370,15 +367,19 @@ export default {
|
|||||||
#header {
|
#header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#albumViewer {
|
#albumViewer {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media (max-width: 480px), (max-height: 480px) {
|
|
||||||
|
@media (max-width: 480px),
|
||||||
|
(max-height: 480px) {
|
||||||
#albumViewer {
|
#albumViewer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#trackList {
|
#trackList {
|
||||||
height: initial;
|
height: initial;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
@ -1,24 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<DialogBase
|
<DialogBase ref="dialogWindow" id="dialogWindow" :title="selectedArtist.name" @canceled="closed" :showFooter="false" :showFullscreenButton="true" :disableXscroll="true" :disableYscroll="true">
|
||||||
ref="dialogWindow"
|
|
||||||
id="dialogWindow"
|
|
||||||
:title="selectedArtist.name"
|
|
||||||
@canceled="closed"
|
|
||||||
:showFooter="false"
|
|
||||||
:showFullscreenButton="true"
|
|
||||||
:disableXscroll="true"
|
|
||||||
:disableYscroll="true"
|
|
||||||
>
|
|
||||||
<div id="artistViewer">
|
<div id="artistViewer">
|
||||||
<div id="header" class="flex-column">
|
<div id="header" class="flex-column">
|
||||||
<div id="background" :style="coverBackground" />
|
<div id="background" :style="coverBackground" />
|
||||||
<awesome-icon
|
<awesome-icon icon="star" size="2x" class="favourite ma4" :class="{ active: isFavourite }" @click="toggleFavourite" />
|
||||||
icon="star"
|
<awesome-icon icon="play" size="2x" class="keepPlaying ma4 primary-text" @click="playProgress" v-if="selectedArtist.progress" title="Keep playing" />
|
||||||
size="2x"
|
|
||||||
class="favourite ma4"
|
|
||||||
:class="{ active: isFavourite }"
|
|
||||||
@click="toggleFavourite"
|
|
||||||
/>
|
|
||||||
<h1 @dblclick="dblclick">
|
<h1 @dblclick="dblclick">
|
||||||
{{ selectedArtist.name }}
|
{{ selectedArtist.name }}
|
||||||
</h1>
|
</h1>
|
||||||
@ -28,41 +14,20 @@
|
|||||||
<b>{{ artist_duration }}</b>
|
<b>{{ artist_duration }}</b>
|
||||||
</span>
|
</span>
|
||||||
<div id="albumList" class="flex-row showOnMobilePortrait">
|
<div id="albumList" class="flex-row showOnMobilePortrait">
|
||||||
<AlbumItem
|
<AlbumItem class="ma" :class="{ playing: playingAlbumId == album._id }" v-for="album in selectedArtist.albums" :key="album._id" :item="album" @click="scrollToAlbum(album)" @dblclick="playAlbum(album)" />
|
||||||
class="ma"
|
|
||||||
:class="{ playing: playingAlbumId == album._id }"
|
|
||||||
v-for="album in selectedArtist.albums"
|
|
||||||
:key="album._id"
|
|
||||||
:item="album"
|
|
||||||
@click="scrollToAlbum(album)"
|
|
||||||
@dblclick="playAlbum(album)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="navigation" class="flex-row center ma-top">
|
<div id="navigation" class="flex-row center ma-top">
|
||||||
<div class="flex-row grow"></div>
|
<div class="flex-row grow"></div>
|
||||||
<div class="flex-row">
|
<div class="flex-row">
|
||||||
<button
|
<button @click="gotoPrevArtist" class="primary ma4" :title="prevArtist.name" :disabled="!prevArtist._id">
|
||||||
@click="gotoPrevArtist"
|
|
||||||
class="primary ma4"
|
|
||||||
:title="prevArtist.name"
|
|
||||||
:disabled="!prevArtist._id"
|
|
||||||
>
|
|
||||||
<awesome-icon icon="angle-left" class="ma4" />
|
<awesome-icon icon="angle-left" class="ma4" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button @click="gotoNextArtist" class="primary ma4" :title="nextArtist.name" :disabled="!nextArtist._id">
|
||||||
@click="gotoNextArtist"
|
|
||||||
class="primary ma4"
|
|
||||||
:title="nextArtist.name"
|
|
||||||
:disabled="!nextArtist._id"
|
|
||||||
>
|
|
||||||
<awesome-icon icon="angle-right" class="ma4" />
|
<awesome-icon icon="angle-right" class="ma4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row grow right center">
|
<div class="flex-row grow right center">
|
||||||
<DropDown
|
<DropDown v-if="$store.getters['user/isAdministrator']" class="hideOnMobile">
|
||||||
v-if="$store.getters['user/isAdministrator']"
|
|
||||||
class="hideOnMobile"
|
|
||||||
>
|
|
||||||
<button class="flat pa8-left pa8-right">
|
<button class="flat pa8-left pa8-right">
|
||||||
<awesome-icon icon="ellipsis-v" />
|
<awesome-icon icon="ellipsis-v" />
|
||||||
</button>
|
</button>
|
||||||
@ -86,23 +51,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex-row overflow-y">
|
<div class="flex-row overflow-y">
|
||||||
<div id="albumList" class="flex-column hideOnMobilePortrait">
|
<div id="albumList" class="flex-column hideOnMobilePortrait">
|
||||||
<AlbumItem
|
<AlbumItem class="ma-top ma-left ma-right" :class="{ playing: playingAlbumId == album._id }" v-for="album in selectedArtist.albums" :key="album._id" :item="album" :id="album._id" :ref="album._id" @click="scrollToAlbum(album)" @dblclick="playAlbum(album)" />
|
||||||
class="ma-top ma-left ma-right"
|
|
||||||
:class="{ playing: playingAlbumId == album._id }"
|
|
||||||
v-for="album in selectedArtist.albums"
|
|
||||||
:key="album._id"
|
|
||||||
:item="album"
|
|
||||||
:id="album._id"
|
|
||||||
:ref="album._id"
|
|
||||||
@click="scrollToAlbum(album)"
|
|
||||||
@dblclick="playAlbum(album)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul id="trackList" class="tracks" :class="{ playing: selectedTrack._id != null }">
|
||||||
id="trackList"
|
|
||||||
class="tracks"
|
|
||||||
:class="{ playing: selectedTrack._id != null }"
|
|
||||||
>
|
|
||||||
<li v-for="track in selectedArtist.tracks" :key="track._id">
|
<li v-for="track in selectedArtist.tracks" :key="track._id">
|
||||||
<TrackItem :track="track" :ref="track._id" />
|
<TrackItem :track="track" :ref="track._id" />
|
||||||
</li>
|
</li>
|
||||||
@ -143,6 +94,14 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
playProgress() {
|
||||||
|
let track = this.selectedArtist.tracks.find(
|
||||||
|
(f) => f._id == this.selectedArtist.progress.id
|
||||||
|
);
|
||||||
|
if (track) {
|
||||||
|
this.$store.dispatch("tracks/play", track);
|
||||||
|
}
|
||||||
|
},
|
||||||
gotoNextArtist() {
|
gotoNextArtist() {
|
||||||
this.$store.dispatch("artists/gotoNextArtist");
|
this.$store.dispatch("artists/gotoNextArtist");
|
||||||
},
|
},
|
||||||
@ -194,6 +153,10 @@ export default {
|
|||||||
uploadNewCover() {
|
uploadNewCover() {
|
||||||
this.$store.dispatch("artists/uploadNewCover", this.selectedArtist);
|
this.$store.dispatch("artists/uploadNewCover", this.selectedArtist);
|
||||||
},
|
},
|
||||||
|
loadUserProgress() {
|
||||||
|
if (!this.isPlaying || this.selectedTrack.parent.parent._id != this.selectedArtist._id)
|
||||||
|
this.$store.dispatch("user/getProgress", this.selectedArtist);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
@ -202,6 +165,7 @@ export default {
|
|||||||
selectedArtist: ["artists/selectedArtist"],
|
selectedArtist: ["artists/selectedArtist"],
|
||||||
selectedTrack: ["tracks/selectedTrack"],
|
selectedTrack: ["tracks/selectedTrack"],
|
||||||
favourites: ["user/favourites"],
|
favourites: ["user/favourites"],
|
||||||
|
isPlaying: ["player/isPlaying"]
|
||||||
}),
|
}),
|
||||||
cover() {
|
cover() {
|
||||||
let covers = this.selectedArtist.covers;
|
let covers = this.selectedArtist.covers;
|
||||||
@ -266,6 +230,7 @@ export default {
|
|||||||
this.$refs.dialogWindow.open();
|
this.$refs.dialogWindow.open();
|
||||||
window.addEventListener("keydown", this.keydownListener);
|
window.addEventListener("keydown", this.keydownListener);
|
||||||
}
|
}
|
||||||
|
this.loadUserProgress();
|
||||||
this.gotoTrack();
|
this.gotoTrack();
|
||||||
} else {
|
} else {
|
||||||
if (this.$refs.dialogWindow.visible) {
|
if (this.$refs.dialogWindow.visible) {
|
||||||
@ -289,6 +254,7 @@ export default {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
#stats {
|
#stats {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -297,33 +263,40 @@ h1,
|
|||||||
color: var(--white);
|
color: var(--white);
|
||||||
text-shadow: 0 1px 2px black;
|
text-shadow: 0 1px 2px black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#artistImage {
|
#artistImage {
|
||||||
width: 512px;
|
width: 512px;
|
||||||
max-height: 256px;
|
max-height: 256px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
width: 760px;
|
width: 760px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#albumList {
|
#albumList {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
#albumList::-webkit-scrollbar {
|
#albumList::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#albumList .album:last-child {
|
#albumList .album:last-child {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#navigation {
|
#navigation {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
background-color: #ffffff40;
|
background-color: #ffffff40;
|
||||||
border-top: 1px solid #ffffff20;
|
border-top: 1px solid #ffffff20;
|
||||||
border-bottom: 1px solid #00000020;
|
border-bottom: 1px solid #00000020;
|
||||||
}
|
}
|
||||||
|
|
||||||
#trackList {
|
#trackList {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
@ -338,12 +311,15 @@ h1,
|
|||||||
width: initial;
|
width: initial;
|
||||||
height: initial;
|
height: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-body button {
|
.dialog-body button {
|
||||||
color: var(--darkgray);
|
color: var(--darkgray);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
#albumList {
|
#albumList {
|
||||||
background-color: initial;
|
background-color: initial;
|
||||||
@ -353,19 +329,21 @@ h1,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px), (max-height: 480px) {
|
@media (max-width: 480px),
|
||||||
|
(max-height: 480px) {
|
||||||
#artistViewer {
|
#artistViewer {
|
||||||
height: initial;
|
height: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#trackList {
|
#trackList {
|
||||||
width: initial;
|
width: initial;
|
||||||
height: initial;
|
height: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
width: initial;
|
width: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 480px) {
|
@media (max-height: 480px) {}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -80,6 +80,31 @@ export default {
|
|||||||
context.commit("setHistory", res.data);
|
context.commit("setHistory", res.data);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
saveProgress(context, item) {
|
||||||
|
if (context.state._id == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
axios
|
||||||
|
.post(context.rootGetters.server + "/api/user/progress", item, context.rootGetters.headers);
|
||||||
|
},
|
||||||
|
getProgress(context, parent) {
|
||||||
|
if (context.state._id == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get(context.rootGetters.server + "/api/user/progress/" + parent._id, context.rootGetters.headers)
|
||||||
|
.then((res) => {
|
||||||
|
parent.progress = res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetProgress(context, parentId) {
|
||||||
|
if (context.state._id == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
axios
|
||||||
|
.delete(context.rootGetters.server + "/api/user/progress/" + parentId, context.rootGetters.headers);
|
||||||
|
},
|
||||||
savePlayerSettings(context) {
|
savePlayerSettings(context) {
|
||||||
let body = {
|
let body = {
|
||||||
repeat: context.rootGetters["player/repeatType"],
|
repeat: context.rootGetters["player/repeatType"],
|
||||||
|
Loading…
Reference in New Issue
Block a user