Skip to content

Commit

Permalink
Naive implementation of player info
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepyfran committed Sep 3, 2024
1 parent 7152a6f commit eddc1f2
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 23 deletions.
1 change: 1 addition & 0 deletions packages/components/player/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./src/player";
17 changes: 17 additions & 0 deletions packages/components/player/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@echo/components-player",
"private": true,
"version": "1.0.0",
"scripts": {
"lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@echo/components-shared-controllers": "^1.0.0",
"@echo/core-types": "^1.0.0",
"@echo/services-bootstrap-runtime": "^1.0.0",
"effect": "^3.6.5",
"lit": "^3.2.0",
"@lit/task": "^1.0.1"
}
}
36 changes: 36 additions & 0 deletions packages/components/player/src/player.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { StreamConsumer } from "@echo/components-shared-controllers";
import { LitElement, html, nothing } from "lit";
import { customElement } from "lit/decorators.js";
import { Player as PlayerService } from "@echo/core-types";

/**
* Component that displays the current status of the player.
*/
@customElement("echo-player")
export class EchoPlayer extends LitElement {
private _player = new StreamConsumer(this, PlayerService.observe);

render() {
return this._player.render({
initial: () => nothing,
item: (player) => html`
<div>
<h5>Player</h5>
<p>Status: ${player.status}</p>
<p>Current track: ${JSON.stringify(player.currentTrack)}</p>
<p>
Previously played tracks:
${JSON.stringify(player.previouslyPlayedTracks)}
</p>
<p>Coming up tracks: ${player.comingUpTracks}</p>
</div>
`,
});
}
}

declare global {
interface HTMLElementTagNameMap {
["echo-player"]: EchoPlayer;
}
}
1 change: 1 addition & 0 deletions packages/components/player/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
7 changes: 7 additions & 0 deletions packages/components/player/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"include": [
"src",
"index.ts"
],
"extends": "../../../tsconfig.json"
}
4 changes: 2 additions & 2 deletions packages/core/types/src/services/player.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Effect, Stream } from "effect";
import { Effect, SubscriptionRef } from "effect";
import type { Album, PlayerState, ProviderId } from "../model";
import type { PlayNotFoundError } from "./media-provider";

Expand Down Expand Up @@ -30,7 +30,7 @@ export type IPlayer = {
* Returns a stream that emits the current player state and any subsequent
* changes to it.
*/
readonly observe: Effect.Effect<Stream.Stream<PlayerState>>;
readonly observe: SubscriptionRef.SubscriptionRef<PlayerState>;
};

/**
Expand Down
31 changes: 12 additions & 19 deletions packages/services/player/src/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,13 @@ import {
ProviderNotReady,
type PlayerState,
} from "@echo/core-types";
import { Effect, Layer, Option, PubSub, Ref, Stream } from "effect";
import { Effect, Layer, Option, Ref, SubscriptionRef } from "effect";
import { PlayerStateRef } from "./state";

const makePlayer = Effect.gen(function* () {
const state = yield* PlayerStateRef;
const providerCache = yield* ActiveMediaProviderCache;

// TODO: Remove all this and switch to subscription ref.
const statePubSub = yield* PubSub.dropping<PlayerState>({
capacity: 1,
replay: 1,
});

// Yield initial state to subscribers.
yield* statePubSub.publish(yield* state.get);

return Player.of({
playAlbum: (album) =>
Effect.gen(function* () {
Expand Down Expand Up @@ -52,27 +43,29 @@ const makePlayer = Effect.gen(function* () {
return Effect.void;
}

yield* Effect.log(`Playing album ${album.name}`);

yield* Ref.update(state, (current) => ({
...current,
status: "playing" as const,
currentTrack: Option.some(firstTrack),
previouslyPlayedTracks: [
...current.previouslyPlayedTracks,
...(Option.isSome(current.currentTrack)
? [current.currentTrack.value]
: []),
],
}));

yield* statePubSub.publish(yield* state.get);
}),
observe: Effect.sync(() =>
Stream.fromPubSub(statePubSub).pipe(
Stream.tap((state) => Effect.logInfo("Player state changed", state)),
Stream.ensuring(Effect.logInfo("Player state stream closed")),
),
),
observe: state,
});
});

const PlayerLiveWithState = Layer.effect(Player, makePlayer);

const PlayerStateLive = Layer.effect(
PlayerStateRef,
Ref.make({
SubscriptionRef.make({
comingUpTracks: [],
previouslyPlayedTracks: [],
currentTrack: Option.none(),
Expand Down
4 changes: 2 additions & 2 deletions packages/services/player/src/state.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { PlayerState } from "@echo/core-types";
import { Context, Ref } from "effect";
import { Context, SubscriptionRef } from "effect";

/**
* Tag that can provide a ref to the current state of the player.
*/
export class PlayerStateRef extends Context.Tag(
"@echo/services-player/PlayerStateRef",
)<PlayerStateRef, Ref.Ref<PlayerState>>() {}
)<PlayerStateRef, SubscriptionRef.SubscriptionRef<PlayerState>>() {}
1 change: 1 addition & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@echo/components-add-provider": "^1.0.0",
"@echo/components-library": "^1.0.0",
"@echo/components-player": "^1.0.0",
"@echo/components-shared-controllers": "^1.0.0",
"@echo/core-types": "^1.0.0",
"@echo/services-bootstrap-runtime": "^1.0.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/web/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AppInit } from "@echo/core-types";
import { EffectConsumer } from "@echo/components-shared-controllers";
import "@echo/components-add-provider";
import "@echo/components-library";
import "@echo/components-player";

initializeWorkers();

Expand All @@ -21,6 +22,7 @@ export class MyElement extends LitElement {
complete: () => html`
<div>
<add-provider></add-provider>
<echo-player></echo-player>
<user-library></user-library>
</div>
`,
Expand Down

0 comments on commit eddc1f2

Please sign in to comment.