Anxiety Aid Tools: guided meditation, peaceful visualization, relaxing sounds - #210
alvinunreal wants to merge 3 commits into
Conversation
…tion Add a "player" session kind for narrated practices: tracks of https audio segments with captions, cover images, a gap between segments and an optional narration-language note. The bridge requires the network permission and refuses segments on unapproved hosts. The host downloads each segment once through a new safeHttpFetchBytes (same guards as ctx.net), caches it under userData with an LRU cap, and serves it on a privileged openpets-session-media: scheme; the coordinator only resolves URLs listed in the open descriptor. Unavailable segments fall back to a timed caption so the practice still works offline. The overlay gets a compact player view (cover, track picker, captions, progress, back 15s / previous / next / mute) and shell hooks for it. Anxiety Aid Tools gains Guided meditation: AAT's eight sessions streamed from R2 in the closest narration language (ja/ko hear English with translated captions), covers, captions in seven locales, and honest Info with verified citations.
Add Peaceful visualization: AAT's nine scenes, seven narrated steps each, streamed from R2 in the closest narration language with captions in seven locales and honest Info (three verified imagery studies described as what they are). Scene covers follow once generated; tracks show the placeholder tile meanwhile. Raise the session practice cap to eight.
Add a "soundscape" session kind: scenes of layers (looping beds or accents on random/wave intervals, with volume, pan, pitch, fades and loop crossfades) and sleep-timer choices. Files follow the player's approved-host rule and host media cache. The overlay mixes them with Web Audio, ported from AAT's ambient engine: crossfaded loops, randomized accents, pause via context suspend, master volume, mute, and a sleep timer that fades out and completes the run. Anxiety Aid Tools gains Relaxing sounds: AAT's eight environments with covers, names in seven locales and honest Info with verified studies.
|
| chip.addEventListener("click", () => { | ||
| timerMinutes = minutes; | ||
| renderTimerChips(); | ||
| renderStatus(); | ||
| }); |
There was a problem hiding this comment.
Changing the sleep timer while a soundscape is active only updates timerMinutes, while the remaining time subtracts elapsedMs accumulated since the run began. For example, selecting 15 minutes after listening for 10 minutes leaves only 5 minutes, and selecting it after 15 minutes starts the fade immediately. Track the timer from when it is selected instead.
| /** Looping bed (exactly one of `loop` or `interval`). */ | ||
| loop?: boolean; | ||
| /** Seconds between accents (1–600); "wave" drifts min→max→min by `increment`. */ | ||
| interval?: { type: "random" | "wave"; min: number; max: number; increment?: number }; |
There was a problem hiding this comment.
The public SDK makes loop and interval independently optional, so TypeScript accepts layers with both properties or neither. Runtime validation rejects both forms, meaning a plugin can type-check successfully but fail when it calls ui.session(). Model looping beds and interval accents as mutually exclusive variants so the published contract matches runtime validation.
Knowledge Base Used:
| async function downloadToCache(url: string, cacheId: string, allowedHosts: ReadonlySet<string>, diagnostics: NetworkDiagnostics): Promise<string> { | ||
| const started = Date.now(); | ||
| const response = await safeHttpFetchBytes(url, allowedHosts, diagnostics, maxMediaFileBytes); |
There was a problem hiding this comment.
Downloads Outlive Session Teardown
This call does not pass the lifecycle signal supported by safeHttpFetchBytes. Stopping or replacing a session, or disabling or reloading its plugin, can therefore leave a media request running for up to 60 seconds and allow it to write an unused cache file afterward. Connect these downloads to session or plugin teardown cancellation.
Knowledge Base Used: Desktop plugin platform
| const loadBuffer = (url) => { | ||
| let pending = buffers.get(url); | ||
| if (!pending) { | ||
| pending = (async () => { | ||
| const localUrl = await ui.resolveMedia(url); | ||
| if (!localUrl || !context) return null; | ||
| const response = await fetch(localUrl); | ||
| if (!response.ok) return null; | ||
| const bytes = await response.arrayBuffer(); | ||
| if (!context) return null; | ||
| return context.decodeAudioData(bytes); | ||
| })().catch(() => null); | ||
| buffers.set(url, pending); | ||
| } | ||
| return pending; |
There was a problem hiding this comment.
loadBuffer stores a promise that resolves to null when media resolution, fetching, or decoding fails. That failed result remains cached for the entire run, so a transient failure can permanently silence a loop or accent even after connectivity recovers. If another bed succeeds, the UI still reports the scene as playing without warning about the missing layers. Remove failed entries from buffers or retry them with a bounded backoff.
Stacked on #207 (base
feat/aat-grounding). Retarget tomainafter #206 and #207 merge.Summary
Platform (host)
playersession kind (narrated tracks) andsoundscapesession kind (layered ambient scenes). Both requirenetwork. Every media URL must be on one of the plugin's approvednetwork.hosts; the bridge refuses the open otherwise.session-media-cache.ts: downloads each file once through a newsafeHttpFetchBytes(same SSRF, host and redirect guards asctx.net) and caches it under userData (1 GB LRU, 25 MB per file, atomic writes, de-duplicated downloads). Files are served on a privilegedopenpets-session-media:scheme, added to the pet window CSP. The coordinator only resolves URLs listed in the open descriptor. Media plays offline after first use.player-practice.cjs: cover thumbnail, track picker, three-line caption, part n/N, time, back 15s / previous / next / mute. An unavailable segment keeps its caption on screen for about 9s and the track moves on.soundscape-practice.cjs: a Web Audio port of AAT's ambient engine (crossfaded loops; random or wave accents with file, volume, pan and pitch variation; pause via context suspend; volume, mute, sleep timer).hidesSharedRows,hidesCount,extraControls,onPause/onResume/onStop,ui.resolveMedia. The practice cap goes from 6 to 8.Anxiety Aid Tools
Verification
plugins:test,plugins:locales,plugins:check,plugins:package,plugins:validate-release(18 plugins): pass.Not yet
docs/*.mdpending sign-off.