A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: introduce transformers + add descriptions to elements on index page

+150 -97
+1
deno.lock
··· 1246 1246 "https://deno.land/x/lume@v3.0.11/deps/toml.ts": "32830bda333eaf4f1c3d79e4306ba449c17a85b25f94aae9b327d3790a2d1dea", 1247 1247 "https://deno.land/x/lume@v3.0.11/deps/vento.ts": "78db4022ee124fbcfd84caeb6c5a70f2c1e1706ec9f6415d0f1fe2e9aabcba2b", 1248 1248 "https://deno.land/x/lume@v3.0.11/deps/yaml.ts": "a639f4fc44ddcfc87f35e38980bbe9fc8101bf8ce34867522e76cc13cb156611", 1249 + "https://deno.land/x/lume@v3.0.11/lint.ts": "23cf68a7cc17edfdb16f2e905de3c5d5a1da541638f04fb8f7d5c762288f2c52", 1249 1250 "https://deno.land/x/lume@v3.0.11/middlewares/basic_auth.ts": "c18f0da9f88be4581e5e3da99214fd7abdad829ab00dbdd2fb3116f1f876add2", 1250 1251 "https://deno.land/x/lume@v3.0.11/middlewares/logger.ts": "c96f1a9f9d5757555b6f141865ce8551ac176f90c8ee3e9ad797b2b400a9a567", 1251 1252 "https://deno.land/x/lume@v3.0.11/middlewares/no_cache.ts": "0119e3ae3a596ab12c42df693b93e5b03dd9608e289d862242751a9739438f35",
+5 -1
src/_components/list.vto
··· 1 1 <ul> 2 2 {{ for item of items }} 3 3 <li> 4 - {{ if item.title.startsWith("(TODO) ") }} 4 + {{ if item.todo }} 5 + <span class="todo">[todo]</span> 5 6 <span>{{item.title}}</span> 6 7 {{ else }} 7 8 <a href="{{item.url}}">{{item.title}}</a> 9 + {{ /if }} 10 + {{ if item.desc }} 11 + <div class="list-description">{{item.desc}}</div> 8 12 {{ /if }} 9 13 </li> 10 14 {{ /for }}
+1 -1
src/common/index.js
··· 1 1 // import * as Uint8 from "uint8arrays"; 2 2 3 3 /** 4 - * @import {Track} from "@components/core/types.d.ts" 4 + * @import {Track} from "@common/types.d.ts" 5 5 */ 6 6 7 7 /**
+1 -1
src/components/configurator/input/worker.js
··· 5 5 import { use } from "@common/worker.js"; 6 6 7 7 /** 8 - * @import { GroupConsult, InputActions as Actions, Track } from "@components/core/types.d.ts"; 8 + * @import { GroupConsult, InputActions as Actions, Track } from "@common/types.d.ts"; 9 9 */ 10 10 11 11 ////////////////////////////////////////////
-24
src/components/core/types.d.ts src/common/types.d.ts
··· 1 - import type { SignalReader } from "@common/signal.d.ts"; 2 - 3 1 /* INPUT */ 4 2 5 3 /** ··· 29 27 }; 30 28 31 29 export type InputElement = HTMLElement & InputActions; 32 - 33 - /* OUTPUT */ 34 - 35 - export interface Output<S = TrackStats, T = TrackTags> { 36 - tracks: Track<S, T>[]; 37 - } 38 - 39 - export type OutputActions = { 40 - getTracks(): Promise<Track[]>; 41 - putTracks(tracks: Track[]): Promise<void>; 42 - }; 43 - 44 - export type OutputElement = HTMLElement & OutputManager; 45 - 46 - export type OutputManager = { 47 - tracks: { 48 - collection: SignalReader<Track[]>; 49 - reload: () => Promise<void>; 50 - save: (tracks: Track[]) => Promise<void>; 51 - state: SignalReader<"loading" | "loaded">; 52 - }; 53 - }; 54 30 55 31 /* TRACKS */ 56 32
+1 -1
src/components/engine/queue/types.d.ts
··· 1 - import type { Track, TrackStats, TrackTags } from "@components/core/types.d.ts"; 1 + import type { Track, TrackStats, TrackTags } from "@common/types.d.ts"; 2 2 import type { SignalReader } from "@common/signal.d.ts"; 3 3 4 4 export type Actions = {
+1 -1
src/components/engine/queue/worker.js
··· 6 6 7 7 /** 8 8 * @import {Actions, Item} from "./types.d.ts" 9 - * @import {Track} from "@components/core/types.d.ts" 9 + * @import {Track} from "@common/types.d.ts" 10 10 */ 11 11 12 12 const QUERY = QS.parse(location.search);
+1 -1
src/components/input/opensubsonic/common.js
··· 8 8 /** 9 9 * @import {Child} from "subsonic-api" 10 10 * @import {Server} from "./types.d.ts"; 11 - * @import {Track} from "@components/core/types.d.ts"; 11 + * @import {Track} from "@common/types.d.ts"; 12 12 */ 13 13 14 14 /**
+1 -1
src/components/input/opensubsonic/element.js
··· 2 2 import { use } from "@common/worker.js"; 3 3 4 4 /** 5 - * @import {InputActions} from "@components/core/types.d.ts" 5 + * @import {InputActions} from "@common/types.d.ts" 6 6 */ 7 7 8 8 ////////////////////////////////////////////
+1 -1
src/components/input/opensubsonic/worker.js
··· 19 19 20 20 /** 21 21 * @import {Child, SubsonicAPI} from "subsonic-api" 22 - * @import {ConsultGrouping, InputActions as Actions, Track} from "@components/core/types.d.ts"; 22 + * @import {ConsultGrouping, InputActions as Actions, Track} from "@common/types.d.ts"; 23 23 * @import {Server} from "./types.d.ts" 24 24 */ 25 25
+1 -1
src/components/input/s3/common.js
··· 6 6 import { ENCODINGS, IDB_BUCKETS, SCHEME } from "./constants.js"; 7 7 8 8 /** 9 - * @import { Track } from "@components/core/types.d.ts"; 9 + * @import { Track } from "@common/types.d.ts"; 10 10 * @import { Bucket } from "./types.d.ts"; 11 11 */ 12 12
+1 -1
src/components/input/s3/worker.js
··· 12 12 import { SCHEME } from "./constants.js"; 13 13 14 14 /** 15 - * @import { InputActions as Actions, Track } from "@components/core/types.d.ts"; 15 + * @import { InputActions as Actions, Track } from "@common/types.d.ts"; 16 16 * @import { Bucket } from "./types.d.ts" 17 17 */ 18 18
+2 -1
src/components/orchestrator/process-tracks/element.js
··· 4 4 import { signal } from "@common/signal.js"; 5 5 6 6 /** 7 - * @import {InputElement, OutputElement, Track} from "@components/core/types.d.ts" 7 + * @import {InputElement, Track} from "@common/types.d.ts" 8 + * @import {OutputElement} from "@components/output/types.d.ts" 8 9 */ 9 10 10 11 ////////////////////////////////////////////
+1 -1
src/components/orchestrator/queue-audio/element.js
··· 2 2 import { untracked } from "@common/signal.js"; 3 3 4 4 /** 5 - * @import {InputElement, OutputElement, Track} from "@components/core/types.d.ts" 5 + * @import {InputElement} from "@common/types.d.ts" 6 6 */ 7 7 8 8 ////////////////////////////////////////////
+4 -3
src/components/orchestrator/queue-tracks/element.js
··· 2 2 import { untracked } from "@common/signal.js"; 3 3 4 4 /** 5 - * @import {InputElement, OutputElement, Track} from "@components/core/types.d.ts" 5 + * @import {InputElement, Track} from "@common/types.d.ts" 6 + * @import {OutputElement} from "@components/output/types.d.ts" 6 7 */ 7 8 8 9 //////////////////////////////////////////// ··· 10 11 //////////////////////////////////////////// 11 12 12 13 /** 13 - * Fill the queue automatically with tracks 14 - * whenever tracks have been loaded, 14 + * Update the queue pool whenever 15 + * tracks have been loaded, 15 16 * or the tracks collection changes. 16 17 */ 17 18 class QueueTracksOrchestrator extends DiffuseElement {
+2 -1
src/components/orchestrator/search-tracks/element.js
··· 1 1 import { DiffuseElement, query } from "@common/element.js"; 2 2 3 3 /** 4 - * @import {InputElement, OutputElement, Track} from "@components/core/types.d.ts" 4 + * @import {InputElement, Track} from "@common/types.d.ts" 5 + * @import {OutputElement} from "@components/output/types.d.ts" 5 6 */ 6 7 7 8 ////////////////////////////////////////////
+6 -5
src/components/output/common.js
··· 1 - import { effect, signal } from "@common/signal.js"; 1 + import { signal } from "@common/signal.js"; 2 2 3 3 /** 4 - * @import {OutputManager, Track} from "@components/core/types.d.ts" 4 + * @import {OutputManager, OutputManagerProperties} from "./types.d.ts" 5 5 */ 6 6 7 7 /** 8 - * @param {{ init?: () => Promise<boolean>; tracks: { get(): Promise<Track[]>; put(tracks: Track[]): Promise<void>; } }} _ 9 - * @returns {OutputManager} 8 + * @template Tracks 9 + * @param {OutputManagerProperties<Tracks>} _ 10 + * @returns {OutputManager<Tracks>} 10 11 */ 11 12 export function outputManager({ init, tracks }) { 12 - const t = signal(/** @type {Track[]} */ ([])); 13 + const t = signal(/** @type {Tracks} */ (tracks.empty())); 13 14 const ts = signal(/** @type {"loading" | "loaded"} */ ("loading")); 14 15 15 16 async function loadTracks() {
-1
src/components/output/indexed-db/constants.js
··· 1 - export const IDB_PREFIX = "@components/output/indexed-db";
+7 -6
src/components/output/indexed-db/element.js src/components/output/polymorphic/indexed-db/element.js
··· 1 1 import { DiffuseElement } from "@common/element.js"; 2 2 import { use } from "@common/worker.js"; 3 - import { outputManager } from "../common.js"; 3 + import { outputManager } from "../../common.js"; 4 4 5 5 /** 6 - * @import {OutputActions, OutputManager, Track} from "@components/core/types.d.ts" 6 + * @import {OutputManager} from "../../types.d.ts" 7 7 */ 8 8 9 9 //////////////////////////////////////////// ··· 11 11 //////////////////////////////////////////// 12 12 13 13 /** 14 - * @implements {OutputManager} 14 + * @implements {OutputManager<any>} 15 15 */ 16 16 class IndexedDBOutput extends DiffuseElement { 17 17 constructor() { 18 18 super(); 19 19 20 20 // Setup worker 21 - const name = `diffuse/output/indexed-db/${this.group}`; 22 - const url = "/components/output/indexed-db/worker.js"; 21 + const name = `diffuse/output/polymorphic/indexed-db/${this.group}`; 22 + const url = "/components/output/polymorphic/indexed-db/worker.js"; 23 23 const worker = new Worker(url, { name, type: "module" }); 24 24 25 25 // Manager 26 26 const manager = outputManager({ 27 27 tracks: { 28 + empty: () => [], 28 29 get: use("getTracks", worker), 29 30 put: use("putTracks", worker), 30 31 }, ··· 41 42 //////////////////////////////////////////// 42 43 43 44 export const CLASS = IndexedDBOutput; 44 - export const NAME = "do-indexed-db"; 45 + export const NAME = "dop-indexed-db"; 45 46 46 47 customElements.define(NAME, IndexedDBOutput);
+8 -13
src/components/output/indexed-db/worker.js src/components/output/polymorphic/indexed-db/worker.js
··· 1 1 import * as IDB from "idb-keyval"; 2 2 3 - import { jsonDecode, jsonEncode } from "@common/index.js"; 4 3 import { IDB_PREFIX } from "./constants.js"; 5 4 import { define, ostiary } from "@common/worker.js"; 6 5 7 6 /** 8 - * @import {OutputActions, Track} from "@components/core/types.d.ts"; 7 + * @import {Track} from "@common/types.d.ts"; 9 8 */ 10 9 11 10 //////////////////////////////////////////// ··· 13 12 //////////////////////////////////////////// 14 13 15 14 /** 16 - * @type {OutputActions['getTracks']} 15 + * @returns {Promise<Track[]>} 17 16 */ 18 17 export async function getTracks() { 19 - const encoded = await get({ name: "tracks.json" }); 20 - if (!encoded) return []; 21 - 22 - /** @type {Track[]} */ 23 - const tracks = jsonDecode(encoded); 24 - return tracks; 18 + /** @type {Track[] | null} */ 19 + const tracks = await get({ name: "tracks.json" }); 20 + return tracks ?? []; 25 21 } 26 22 27 23 /** 28 - * @type {OutputActions['putTracks']} 24 + * @param {Track[]} tracks 29 25 */ 30 26 export async function putTracks(tracks) { 31 - const data = jsonEncode(tracks); 32 - await put({ name: "tracks.json", data }); 27 + await put({ name: "tracks.json", data: tracks }); 33 28 } 34 29 35 30 //////////////////////////////////////////// ··· 54 49 } 55 50 56 51 /** 57 - * @param {{ data: Uint8Array; name: string }} _ 52 + * @param {{ data: any; name: string }} _ 58 53 */ 59 54 async function put({ data, name }) { 60 55 return await IDB.set(`${IDB_PREFIX}/${name}`, data);
+1
src/components/output/polymorphic/indexed-db/constants.js
··· 1 + export const IDB_PREFIX = "@components/output/polymorphic/indexed-db";
+28
src/components/output/types.d.ts
··· 1 + import type { SignalReader } from "@common/signal.d.ts"; 2 + import type { Track } from "@common/types.d.ts"; 3 + 4 + // TODO: Do we need this? 5 + // 6 + // export interface Output<S = TrackStats, T = TrackTags> { 7 + // tracks: Track<S, T>[]; 8 + // } 9 + 10 + export type OutputElement = HTMLElement & OutputManager<Track[]>; 11 + 12 + export type OutputManager<Tracks> = { 13 + tracks: { 14 + collection: SignalReader<Tracks>; 15 + reload: () => Promise<void>; 16 + save: (tracks: Tracks) => Promise<void>; 17 + state: SignalReader<"loading" | "loaded">; 18 + }; 19 + }; 20 + 21 + export type OutputManagerProperties<Tracks> = { 22 + init?: () => Promise<boolean>; 23 + tracks: { 24 + empty(): Tracks; 25 + get(): Promise<Tracks>; 26 + put(tracks: Tracks): Promise<void>; 27 + }; 28 + };
+1 -1
src/components/processor/artwork/types.d.ts
··· 1 - import type { TrackTags } from "@components/core/types.d.ts"; 1 + import type { TrackTags } from "@common/types.d.ts"; 2 2 3 3 export type Actions = { 4 4 artwork(request: ArtworkRequest): Promise<Artwork[]>;
+1 -1
src/components/processor/metadata/common.js
··· 4 4 import { tokenizer as rangeTokenizer } from "@tokenizer/range"; 5 5 6 6 /** 7 - * @import { TrackStats, TrackTags } from "@components/core/types.d.ts"; 7 + * @import { TrackStats, TrackTags } from "@common/types.d.ts"; 8 8 * @import { Extraction, Urls } from "./types.d.ts"; 9 9 */ 10 10
+1 -1
src/components/processor/metadata/types.d.ts
··· 1 1 import type { IPicture } from "music-metadata"; 2 - import type { TrackStats, TrackTags } from "@components/core/types.d.ts"; 2 + import type { TrackStats, TrackTags } from "@common/types.d.ts"; 3 3 4 4 export type Actions = { 5 5 supply: (
+1 -1
src/components/processor/search/types.d.ts
··· 1 - import type { Track } from "@components/core/types.d.ts"; 1 + import type { Track } from "@common/types.d.ts"; 2 2 3 3 export type Actions = { 4 4 search(term: string): Promise<Track[]>;
+1 -1
src/components/processor/search/worker.js
··· 7 7 import { signal } from "@common/signal.js"; 8 8 9 9 /** 10 - * @import {Track} from "@components/core/types.d.ts" 10 + * @import {Track} from "@common/types.d.ts" 11 11 * @import {Actions} from "./types.d.ts" 12 12 */ 13 13
+13
src/index.css
··· 79 79 min-width: min(var(--container-xs), 100%); 80 80 width: 32.5%; 81 81 } 82 + 83 + .list-description { 84 + font-size: var(--fs-xs); 85 + margin-bottom: var(--space-xs); 86 + margin-top: var(--space-2xs); 87 + opacity: 0.6; 88 + } 89 + 90 + .todo { 91 + font-size: var(--fs-sm); 92 + font-weight: 600; 93 + opacity: 0.4; 94 + }
+39 -10
src/index.vto
··· 11 11 12 12 # ELEMENTS 13 13 14 + configurators: 15 + - title: "Input" 16 + desc: "Add multiple inputs." 17 + todo: true 18 + - title: "Output" 19 + desc: "Allows the user to configure a specific output." 20 + todo: true 21 + 14 22 engines: 15 23 - url: "components/engine/audio/element.js" 16 24 title: "Audio" 25 + desc: "Plays audio through audio elements." 17 26 - url: "components/engine/queue/element.js" 18 27 title: "Queue" 28 + desc: "A simple queue for tracks. NOTE: Temporarily automatically adds tracks shuffled to the queue." 19 29 20 30 input: 21 31 - url: "components/input/opensubsonic/element.js" 22 32 title: "Opensubsonic" 23 33 - url: "components/input/s3/element.js" 24 - title: "S3 (TODO)" 34 + title: "S3" 35 + desc: "AWS S3 and services that provide the same surface API such as Cloudflare R2." 36 + todo: true 25 37 26 38 orchestrators: 27 39 - url: "components/orchestrator/process-tracks/element.js" 28 40 title: "Process inputs into tracks" 41 + desc: "Whenever the cached tracks are initially loaded through the passed output element it will contextualize and then list tracks by using the passed input element. Afterwards it loops over all tracks and checks if metadata needs to be fetched. If anything has changed, it'll pass the results to the output element." 29 42 - url: "components/orchestrator/queue-audio/element.js" 30 43 title: "Queue ⭤ Audio" 44 + desc: "Connects the given queue engine to the given audio engine." 31 45 - url: "components/orchestrator/queue-tracks/element.js" 32 46 title: "Queue ⭤ Tracks" 47 + desc: "Sets the given queue element pool whenever the tracks signal from the given output changes." 48 + - url: "components/orchestrator/search-tracks/element.js" 49 + title: "Search ⭤ Tracks" 50 + desc: "Supplies tracks to the given search processor whenever the tracks collection changes." 33 51 34 52 output: 35 - - url: "components/output/indexed-db/element.js" 36 - title: "IndexedDB" 53 + - url: "components/output/polymorphic/indexed-db/element.js" 54 + title: "Polymorphic / IndexedDB" 55 + desc: "Stores output into the local indexedDB. Supports any type of data that indexedDB supports." 37 56 38 57 processors: 39 58 - url: "components/processor/artwork/element.js" 40 59 title: "Artwork" 60 + desc: "Fetches cover art for a given set of tracks, stored locally in indexedDB. Checks the audio metadata first, then MusicBrainz and uses Last.fm as the fallback." 41 61 - url: "components/processor/metadata/element.js" 42 62 title: "Metadata" 63 + desc: "Fetch audio metadata for a given set of tracks, adding to the `Track` object." 43 64 - url: "components/processor/search/element.js" 44 65 title: "Search" 66 + desc: "Provides a way to search through a collection of tracks, powered by orama.js" 67 + 68 + supplements: 69 + - title: "Last.fm scrobbler" 70 + todo: true 45 71 46 72 transformers: 47 - - url: "components/transformer/output-lenses/element.js" 48 - title: "Output Lenses (TODO)" 73 + - url: "components/transformer/output/bytes/cambria/element.js" 74 + title: "Output / Bytes / Cambria lenses" 75 + desc: "Uses the Cambria library to seamlessly translate between data schemas so that no data migration is needed." 76 + todo: true 49 77 50 78 # SCHEMAS 51 79 52 80 schemas: 53 81 - url: "schemas/output/tracks/lexicon.json" 54 - title: "Output / Tracks (TODO)" 82 + title: "Output / Tracks" 83 + todo: true 55 84 56 85 --- 57 86 <link rel="stylesheet" href="index.css" /> ··· 111 140 title: "Configurators", 112 141 items: configurators, 113 142 content: ` 114 - Elements that serve as an intermediate in order to make a particular kind of element configurable. In other words, these allow for an element to be swapped out with another that takes the same, or a subset of the actions and data output. 143 + Elements that serve as an intermediate in order to make a particular kind of element configurable. In other words, these allow for an element to be swapped out with another that takes the same set of the actions and data output. 115 144 ` 116 145 }) }} 117 146 ··· 143 172 title: "Output", 144 173 items: output, 145 174 content: ` 146 - Output is application-derived data such as playlists. These elements can receive such data and keep it around. 175 + Output is application-derived data such as playlists. These elements can receive such data and keep it around. These are categorised by the type of data they ingest, or many types in the case of polymorphic. 147 176 ` 148 177 }) }} 149 178 ··· 167 196 title: "Transformers", 168 197 items: transformers, 169 198 content: ` 170 - Transform data from one schema into another. See schema section below for more information. 199 + Transform data from one format or schema into another. See schema section below for more information. Just as configurators, these are intermediates and require to have the same set of actions as the element it targets. 171 200 ` 172 201 }) }} 173 202 </div> ··· 177 206 <section> 178 207 <h2 id="schemas">Schemas</h2> 179 208 180 - <p>All of the elements here are built with these specific data schemas in mind. That said, you can mix elements that use different schemas; you just have to put a transformer between them in order to translate between the schemas.</p> 209 + <p>All of the elements here are built with these data schemas in mind. That said, you can mix elements that use different schemas; you just have to put a transformer between them in order to translate between the schemas.</p> 181 210 182 211 {{ await comp.list({ items: schemas }) }} 183 212 </section>
+1 -5
src/themes/blur/index.js
··· 5 5 import "@components/orchestrator/queue-tracks/element.js"; 6 6 import "@components/processor/metadata/element.js"; 7 7 8 - import * as Output from "@components/output/indexed-db/element.js"; 8 + import * as Output from "@components/output/polymorphic/indexed-db/element.js"; 9 9 import * as Queue from "@components/engine/queue/element.js"; 10 10 11 11 import { component } from "@common/element.js"; 12 12 import { effect } from "@common/signal.js"; 13 - 14 - /** 15 - * @import {Item} from "@components/engine/queue/types.d.ts" 16 - */ 17 13 18 14 const output = component(Output); 19 15 const queue = component(Queue);
+3 -3
src/themes/blur/index.vto
··· 14 14 15 15 <!-- Inputs, Outputs & Processors --> 16 16 <di-opensubsonic></di-opensubsonic> 17 - <do-indexed-db></do-indexed-db> 17 + <dop-indexed-db></dop-indexed-db> 18 18 <dp-metadata></dp-metadata> 19 19 20 20 <!-- Orchestrators --> 21 21 <do-process-tracks 22 22 input-selector="di-opensubsonic" 23 23 metadata-processor-selector="dp-metadata" 24 - output-selector="do-indexed-db" 24 + output-selector="dop-indexed-db" 25 25 ></do-process-tracks> 26 26 27 27 <do-queue-audio ··· 32 32 33 33 <do-queue-tracks 34 34 input-selector="di-opensubsonic" 35 - output-selector="do-indexed-db" 35 + output-selector="dop-indexed-db" 36 36 queue-engine-selector="de-queue" 37 37 ></do-queue-tracks> 38 38
+2 -1
src/themes/webamp/browser/element.js
··· 2 2 3 3 /** 4 4 * @import {RenderArg} from "@common/element.d.ts" 5 - * @import {InputElement, OutputElement, Track} from "@components/core/types.d.ts" 5 + * @import {InputElement, Track} from "@common/types.d.ts" 6 + * @import {OutputElement} from "@components/output/types.d.ts" 6 7 */ 7 8 8 9 class Browser extends DiffuseElement {
+2 -2
src/themes/webamp/index.js
··· 1 - // import "@components/orchestrator/process-tracks/element.js"; 1 + import "@components/orchestrator/process-tracks/element.js"; 2 2 import "@components/orchestrator/queue-tracks/element.js"; 3 - import "@components/output/indexed-db/element.js"; 3 + import "@components/output/polymorphic/indexed-db/element.js"; 4 4 import "@components/processor/metadata/element.js"; 5 5 6 6 import * as Input from "@components/input/opensubsonic/element.js";
+10 -5
src/themes/webamp/index.vto
··· 16 16 <main> 17 17 <section class="windows"> 18 18 <dtw-window-manager> 19 + <!-- INPUT --> 19 20 <dtw-window id="input-window"> 20 21 <span slot="title-icon"><img src="/images/icons/windows_98/cd_audio_cd_a-0.png" height="14" /></span> 21 22 <span slot="title">Manage audio inputs</span> 22 23 <p>👀</p> 23 24 </dtw-window> 25 + 26 + <!-- OUTPUT --> 24 27 <dtw-window id="output-window"> 25 28 <span slot="title-icon"><img src="/images/icons/windows_98/computer_user_pencil-0.png" height="14" /></span> 26 29 <span slot="title">Manage user data</span> 27 30 <p>👀</p> 28 31 </dtw-window> 32 + 33 + <!-- BROWSER --> 29 34 <dtw-window id="browser-window" open> 30 35 <span slot="title-icon"><img src="/images/icons/windows_98/directory_explorer-4.png" height="14" /></span> 31 36 <span slot="title">Browse collection</span> 32 37 <dtw-browser 33 38 input-selector="di-opensubsonic" 34 - output-selector="do-indexed-db" 39 + output-selector="dop-indexed-db" 35 40 queue-selector="de-queue" 36 41 ></dtw-browser> 37 42 </dtw-window> ··· 72 77 --> 73 78 <de-queue fill-size="5"></de-queue> 74 79 75 - <!-- Inputs, Outputs & Processors --> 80 + <!-- Inputs, Outputs, Processors & Transformers --> 76 81 <di-opensubsonic></di-opensubsonic> 77 - <do-indexed-db></do-indexed-db> 82 + <dop-indexed-db></dop-indexed-db> 78 83 <dp-metadata></dp-metadata> 79 84 80 85 <!-- Orchestrators --> 81 86 <do-process-tracks 82 87 input-selector="di-opensubsonic" 83 88 metadata-processor-selector="dp-metadata" 84 - output-selector="do-indexed-db" 89 + output-selector="dop-indexed-db" 85 90 ></do-process-tracks> 86 91 87 92 <do-queue-tracks 88 93 input-selector="di-opensubsonic" 89 - output-selector="do-indexed-db" 94 + output-selector="dop-indexed-db" 90 95 queue-engine-selector="de-queue" 91 96 ></do-queue-tracks> 92 97
+1 -1
src/themes/webamp/webamp/element.js
··· 1 1 import Webamp from "webamp/lazy"; 2 2 3 3 /** 4 - * @import {Track} from "@components/core/types.d.ts" 4 + * @import {Track} from "@common/types.d.ts" 5 5 */ 6 6 class WebampElement extends HTMLElement { 7 7 constructor() {