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

Configure Feed

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

fix: bunch of output things

+103 -23
+1 -3
src/components/configurator/output-fallback/element.js
··· 143 143 144 144 // SIGNALS 145 145 146 - #activeOutput = signal(/** @type {OutputElement<Encoding> | null} */ (null), { 147 - eager: true, 148 - }); 146 + #activeOutput = signal(/** @type {OutputElement<Encoding> | null} */ (null)); 149 147 #setupFinished = signal(false); 150 148 151 149 // STATE
+32 -7
src/components/configurator/output/element.js
··· 1 - import { DiffuseElement } from "@common/element.js"; 1 + import { 2 + BroadcastableDiffuseElement, 3 + DiffuseElement, 4 + } from "@common/element.js"; 2 5 import { batch, computed, signal } from "@common/signal.js"; 3 6 4 7 /** ··· 21 24 /** 22 25 * @implements {OutputConfiguratorElement} 23 26 */ 24 - class OutputConfigurator extends DiffuseElement { 27 + class OutputConfigurator extends BroadcastableDiffuseElement { 25 28 static NAME = "diffuse/configurator/output"; 26 29 27 30 constructor() { ··· 199 202 this.playlists = manager.playlists; 200 203 this.themes = manager.themes; 201 204 this.tracks = manager.tracks; 202 - this.ready = manager.ready 205 + this.ready = manager.ready; 203 206 } 204 207 205 208 // SIGNALS ··· 231 234 * @override 232 235 */ 233 236 async connectedCallback() { 237 + // Broadcast if needed 238 + if (this.hasAttribute("group")) { 239 + const actions = this.broadcast(this.nameWithGroup, { 240 + selectOutput: { 241 + strategy: "replicate", 242 + fn: this.#selectOutput, 243 + }, 244 + }); 245 + 246 + if (actions) { 247 + this.#selectOutput = actions.selectOutput; 248 + } 249 + } 250 + 251 + // Super 234 252 super.connectedCallback(); 235 253 236 254 /** @type {Output | null | undefined} */ ··· 244 262 const selectedOutput = await this.#findSelectedOutput(); 245 263 246 264 batch(() => { 247 - this.#defaultOutput.value = defaultOutput; 248 265 this.#selectedOutput.value = selectedOutput; 266 + this.#defaultOutput.value = defaultOutput; 249 267 this.#setupFinished.value = true; 250 268 }); 251 269 } ··· 253 271 // MISC 254 272 255 273 /** 256 - * @param {string} id 274 + * @param {string | null} id 275 + */ 276 + #selectOutput = async (id) => { 277 + this.#selectedOutput.value = await this.#findOutput(id); 278 + }; 279 + 280 + /** 281 + * @param {string | null} id 257 282 */ 258 283 async #findOutput(id) { 259 284 const el = id ? this.root().querySelector(`#${id}`) : null; ··· 301 326 302 327 deselect = async () => { 303 328 localStorage.removeItem(`${STORAGE_PREFIX}/selected/id`); 304 - this.#selectedOutput.value = await this.#findSelectedOutput(); 329 + await this.#selectOutput(null); 305 330 }; 306 331 307 332 options = async () => { ··· 326 351 */ 327 352 select = async (id) => { 328 353 localStorage.setItem(`${STORAGE_PREFIX}/selected/id`, id); 329 - this.#selectedOutput.value = await this.#findSelectedOutput(); 354 + await this.#selectOutput(id); 330 355 }; 331 356 } 332 357
+5 -1
src/components/orchestrator/output/element.js
··· 126 126 </dc-output-fallback> 127 127 128 128 <!-- OUTPUT CONFIGURATOR --> 129 - <dc-output id="do-output__dc-output" default="do-output__dc-output__local"> 129 + <dc-output 130 + id="do-output__dc-output" 131 + default="do-output__dc-output__local" 132 + group="${ifDefined(group)}" 133 + > 130 134 <dtos-json 131 135 id="do-output__dc-output__local" 132 136 output-selector="#do-output__dop-indexed-db__json"
+1 -1
src/components/orchestrator/process-tracks/element.js
··· 107 107 return; 108 108 } 109 109 110 - this.#performedInitialProcess.value = true; 110 + this.#performedInitialProcess.set(true); 111 111 112 112 const skip = /** @type {any} */ (import.meta).env 113 113 ?.DISABLE_AUTOMATIC_TRACKS_PROCESSING ?? false;
+10 -3
src/components/output/bytes/s3/element.js
··· 100 100 101 101 #bucket = signal(/** @type {Bucket | undefined} */ (undefined)); 102 102 103 + bucket = this.#bucket.get; 104 + 103 105 /** @returns {Promise<Bucket | undefined>} */ 104 - async bucket() { 106 + async getBucket() { 105 107 if (!this.#bucket.value) { 106 108 /** @type {Bucket | undefined} */ 107 109 const stored = await IDB.get(`${STORAGE_PREFIX}/bucket`); ··· 120 122 await IDB.set(`${STORAGE_PREFIX}/bucket`, bucket); 121 123 } 122 124 125 + async unsetBucket() { 126 + this.#bucket.value = undefined; 127 + await IDB.del(`${STORAGE_PREFIX}/bucket`); 128 + } 129 + 123 130 // GET & PUT 124 131 125 132 /** @param {string} name */ 126 133 #getProxy = async (name) => { 127 - const bucket = await this.bucket(); 134 + const bucket = await this.getBucket(); 128 135 if (!bucket) return undefined; 129 136 return this.proxy.get({ bucket, name: this.#cat(name) }); 130 137 }; ··· 133 140 134 141 /** @param {string} name; @param {any} data */ 135 142 #putProxy = async (name, data) => { 136 - const bucket = await this.bucket(); 143 + const bucket = await this.getBucket(); 137 144 if (!bucket) return undefined; 138 145 return this.proxy.put({ bucket, data, name: this.#cat(name) }); 139 146 };
+6 -1
src/components/output/bytes/s3/types.d.ts
··· 1 + import type { SignalReader } from "@common/signal.d.ts"; 1 2 import type { OutputElement } from "../../types.d.ts"; 2 3 import type { Bucket } from "@components/input/s3/types.d.ts"; 3 4 4 5 export type S3OutputElement = 5 6 & OutputElement<Uint8Array | undefined> 6 7 & { 7 - setBucket(bucket: Bucket): void; 8 + bucket: SignalReader<Bucket | undefined>; 9 + 10 + getBucket(): Promise<Bucket | undefined>; 11 + setBucket(bucket: Bucket): Promise<void>; 12 + unsetBucket(): Promise<void>; 8 13 }; 9 14 10 15 export type S3OutputWorkerActions = {
+8 -1
src/themes/webamp/98-extra.css
··· 1 + :root, 2 + :host { 3 + line-height: 1.4; 4 + } 5 + 1 6 fieldset + fieldset, 2 7 fieldset + form { 3 8 margin-top: var(--grouped-element-spacing); ··· 7 12 margin-bottom: var(--grouped-element-spacing); 8 13 } 9 14 10 - p { 15 + p, 16 + ul, 17 + ol { 11 18 margin: var(--grouped-element-spacing) 0; 12 19 } 13 20
+40 -6
src/themes/webamp/configurators/output/element.js
··· 113 113 /** 114 114 * @param {Event} event 115 115 */ 116 - #handleS3SetBucket = (event) => { 116 + #handleS3SetBucket = async (event) => { 117 117 event.preventDefault(); 118 118 119 119 const s3 = this.$s3.value; ··· 160 160 secretKey, 161 161 }; 162 162 163 - s3.setBucket(bucket); 163 + await s3.setBucket(bucket); 164 164 165 165 if (button) button.disabled = false; 166 + }; 167 + 168 + #handleS3Unset = async () => { 169 + const s3 = this.$s3.value; 170 + if (!s3) return; 171 + 172 + await s3.unsetBucket(); 166 173 }; 167 174 168 175 #handleS3Activate = async () => { ··· 365 372 </fieldset> 366 373 367 374 <p class="button-row"> 368 - <button @click="${this 369 - .#handleAtprotoLogout}">Sign out</button> 375 + <button @click="${this.#handleAtprotoLogout}">Sign out</button> 370 376 ${this.#renderAtprotoActivation(html, selectedOutput)} 371 377 </p> 372 378 `; ··· 399 405 400 406 <p> 401 407 <button type="submit" id="atproto-submit">Sign in</button> 408 + ${this.#renderAtprotoActivation(html, selectedOutput)} 402 409 </p> 403 410 </form> 404 411 `; ··· 423 430 : undefined; 424 431 425 432 const configured = () => { 433 + const bucket = s3?.bucket(); 434 + 426 435 return html` 427 436 <fieldset> 428 - <span class="with-icon with-icon--large"> 437 + <div class="with-icon with-icon--large"> 429 438 <img src="images/icons/windows_98/computer_user_pencil-0.png" width="24" /> 430 - <span>S3 bucket configured.</span> 439 + <div> 440 + Bucket configured: 441 + <ul 442 + style="margin-bottom: 0; padding-left: 0; list-style-position: inside;" 443 + > 444 + <li>Name: <strong>${bucket?.bucketName}</strong></li> 445 + <li>Host: ${bucket?.host}</li> 446 + <li>Access key: ${bucket?.accessKey}</li> 447 + </ul> 448 + </div> 449 + </div> 450 + </fieldset> 451 + 452 + <fieldset> 453 + <span class="with-icon with-icon--large"> 454 + <img 455 + src="images/icons/windows_98/msg_information-0.png" 456 + width="24" 457 + /> 458 + <span> 459 + Make sure the bucket has CORS configured properly. 460 + </span> 431 461 </span> 432 462 </fieldset> 433 463 434 464 <p class="button-row"> 465 + <button id="s3-unset-bucket" @click="${this.#handleS3Unset}"> 466 + Remove bucket configuration 467 + </button> 435 468 ${this.#renderS3Activation(html, selectedOutput)} 436 469 </p> 437 470 `; ··· 497 530 498 531 <p> 499 532 <button type="submit" id="s3-submit">Set bucket</button> 533 + ${this.#renderS3Activation(html, selectedOutput)} 500 534 </p> 501 535 </form> 502 536 `;