feat: ios widget

This commit is contained in:
Fredrik Burmester
2026-01-05 21:28:00 +01:00
parent cbbac3c25c
commit 6c95962e12
28 changed files with 759 additions and 23 deletions

View File

@@ -1,3 +1,4 @@
import { ExtensionStorage } from "@bacons/apple-targets";
import type { Api } from "@jellyfin/sdk";
import type {
BaseItemDto,
@@ -15,6 +16,7 @@ import React, {
useRef,
useState,
} from "react";
import { Platform } from "react-native";
import TrackPlayer, {
Capability,
type Progress,
@@ -33,6 +35,12 @@ import { settingsAtom } from "@/utils/atoms/settings";
import { getAudioStreamUrl } from "@/utils/jellyfin/audio/getAudioStreamUrl";
import { storage } from "@/utils/mmkv";
// Widget storage for iOS
const widgetStorage =
Platform.OS === "ios"
? new ExtensionStorage("group.com.fredrikburmester.streamyfin.widgets")
: null;
// Storage keys
const STORAGE_KEYS = {
QUEUE: "music_player_queue",
@@ -388,6 +396,38 @@ export const MusicPlayerProvider: React.FC<MusicPlayerProviderProps> = ({
}
}, [state.progress, state.currentTrack]);
// Sync now playing data to iOS widget
useEffect(() => {
if (!widgetStorage) return;
if (state.currentTrack && api) {
const albumId = state.currentTrack.AlbumId || state.currentTrack.ParentId;
const artworkId = albumId || state.currentTrack.Id;
const artworkUrl = artworkId
? `${api.basePath}/Items/${artworkId}/Images/Primary?maxHeight=300`
: null;
widgetStorage.set(
"nowPlaying",
JSON.stringify({
title: state.currentTrack.Name || "Unknown Track",
artist:
state.currentTrack.Artists?.join(", ") ||
state.currentTrack.AlbumArtist ||
"Unknown Artist",
album: state.currentTrack.Album || "",
artworkUrl,
isPlaying: state.isPlaying,
updatedAt: Date.now(),
}),
);
ExtensionStorage.reloadWidget();
} else {
widgetStorage.set("nowPlaying", undefined);
ExtensionStorage.reloadWidget();
}
}, [state.currentTrack?.Id, state.isPlaying, api]);
const reportPlaybackStart = useCallback(
async (track: BaseItemDto, sessionId: string | null) => {
if (!api || !user?.Id || !track.Id) return;