🔨 Retrive all info for audio preview

This commit is contained in:
SebClem 2022-06-22 16:09:12 +02:00
parent dba5455b5e
commit 5be4b1d41c
Signed by: sebclem
GPG Key ID: 5A4308F6A359EA50
6 changed files with 350 additions and 57 deletions

View File

@ -0,0 +1,282 @@
<template>
<v-card title="Audio">
<template v-slot:prepend>
<v-icon color="primary" size="x-large">mdi-music-circle</v-icon>
</template>
<template v-slot:append v-if="status.connected && status.canView">
<v-btn color="black" :disabled="connectBtnDisable" size="small">
{{ status.channel?.name }}
</v-btn>
</template>
<v-container class="pt-0">
<v-row>
<v-col v-if="!status.connected" class="d-flex align-center">
<v-avatar color="grey-darken-3" size="x-large">
<v-icon icon="mdi-connection"></v-icon>
</v-avatar>
<v-row class="ml-3">
<v-col>
<h4>Not connected to voice channel</h4>
</v-col>
</v-row>
</v-col>
<v-col v-else-if="status.connected">
<v-row>
<v-col class="d-flex align-center">
<template v-if="status.canView && !status.playBackInfo?.stopped">
<v-avatar
color="grey-darken-3"
size="x-large"
:image="
'https://img.youtube.com/vi/' +
status.playBackInfo?.trackInfo?.detail.identifier +
'/hqdefault.jpg'
"
/>
<v-row class="ml-3">
<v-col>
<h4>
{{ status.playBackInfo?.trackInfo?.detail.title }}
</h4>
<div class="d-flex align-center mr-6">
<h5 class="text-grey-lighten-1">
{{ status.playBackInfo?.trackInfo?.detail.author }}
</h5>
<v-spacer />
<v-avatar
size="x-small"
:color="
status.playBackInfo?.trackInfo?.submitter.avatar
? ''
: 'grey-darken-3'
"
class="mr-2"
>
<v-img
v-if="
status.playBackInfo?.trackInfo?.submitter.avatar
"
:src="
status.playBackInfo?.trackInfo?.submitter.avatar
"
></v-img>
<template
v-if="
!status.playBackInfo?.trackInfo?.submitter.avatar
"
>{{
status.playBackInfo?.trackInfo?.submitter.avatar[1]
}}</template
></v-avatar
>
<h5 class="text-grey-lighten-1">
{{ status.playBackInfo?.trackInfo?.submitter.username }}
</h5>
</div>
</v-col>
</v-row>
</template>
<template
v-else-if="status.canView && status.playBackInfo?.stopped"
>
<v-avatar
color="grey-darken-3"
size="x-large"
icon="mdi-stop"
/>
<v-row class="ml-3">
<v-col>
<h4>Playback stoped</h4>
</v-col>
</v-row>
</template>
<template v-else-if="!status.canView">
<v-avatar
color="grey-darken-3"
size="x-large"
icon="mdi-lock"
/>
</template>
</v-col>
</v-row>
</v-col>
</v-row>
<v-row class="px-7">
<v-col class="pb-0"> {{ currentProgress }} </v-col>
<v-col class="d-flex justify-end pb-0"> {{ totalTime }} </v-col>
</v-row>
<v-row>
<v-col class="px-10 mt-1">
<v-progress-linear
v-model="progress"
background-color="blue-grey"
color="lime"
height="10"
rounded
></v-progress-linear>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex justify-center mt-2">
<v-btn
:icon="playPauseIcon"
class="mr-4 elevation-10"
variant="outlined"
:disabled="actionBtnDisable"
:color="actionBtnDisable ? '' : 'primary'"
></v-btn>
<v-btn
icon="mdi-skip-next"
class="mr-4 elevation-10"
variant="outlined"
:disabled="actionBtnDisable"
:color="actionBtnDisable ? '' : 'primary'"
></v-btn>
<v-btn
icon="mdi-stop"
class="mr-4 elevation-10"
:disabled="actionBtnDisable"
:color="actionBtnDisable ? '' : 'primary'"
variant="outlined"
></v-btn>
<v-btn
:icon="connectBtnIcon"
variant="outlined"
:disabled="connectBtnDisable"
:color="connectBtnDisable ? '' : 'primary'"
class="elevation-10"
></v-btn>
</v-col>
</v-row>
<v-overlay
v-model="loading"
contained
class="align-center justify-center"
persistent
scrim="black"
>
<v-progress-circular
color="primary"
indeterminate
size="100"
width="7"
/>
</v-overlay>
<v-overlay
v-model="privateChan"
contained
class="align-center justify-center"
persistent
scrim="black"
>
<h2 class="text-center mb-3"><v-icon>mdi-lock</v-icon></h2>
<h2 class="text-center">Connected to private channel</h2>
</v-overlay>
</v-container>
</v-card>
</template>
<script setup lang="ts">
import type { Guild } from "@/data/guild/Guild";
import type { Status } from "@/data/music/Status";
import { getAudioStatus } from "@/services/audioService";
import { computed } from "@vue/reactivity";
import { ref } from "vue";
const properties = defineProps<{
guild: Guild;
}>();
const loading = ref(true);
const status = ref<Status>({ connected: false });
getAudioStatus(properties.guild.id).then((value) => {
status.value = value;
loading.value = false;
});
const progress = computed(() => {
if (
!status.value.connected ||
!status.value.canView ||
status.value.playBackInfo?.stopped
) {
return 0;
} else {
if (
status.value.playBackInfo &&
status.value.playBackInfo?.progress &&
status.value.playBackInfo?.trackInfo?.detail.length
) {
return (
(status.value.playBackInfo?.progress /
status.value.playBackInfo?.trackInfo?.detail.length) *
100
);
} else {
return 0;
}
}
});
const actionBtnDisable = computed(() => {
return (
!status.value.connected ||
!status.value.canInteract ||
status.value.playBackInfo?.stopped
);
});
const connectBtnDisable = computed(() => {
return status.value.connected && !status.value.canInteract;
});
const playPauseIcon = computed(() => {
return status.value.playBackInfo?.paused ? "mdi-play" : "mdi-pause";
});
const connectBtnIcon = computed(() => {
return status.value.connected ? "mdi-eject" : "mdi-connection";
});
const currentProgress = computed(() => {
if (
!status.value.connected ||
!status.value.canView ||
!status.value.playBackInfo?.progress
) {
return "--:--";
}
return timeToMMSS(status.value.playBackInfo.progress);
});
const totalTime = computed(() => {
if (
!status.value.connected ||
!status.value.canView ||
!status.value.playBackInfo?.trackInfo?.detail.length
) {
return "--:--";
}
return timeToMMSS(status.value.playBackInfo?.trackInfo?.detail.length);
});
const privateChan = computed(() => {
return status.value.connected && !status.value.canView;
});
function timeToMMSS(time: number) {
let seconds = Math.floor(time / 1000);
const minutes = Math.floor(seconds / 60);
seconds = seconds % 60;
return `${minutes}:${("0" + seconds).slice(-2)}`;
}
setInterval(() => {
getAudioStatus(properties.guild.id).then((value) => {
status.value = value;
});
}, 1000);
</script>
<style scoped></style>

