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 @@ -3,6 +3,7 @@ import { useAuth0 } from "@auth0/auth0-vue";
import { watch } from "vue";
import privatePlaylist from "@/components/privatePlaylist.vue";
import ChangeLocale from "./components/ChangeLocale.vue";
import MediaPlayer from "./components/MediaPlayer.vue";

// logout
const { isLoading, loginWithRedirect, isAuthenticated } = useAuth0();
Expand All @@ -27,6 +28,9 @@ watch(isLoading, async (loading) => {
<router-view v-if="isAuthenticated" />
</main>
</div>
<footer>
<media-player />
kkuepper marked this conversation as resolved.
Show resolved Hide resolved
</footer>
</template>

<style scoped>
Expand Down
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
88 changes: 88 additions & 0 deletions src/plugins/mediaPlayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { App, computed, ComputedRef, InjectionKey, Ref, ref } from "vue";

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(src);
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;
});
},
});
};
2 changes: 2 additions & 0 deletions src/views/BrowseView.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<script setup lang="ts"></script>

<template>
<h2>{{ $t("nav.browse") }}</h2>
</template>
33 changes: 31 additions & 2 deletions src/views/Playlist/CuratedPlaylistDetails.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<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 filters from "@/utils/filters";
import { MediaPlaylistInjectionKey } from "@/plugins/mediaPlayer";
import auth0 from "@/auth0";

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

const { setCurrentSong } = inject(MediaPlaylistInjectionKey)!;
// TODO: Please move this into a plugin or something the-like which configures the authorize-url function.
let token: string = "";
(async () => {
token =
SimonSimCity marked this conversation as resolved.
Show resolved Hide resolved
(await (() => {
const { getAccessTokenSilently, isAuthenticated } = auth0;
if (!isAuthenticated.value) {
return null;
}
return getAccessTokenSilently();
})()) ?? "";
})();

new PlaylistApi()
.playlistIdGet({ id: playlistId })
.then((result) => {
Expand All @@ -39,7 +56,19 @@ 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(
filters.authorizedUrl(
track.media?.[0]?.files?.[0]?.url || '',
token
)
)
"
>
{{ track.meta?.title }} - <b>{{ track.meta?.artist }}</b>
</li>
</ol>
Expand Down