mirror of
https://github.com/AzuraCast/AzuraCast.git
synced 2024-06-14 13:16:37 +00:00
201 lines
8.4 KiB
Vue
201 lines
8.4 KiB
Vue
<template>
|
|
<section class="card mb-4 nowplaying" role="region" id="profile-nowplaying">
|
|
<div class="card-header bg-primary-dark">
|
|
<div class="d-flex align-items-center">
|
|
<h3 class="flex-shrink card-title my-0">{{ $gettext('On the Air') }}</h3>
|
|
<h6 class="card-subtitle text-right flex-fill my-0" style="line-height: 1;">
|
|
<icon class="sm align-middle" icon="headset"></icon>
|
|
<span class="pl-1">
|
|
{{ langListeners }}
|
|
</span>
|
|
|
|
<br>
|
|
<small>
|
|
<span class="pr-1">{{ np.listeners.unique }}</span>
|
|
{{ $gettext('Unique') }}
|
|
</small>
|
|
</h6>
|
|
</div>
|
|
</div>
|
|
<b-overlay variant="card" :show="np.loading">
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="clearfix">
|
|
<h6 style="margin-left: 32px;">
|
|
<icon icon="music_note"></icon>
|
|
{{ $gettext('Now Playing') }}
|
|
</h6>
|
|
<div class="media">
|
|
<a class="mr-2" v-if="np.now_playing.song.art" :href="np.now_playing.song.art"
|
|
data-fancybox target="_blank">
|
|
<img class="rounded" :src="np.now_playing.song.art" alt="Album Art"
|
|
style="width: 50px;">
|
|
</a>
|
|
<div class="media-body">
|
|
<div v-if="!np.is_online">
|
|
<h5 class="media-heading m-0 text-muted">
|
|
{{ $gettext('Station Offline') }}
|
|
</h5>
|
|
</div>
|
|
<div v-else-if="np.now_playing.song.title !== ''">
|
|
<h5 class="media-heading m-0" style="line-height: 1;">
|
|
{{ np.now_playing.song.title }}<br>
|
|
<small>{{ np.now_playing.song.artist }}</small>
|
|
</h5>
|
|
</div>
|
|
<div v-else>
|
|
<h5 class="media-heading m-0" style="line-height: 1;">
|
|
{{ np.now_playing.song.text }}</h5>
|
|
</div>
|
|
<div v-if="np.now_playing.playlist">
|
|
<small class="text-muted">
|
|
{{ $gettext('Playlist') }}
|
|
: {{ np.now_playing.playlist }}</small>
|
|
</div>
|
|
<div class="nowplaying-progress" v-if="timeDisplay">
|
|
<small>{{ timeDisplay }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="clearfix" v-if="!np.live.is_live && np.playing_next">
|
|
<h6 style="margin-left: 22px;">
|
|
<icon icon="skip_next"></icon>
|
|
{{ $gettext('Playing Next') }}
|
|
</h6>
|
|
|
|
<div class="media">
|
|
<a class="mr-2" v-if="np.playing_next.song.art" :href="np.playing_next.song.art"
|
|
data-fancybox target="_blank">
|
|
<img :src="np.playing_next.song.art" class="rounded" alt="Album Art"
|
|
style="width: 40px;">
|
|
</a>
|
|
<div class="media-body">
|
|
<div v-if="np.playing_next.song.title !== ''">
|
|
<h5 class="media-heading m-0" style="line-height: 1;">
|
|
{{ np.playing_next.song.title }}<br>
|
|
<small>{{ np.playing_next.song.artist }}</small>
|
|
</h5>
|
|
</div>
|
|
<div v-else>
|
|
<h5 class="media-heading m-0" style="line-height: 1;">
|
|
{{ np.playing_next.song.text }}</h5>
|
|
</div>
|
|
|
|
<div v-if="np.playing_next.playlist">
|
|
<small class="text-muted">
|
|
{{ $gettext('Playlist') }}
|
|
: {{ np.playing_next.playlist }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="clearfix" v-else-if="np.live.is_live">
|
|
<h6 style="margin-left: 22px;">
|
|
<icon icon="mic"></icon>
|
|
{{ $gettext('Live') }}
|
|
</h6>
|
|
|
|
<h4 class="media-heading" style="margin-left: 22px;">
|
|
{{ np.live.streamer_name }}
|
|
</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</b-overlay>
|
|
|
|
<div class="card-actions flex-shrink" v-if="isLiquidsoap && userCanManageBroadcasting">
|
|
<a id="btn_skip_song" class="btn btn-outline-primary api-call no-reload" role="button"
|
|
v-if="!np.live.is_live" :href="backendSkipSongUri">
|
|
<icon icon="skip_next"></icon>
|
|
{{ $gettext('Skip Song') }}
|
|
</a>
|
|
<a id="btn_disconnect_streamer" class="btn btn-outline-primary api-call no-reload" role="button"
|
|
v-if="np.live.is_live" :href="backendDisconnectStreamerUri">
|
|
<icon icon="volume_off"></icon>
|
|
{{ $gettext('Disconnect Streamer') }}
|
|
</a>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script>
|
|
export const profileNowPlayingProps = {
|
|
backendType: String,
|
|
userCanManageBroadcasting: Boolean,
|
|
backendSkipSongUri: String,
|
|
backendDisconnectStreamerUri: String
|
|
};
|
|
|
|
export default {
|
|
inheritAttrs: false
|
|
};
|
|
</script>
|
|
|
|
<script setup>
|
|
import {BACKEND_LIQUIDSOAP} from '~/components/Entity/RadioAdapters.js';
|
|
import Icon from '~/components/Common/Icon';
|
|
import {computed, onMounted, ref} from "vue";
|
|
import {useIntervalFn} from "@vueuse/core";
|
|
import gettext from "~/vendor/gettext";
|
|
import formatTime from "~/functions/formatTime";
|
|
|
|
const props = defineProps({
|
|
...profileNowPlayingProps,
|
|
np: Object
|
|
});
|
|
|
|
const npElapsed = ref(0);
|
|
|
|
onMounted(() => {
|
|
useIntervalFn(
|
|
() => {
|
|
let current_time = Math.floor(Date.now() / 1000);
|
|
let np_elapsed = current_time - props.np.now_playing.played_at;
|
|
if (np_elapsed < 0) {
|
|
np_elapsed = 0;
|
|
} else if (np_elapsed >= props.np.now_playing.duration) {
|
|
np_elapsed = props.np.now_playing.duration;
|
|
}
|
|
|
|
npElapsed.value = np_elapsed;
|
|
},
|
|
1000
|
|
);
|
|
});
|
|
|
|
const {$ngettext} = gettext;
|
|
|
|
const langListeners = computed(() => {
|
|
return $ngettext(
|
|
'%{listeners} Listener',
|
|
'%{listeners} Listeners',
|
|
props.np.listeners.total,
|
|
{listeners: props.np.listeners.total}
|
|
);
|
|
});
|
|
|
|
const isLiquidsoap = computed(() => {
|
|
return props.backendType === BACKEND_LIQUIDSOAP;
|
|
});
|
|
|
|
const timeDisplay = computed(() => {
|
|
let time_played = npElapsed.value;
|
|
let time_total = props.np.now_playing.duration;
|
|
|
|
if (!time_total) {
|
|
return null;
|
|
}
|
|
|
|
if (time_played > time_total) {
|
|
time_played = time_total;
|
|
}
|
|
|
|
return formatTime(time_played) + ' / ' + formatTime(time_total);
|
|
});
|
|
</script>
|