View File

@ -1,55 +0,0 @@
<template>
<v-card title="Music" disabled>
<template v-slot:prepend>
<v-icon color="yellow" size="x-large">mdi-music-circle</v-icon>
</template>
<v-container class="pt-0">
<v-row>
<v-col class="d-flex align-center">
<v-avatar color="grey-darken-3" size="x-large">
<v-icon icon="mdi-connection"></v-icon>
</v-avatar>
<v-row class="ml-3">
<v-col>
<h4>Not connected to voice channel</h4>
</v-col>
</v-row>
</v-col>
</v-row>
<v-row>
<v-col>
<v-progress-linear
model-value="0"
background-color="blue-grey"
color="lime"
height="10"
rounded
></v-progress-linear>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex justify-center">
<v-btn icon="mdi-play" class="mr-2" variant="outlined"></v-btn>
<v-btn icon="mdi-skip-next" class="mr-2" variant="outlined"></v-btn>
<v-btn icon="mdi-stop" class="mr-2" variant="outlined"></v-btn>
<v-btn icon="mdi-eject" class="mr-2" variant="outlined"></v-btn>
</v-col>
</v-row>
</v-container>
<v-overlay
v-model="loading"
contained
class="align-center justify-center"
persistent
>
</v-overlay>
</v-card>
</template>
<script setup lang="ts">
import { ref } from "vue";
const loading = ref(false);
</script>
<style scoped></style>

