2023-02-08 12:37:55 +01:00
|
|
|
<template>
|
|
|
|
<div id="app">
|
|
|
|
<nav
|
2023-02-17 22:08:04 +01:00
|
|
|
v-show="
|
|
|
|
$route.path != '/login' &&
|
|
|
|
$route.path != '/setup' &&
|
|
|
|
$route.path != '/share'
|
|
|
|
"
|
2023-02-08 12:37:55 +01:00
|
|
|
:class="{ slideOverTop: $store.getters.isDialogOpen }"
|
|
|
|
>
|
|
|
|
<div>
|
|
|
|
<router-link to="/" title="Home" class="primary">
|
|
|
|
<awesome-icon icon="home" />
|
|
|
|
</router-link>
|
|
|
|
<router-link to="/albums" title="Albums">
|
|
|
|
<awesome-icon icon="compact-disc" />
|
|
|
|
<span class="navigation-title">Albums</span>
|
|
|
|
</router-link>
|
|
|
|
<router-link to="/artists" title="Artists">
|
|
|
|
<awesome-icon icon="user-circle" />
|
|
|
|
<span class="navigation-title">Artists</span>
|
|
|
|
</router-link>
|
|
|
|
<router-link to="/radios" title="Online Radio">
|
|
|
|
<awesome-icon icon="podcast" />
|
|
|
|
<span class="navigation-title">Radios</span>
|
|
|
|
</router-link>
|
|
|
|
<router-link to="/boxes" title="Boxes">
|
|
|
|
<awesome-icon icon="film" />
|
|
|
|
<span class="navigation-title">Videos</span>
|
|
|
|
</router-link>
|
|
|
|
<router-link
|
|
|
|
to="/favourites"
|
|
|
|
title="Favourites"
|
|
|
|
v-if="user.favourites.length > 0"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="star" />
|
|
|
|
<span class="navigation-title">Favourites</span>
|
|
|
|
</router-link>
|
|
|
|
</div>
|
|
|
|
<div></div>
|
|
|
|
<div>
|
|
|
|
<input
|
|
|
|
type="search"
|
|
|
|
@focus="gotoSearchView"
|
|
|
|
@search="searchTermChanged"
|
|
|
|
incremental
|
|
|
|
v-model.lazy="$store.state.search.term"
|
|
|
|
placeholder="Search…"
|
|
|
|
autocomplete="one-time-code"
|
|
|
|
class="hideOnMobile"
|
|
|
|
/>
|
|
|
|
<DropDown v-if="user.token">
|
|
|
|
<template v-slot:default>
|
|
|
|
<button>
|
|
|
|
<awesome-icon icon="cog" />
|
|
|
|
</button>
|
|
|
|
</template>
|
|
|
|
<template v-slot:dropdown-content>
|
|
|
|
<button
|
|
|
|
v-for="(menuItem, i) in $store.getters.viewMenu"
|
|
|
|
:key="i"
|
|
|
|
@click="menuItem.event"
|
|
|
|
>
|
|
|
|
<awesome-icon :icon="menuItem.icon" />{{ menuItem.title }}
|
|
|
|
</button>
|
|
|
|
<hr v-if="$store.getters.viewMenu.length > 0" />
|
|
|
|
<button
|
|
|
|
@click="openDialog('dialogUsers')"
|
|
|
|
v-if="$store.getters['user/isModerator']"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="users" />User management
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
@click="openDialog('serverSettings')"
|
|
|
|
v-if="$store.getters['user/isAdministrator']"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="server" />Server settings
|
|
|
|
</button>
|
2023-02-17 22:08:04 +01:00
|
|
|
|
|
|
|
<button
|
|
|
|
@click="openDialog('sharedItems')"
|
|
|
|
v-if="$store.getters['user/isAdministrator']"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="share" />Shared items
|
|
|
|
</button>
|
|
|
|
|
2023-02-08 12:37:55 +01:00
|
|
|
<button
|
|
|
|
v-if="$store.getters.isElectron"
|
|
|
|
@click="openDialog('dialogSettings')"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="cog" />Settings
|
|
|
|
</button>
|
|
|
|
<hr />
|
|
|
|
<button
|
|
|
|
@click="openDialog('audioUploader')"
|
|
|
|
v-if="!$store.getters['user/isGuest']"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="music" />
|
|
|
|
Upload Audio Files
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
@click="openDialog('videoUploader')"
|
|
|
|
v-if="!$store.getters['user/isGuest']"
|
|
|
|
>
|
|
|
|
<awesome-icon icon="video" />
|
|
|
|
Upload Video Files
|
|
|
|
</button>
|
|
|
|
<hr />
|
|
|
|
<button @click="openDialog('dialogUserProfile')">
|
|
|
|
<awesome-icon icon="user" />Profile
|
|
|
|
</button>
|
|
|
|
<button @click="logout">
|
|
|
|
<awesome-icon icon="sign-out-alt" />Logout [{{ user.name }}]
|
|
|
|
</button>
|
|
|
|
</template>
|
|
|
|
</DropDown>
|
|
|
|
<button v-else title="Login" @click="logout">
|
|
|
|
<awesome-icon icon="sign-in-alt" size="2x" />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
<div id="app-body">
|
|
|
|
<router-view v-slot="{ Component }">
|
|
|
|
<keep-alive>
|
|
|
|
<component :is="Component" />
|
|
|
|
</keep-alive>
|
|
|
|
</router-view>
|
|
|
|
</div>
|
2023-02-19 17:55:11 +01:00
|
|
|
<div id="popup-collection">
|
2023-02-19 19:06:17 +01:00
|
|
|
<PopUp
|
|
|
|
v-for="popup in $store.state.popups"
|
|
|
|
:key="popup.time"
|
|
|
|
:item="popup"
|
|
|
|
/>
|
2023-02-19 17:55:11 +01:00
|
|
|
</div>
|
2023-02-08 12:37:55 +01:00
|
|
|
<Player ref="player" />
|
|
|
|
<Users ref="dialogUsers" />
|
|
|
|
<UserProfile ref="dialogUserProfile" />
|
|
|
|
<ServerSettings ref="serverSettings" />
|
|
|
|
<DesktopSettings ref="dialogSettings" />
|
|
|
|
<VideoScreen />
|
|
|
|
<AudioUploadDialog ref="audioUploader" />
|
|
|
|
<VideoUploadDialog ref="videoUploader" />
|
2023-02-17 22:08:04 +01:00
|
|
|
<SharedItems ref="sharedItems" />
|
2023-02-08 12:37:55 +01:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import VideoScreen from "./components/dialogs/VideoScreen";
|
|
|
|
import DropDown from "./components/base-components/DropDown";
|
|
|
|
import Users from "./components/dialogs/Users";
|
|
|
|
import UserProfile from "./components/dialogs/UserProfile";
|
|
|
|
import DesktopSettings from "./components/dialogs/DesktopSettings";
|
|
|
|
import Player from "./components/Player";
|
|
|
|
import ServerSettings from "./components/dialogs/ServerSettings";
|
|
|
|
import AudioUploadDialog from "./components/dialogs/AudioUpload";
|
|
|
|
import VideoUploadDialog from "./components/dialogs/VideoUpload";
|
2023-02-17 22:08:04 +01:00
|
|
|
import SharedItems from "./components/dialogs/SharedItems";
|
2023-02-19 17:55:11 +01:00
|
|
|
import PopUp from "./components/base-components/PopUp";
|
2023-02-08 12:37:55 +01:00
|
|
|
|
|
|
|
import { mapGetters } from "vuex";
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: "app",
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
searchTimer: 0,
|
|
|
|
timeoutHandler: 0,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
created() {
|
|
|
|
this.login();
|
|
|
|
this.$store.dispatch("loadClientConfigs").then(() => {
|
|
|
|
this.$store.dispatch("system/loadLists");
|
|
|
|
this.$store.dispatch("loadServerInfo");
|
|
|
|
this.$store.dispatch("loadSystemSettings");
|
|
|
|
});
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
document.addEventListener("keydown", (e) => {
|
|
|
|
switch (e.key) {
|
|
|
|
case "MediaPlay":
|
|
|
|
this.$refs.player.togglePlaying();
|
|
|
|
break;
|
|
|
|
case "MediaTrackNext":
|
|
|
|
this.$store.dispatch(
|
|
|
|
"tracks/playNextTo",
|
|
|
|
this.$store.getters("tracks/selectedTrack")
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case "MediaTrackPrevious":
|
|
|
|
this.$store.dispatch(
|
|
|
|
"tracks/playPrevTo",
|
|
|
|
this.$store.getters("tracks/selectedTrack")
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
pushMediaInfo(track) {
|
|
|
|
if ("mediaSession" in navigator && track._id) {
|
|
|
|
navigator.mediaSession.metadata = new MediaMetadata({
|
|
|
|
title: track.title,
|
|
|
|
artist: track.parent.artist_name,
|
|
|
|
album: track.parent.title,
|
|
|
|
artwork: [
|
|
|
|
{
|
|
|
|
src: track.parent.covers.cover32,
|
|
|
|
sizes: "32x32",
|
|
|
|
type: "image/png",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
src: track.parent.covers.cover64,
|
|
|
|
sizes: "64x64",
|
|
|
|
type: "image/png",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
src: track.parent.covers.cover128,
|
|
|
|
sizes: "96x96",
|
|
|
|
type: "image/png",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
src: track.parent.covers.cover128,
|
|
|
|
sizes: "128x128",
|
|
|
|
type: "image/png",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
src: track.parent.covers.cover128,
|
|
|
|
sizes: "256x256",
|
|
|
|
type: "image/png",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
gotoSearchView() {
|
|
|
|
if (this.$route.path != "/search") {
|
|
|
|
let q = this.$store.getters["search/term"];
|
|
|
|
if (q != "") {
|
|
|
|
this.$router.push("/search?q=" + q);
|
|
|
|
} else {
|
|
|
|
this.$router.push("/search");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
searchTermChanged(e) {
|
|
|
|
clearTimeout(this.searchTimer);
|
|
|
|
this.searchTimer = setTimeout(() => {
|
|
|
|
let v = e.srcElement.value;
|
|
|
|
if (!v) {
|
|
|
|
this.$store.commit("search/setTerm", v);
|
|
|
|
if (this.$route.query.q) {
|
|
|
|
this.$router.replace("/search");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else if (v == this.$store.getters["search/term"]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$store.commit("search/setTerm", v);
|
|
|
|
this.$router.replace("/search?q=" + this.$store.getters["search/term"]);
|
|
|
|
}, 250);
|
|
|
|
},
|
|
|
|
openDialog(name) {
|
|
|
|
this.$refs[name].open();
|
|
|
|
},
|
|
|
|
login() {
|
|
|
|
let hash = window.location.hash.replace("#/", "");
|
2023-02-17 22:08:04 +01:00
|
|
|
if (
|
|
|
|
!hash.startsWith("login") &&
|
|
|
|
!hash.startsWith("setup") &&
|
|
|
|
!hash.startsWith("share")
|
|
|
|
) {
|
2023-02-08 12:37:55 +01:00
|
|
|
let redirect = encodeURIComponent(hash);
|
|
|
|
if (redirect) {
|
|
|
|
this.$router.replace({
|
|
|
|
path: "login",
|
|
|
|
query: { redirect: redirect },
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.$router.replace("login");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
logout() {
|
|
|
|
this.$store.dispatch("user/logout");
|
|
|
|
},
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
...mapGetters({
|
|
|
|
selectedTrack: "tracks/selectedTrack",
|
|
|
|
user: "user/user",
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
selectedTrack(newVal) {
|
|
|
|
if (newVal._id) {
|
|
|
|
this.pushMediaInfo(newVal);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
components: {
|
|
|
|
Player,
|
|
|
|
AudioUploadDialog,
|
|
|
|
DropDown,
|
|
|
|
ServerSettings,
|
|
|
|
DesktopSettings,
|
|
|
|
Users,
|
|
|
|
UserProfile,
|
|
|
|
VideoScreen,
|
|
|
|
VideoUploadDialog,
|
2023-02-17 22:08:04 +01:00
|
|
|
SharedItems,
|
2023-02-19 17:55:11 +01:00
|
|
|
PopUp,
|
2023-02-08 12:37:55 +01:00
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|