···11+{
22+ "name": "diffuse/configurator/input",
33+ "title": "Diffuse Configurator | Input",
44+ "entrypoint": "index.html",
55+ "actions": {
66+ "list": {
77+ "title": "List",
88+ "description": "List tracks from all inputs.",
99+ "params_schema": {
1010+ "type": "object",
1111+ "properties": {
1212+ "tracks": {
1313+ "type": "array",
1414+ "description": "A list of (cached) tracks",
1515+ "items": {
1616+ "type": "object"
1717+ }
1818+ }
1919+ }
2020+ }
2121+ },
2222+ "resolve": {
2323+ "title": "Resolve",
2424+ "description": "Potentially translates a track uri with a matching scheme into a URL pointing at the audio bytes. If it can be resolved that is, otherwise you'll get `undefined`.",
2525+ "params_schema": {
2626+ "type": "string",
2727+ "description": "The uri to resolve"
2828+ }
2929+ }
3030+ }
3131+}
+9
src/pages/configurator/input/index.astro
···11+---
22+import Layout from "@layouts/applet-pico-ui.astro";
33+import Applet from "./_applet.astro";
44+import { title } from "./_manifest.json";
55+---
66+77+<Layout title={title}>
88+ <Applet />
99+</Layout>
+5-2
src/pages/index.astro
···2424// TODO
25252626// Applets
2727-const configurators = [{ url: "configurator/output/", title: "Output" }];
2727+const configurators = [
2828+ { url: "configurator/input/", title: "Input" },
2929+ { url: "configurator/output/", title: "Output" },
3030+];
28312932const engines = [
3033 { url: "engine/audio/", title: "Audio" },
···121124 <Applet title="Configurators" list={configurators}>
122125 Applets that serve as an intermediate in order to make a particular kind of applet
123126 configurable. In other words, these allow for an applet to be swapped out with another
124124- that takes the same actions and data output.
127127+ that takes the same, or a subset of the actions and data output.
125128 </Applet>
126129127130 <Applet title="Engines" list={engines}>
+34-15
src/pages/input/native-fs/_applet.astro
···11<main class="container">
22- <h1>Native File System Input</h1>
33- <p>Add music from your device.</p>
22+ <h1>Native file system input</h1>
33+ <p>
44+ Add music from your device.
55+ <br />Music added so far:
66+ </p>
47 <div id="directories">
58 <p>
69 <span class="with-icon">
···1619 import * as IDB from "idb-keyval";
17201821 import { applets } from "@web-applets/sdk";
1919- import { computed, Signal, signal } from "spellcaster";
2222+ import { computed, effect, Signal, signal } from "spellcaster";
2023 import { repeat, tags, text } from "spellcaster/hyperscript.js";
2124 import { type FileSystemDirectoryHandle, showDirectoryPicker } from "native-file-system-adapter";
2225 import * as URI from "uri-js";
···3639 ////////////////////////////////////////////
3740 const IDB_PREFIX = "@applets/input/native-fs";
3841 const IDB_HANDLES = `${IDB_PREFIX}/handles`;
3939- const INPUT_SCHEME = manifest.input_properties.scheme;
4242+ const SCHEME = manifest.input_properties.scheme;
40434144 const context = applets.register();
4245···6972 };
70737174 const Directories = computed(() => {
7575+ if (mounts().length === 0) {
7676+ return tags.p({ id: "directories" }, [
7777+ tags.small({}, [
7878+ tags.em({}, text("No audio added yet, click the button below to add some.")),
7979+ ]),
8080+ ]);
8181+ }
8282+7283 return tags.ul({ id: "directories" }, repeat(dirList, Item));
7384 });
74857586 // Add to DOM
7676- document.getElementById("directories")?.replaceWith(Directories());
8787+ effect(() => {
8888+ document.getElementById("directories")?.replaceWith(Directories());
8989+ });
77907891 ////////////////////////////////////////////
7992 // ACTIONS
8093 ////////////////////////////////////////////
8181- const isAvailable = async (fileUri: string) => {
9494+ const consult = async (fileUriOrScheme: string) => {
8295 const isSupported = !!(globalThis as any).showDirectoryPicker;
8396 if (!isSupported) {
8484- console.warn(
8585- "`input/native-fs` is not supported on this platform, missing File System Access API.",
8686- );
8787- return false;
9797+ return { supported: false, reason: "File System Access API is not supported" };
9898+ }
9999+100100+ if (!fileUriOrScheme.includes(":")) {
101101+ if (fileUriOrScheme !== SCHEME) return { supported: false, reason: "Scheme does not match" };
102102+ return { supported: true };
88103 }
8910490105 const handles = await fetchHandles();
9191- const uri = URI.parse(fileUri);
9292- return uri.host && !!handles[uri.host];
106106+ const uri = URI.parse(fileUriOrScheme);
107107+ if (uri.scheme !== SCHEME) return { supported: false, reason: "Scheme does not match" };
108108+ return { supported: true, consultation: uri.host && !!handles[uri.host] };
93109 };
9411095111 const list = async (cachedTracks: Track[] = []) => {
···137153 };
138154139155 const resolve = async (fileUri: string) => {
156156+ const isSupported = !!(globalThis as any).showDirectoryPicker;
157157+ if (!isSupported) return undefined;
158158+140159 const uri = URI.parse(fileUri);
141141- if (uri.scheme !== INPUT_SCHEME) return undefined;
160160+ if (uri.scheme !== SCHEME) return undefined;
142161 if (!uri.host || !uri.path) return undefined;
143162144163 const handles = await fetchHandles();
···191210 setMounts(await fetchHandlesList());
192211 };
193212194194- context.setActionHandler("isAvailable", isAvailable);
213213+ context.setActionHandler("consult", consult);
195214 context.setActionHandler("list", list);
196215 context.setActionHandler("resolve", resolve);
197216 context.setActionHandler("mount", mount);
···231250 for await (const item of dir.values()) {
232251 if (item.kind === "file" && isAudioFile(item.name)) {
233252 const uri = URI.serialize({
234234- scheme: INPUT_SCHEME,
253253+ scheme: SCHEME,
235254 host: rootHandleId,
236255 path: `${path.length ? "/" + path.join("/") : ""}/${item.name}`,
237256 });
+1-1
src/pages/input/native-fs/_manifest.json
···3232 },
3333 "resolve": {
3434 "title": "Resolve",
3535- "description": "Potentially translates a track uri with a matching scheme into a URL pointing at the audio bytes. If it can be resolved that is, otherwise you'll get `undefined`.",
3535+ "description": "Potentially translates a track uri with a matching scheme into a URL pointing at the audio bytes. If it can be resolved that is, otherwise you'll get `undefined`. Use the `consult` action to get a more detailed answer.",
3636 "params_schema": {
3737 "type": "string",
3838 "description": "The uri to resolve"