diff --git a/packages/components/add-provider/package.json b/packages/components/add-provider/package.json index a40b79b..7abc669 100644 --- a/packages/components/add-provider/package.json +++ b/packages/components/add-provider/package.json @@ -9,6 +9,7 @@ "dependencies": { "@echo/core-types": "^1.0.0", "@echo/services-bootstrap": "^1.0.0", + "@echo/services-bootstrap-services": "^1.0.0", "@effect-rx/rx": "^0.33.8", "@effect-rx/rx-react": "^0.30.11", "effect": "^3.2.8" @@ -17,4 +18,4 @@ "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22" } -} +} \ No newline at end of file diff --git a/packages/components/add-provider/src/AddProvider.tsx b/packages/components/add-provider/src/AddProvider.tsx index b36e103..9f8106a 100644 --- a/packages/components/add-provider/src/AddProvider.tsx +++ b/packages/components/add-provider/src/AddProvider.tsx @@ -1,21 +1,36 @@ import { + ActiveMediaProviderCache, AvailableProviders, MediaProviderMainThreadBroadcastChannel, type Authentication, type AuthenticationInfo, type FolderMetadata, + type MediaPlayer, type MediaProvider, type ProviderMetadata, } from "@echo/core-types"; -import { LazyLoadedProvider, MainLive } from "@echo/services-bootstrap"; +import { LazyLoadedProvider } from "@echo/services-bootstrap"; +import { AppLive } from "@echo/services-bootstrap-services"; +import { LazyLoadedMediaPlayer } from "@echo/services-bootstrap/src/loaders"; import { Rx } from "@effect-rx/rx"; import { useRx } from "@effect-rx/rx-react"; import { Effect, Match } from "effect"; import { useCallback, useEffect, useMemo } from "react"; -const runtime = Rx.runtime(MainLive); -const loadProviderFn = runtime.fn((metadata: ProviderMetadata) => - LazyLoadedProvider.load(metadata), +const runtime = Rx.runtime(AppLive); +const loadProviderFn = runtime.fn(LazyLoadedProvider.load); +const loadMediaPlayerFn = runtime.fn( + ({ + metadata, + authInfo, + }: { + metadata: ProviderMetadata; + authInfo: AuthenticationInfo; + }) => + Effect.gen(function* () { + const { createMediaPlayer } = yield* LazyLoadedMediaPlayer.load(metadata); + return yield* createMediaPlayer(authInfo); + }), ); export const AddProvider = () => { @@ -105,6 +120,18 @@ const listRootFn = runtime.fn( (mediaProvider: MediaProvider) => mediaProvider.listRoot, ); +const addMediaProviderToCacheFn = runtime.fn( + ({ + metadata, + provider, + player, + }: { + metadata: ProviderMetadata; + provider: MediaProvider; + player: MediaPlayer; + }) => ActiveMediaProviderCache.add(metadata, provider, player), +); + const SelectRoot = ({ authInfo, metadata, @@ -114,16 +141,34 @@ const SelectRoot = ({ metadata: ProviderMetadata; createMediaProvider: (authInfo: AuthenticationInfo) => MediaProvider; }) => { + const [mediaPlayerStatus, createMediaPlayer] = useRx(loadMediaPlayerFn); + const mediaProvider = useMemo( () => createMediaProvider(authInfo), [createMediaProvider, authInfo], ); const [listStatus, listRoot] = useRx(listRootFn); + const [, addMediaProviderToCache] = useRx(addMediaProviderToCacheFn); useEffect(() => { listRoot(mediaProvider); - }); + createMediaPlayer({ metadata, authInfo }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // TODO: Refactor this mess somehow? + useEffect(() => { + Match.value(mediaPlayerStatus).pipe( + Match.tag("Success", ({ value: player }) => { + addMediaProviderToCache({ + metadata, + provider: mediaProvider, + player, + }); + }), + ); + }, [mediaPlayerStatus, mediaProvider, metadata, addMediaProviderToCache]); return (
diff --git a/packages/components/library/package.json b/packages/components/library/package.json index ddc8cfd..fb1c6c5 100644 --- a/packages/components/library/package.json +++ b/packages/components/library/package.json @@ -8,8 +8,9 @@ }, "dependencies": { "@echo/core-types": "^1.0.0", - "@echo/services-bootstrap": "^1.0.0", + "@echo/services-bootstrap-services": "^1.0.0", "@echo/services-library": "^1.0.0", + "@echo/services-player": "^1.0.0", "@effect-rx/rx": "^0.33.8", "@effect-rx/rx-react": "^0.30.11", "effect": "^3.2.8" diff --git a/packages/components/library/src/Library.tsx b/packages/components/library/src/Library.tsx index 0419cf2..a26cf70 100644 --- a/packages/components/library/src/Library.tsx +++ b/packages/components/library/src/Library.tsx @@ -1,38 +1,30 @@ -import { Library, type Track } from "@echo/core-types"; -import { MainLive } from "@echo/services-bootstrap"; +import { Library, Player } from "@echo/core-types"; +import { AppLive } from "@echo/services-bootstrap-services"; import { Rx } from "@effect-rx/rx"; import { Layer, Stream } from "effect"; -import { Suspense, useState } from "react"; +import { Suspense } from "react"; import { LibraryLive } from "@echo/services-library"; -import { useRxSuspenseSuccess } from "@effect-rx/rx-react"; +import { PlayerLive } from "@echo/services-player"; +import { useRx, useRxSuspenseSuccess } from "@effect-rx/rx-react"; -const runtime = Rx.runtime(LibraryLive.pipe(Layer.provide(MainLive))); +const runtime = Rx.runtime( + Layer.mergeAll(LibraryLive, PlayerLive).pipe(Layer.provide(AppLive)), +); const observeLibrary = runtime.rx(Stream.unwrap(Library.observeAlbums())); +const playAlbumFn = runtime.fn(Player.playAlbum); const UserLibrary = () => { - const [src, setSrc] = useState(undefined); const albums = useRxSuspenseSuccess(observeLibrary).value; - - const playFirstTrack = (tracks: Track[]) => { - const track = tracks[0]; - switch (track.resource.type) { - case "file": - setSrc(track.resource.uri); - break; - case "api": - break; - } - }; + const [, playAlbum] = useRx(playAlbumFn); return (

-