Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added first draft of a media-player #46

Merged
merged 8 commits into from
Apr 14, 2023
4 changes: 4 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useI18n } from "vue-i18n";
import privatePlaylist from "@/components/privatePlaylist.vue";
import ChangeLocale from "./components/ChangeLocale.vue";
import Toolbar from "./components/AppToolbar.vue";
import MediaPlayer from "./components/MediaPlayer.vue";

// logout
const { isLoading, loginWithRedirect, isAuthenticated } = useAuth0();
Expand Down Expand Up @@ -53,5 +54,8 @@ watch(
<router-view v-if="isAuthenticated" />
</main>
</div>
<footer>
<media-player v-if="isAuthenticated" />
</footer>
</div>
</template>
24 changes: 24 additions & 0 deletions src/components/MediaPlayer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup lang="ts">
import {
MediaPlayerInjectionKey,
MediaPlayerStatus,
MediaPlaylistInjectionKey,
} from "@/plugins/mediaPlayer";
import { inject } from "vue";

const { status, play, pause } = inject(MediaPlayerInjectionKey)!;
const { currentSong } = inject(MediaPlaylistInjectionKey)!;
kkuepper marked this conversation as resolved.
Show resolved Hide resolved
</script>
<template>
<a href="">⏪</a>
<a v-if="status !== MediaPlayerStatus.Playing" @click="play()">⏵</a>
<a v-if="status === MediaPlayerStatus.Playing" @click="pause()">⏸</a>
<a href="">⏩</a>

<a href="">🔀</a>
<a href="">🔁</a>

<span style="max-width: 100px; overflow: hidden; display: inline-block"
>Current track: {{ currentSong }}</span
>
</template>
3 changes: 3 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "./style.css";
import App from "./App.vue";
import router from "./router";
import Store from "./store";
import mediaPlayer from "./plugins/mediaPlayer";
import auth0 from "./auth0";
import bmmApi from "./plugins/bmm-api";
import i18n from "./plugins/i18n";
Expand All @@ -17,6 +18,8 @@ app.use(bmmApi);

app.use(i18n);

app.use(mediaPlayer);

app.provide(
"store",
new Store({
Expand Down
100 changes: 100 additions & 0 deletions src/plugins/mediaPlayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { App, computed, ComputedRef, InjectionKey, Ref, ref, watch } from "vue";
import auth0 from "@/auth0";
import filters from "@/utils/filters";

const { getAccessTokenSilently, isAuthenticated } = auth0;
const authToken: Ref<string | undefined> = ref();
watch(
isAuthenticated,
async () => {
authToken.value = await getAccessTokenSilently();
},
{ immediate: true }
);

export interface MediaPlayer {
status: ComputedRef<MediaPlayerStatus>;
play: () => void;
pause: () => void;
}

export interface MediaPlaylist {
currentSong: ComputedRef<string | undefined>;
setCurrentSong: (src: string) => void;
clearCurrentSong: (src: string) => void;
}

export const MediaPlayerInjectionKey: InjectionKey<MediaPlayer> = Symbol(
"Vue InjectionKey MediaPlayer"
);

export const MediaPlaylistInjectionKey: InjectionKey<MediaPlaylist> = Symbol(
"Vue InjectionKey MediaPlaylist"
);

export enum MediaPlayerStatus {
Paused = "PAUSED",
Playing = "PLAYING",
Stopped = "STOPPED",
}

export default (app: App) => {
// Good to know when writing tests: https://github.com/jsdom/jsdom/issues/2155#issuecomment-366703395
let activeMedia: HTMLAudioElement | undefined;

const paused = ref(true);
const ended = ref(false);
const currentSong: Ref<string | undefined> = ref(undefined);

const playerStatus = computed(() => {
if (paused.value) return MediaPlayerStatus.Paused;
if (ended.value) return MediaPlayerStatus.Stopped;
return MediaPlayerStatus.Playing;
});

app.provide(MediaPlayerInjectionKey, {
status: playerStatus,
play: () => activeMedia?.play(),
pause: () => activeMedia?.pause(),
});

app.provide(MediaPlaylistInjectionKey, {
currentSong: computed(() => currentSong.value),
clearCurrentSong() {
activeMedia?.pause();
activeMedia = undefined;
currentSong.value = "";
paused.value = true;
ended.value = false;
},
setCurrentSong(src) {
activeMedia?.pause();

activeMedia = new Audio(filters.authorizedUrl(src, authToken.value));
activeMedia.autoplay = true;
currentSong.value = src;
paused.value = true;
ended.value = false;

activeMedia.addEventListener("pause", () => {
paused.value = true;
});
activeMedia.addEventListener("loadstart", () => {
if (activeMedia?.autoplay) {
paused.value = false;
ended.value = false;
}
});
activeMedia.addEventListener("play", () => {
paused.value = false;
ended.value = false;
});
activeMedia.addEventListener("playing", () => {
paused.value = false;
});
activeMedia.addEventListener("ended", () => {
ended.value = true;
});
},
});
};
12 changes: 10 additions & 2 deletions src/views/Playlist/CuratedPlaylistDetails.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<script setup lang="ts">
import { ref, Ref } from "vue";
import { inject, ref, Ref } from "vue";
import {
TrackModel,
PlaylistModel,
PlaylistApi,
} from "@bcc-code/bmm-sdk-fetch";
import ProtectedImage from "@/components/ProtectedImage.vue";
import { MediaPlaylistInjectionKey } from "@/plugins/mediaPlayer";

const props = defineProps<{
playlistId: string;
Expand All @@ -14,6 +15,8 @@ const playlistId = Number(props.playlistId);
const playlist: Ref<PlaylistModel> = ref({});
const tracks: Ref<TrackModel[]> = ref([]);

const { setCurrentSong } = inject(MediaPlaylistInjectionKey)!;

new PlaylistApi()
.playlistIdGet({ id: playlistId })
.then((result) => {
Expand All @@ -39,7 +42,12 @@ new PlaylistApi()
<h3>{{ playlist.title }}</h3>
<br />
<ol class="list-decimal list-inside">
<li v-for="track in tracks" :key="track.id || 0" class="flex">
<li
v-for="track in tracks"
:key="track.id || 0"
class="flex"
@click="setCurrentSong(track.media?.[0]?.files?.[0]?.url || '')"
>
{{ track.meta?.title }} - <b>{{ track.meta?.artist }}</b>
</li>
</ol>
Expand Down