diff --git a/src/components/artwork/input/element.js b/src/components/artwork/input/element.js new file mode 100644 index 00000000..7c34ef4b --- /dev/null +++ b/src/components/artwork/input/element.js @@ -0,0 +1,61 @@ +import { DiffuseElement, query } from "~/common/element.js"; + +/** + * @import {ProxiedActions} from "~/common/worker.d.ts" + * @import {InputElement} from "~/components/input/types.d.ts" + * @import {Actions} from "~/components/artwork/types.d.ts" + */ + +//////////////////////////////////////////// +// ELEMENT +//////////////////////////////////////////// + +/** + * @implements {ProxiedActions} + */ +class InputArtwork extends DiffuseElement { + static NAME = "diffuse/artwork/input"; + static WORKER_URL = "components/artwork/input/worker.js"; + + constructor() { + super(); + + /** @type {ProxiedActions} */ + const p = this.workerProxy(); + + this.get = p.get; + } + + // LIFECYCLE + + /** @override */ + async connectedCallback() { + super.connectedCallback(); + + /** @type {InputElement} */ + this.input = query(this, "input-selector"); + + await customElements.whenDefined(this.input.localName); + } + + // WORKERS + + /** + * @override + */ + dependencies() { + if (!this.input) throw new Error("Input element not defined yet"); + return { input: this.input }; + } +} + +export default InputArtwork; + +//////////////////////////////////////////// +// REGISTER +//////////////////////////////////////////// + +export const CLASS = InputArtwork; +export const NAME = "da-input"; + +customElements.define(NAME, InputArtwork); diff --git a/src/components/artwork/input/worker.js b/src/components/artwork/input/worker.js new file mode 100644 index 00000000..1f7babba --- /dev/null +++ b/src/components/artwork/input/worker.js @@ -0,0 +1,32 @@ +import { ostiary, rpc, workerProxy } from "~/common/worker.js"; + +/** + * @import {ActionsWithTunnel, ProxiedActions} from "~/common/worker.d.ts" + * @import {InputActions} from "~/components/input/types.d.ts" + * @import {Actions} from "~/components/artwork/types.d.ts" + */ + +//////////////////////////////////////////// +// ACTIONS +//////////////////////////////////////////// + +/** + * @type {ActionsWithTunnel['get']} + */ +export async function get({ data: track, ports }) { + /** @type {ProxiedActions} */ + const input = workerProxy(() => { + ports.input.start(); + return ports.input; + }); + + return await input.artwork(track.uri); +} + +//////////////////////////////////////////// +// ⚡️ +//////////////////////////////////////////// + +ostiary((context) => { + rpc(context, { get }); +}); diff --git a/src/components/configurator/input/element.js b/src/components/configurator/input/element.js index 45b11080..4b8fc68a 100644 --- a/src/components/configurator/input/element.js +++ b/src/components/configurator/input/element.js @@ -27,6 +27,7 @@ class InputConfigurator extends DiffuseElement { /** @type {ProxiedActions} */ const proxy = this.workerProxy(); + this.artwork = proxy.artwork; this.consult = proxy.consult; this.detach = proxy.detach; this.groupConsult = proxy.groupConsult; diff --git a/src/components/input/https/element.js b/src/components/input/https/element.js index fef3c391..a0060ff4 100644 --- a/src/components/input/https/element.js +++ b/src/components/input/https/element.js @@ -28,6 +28,7 @@ class HttpsInput extends DiffuseElement { /** @type {ProxiedActions} */ this.proxy = this.workerProxy(); + this.artwork = this.proxy.artwork; this.consult = this.proxy.consult; this.detach = this.proxy.detach; this.groupConsult = this.proxy.groupConsult; diff --git a/src/components/input/icecast/element.js b/src/components/input/icecast/element.js index 0fcbf97f..a7b23f7a 100644 --- a/src/components/input/icecast/element.js +++ b/src/components/input/icecast/element.js @@ -28,6 +28,7 @@ class IcecastInput extends DiffuseElement { /** @type {ProxiedActions} */ this.proxy = this.workerProxy(); + this.artwork = this.proxy.artwork; this.consult = this.proxy.consult; this.detach = this.proxy.detach; this.groupConsult = this.proxy.groupConsult; diff --git a/src/components/input/local/element.js b/src/components/input/local/element.js index 1e284725..e3cc286c 100644 --- a/src/components/input/local/element.js +++ b/src/components/input/local/element.js @@ -37,6 +37,7 @@ class LocalInput extends DiffuseElement { /** @type {ProxiedActions} */ this.proxy = this.workerProxy(); + this.artwork = this.proxy.artwork; this.consult = this.proxy.consult; this.detach = this.proxy.detach; this.groupConsult = this.proxy.groupConsult; diff --git a/src/components/input/opensubsonic/element.js b/src/components/input/opensubsonic/element.js index 4aceafe6..1859516b 100644 --- a/src/components/input/opensubsonic/element.js +++ b/src/components/input/opensubsonic/element.js @@ -28,6 +28,7 @@ class OpensubsonicInput extends DiffuseElement { /** @type {ProxiedActions} */ this.proxy = this.workerProxy(); + this.artwork = this.proxy.artwork; this.consult = this.proxy.consult; this.detach = this.proxy.detach; this.groupConsult = this.proxy.groupConsult; diff --git a/src/components/input/s3/element.js b/src/components/input/s3/element.js index b1021e1e..b9034945 100644 --- a/src/components/input/s3/element.js +++ b/src/components/input/s3/element.js @@ -29,6 +29,7 @@ class S3Input extends DiffuseElement { /** @type {ProxiedActions Demo }>} */ this.proxy = this.workerProxy(); + this.artwork = this.proxy.artwork; this.consult = this.proxy.consult; this.detach = this.proxy.detach; this.groupConsult = this.proxy.groupConsult; diff --git a/tests/components/artwork/input/test.ts b/tests/components/artwork/input/test.ts new file mode 100644 index 00000000..56fbbffd --- /dev/null +++ b/tests/components/artwork/input/test.ts @@ -0,0 +1,42 @@ +import { describe, it } from "@std/testing/bdd"; +import { expect } from "@std/expect"; + +import { testWeb } from "@tests/common/index.ts"; + +describe("components/artwork/input", () => { + it("delegates to input.artwork and returns null when input has no artwork", async () => { + const result = await testWeb(async () => { + const HttpsInput = await import("~/components/input/https/element.js"); + const InputArtwork = await import( + "~/components/artwork/input/element.js" + ); + + const input = new HttpsInput.CLASS(); + input.id = "test-https-input-artwork"; + document.body.append(input); + + const artwork = new InputArtwork.CLASS(); + artwork.setAttribute("input-selector", "#test-https-input-artwork"); + document.body.append(artwork); + + await customElements.whenDefined(input.localName); + await customElements.whenDefined(artwork.localName); + + const blob = await fetch("http://localhost:3000/testing/sample/audio.mp3") + .then((r) => r.blob()); + const blobUri = URL.createObjectURL(blob); + + const result = await artwork.get({ + $type: "sh.diffuse.output.track" as const, + id: "input-artwork-test", + uri: blobUri, + }); + + URL.revokeObjectURL(blobUri); + + return result ?? null; + }); + + expect(result).toBe(null); + }); +});