Skip to content

Commit

Permalink
add proper media session support
Browse files Browse the repository at this point in the history
  • Loading branch information
SuspiciousLookingOwl committed May 10, 2024
1 parent 7691311 commit 5760f56
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 20 deletions.
Binary file added public/audio/silence.mp3
Binary file not shown.
72 changes: 58 additions & 14 deletions src/apps/app/providers/app/hooks/media-session.hook.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,85 @@
import { type IMediaSource } from "@media-source";
import { useQueue } from "@queue";
import { createEffect, onMount } from "solid-js";
import { useSettings } from "@settings";
import { type ISpotifyImage } from "@spotify";
import { type IThumbnail } from "@youtube";
import { createEffect } from "solid-js";

export const useMediaSession = () => {
if (!("mediaSession" in navigator)) return;

const mediaSession = navigator.mediaSession;
const { settings } = useSettings();
const queue = useQueue();

onMount(() => {
mediaSession.setActionHandler("play", () => queue.unpause());
mediaSession.setActionHandler("pause", () => queue.pause());
mediaSession.setActionHandler("nexttrack", () => queue.skipTrack());
mediaSession.setActionHandler("seekto", (details) => queue.seek((details.seekTime || 0) * 1000));
const audioSrc = "/audio/silence.mp3";
const audio = new Audio();
audio.volume = 0;
audio.autoplay = true;
audio.loop = true;
audio.src = audioSrc;

// trigger play on first user interaction, in case autoplay doesn't work
document.addEventListener("click", () => audio.play(), { once: true });

createEffect(() => {
if (settings["app.mediaSession.enabled"]) {
audio.autoplay = true;
audio.src = audioSrc;

mediaSession.setActionHandler("play", togglePause);
mediaSession.setActionHandler("pause", togglePause);
mediaSession.setActionHandler("nexttrack", () => queue.skipTrack());
mediaSession.setActionHandler("seekto", (details) => queue.seek((details.seekTime || 0) * 1000));
} else {
audio.src = "";
}
});

createEffect(() => {
const { nowPlaying } = queue.data;
if (!settings["app.mediaSession.enabled"]) return;

if (nowPlaying) {
mediaSession.playbackState = !queue.data.isPaused ? "playing" : "paused";
const { nowPlaying, isPaused } = queue.data;
mediaSession.playbackState = isPaused ? "paused" : "playing";

if (nowPlaying) {
const duration = nowPlaying.mediaSource.duration;
let position = queue.data.position / 1000;
if (position > duration) position = 0;
if (position > duration) position = duration;

mediaSession.setPositionState({ duration, position, playbackRate: 1 });

mediaSession.metadata = new MediaMetadata({
title: nowPlaying.mediaSource.title,
artist: nowPlaying.mediaSource.creator,
artwork: [
{ src: nowPlaying.mediaSource.minThumbnailUrl },
{ src: nowPlaying.mediaSource.maxThumbnailUrl },
],
artwork: getMediaSourceImages(nowPlaying.mediaSource),
});
} else {
mediaSession.metadata = null;
mediaSession.setPositionState();
}
});

const getMediaSourceImages = (mediaSource: IMediaSource): MediaImage[] => {
const { youtubeVideo, spotifyTrack } = mediaSource;
let images: (IThumbnail | ISpotifyImage)[] = [];

if (youtubeVideo) images = youtubeVideo.thumbnails;
if (spotifyTrack?.album) images = spotifyTrack.album.images;

return images.map((t) => ({
src: t.url,
sizes: `${t.width}x${t.height}`,
}));
};

const togglePause = async () => {
if (queue.data.isPaused) {
await queue.unpause();
audio.play();
} else {
await queue.pause();
audio.pause();
}
};
};
14 changes: 8 additions & 6 deletions src/apps/app/views/settings/settings.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const Settings: Component = () => {

const categories: Accessor<SettingsCategory[]> = () => [
{
label: "Notification",
label: "Preferences",
items: [
{
label: "Enable In App Notifications",
Expand All @@ -89,11 +89,13 @@ export const Settings: Component = () => {
value: () => settings["notification.browser"],
onChange: () => setSettings("notification.browser", (v) => !v),
},
],
},
{
label: "Appearance",
items: [
{
label: "Enable Media Session",
type: "switch",
description: "Control playback using media keys",
value: () => settings["app.mediaSession.enabled"],
onChange: (v) => setSettings("app.mediaSession.enabled", v),
},
{
label: "Zoom",
type: "slider",
Expand Down
2 changes: 2 additions & 0 deletions src/libs/settings/providers/settings/settings.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type Settings = {
["app.snowfall.enabled"]: boolean;
["app.snowfall.amount"]: number;
["app.snowfall.speed"]: number;
["app.mediaSession.enabled"]: boolean;
["overlay.enabled"]: boolean;
["overlay.shortcut"]: string[];
["spotify.enabled"]: boolean;
Expand All @@ -44,6 +45,7 @@ const defaultSettings: Settings = {
["app.snowfall.enabled"]: true,
["app.snowfall.amount"]: 10,
["app.snowfall.speed"]: 50,
["app.mediaSession.enabled"]: true,
["overlay.enabled"]: true,
["overlay.shortcut"]: ["Control", "Shift", "B"],
["spotify.enabled"]: false,
Expand Down

0 comments on commit 5760f56

Please sign in to comment.