17
src/data/music/Status.ts Normal file
View File

@ -0,0 +1,17 @@
import type { Chanel } from "../guild/Channel";
import type { TrackInfo } from "./TrackInfo";
type Status = {
connected: boolean;
canView?: boolean;
canInteract?: boolean;
channel?: Chanel;
playBackInfo?: {
paused: boolean;
stopped: boolean;
progress?: number;
trackInfo?: TrackInfo;
};
};
export type { Status };

View File

@ -0,0 +1,17 @@
type TrackInfo = {
submitter: {
id: string;
username: string;
avatar: string;
};
detail: {
title: string;
author: string;
length: number;
identifier: string;
isStream: boolean;
uri: string;
};
};
export type { TrackInfo };

View File

@ -0,0 +1,32 @@
import type { Status } from "@/data/music/Status";
import { useEventQueuStore } from "@/stores/eventQueu";
import { useUserStore } from "@/stores/user";
import axios from "axios";
function getAudioStatus(guildId: string): Promise<Status> {
return new Promise((resolve, reject) => {
const userStore = useUserStore();
axios
.get<Status>(`/audio/${guildId}/status`, {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
resolve(value.data);
})
.catch((reason) => {
console.error(`Fail to retrive audio status !`);
console.log(reason);
const eventQueuStore = useEventQueuStore();
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Fail to retrive audio status !",
});
reject(reason);
});
});
}
export { getAudioStatus };

View File

@ -9,7 +9,7 @@
<v-col> <v-col>
<v-row> <v-row>
<v-col md="6" cols="12"> <v-col md="6" cols="12">
<MusicPreviewComponent></MusicPreviewComponent> <AudioPreviewComponent :guild="guild"></AudioPreviewComponent>
</v-col> </v-col>
<v-col md="6" cols="12"> <v-col md="6" cols="12">
<StatsPreviewComponent></StatsPreviewComponent> <StatsPreviewComponent></StatsPreviewComponent>
@ -28,7 +28,7 @@ import { useMutualGuildsStore } from "@/stores/mutualGuilds";
import { redirectIfNoGuild } from "@/tools/GuildTools"; import { redirectIfNoGuild } from "@/tools/GuildTools";
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import MusicPreviewComponent from "../components/guild/home/MusicPreviewComponent.vue"; import AudioPreviewComponent from "../components/guild/home/AudioPreviewComponent.vue";
import SettingPreviewComponent from "../components/guild/home/SettingPreviewComponent.vue"; import SettingPreviewComponent from "../components/guild/home/SettingPreviewComponent.vue";
import StatsPreviewComponent from "../components/guild/home/StatsPreviewComponent.vue"; import StatsPreviewComponent from "../components/guild/home/StatsPreviewComponent.vue";
import GuildHeaderComponent from "@/components/guild/GuildHeaderComponent.vue"; import GuildHeaderComponent from "@/components/guild/GuildHeaderComponent.vue";