371 lines
9.4 KiB
Vue
371 lines
9.4 KiB
Vue
|
<template>
|
||
|
<DialogBase
|
||
|
ref="dialogWindow"
|
||
|
id="dialogWindow"
|
||
|
:title="selectedArtist.name"
|
||
|
@canceled="closed"
|
||
|
:showFooter="false"
|
||
|
:showFullscreenButton="true"
|
||
|
:disableXscroll="true"
|
||
|
:disableYscroll="true"
|
||
|
>
|
||
|
<div id="artistViewer">
|
||
|
<div id="header" class="flex-column">
|
||
|
<div id="background" :style="coverBackground" />
|
||
|
<awesome-icon
|
||
|
icon="star"
|
||
|
size="2x"
|
||
|
class="favourite ma4"
|
||
|
:class="{ active: isFavourite }"
|
||
|
@click="toggleFavourite"
|
||
|
/>
|
||
|
<h1 @dblclick="dblclick" class="hideOnMobileLandscape">
|
||
|
{{ selectedArtist.name }}
|
||
|
</h1>
|
||
|
<span id="stats" class="hideOnMobileLandscape ma-bottom">
|
||
|
<b>{{ artist_tracks.length }}</b> Tracks in
|
||
|
<b>{{ artist_albums.length }}</b> Albums with a duration of
|
||
|
<b>{{ artist_duration }}</b>
|
||
|
</span>
|
||
|
<div id="albumList" class="flex-row showOnMobile">
|
||
|
<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)"
|
||
|
/>
|
||
|
</div>
|
||
|
<div id="navigation" class="flex-row center">
|
||
|
<div class="flex-row grow"></div>
|
||
|
<div class="flex-row">
|
||
|
<button
|
||
|
@click="gotoPrevArtist"
|
||
|
class="primary ma4"
|
||
|
:title="prevArtist.name"
|
||
|
:disabled="!prevArtist._id"
|
||
|
>
|
||
|
<awesome-icon icon="angle-left" class="ma4" />
|
||
|
</button>
|
||
|
<button
|
||
|
@click="gotoNextArtist"
|
||
|
class="primary ma4"
|
||
|
:title="nextArtist.name"
|
||
|
:disabled="!nextArtist._id"
|
||
|
>
|
||
|
<awesome-icon icon="angle-right" class="ma4" />
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="flex-row grow right center">
|
||
|
<DropDown
|
||
|
v-if="$store.getters['user/isAdministrator']"
|
||
|
class="hideOnMobile"
|
||
|
>
|
||
|
<button class="flat pa8-left pa8-right">
|
||
|
<awesome-icon icon="ellipsis-v" />
|
||
|
</button>
|
||
|
<template v-slot:dropdown-content>
|
||
|
<div>
|
||
|
<button @click="uploadNewCover">
|
||
|
<awesome-icon icon="image" />Set new Cover...
|
||
|
</button>
|
||
|
<button @click="resetCover">
|
||
|
<awesome-icon icon="eraser" />Reset Cover
|
||
|
</button>
|
||
|
<hr />
|
||
|
<button @click="mergeArtist">
|
||
|
<awesome-icon icon="compress-alt" />Merge Artists...
|
||
|
</button>
|
||
|
</div>
|
||
|
</template>
|
||
|
</DropDown>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="flex-row overflow-y">
|
||
|
<div id="albumList" class="flex-column hideOnMobile">
|
||
|
<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)"
|
||
|
/>
|
||
|
</div>
|
||
|
<ul
|
||
|
id="trackList"
|
||
|
class="tracks"
|
||
|
:class="{ playing: selectedTrack._id != null }"
|
||
|
>
|
||
|
<li v-for="track in selectedArtist.tracks" :key="track._id">
|
||
|
<TrackItem :track="track" :ref="track._id" />
|
||
|
</li>
|
||
|
</ul>
|
||
|
</div>
|
||
|
</div>
|
||
|
<ArtistMerge ref="mergeDialog" />
|
||
|
</DialogBase>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import ArtistMerge from "./ArtistMerge";
|
||
|
import TrackItem from "../Track";
|
||
|
import { mapGetters } from "vuex";
|
||
|
|
||
|
export default {
|
||
|
mounted() {
|
||
|
if (this.selectedArtist._id) {
|
||
|
this.$refs.dialogWindow.open();
|
||
|
window.addEventListener("keydown", this.keydownListener);
|
||
|
}
|
||
|
},
|
||
|
methods: {
|
||
|
dblclick() {
|
||
|
this.$store.commit("tracks/resetSelectedTrack");
|
||
|
this.$store.commit("radios/resetSelectedRadio");
|
||
|
this.$store.dispatch("tracks/playContainer", this.selectedArtist);
|
||
|
},
|
||
|
gotoTrack() {
|
||
|
if (this.$route.query.play) {
|
||
|
if (!this.selectedTrack._id) {
|
||
|
let track = this.selectedArtist.tracks.find(
|
||
|
(f) => f._id == this.$route.query.play
|
||
|
);
|
||
|
if (track) {
|
||
|
this.$store.dispatch("tracks/play", track);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
gotoNextArtist() {
|
||
|
this.$store.dispatch("artists/gotoNextArtist");
|
||
|
},
|
||
|
gotoPrevArtist() {
|
||
|
this.$store.dispatch("artists/gotoPrevArtist");
|
||
|
},
|
||
|
closed() {
|
||
|
if (
|
||
|
window.history.state.back.indexOf("?") == -1 ||
|
||
|
window.history.state.back.startsWith("/search")
|
||
|
) {
|
||
|
this.$router.back();
|
||
|
} else {
|
||
|
this.$store.dispatch("artists/resetSelectedArtist");
|
||
|
}
|
||
|
},
|
||
|
playAlbum(album) {
|
||
|
this.$store.dispatch("tracks/playContainer", album);
|
||
|
},
|
||
|
keydownListener(e) {
|
||
|
if (e.key == "ArrowLeft") {
|
||
|
e.preventDefault();
|
||
|
this.gotoPrevArtist();
|
||
|
}
|
||
|
if (e.key == "ArrowRight") {
|
||
|
e.preventDefault();
|
||
|
this.gotoNextArtist();
|
||
|
}
|
||
|
},
|
||
|
mergeArtist() {
|
||
|
this.$refs.mergeDialog.open(this.selectedArtist);
|
||
|
},
|
||
|
resetCover() {
|
||
|
this.$store.dispatch("artists/resetCover", this.selectedArtist);
|
||
|
},
|
||
|
scrollToAlbum(album) {
|
||
|
let track = album.tracks[0];
|
||
|
let control = this.$refs[track._id];
|
||
|
control[0].scrollFunction(true);
|
||
|
control = this.$refs[album._id];
|
||
|
control[0].scrollFunction();
|
||
|
},
|
||
|
toggleFavourite() {
|
||
|
this.$store.dispatch("user/toggleFavourite", {
|
||
|
itemId: this.selectedArtist._id,
|
||
|
type: "artist",
|
||
|
});
|
||
|
},
|
||
|
uploadNewCover() {
|
||
|
this.$store.dispatch("artists/uploadNewCover", this.selectedArtist);
|
||
|
},
|
||
|
},
|
||
|
computed: {
|
||
|
...mapGetters({
|
||
|
prevArtist: ["artists/prevArtist"],
|
||
|
nextArtist: ["artists/nextArtist"],
|
||
|
selectedArtist: ["artists/selectedArtist"],
|
||
|
selectedTrack: ["tracks/selectedTrack"],
|
||
|
favourites: ["user/favourites"],
|
||
|
}),
|
||
|
cover() {
|
||
|
let covers = this.selectedArtist.covers;
|
||
|
if (covers.cover512) {
|
||
|
return covers.cover512;
|
||
|
}
|
||
|
return "/static/icons/dummy/artist.svg";
|
||
|
},
|
||
|
coverBackground() {
|
||
|
return "background-image: url('" + this.cover + "')";
|
||
|
},
|
||
|
artist_albums() {
|
||
|
return this.selectedArtist.albums || [];
|
||
|
},
|
||
|
artist_duration() {
|
||
|
let duration = 0;
|
||
|
let hours = 0;
|
||
|
let minutes = 0;
|
||
|
let seconds = 0;
|
||
|
|
||
|
this.selectedArtist.tracks.forEach((track) => {
|
||
|
duration += track.duration;
|
||
|
});
|
||
|
|
||
|
if (duration >= 3600) {
|
||
|
hours = parseInt(duration / 3600);
|
||
|
duration -= hours * 3600;
|
||
|
}
|
||
|
|
||
|
minutes = parseInt(duration / 60);
|
||
|
seconds = parseInt(duration - minutes * 60);
|
||
|
return (
|
||
|
(hours > 0 ? hours + ":" : "") +
|
||
|
(minutes < 10 ? "0" : "") +
|
||
|
minutes +
|
||
|
":" +
|
||
|
(seconds < 10 ? "0" : "") +
|
||
|
seconds
|
||
|
);
|
||
|
},
|
||
|
artist_tracks() {
|
||
|
return this.selectedArtist.tracks || [];
|
||
|
},
|
||
|
isFavourite() {
|
||
|
return (
|
||
|
this.favourites.find((f) => f.itemId == this.selectedArtist._id) !=
|
||
|
undefined
|
||
|
);
|
||
|
},
|
||
|
playingAlbumId() {
|
||
|
if (this.selectedTrack) {
|
||
|
return this.selectedTrack.parent._id;
|
||
|
} else {
|
||
|
return "";
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
watch: {
|
||
|
selectedArtist(newVal) {
|
||
|
if (newVal._id) {
|
||
|
if (!this.$refs.dialogWindow.visible) {
|
||
|
this.$refs.dialogWindow.open();
|
||
|
window.addEventListener("keydown", this.keydownListener);
|
||
|
}
|
||
|
this.gotoTrack();
|
||
|
} else {
|
||
|
if (this.$refs.dialogWindow.visible) {
|
||
|
this.$refs.dialogWindow.close();
|
||
|
}
|
||
|
window.removeEventListener("keydown", this.keydownListener);
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
components: {
|
||
|
ArtistMerge,
|
||
|
TrackItem,
|
||
|
},
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<style scoped>
|
||
|
#artistViewer {
|
||
|
height: 640px;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
h1,
|
||
|
#stats {
|
||
|
z-index: 1;
|
||
|
text-align: center;
|
||
|
width: 100%;
|
||
|
color: var(--white);
|
||
|
text-shadow: 0 1px 2px black;
|
||
|
}
|
||
|
#artistImage {
|
||
|
width: 512px;
|
||
|
max-height: 256px;
|
||
|
}
|
||
|
#header {
|
||
|
position: relative;
|
||
|
background-color: black;
|
||
|
width: 760px;
|
||
|
max-width: 100%;
|
||
|
}
|
||
|
#albumList {
|
||
|
z-index: 1;
|
||
|
overflow-y: auto;
|
||
|
background-color: var(--white);
|
||
|
}
|
||
|
#albumList::-webkit-scrollbar {
|
||
|
display: none;
|
||
|
}
|
||
|
#albumList .album:last-child {
|
||
|
margin-bottom: 12px;
|
||
|
}
|
||
|
#navigation {
|
||
|
z-index: 2;
|
||
|
background-color: #ffffff40;
|
||
|
border-top: 1px solid #ffffff20;
|
||
|
border-bottom: 1px solid #00000020;
|
||
|
}
|
||
|
#trackList {
|
||
|
z-index: 1;
|
||
|
background-color: var(--white);
|
||
|
}
|
||
|
|
||
|
.album.playing {
|
||
|
box-shadow: 0px 6px 12px #000000a0 !important;
|
||
|
}
|
||
|
|
||
|
.dialog-window.fullscreen #artistViewer,
|
||
|
.dialog-window.fullscreen #header {
|
||
|
width: initial;
|
||
|
height: initial;
|
||
|
}
|
||
|
.dialog-body button {
|
||
|
color: var(--darkgray);
|
||
|
}
|
||
|
.container {
|
||
|
flex-grow: 0;
|
||
|
}
|
||
|
@media (max-width: 480px) {
|
||
|
}
|
||
|
|
||
|
@media (max-width: 480px), (max-height: 480px) {
|
||
|
#artistViewer {
|
||
|
height: initial;
|
||
|
}
|
||
|
#trackList {
|
||
|
width: initial;
|
||
|
height: initial;
|
||
|
}
|
||
|
#header {
|
||
|
width: initial;
|
||
|
}
|
||
|
#albumList {
|
||
|
background-color: initial;
|
||
|
align-self: center;
|
||
|
padding-bottom: 0;
|
||
|
max-width: 100%;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@media (max-height: 480px) {
|
||
|
}
|
||
|
</style>
|