@audiodn/components
Advanced tools
| /** | ||
| * Shared audio input/output device helpers for the Player and Recorder. | ||
| * | ||
| * The selected microphone (input) and speaker (output) are page-wide | ||
| * preferences: picking one in any player or recorder should apply to every | ||
| * other instance and persist for the session. This mirrors how volume is | ||
| * coordinated in the player — a `sessionStorage`-backed value plus a document | ||
| * event that other instances listen to. | ||
| * | ||
| * Output routing relies on `HTMLMediaElement.setSinkId`, which is not available | ||
| * in every browser (notably Safari). When it is missing we simply skip the | ||
| * output UI and never claim to change the output device. | ||
| */ | ||
| export interface AudioDevice { | ||
| deviceId: string; | ||
| label: string; | ||
| } | ||
| /** Document events used to sync device selection across instances. */ | ||
| export declare const INPUT_CHANGE_EVENT = "adn-inputchange"; | ||
| export declare const OUTPUT_CHANGE_EVENT = "adn-outputchange"; | ||
| /** True when the browser can route audio to a chosen output device. */ | ||
| export declare function supportsSinkId(): boolean; | ||
| export declare function enumerateAudioInputs(): Promise<AudioDevice[]>; | ||
| export declare function enumerateAudioOutputs(): Promise<AudioDevice[]>; | ||
| export declare function getPreferredAudioInputId(): string; | ||
| export declare function setPreferredAudioInputId(deviceId: string): void; | ||
| export declare function getPreferredAudioOutputId(): string; | ||
| export declare function setPreferredAudioOutputId(deviceId: string): void; | ||
| /** | ||
| * Route a media element to the preferred output device. No-op when the API is | ||
| * unsupported or no device is selected. Failures (e.g. the device was | ||
| * unplugged) are swallowed so playback stays on the current sink. | ||
| */ | ||
| export declare function applySinkId(el: HTMLMediaElement | null | undefined, deviceId: string): Promise<void>; |
| import { w as d, n as E, r as U, i as b, a as I, b as y, t as R } from "./lit-DpNjQO9d.js"; | ||
| import { t as V } from "./i18n-BI0dP23M.js"; | ||
| function D(t) { | ||
| if (!t || typeof t != "object") return !1; | ||
| const e = t.url; | ||
| return !(typeof e != "string" || !e.trim() || /\/(null|undefined)(?:\/|$)/i.test(e)); | ||
| } | ||
| function A(t) { | ||
| if (!t || typeof t != "object") return; | ||
| const e = t, n = {}; | ||
| let o = !1; | ||
| for (const r of ["icon", "small", "regular", "large"]) { | ||
| const i = e[r]; | ||
| D(i) && (n[r] = { | ||
| height: Number(i.height) || 0, | ||
| type: String(i.type || ""), | ||
| url: i.url.trim(), | ||
| width: Number(i.width) || 0 | ||
| }, o = !0); | ||
| } | ||
| return o ? n : void 0; | ||
| } | ||
| const ct = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>`, lt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>`, pt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 5V2L7 7l5 5V8a5 5 0 1 1-4.9 6h-2.05A7 7 0 1 0 12 5z"/></svg>`, dt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l9.5 16.5H2.5L12 3z"/><path d="M12 10v4"/><path d="M12 17.5v.01"/></svg>`; | ||
| d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M475.8 175.3c3 8 .4 16.8-5.9 22.5l-39.6 36a176.6 176.6 0 0 1 0 46.5l39.6 36a20.7 20.7 0 0 1 5.9 22.5c-4 10.9-9 21.3-14.5 31.3l-4.3 7.4c-6 10.1-12.8 19.6-20.2 28.6a20.8 20.8 0 0 1-22.5 6.2l-51-16.2a176.3 176.3 0 0 1-40.3 23.2l-11.4 52.2a20.7 20.7 0 0 1-16.7 16.3 237 237 0 0 1-77.9 0c-8.4-1.4-14.8-8-16.6-16.3l-11.5-52.2a179 179 0 0 1-40.3-23.2l-51 16.3a21 21 0 0 1-22.4-6.2c-7.4-9-14.2-18.5-20.2-28.6l-4.3-7.4a234 234 0 0 1-14.5-31.3c-3-8-.4-16.9 5.9-22.5l39.6-36a179 179 0 0 1 0-46.6l-39.6-36a20.7 20.7 0 0 1-5.9-22.5c4-10.9 9-21.3 14.5-31.3l4.3-7.5c6-10 12.8-19.5 20.2-28.5a20.8 20.8 0 0 1 22.5-6.2l51 16.2A176.3 176.3 0 0 1 189 94.8l11.4-52.2a20.7 20.7 0 0 1 16.7-16.3 227.5 227.5 0 0 1 77.9-.1c8.4 1.4 14.8 8 16.6 16.3l11.5 52.2a179 179 0 0 1 40.3 23.2l51-16.2c8-2.5 17-.3 22.4 6.2 7.5 9 14.2 18.5 20.3 28.6l4.3 7.4c5.6 10 10.4 20.4 14.5 31.3l-.1.1ZM256 330a73 73 0 1 0 0-146 73 73 0 0 0 0 146Z"/></svg>`; | ||
| const ut = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M267.6 64.4A27.8 27.8 0 0 1 284 89.7v332.6a27.8 27.8 0 0 1-46.1 20.7L121 339H62.4A55.5 55.5 0 0 1 7 283.7v-55.4a55.5 55.5 0 0 1 55.4-55.5h58.7L237.9 69c8.1-7.3 19.8-9 29.7-4.6Zm107.8 114.7 47.6 47.6 47.6-47.6a20.8 20.8 0 0 1 29.3 29.3L452.3 256l47.6 47.6a20.8 20.8 0 0 1-29.3 29.3L423 285.3 375.4 333a20.8 20.8 0 0 1-29.3-29.3l47.6-47.6-47.6-47.6a20.8 20.8 0 0 1 29.3-29.3Z"/></svg>`, mt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M279.8 64.4A27.8 27.8 0 0 1 296 89.7v332.6a28 28 0 0 1-16.2 25.3 27.3 27.3 0 0 1-29.6-4.6l-116-104H76c-30.3 0-55-24.8-55-55.4v-55.4a55.3 55.3 0 0 1 55-55.5h58.3L250.2 69c8-7.3 19.7-9 29.6-4.6Zm149 62.3a166 166 0 0 1 0 257.6 20.8 20.8 0 0 1-26.1-32.2 124.4 124.4 0 0 0 0-193.2 20.8 20.8 0 0 1 26.1-32.2Zm-52.6 65a82.7 82.7 0 0 1 0 128.6 21 21 0 0 1-29.5-3c-7.3-8.9-6-22 3-29.2a41.2 41.2 0 0 0 0-64.3 20.7 20.7 0 0 1-3-29.2 21.1 21.1 0 0 1 29.5-3v.1Z"/></svg>`, ft = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M280.8 64.4A27.8 27.8 0 0 1 297 89.7v332.6a28 28 0 0 1-16.2 25.3 27.3 27.3 0 0 1-29.6-4.6l-116-104H77c-30.3 0-55-24.8-55-55.4v-55.4a55.3 55.3 0 0 1 55-55.5h58.3L251.2 69c8-7.3 19.7-9 29.6-4.6Zm96.4 127.3a82.7 82.7 0 0 1 0 128.6 21 21 0 0 1-29.5-3c-7.3-8.9-6-22 3-29.2a41.2 41.2 0 0 0 0-64.3 20.7 20.7 0 0 1-3-29.2 21.1 21.1 0 0 1 29.5-3v.1Z"/></svg>`, ht = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M96 480a32 32 0 1 1 0-64h320a32 32 0 1 1 0 64H96Zm182.6-137.4a32 32 0 0 1-45.3 0l-128-128a32 32 0 0 1 45.3-45.3l73.4 73.4V64a32 32 0 1 1 64 0v178.7l73.4-73.4a32 32 0 0 1 45.3 45.3l-128 128h-.1Z"/></svg>`, gt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M242.7 165.4h.1a22 22 0 0 1 6.5 4.6l45.4 45.2a22 22 0 0 1-31.1 31.2l-7.8-7.8v83.6a22 22 0 0 1-44 0v-83.6l-7.8 7.8a22 22 0 0 1-30.8.2l-.3-.3a22 22 0 0 1 0-31l45.3-45.3a22.1 22.1 0 0 1 .7-.7h.1l.4-.5h.2c1.6-1.5 3.4-2.6 5.3-3.4l.3-.1a22.2 22.2 0 0 1 7.6-1.7h.1a17.8 17.8 0 0 1 1.2 0h-.3a22.4 22.4 0 0 1 .9 0h.7c2.6.2 5 .8 7.3 1.8Z"/><path d="M199.1 21c68.5 0 131 35 167.3 91.1l.1.3h2a153.7 153.7 0 0 1 143.5 151v2.5c0 46.4-20.7 89.6-55.8 118.6a28.5 28.5 0 0 1-36.3-43.8A96.8 96.8 0 0 0 358.4 169c-15 0-29-7.9-36.7-20.9A142 142 0 0 0 57 220.3 142 142 0 0 0 98.5 321 28.4 28.4 0 1 1 58 361 199.2 199.2 0 0 1 199 21Z"/></svg>`, vt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.49 6-3.31 6-6.72h-1.7z"/></svg>`, wt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6 6h12v12H6z"/></svg>`, xt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>`; | ||
| d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>`; | ||
| const yt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`, bt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/></svg>`, H = { VITE_API_URL: "https://api.audiodelivery.net" }, F = H, f = F?.VITE_API_URL; | ||
| class m extends Error { | ||
| constructor(e, n) { | ||
| super(e), this.name = "ApiError", this.status = n; | ||
| } | ||
| } | ||
| const S = 1, N = 1e3; | ||
| async function h(t, e) { | ||
| let n = null; | ||
| for (let o = 0; o <= S; o++) | ||
| try { | ||
| return await fetch(t, e); | ||
| } catch (r) { | ||
| n = r instanceof Error ? r : new Error(String(r)), o < S && await new Promise((i) => setTimeout(i, N * Math.pow(2, o))); | ||
| } | ||
| throw n || new m("Network request failed", 0); | ||
| } | ||
| async function g(t, e, n) { | ||
| return n(); | ||
| } | ||
| function v(t, e = {}) { | ||
| return t ? { | ||
| ...e, | ||
| headers: { | ||
| ...e.headers, | ||
| "Accept-Language": t | ||
| } | ||
| } : e; | ||
| } | ||
| async function Z(t, e, n, o, r, i, s) { | ||
| const a = `/v1/play_session/${e}`; | ||
| return g("POST", a, async () => { | ||
| const l = `${f}${a}`, c = await h(l, v(i, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${t}` | ||
| }, | ||
| body: JSON.stringify({ | ||
| [`${e}_id`]: n, | ||
| variants: o, | ||
| ...r && { expires_in: r }, | ||
| // Requested download intent; the API key is the authoritative gate and | ||
| // the server stores (key AND this) on the session. | ||
| ...s && { is_downloadable: !0 } | ||
| }) | ||
| })), p = await c.json(); | ||
| if (!c.ok || !p.ok) | ||
| throw new m(p.message || "Failed to create play session", c.status); | ||
| if (!p.tracks?.length) | ||
| throw new m("No tracks found in session", c.status); | ||
| const x = { | ||
| ok: p.ok, | ||
| playSessionId: p.play_session_id, | ||
| expiresAt: new Date(p.expires_at), | ||
| playSession: u(p.play_session), | ||
| tracks: [] | ||
| }; | ||
| x.playSession.expiresAt = new Date(x.playSession.expiresAt); | ||
| for (const O of p.tracks) | ||
| x.tracks.push(u(O)); | ||
| return p.first_track && (x.firstTrack = B(p.first_track)), x; | ||
| }); | ||
| } | ||
| async function G(t, e) { | ||
| const n = `/v1/play_session/${t}`; | ||
| return g("GET", n, async () => { | ||
| const o = `${f}${n}`, r = await h(o, v(e)), i = await r.json(); | ||
| if (!r.ok || !i.ok) | ||
| throw new m(i.message || "Failed to fetch play session", r.status); | ||
| if (!i.tracks?.length) | ||
| throw new m("No tracks found in session", r.status); | ||
| const s = { | ||
| ok: i.ok, | ||
| playSessionId: i.play_session_id, | ||
| expiresAt: new Date(i.expires_at || i.play_session.expires_at), | ||
| playSession: u(i.play_session), | ||
| tracks: [] | ||
| }; | ||
| s.playSession.expiresAt = new Date(s.playSession.expiresAt); | ||
| for (const a of i.tracks) | ||
| s.tracks.push(u(a)); | ||
| return i.first_track && (s.firstTrack = B(i.first_track)), s; | ||
| }); | ||
| } | ||
| async function _t(t, e, n) { | ||
| const o = `/v1/play/${t}/${e}`; | ||
| return g("GET", o, async () => { | ||
| const r = `${f}${o}`, i = await h(r, v(n)), s = await i.json(); | ||
| if (!i.ok || !s.ok) | ||
| throw new m(s.message || "Failed to fetch track data", i.status); | ||
| return { | ||
| ok: s.ok, | ||
| playSessionId: s.play_session_id, | ||
| trackId: s.track_id, | ||
| playSession: u(s.play_session), | ||
| track: u(s.track), | ||
| levels: u(s.levels), | ||
| variants: z(s.variants), | ||
| coverImage: A(u(s.cover_image)) | ||
| }; | ||
| }); | ||
| } | ||
| async function kt(t, e, n, o) { | ||
| const r = `/v1/play/${t}/${e}/${encodeURIComponent(String(n).toLowerCase())}/download`; | ||
| return g("GET", r, async () => { | ||
| const i = `${f}${r}`, s = await h(i, v(o)), a = await s.json(); | ||
| if (!s.ok || !a?.ok) | ||
| throw new m(a?.message || "Failed to fetch download URL", s.status); | ||
| return a; | ||
| }); | ||
| } | ||
| async function St(t, e, n) { | ||
| const o = "/v1/upload_session"; | ||
| return g("POST", o, async () => { | ||
| const r = `${f}${o}`, i = {}; | ||
| e && (i.collection_id = e); | ||
| const s = await h(r, v(n, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${t}` | ||
| }, | ||
| body: JSON.stringify(i) | ||
| })), a = await s.json(); | ||
| if (!s.ok || !a?.ok) | ||
| throw new m(a?.message || "Failed to create upload session", s.status); | ||
| return a; | ||
| }); | ||
| } | ||
| async function Tt(t, e, n, o, r) { | ||
| const i = "/v1/upload_session"; | ||
| return g("POST", i, async () => { | ||
| const s = `${f}${i}`, a = { file_name: n }; | ||
| o?.player_title && (a.player_title = o.player_title), o?.player_subtitle && (a.player_subtitle = o.player_subtitle), o?.player_color && (a.player_color = o.player_color), o?.metadata && (a.metadata = o.metadata), o?.organization_index && (a.organization_index = o.organization_index); | ||
| const l = { track: a }; | ||
| e && (l.collection_id = e); | ||
| const c = await h(s, v(r, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${t}` | ||
| }, | ||
| body: JSON.stringify(l) | ||
| })), p = await c.json(); | ||
| if (!c.ok || !p?.ok) | ||
| throw new m(p?.message || "Failed to create upload session with track", c.status); | ||
| if (!p.track_id || !p.track_upload?.upload_url) | ||
| throw new m("Upload session created but track upload URL was missing", c.status); | ||
| return p; | ||
| }); | ||
| } | ||
| async function $t(t, e) { | ||
| const n = `/v1/upload_session/${t}`; | ||
| return g("GET", n, async () => { | ||
| const o = `${f}${n}`, r = await h(o, v(e)), i = await r.json(); | ||
| if (!r.ok || !i?.ok) | ||
| throw new m(i?.message || "Failed to fetch upload session", r.status); | ||
| return i; | ||
| }); | ||
| } | ||
| async function Ct(t, e, n, o) { | ||
| const r = `/v1/upload/${t}/track`; | ||
| return g("POST", r, async () => { | ||
| const i = `${f}${r}`, s = await h(i, v(o, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json" | ||
| }, | ||
| body: JSON.stringify({ | ||
| file_name: e, | ||
| file_size: n | ||
| }) | ||
| })), a = await s.json(); | ||
| if (!s.ok || !a?.ok) | ||
| throw new m(a?.message || "Failed to get upload URL", s.status); | ||
| return a; | ||
| }); | ||
| } | ||
| function z(t) { | ||
| return t.map((e) => { | ||
| const n = u(e); | ||
| return e.data !== null && (n.isPreview = !0, n.preview = { | ||
| offsetStart: e.data.capture_start, | ||
| offsetEnd: e.data.capture_end, | ||
| duration: e.data.duration | ||
| }), n; | ||
| }); | ||
| } | ||
| function B(t) { | ||
| return { | ||
| ok: !0, | ||
| playSessionId: "", | ||
| trackId: t.track_id, | ||
| playSession: {}, | ||
| track: u(t.track), | ||
| levels: u(t.levels), | ||
| variants: z(t.variants), | ||
| coverImage: A(u(t.cover_image)) | ||
| }; | ||
| } | ||
| function T(t) { | ||
| return t.toLowerCase().replace(/([-_][a-z])/g, function(e) { | ||
| return e.toUpperCase().replace("-", "").replace("_", ""); | ||
| }); | ||
| } | ||
| function u(t) { | ||
| if (t == null) return t; | ||
| const e = {}; | ||
| for (const [n, o] of Object.entries(t)) { | ||
| if (o != null && o.constructor === Object) { | ||
| e[T(n)] = u(o); | ||
| continue; | ||
| } | ||
| Object.hasOwn(t, n) && (e[T(n)] = o); | ||
| } | ||
| return e; | ||
| } | ||
| var W = Object.defineProperty, Y = Object.getOwnPropertyDescriptor, _ = (t, e, n, o) => { | ||
| for (var r = o > 1 ? void 0 : o ? Y(e, n) : e, i = t.length - 1, s; i >= 0; i--) | ||
| (s = t[i]) && (r = (o ? s(e, n, r) : s(r)) || r); | ||
| return o && r && W(e, n, r), r; | ||
| }; | ||
| const P = 180, J = { | ||
| error: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M15 9l-6 6M9 9l6 6"/></svg>`, | ||
| warning: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9.5 16.5H2.5L12 3z"/><path d="M12 10v4"/><path d="M12 17.5v.01"/></svg>`, | ||
| info: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 11v5"/><path d="M12 8v.01"/></svg>`, | ||
| success: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M8.5 12.5l2.5 2.5 4.5-5"/></svg>` | ||
| }; | ||
| let w = class extends I { | ||
| constructor() { | ||
| super(...arguments), this.duration = 5e3, this.locale = "en", this.notifications = [], this.nextId = 0; | ||
| } | ||
| add(t, e, n = {}) { | ||
| const o = n.duration ?? (t === "error" || t === "warning" ? 0 : this.duration), r = this.notifications.find((c) => !c.dismissing && c.type === t && c.message === e); | ||
| if (r) | ||
| return r.timeout && clearTimeout(r.timeout), r.action = n.action, o > 0 && (r.timeout = setTimeout(() => this.dismiss(r.id), o)), this.notifications = [...this.notifications], r.id; | ||
| const i = this.nextId++, s = { id: i, type: t, message: e, action: n.action }; | ||
| o > 0 && (s.timeout = setTimeout(() => this.dismiss(i), o)); | ||
| const a = [...this.notifications, s]; | ||
| this.notifications = a.length > 4 ? a.slice(a.length - 4) : a; | ||
| const l = t === "error" ? "adn-error" : t === "success" ? "adn-success" : `adn-${t}`; | ||
| return this.dispatchEvent(new CustomEvent(l, { | ||
| detail: { message: e }, | ||
| bubbles: !0, | ||
| composed: !0 | ||
| })), i; | ||
| } | ||
| dismiss(t) { | ||
| const e = this.notifications.find((n) => n.id === t); | ||
| !e || e.dismissing || (e.timeout && clearTimeout(e.timeout), e.dismissing = !0, this.notifications = [...this.notifications], setTimeout(() => { | ||
| this.notifications = this.notifications.filter((n) => n.id !== t); | ||
| }, P)); | ||
| } | ||
| clear() { | ||
| for (const t of this.notifications) | ||
| t.timeout && clearTimeout(t.timeout); | ||
| this.notifications = []; | ||
| } | ||
| runAction(t) { | ||
| t.action?.onClick(), this.dismiss(t.id); | ||
| } | ||
| disconnectedCallback() { | ||
| super.disconnectedCallback(), this.clear(); | ||
| } | ||
| render() { | ||
| return this.notifications.length === 0 ? y`` : y` | ||
| <div class="notification-stack"> | ||
| ${[...this.notifications].reverse().map((t) => y` | ||
| <div | ||
| class="notification notification-${t.type} ${t.dismissing ? "is-dismissing" : ""}" | ||
| role=${t.type === "error" || t.type === "warning" ? "alert" : "status"} | ||
| aria-live=${t.type === "error" || t.type === "warning" ? "assertive" : "polite"} | ||
| > | ||
| <span class="notification-icon">${J[t.type]}</span> | ||
| <span class="notification-message">${t.message}</span> | ||
| ${t.action ? y` | ||
| <button class="notification-action" @click=${() => this.runAction(t)}>${t.action.label}</button> | ||
| ` : ""} | ||
| <button class="notification-dismiss" @click=${() => this.dismiss(t.id)} aria-label=${V(this.locale, "notification.dismiss")}> | ||
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg> | ||
| </button> | ||
| </div> | ||
| `)} | ||
| </div> | ||
| `; | ||
| } | ||
| }; | ||
| w.styles = q(); | ||
| _([ | ||
| E({ type: Number }) | ||
| ], w.prototype, "duration", 2); | ||
| _([ | ||
| E({ type: String, attribute: "locale" }) | ||
| ], w.prototype, "locale", 2); | ||
| _([ | ||
| U() | ||
| ], w.prototype, "notifications", 2); | ||
| w = _([ | ||
| R("audiodn-notification") | ||
| ], w); | ||
| function q() { | ||
| return b` | ||
| .notification-stack { | ||
| position: absolute; | ||
| top: 0; | ||
| left: 0; | ||
| right: 0; | ||
| z-index: 9999; | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: var(--adn-notification-gap, 6px); | ||
| padding: var(--adn-notification-padding, 6px); | ||
| pointer-events: none; | ||
| } | ||
| .notification { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 8px; | ||
| padding: 8px 10px; | ||
| border-radius: var(--adn-notification-radius, 8px); | ||
| font-size: var(--adn-notification-font-size, var(--step--1, 0.833rem)); | ||
| font-family: var(--adn-font-family, sans-serif); | ||
| line-height: 1.3; | ||
| color: var(--_notif-fg, #fff); | ||
| background: var(--_notif-bg); | ||
| box-shadow: var(--adn-notification-box-shadow, 0 4px 14px rgba(0, 0, 0, 0.35)); | ||
| pointer-events: auto; | ||
| animation: notif-in 200ms cubic-bezier(0.16, 1, 0.3, 1); | ||
| } | ||
| .notification.is-dismissing { | ||
| animation: notif-out ${P}ms ease-in forwards; | ||
| pointer-events: none; | ||
| } | ||
| .notification-error { | ||
| --_notif-bg: var(--adn-notification-bg-error, #dc2626); | ||
| } | ||
| .notification-warning { | ||
| --_notif-bg: var(--adn-notification-bg-warning, #d97706); | ||
| } | ||
| .notification-info { | ||
| --_notif-bg: var(--adn-notification-bg-info, #2563eb); | ||
| } | ||
| .notification-success { | ||
| --_notif-bg: var(--adn-notification-bg-success, #16a34a); | ||
| } | ||
| .notification-icon { | ||
| display: inline-flex; | ||
| flex-shrink: 0; | ||
| } | ||
| .notification-icon svg { | ||
| width: 1.15em; | ||
| height: 1.15em; | ||
| } | ||
| .notification-message { | ||
| flex: 1; | ||
| min-width: 0; | ||
| } | ||
| .notification-action { | ||
| flex-shrink: 0; | ||
| appearance: none; | ||
| border: 1px solid currentColor; | ||
| background: transparent; | ||
| color: inherit; | ||
| font: inherit; | ||
| font-weight: 600; | ||
| padding: 3px 10px; | ||
| border-radius: 999px; | ||
| cursor: pointer; | ||
| opacity: 0.95; | ||
| transition: background-color 120ms ease, opacity 120ms ease; | ||
| } | ||
| .notification-action:hover { | ||
| background: rgba(255, 255, 255, 0.18); | ||
| opacity: 1; | ||
| } | ||
| .notification-dismiss { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| flex-shrink: 0; | ||
| appearance: none; | ||
| border: none; | ||
| background: transparent; | ||
| color: inherit; | ||
| cursor: pointer; | ||
| padding: 2px; | ||
| opacity: 0.7; | ||
| transition: opacity 120ms ease; | ||
| } | ||
| .notification-dismiss svg { | ||
| width: 1em; | ||
| height: 1em; | ||
| } | ||
| .notification-dismiss:hover { | ||
| opacity: 1; | ||
| } | ||
| @keyframes notif-in { | ||
| from { opacity: 0; transform: translateY(-8px); } | ||
| to { opacity: 1; transform: translateY(0); } | ||
| } | ||
| @keyframes notif-out { | ||
| from { opacity: 1; transform: translateY(0); } | ||
| to { opacity: 0; transform: translateY(-8px); } | ||
| } | ||
| @media (prefers-reduced-motion: reduce) { | ||
| .notification, | ||
| .notification.is-dismissing { | ||
| animation-duration: 1ms; | ||
| } | ||
| } | ||
| `; | ||
| } | ||
| const Mt = b` | ||
| /* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,18,1.25,5,3,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ | ||
| /* Step -3: 9.2593px → 9.216px */ | ||
| --step--3: clamp(0.576rem, 0.5796rem + -0.0047vw, 0.5787rem); | ||
| /* Step -2: 11.1111px → 11.52px */ | ||
| --step--2: clamp(0.6944rem, 0.6856rem + 0.0444vw, 0.72rem); | ||
| /* Step -1: 13.3333px → 14.4px */ | ||
| --step--1: clamp(0.8333rem, 0.8101rem + 0.1159vw, 0.9rem); | ||
| /* Step 0: 16px → 18px */ | ||
| --step-0: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); | ||
| /* Step 1: 19.2px → 22.5px */ | ||
| --step-1: clamp(1.2rem, 1.1283rem + 0.3587vw, 1.4063rem); | ||
| /* Step 2: 23.04px → 28.125px */ | ||
| --step-2: clamp(1.44rem, 1.3295rem + 0.5527vw, 1.7578rem); | ||
| /* Step 3: 27.648px → 35.1563px */ | ||
| --step-3: clamp(1.728rem, 1.5648rem + 0.8161vw, 2.1973rem); | ||
| /* @link https://utopia.fyi/space/calculator?c=320,16,1.2,1240,18,1.25,5,1,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ | ||
| /* Space 3xs: 4px → 5px */ | ||
| --space-3xs: clamp(0.25rem, 0.2283rem + 0.1087vw, 0.3125rem); | ||
| /* Space 2xs: 8px → 9px */ | ||
| --space-2xs: clamp(0.5rem, 0.4783rem + 0.1087vw, 0.5625rem); | ||
| /* Space xs: 12px → 14px */ | ||
| --space-xs: clamp(0.75rem, 0.7065rem + 0.2174vw, 0.875rem); | ||
| /* Space s: 16px → 18px */ | ||
| --space-s: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); | ||
| /* Space m: 24px → 27px */ | ||
| --space-m: clamp(1.5rem, 1.4348rem + 0.3261vw, 1.6875rem); | ||
| /* Space l: 32px → 36px */ | ||
| --space-l: clamp(2rem, 1.913rem + 0.4348vw, 2.25rem); | ||
| /* Space xl: 48px → 54px */ | ||
| --space-xl: clamp(3rem, 2.8696rem + 0.6522vw, 3.375rem); | ||
| /* Space 2xl: 64px → 72px */ | ||
| --space-2xl: clamp(4rem, 3.8261rem + 0.8696vw, 4.5rem); | ||
| /* Space 3xl: 96px → 108px */ | ||
| --space-3xl: clamp(6rem, 5.7391rem + 1.3043vw, 6.75rem); | ||
| /* One-up pairs */ | ||
| /* Space 3xs-2xs: 4px → 9px */ | ||
| --space-3xs-2xs: clamp(0.25rem, 0.1413rem + 0.5435vw, 0.5625rem); | ||
| /* Space 2xs-xs: 8px → 14px */ | ||
| --space-2xs-xs: clamp(0.5rem, 0.3696rem + 0.6522vw, 0.875rem); | ||
| /* Space xs-s: 12px → 18px */ | ||
| --space-xs-s: clamp(0.75rem, 0.6196rem + 0.6522vw, 1.125rem); | ||
| /* Space s-m: 16px → 27px */ | ||
| --space-s-m: clamp(1rem, 0.7609rem + 1.1957vw, 1.6875rem); | ||
| /* Space m-l: 24px → 36px */ | ||
| --space-m-l: clamp(1.5rem, 1.2391rem + 1.3043vw, 2.25rem); | ||
| /* Space l-xl: 32px → 54px */ | ||
| --space-l-xl: clamp(2rem, 1.5217rem + 2.3913vw, 3.375rem); | ||
| /* Space xl-2xl: 48px → 72px */ | ||
| --space-xl-2xl: clamp(3rem, 2.4783rem + 2.6087vw, 4.5rem); | ||
| /* Space 2xl-3xl: 64px → 108px */ | ||
| --space-2xl-3xl: clamp(4rem, 3.0435rem + 4.7826vw, 6.75rem); | ||
| /* Custom pairs */ | ||
| /* Space s-l: 16px → 36px */ | ||
| --space-s-l: clamp(1rem, 0.5652rem + 2.1739vw, 2.25rem); | ||
| /* --adn-volume-width: clamp(3.125rem, -0.4464rem + 17.8571vw, 6.25rem); */ | ||
| `, Et = b` | ||
| :host([theme="light"]) { | ||
| --_bg: var(--adn-bg, #f4f4f5); | ||
| --_bg-light: var(--adn-bg-light, #e4e4e7); | ||
| --_color-font: var(--adn-color-font, #1c1c1e); | ||
| --_color-font-muted: var(--adn-color-font-muted, #52525b); | ||
| --_border-color: var(--adn-border-color, #d4d4d8); | ||
| --_color-highlight: var(--adn-color-highlight, rgba(0, 0, 0, 0.06)); | ||
| /* Darker greyscale accent so controls read on the light background. */ | ||
| --_color-accent: var(--adn-color-accent, #52525b); | ||
| --_color-accent-rgb: var(--adn-color-accent-rgb, 82, 82, 91); | ||
| } | ||
| @media (prefers-color-scheme: light) { | ||
| :host([theme="auto"]) { | ||
| --_bg: var(--adn-bg, #f4f4f5); | ||
| --_bg-light: var(--adn-bg-light, #e4e4e7); | ||
| --_color-font: var(--adn-color-font, #1c1c1e); | ||
| --_color-font-muted: var(--adn-color-font-muted, #52525b); | ||
| --_border-color: var(--adn-border-color, #d4d4d8); | ||
| --_color-highlight: var(--adn-color-highlight, rgba(0, 0, 0, 0.06)); | ||
| --_color-accent: var(--adn-color-accent, #52525b); | ||
| --_color-accent-rgb: var(--adn-color-accent-rgb, 82, 82, 91); | ||
| } | ||
| } | ||
| `, At = b` | ||
| *, *:before, *:after { | ||
| box-sizing: border-box; | ||
| } | ||
| @media (prefers-reduced-motion: no-preference) { | ||
| interpolate-size: allow-keywords; | ||
| } | ||
| img,canvas, svg { | ||
| display: block; | ||
| max-width: 100%; | ||
| } | ||
| input, button { | ||
| font: inherit; | ||
| } | ||
| `, X = 3e4; | ||
| async function zt({ | ||
| playSessionId: t, | ||
| id: e, | ||
| apiKey: n, | ||
| scope: o, | ||
| variants: r, | ||
| sessionTtl: i, | ||
| locale: s, | ||
| downloadable: a | ||
| }) { | ||
| if (t) | ||
| try { | ||
| const c = await G(t, s); | ||
| if (c) | ||
| return c; | ||
| } catch (c) { | ||
| if (!(n && o && e)) | ||
| throw new Error("failed to fetch session", { cause: c }); | ||
| } | ||
| if (!n) | ||
| throw new Error("apiKey must be provided"); | ||
| if (!o) | ||
| throw new Error("scope must be provided"); | ||
| if (!e) | ||
| throw new Error("id must be provided"); | ||
| if (!r.length) | ||
| throw new Error("no variants provided"); | ||
| const l = await Z(n, o, e, r, i, s, a); | ||
| if (!l) | ||
| throw new Error("failed to load session data"); | ||
| return l.tracks = l.tracks.sort((c, p) => c.order - p.order).map((c, p) => (c.order = p + 1, c)), l; | ||
| } | ||
| class Bt { | ||
| constructor() { | ||
| this._warningTimer = null, this._expiryTimer = null; | ||
| } | ||
| schedule(e, n) { | ||
| this.clear(); | ||
| const o = Date.now(), i = e.getTime() - o, s = i - X; | ||
| if (i <= 0) { | ||
| n.onExpiry(); | ||
| return; | ||
| } | ||
| s <= 0 ? n.onWarning() : this._warningTimer = setTimeout(n.onWarning, s), this._expiryTimer = setTimeout(n.onExpiry, i); | ||
| } | ||
| clear() { | ||
| this._warningTimer !== null && (clearTimeout(this._warningTimer), this._warningTimer = null), this._expiryTimer !== null && (clearTimeout(this._expiryTimer), this._expiryTimer = null); | ||
| } | ||
| } | ||
| const K = { r: 244, g: 244, b: 245 }, Q = { r: 0, g: 0, b: 0 }, $ = 3, tt = 0.02, L = (t, e, n) => Math.min(n, Math.max(e, t)); | ||
| function j(t) { | ||
| if (typeof t != "string") return null; | ||
| let e = t.trim().replace(/^#/, ""); | ||
| return e.length === 3 && (e = e.split("").map((n) => n + n).join("")), /^[0-9a-fA-F]{6}$/.test(e) ? { | ||
| r: parseInt(e.substring(0, 2), 16), | ||
| g: parseInt(e.substring(2, 4), 16), | ||
| b: parseInt(e.substring(4, 6), 16) | ||
| } : null; | ||
| } | ||
| function et({ r: t, g: e, b: n }) { | ||
| const o = (r) => L(Math.round(r), 0, 255).toString(16).padStart(2, "0"); | ||
| return `#${o(t)}${o(e)}${o(n)}`; | ||
| } | ||
| function ot({ r: t, g: e, b: n }) { | ||
| const o = t / 255, r = e / 255, i = n / 255, s = Math.max(o, r, i), a = Math.min(o, r, i), l = s - a; | ||
| let c = 0; | ||
| l !== 0 && (s === o ? c = (r - i) / l % 6 : s === r ? c = (i - o) / l + 2 : c = (o - r) / l + 4, c *= 60, c < 0 && (c += 360)); | ||
| const p = s === 0 ? 0 : l / s; | ||
| return { h: c, s: p, v: s }; | ||
| } | ||
| function C({ h: t, s: e, v: n }) { | ||
| const o = n * e, r = o * (1 - Math.abs(t / 60 % 2 - 1)), i = n - o; | ||
| let s = 0, a = 0, l = 0; | ||
| return t < 60 ? (s = o, a = r, l = 0) : t < 120 ? (s = r, a = o, l = 0) : t < 180 ? (s = 0, a = o, l = r) : t < 240 ? (s = 0, a = r, l = o) : t < 300 ? (s = r, a = 0, l = o) : (s = o, a = 0, l = r), { | ||
| r: (s + i) * 255, | ||
| g: (a + i) * 255, | ||
| b: (l + i) * 255 | ||
| }; | ||
| } | ||
| function k({ r: t, g: e, b: n }) { | ||
| const o = [t / 255, e / 255, n / 255].map((r) => r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4)); | ||
| return 0.2126 * o[0] + 0.7152 * o[1] + 0.0722 * o[2]; | ||
| } | ||
| function M(t, e) { | ||
| const n = k(t), o = k(e), r = Math.max(n, o), i = Math.min(n, o); | ||
| return (r + 0.05) / (i + 0.05); | ||
| } | ||
| function Pt(t, e = 0.179) { | ||
| const n = j(t); | ||
| return n ? k(n) <= e : !0; | ||
| } | ||
| function nt(t, e, n) { | ||
| let { v: o } = t, r = C({ ...t, v: o }); | ||
| if (M(r, e) >= $) return r; | ||
| for (let i = 0; i < 60 && (o = L(o + n * tt, 0, 1), r = C({ ...t, v: o }), !(M(r, e) >= $ || o === 0 || o === 1)); i++) | ||
| ; | ||
| return r; | ||
| } | ||
| function rt(t, e) { | ||
| const n = j(t); | ||
| if (!n) return null; | ||
| const o = ot(n); | ||
| return et(nt(o, e === "light" ? K : Q, e === "light" ? -1 : 1)); | ||
| } | ||
| const it = "#71717a"; | ||
| function Lt(t) { | ||
| return rt(it, t) ?? (t === "light" ? "#52525b" : "#a1a1aa"); | ||
| } | ||
| export { | ||
| zt as A, | ||
| m as B, | ||
| _t as C, | ||
| Lt as D, | ||
| Bt as S, | ||
| rt as a, | ||
| Ct as b, | ||
| Tt as c, | ||
| dt as d, | ||
| yt as e, | ||
| wt as f, | ||
| $t as g, | ||
| vt as h, | ||
| Pt as i, | ||
| xt as j, | ||
| ct as k, | ||
| lt as l, | ||
| bt as m, | ||
| At as n, | ||
| Mt as o, | ||
| j as p, | ||
| St as q, | ||
| gt as r, | ||
| D as s, | ||
| Et as t, | ||
| pt as u, | ||
| ut as v, | ||
| mt as w, | ||
| ft as x, | ||
| kt as y, | ||
| ht as z | ||
| }; |
| const l = ["en", "fr", "es", "de"]; | ||
| const n = { | ||
| "action.retry": "Retry", | ||
| "action.reload": "Reload", | ||
| "player.notify.loadFailed": "Couldn’t load the player.", | ||
| "player.notify.sessionExpired": "Your session expired.", | ||
| "player.notify.noSession": "No play session available", | ||
| "player.notify.trackLoadFailed": "Couldn’t load this track.", | ||
| "player.notify.playFailed": "Couldn’t play this track.", | ||
| "player.aria.loading": "Loading audio player", | ||
| "player.loadingText": "Loading audio player…", | ||
| "player.aria.region": "Audio player", | ||
| "player.status.playbackError": "Playback error", | ||
| "player.status.buffering": "Buffering", | ||
| "player.status.nowPlaying": "Now playing: {title}", | ||
| "playButton.retry": "Retry", | ||
| "playButton.loading": "Loading", | ||
| "playButton.pause": "Pause", | ||
| "playButton.play": "Play", | ||
| "progress.aria.label": "Playback progress", | ||
| "progress.aria.valueText": "{current} of {total}", | ||
| "playTime.aria": "Playback time: {elapsed} of {total}", | ||
| "volume.aria": "Volume", | ||
| "settings.aria": "More options", | ||
| "settings.download": "Download {label}", | ||
| "settings.notDownloadable": "This track isn’t downloadable.", | ||
| "settings.output.menuLabel": "Output device", | ||
| "settings.output.unnamed": "Speaker {n}", | ||
| "trackTitle.none": "No track selected", | ||
| "coverArt.none": "No cover art", | ||
| "coverArt.alt": "Cover art", | ||
| "tracklist.aria": "Track list", | ||
| "waveform.aria": "Audio waveform", | ||
| "notification.dismiss": "Dismiss notification", | ||
| "uploader.notify.sessionExpired": "Your upload session expired.", | ||
| "uploader.notify.uploadSuccess": "{filename} uploaded successfully", | ||
| "uploader.notify.uploadFailed": "{filename}: upload failed", | ||
| "uploader.notify.networkError": "{filename}: network error", | ||
| "uploader.notify.uploadFailedDetail": "{filename}: {error}", | ||
| "uploader.notify.noAudioFiles": "No audio files detected. Please select audio files.", | ||
| "uploader.notify.limitExceeded": "You can upload at most {limit} file(s).", | ||
| "uploader.error.tryAgain": "Try again", | ||
| "uploader.aria.loading": "Loading uploader", | ||
| "uploader.loadingText": "Loading…", | ||
| "uploader.aria.fileArea": "File upload area", | ||
| "uploader.dropHeading": "Drop Audio Tracks To Collection", | ||
| "uploader.or": "or", | ||
| "uploader.browseFiles": "Browse Files", | ||
| "uploader.aria.selectFiles": "Select audio files to upload", | ||
| "uploader.aria.totalProgress": "Total upload progress", | ||
| "uploader.totalProgressText": "{percent}% total", | ||
| "uploader.aria.queue": "Upload queue", | ||
| "uploader.aria.fileProgress": "Upload progress for {filename}", | ||
| "uploader.aria.retryFile": "Retry upload for {filename}", | ||
| "uploader.aria.cancelUpload": "Cancel upload for {filename}", | ||
| "uploader.aria.removeFile": "Remove file {filename}", | ||
| "recorder.notify.sessionExpired": "Your upload session expired.", | ||
| "recorder.notify.uploadSuccess": "Recording uploaded successfully", | ||
| "recorder.notify.uploadFailed": "Upload failed", | ||
| "recorder.notify.networkError": "Network error during upload", | ||
| "recorder.notify.uploadFailedDetail": "Upload failed: {error}", | ||
| "recorder.notify.micDenied": "Microphone access was denied.", | ||
| "recorder.notify.micUnavailable": "Microphone is not available.", | ||
| "recorder.notify.maxDuration": "Maximum recording length reached.", | ||
| "recorder.error.tryAgain": "Try again", | ||
| "recorder.aria.loading": "Loading recorder", | ||
| "recorder.loadingText": "Loading…", | ||
| "recorder.aria.region": "Voice recorder", | ||
| "recorder.aria.start": "Start recording", | ||
| "recorder.aria.pause": "Pause recording", | ||
| "recorder.aria.resume": "Resume recording", | ||
| "recorder.aria.stop": "Stop recording", | ||
| "recorder.aria.discard": "Discard recording", | ||
| "recorder.aria.send": "Confirm recording", | ||
| "recorder.aria.cancelCountdown": "Cancel countdown", | ||
| "recorder.idle.hint": "Tap to record", | ||
| "recorder.countdown.hint": "Get ready…", | ||
| "recorder.aria.selectMic": "Select microphone", | ||
| "recorder.device.unnamed": "Microphone {n}", | ||
| "recorder.device.menuLabel": "Microphones", | ||
| "recorder.aria.moreOptions": "More options", | ||
| "recorder.menu.preview": "Preview", | ||
| "recorder.menu.stopPreview": "Stop preview", | ||
| "recorder.menu.delete": "Delete", | ||
| "recorder.menu.stopUpload": "Stop upload", | ||
| "recorder.aria.cancelUpload": "Cancel upload", | ||
| "recorder.aria.play": "Play recording", | ||
| "recorder.aria.pausePreview": "Pause playback", | ||
| "recorder.aria.progress": "Upload progress", | ||
| "recorder.aria.done": "Upload complete", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, d = { | ||
| "action.retry": "Réessayer", | ||
| "action.reload": "Recharger", | ||
| "player.notify.loadFailed": "Impossible de charger le lecteur.", | ||
| "player.notify.sessionExpired": "Votre session a expiré.", | ||
| "player.notify.noSession": "Aucune session de lecture disponible", | ||
| "player.notify.trackLoadFailed": "Impossible de charger cette piste.", | ||
| "player.notify.playFailed": "Impossible de lire cette piste.", | ||
| "player.aria.loading": "Chargement du lecteur audio", | ||
| "player.loadingText": "Chargement du lecteur audio…", | ||
| "player.aria.region": "Lecteur audio", | ||
| "player.status.playbackError": "Erreur de lecture", | ||
| "player.status.buffering": "Mise en mémoire tampon", | ||
| "player.status.nowPlaying": "Lecture en cours : {title}", | ||
| "playButton.retry": "Réessayer", | ||
| "playButton.loading": "Chargement", | ||
| "playButton.pause": "Pause", | ||
| "playButton.play": "Lecture", | ||
| "progress.aria.label": "Progression de la lecture", | ||
| "progress.aria.valueText": "{current} sur {total}", | ||
| "playTime.aria": "Temps de lecture : {elapsed} sur {total}", | ||
| "volume.aria": "Volume", | ||
| "settings.aria": "Plus d’options", | ||
| "settings.download": "Télécharger {label}", | ||
| "settings.notDownloadable": "Cette piste n’est pas téléchargeable.", | ||
| "settings.output.menuLabel": "Périphérique de sortie", | ||
| "settings.output.unnamed": "Haut-parleur {n}", | ||
| "trackTitle.none": "Aucune piste sélectionnée", | ||
| "coverArt.none": "Pas de pochette", | ||
| "coverArt.alt": "Pochette", | ||
| "tracklist.aria": "Liste des pistes", | ||
| "waveform.aria": "Forme d’onde audio", | ||
| "notification.dismiss": "Ignorer la notification", | ||
| "uploader.notify.sessionExpired": "Votre session de téléversement a expiré.", | ||
| "uploader.notify.uploadSuccess": "{filename} téléversé avec succès", | ||
| "uploader.notify.uploadFailed": "{filename} : échec du téléversement", | ||
| "uploader.notify.networkError": "{filename} : erreur réseau", | ||
| "uploader.notify.uploadFailedDetail": "{filename} : {error}", | ||
| "uploader.notify.noAudioFiles": "Aucun fichier audio détecté. Veuillez sélectionner des fichiers audio.", | ||
| "uploader.notify.limitExceeded": "Vous ne pouvez téléverser que {limit} fichier(s).", | ||
| "uploader.error.tryAgain": "Réessayer", | ||
| "uploader.aria.loading": "Chargement du téléverseur", | ||
| "uploader.loadingText": "Chargement…", | ||
| "uploader.aria.fileArea": "Zone de téléversement de fichiers", | ||
| "uploader.dropHeading": "Déposez des pistes audio dans la collection", | ||
| "uploader.or": "ou", | ||
| "uploader.browseFiles": "Parcourir les fichiers", | ||
| "uploader.aria.selectFiles": "Sélectionner des fichiers audio à téléverser", | ||
| "uploader.aria.totalProgress": "Progression totale du téléversement", | ||
| "uploader.totalProgressText": "{percent}% au total", | ||
| "uploader.aria.queue": "File de téléversement", | ||
| "uploader.aria.fileProgress": "Progression du téléversement pour {filename}", | ||
| "uploader.aria.retryFile": "Réessayer le téléversement pour {filename}", | ||
| "uploader.aria.cancelUpload": "Annuler le téléversement pour {filename}", | ||
| "uploader.aria.removeFile": "Retirer le fichier {filename}", | ||
| "recorder.notify.sessionExpired": "Votre session de téléversement a expiré.", | ||
| "recorder.notify.uploadSuccess": "Enregistrement téléversé avec succès", | ||
| "recorder.notify.uploadFailed": "Échec du téléversement", | ||
| "recorder.notify.networkError": "Erreur réseau pendant le téléversement", | ||
| "recorder.notify.uploadFailedDetail": "Échec du téléversement : {error}", | ||
| "recorder.notify.micDenied": "L’accès au microphone a été refusé.", | ||
| "recorder.notify.micUnavailable": "Le microphone n’est pas disponible.", | ||
| "recorder.notify.maxDuration": "Durée maximale d’enregistrement atteinte.", | ||
| "recorder.error.tryAgain": "Réessayer", | ||
| "recorder.aria.loading": "Chargement de l’enregistreur", | ||
| "recorder.loadingText": "Chargement…", | ||
| "recorder.aria.region": "Enregistreur vocal", | ||
| "recorder.aria.start": "Démarrer l’enregistrement", | ||
| "recorder.aria.pause": "Mettre en pause", | ||
| "recorder.aria.resume": "Reprendre l’enregistrement", | ||
| "recorder.aria.stop": "Arrêter l’enregistrement", | ||
| "recorder.aria.discard": "Supprimer l’enregistrement", | ||
| "recorder.aria.send": "Confirmer l’enregistrement", | ||
| "recorder.aria.cancelCountdown": "Annuler le compte à rebours", | ||
| "recorder.idle.hint": "Appuyez pour enregistrer", | ||
| "recorder.countdown.hint": "Préparez-vous…", | ||
| "recorder.aria.selectMic": "Choisir le microphone", | ||
| "recorder.device.unnamed": "Microphone {n}", | ||
| "recorder.device.menuLabel": "Microphones", | ||
| "recorder.aria.moreOptions": "Plus d’options", | ||
| "recorder.menu.preview": "Écouter", | ||
| "recorder.menu.stopPreview": "Arrêter l’écoute", | ||
| "recorder.menu.delete": "Supprimer", | ||
| "recorder.menu.stopUpload": "Arrêter l’envoi", | ||
| "recorder.aria.cancelUpload": "Annuler le téléversement", | ||
| "recorder.aria.play": "Lire l’enregistrement", | ||
| "recorder.aria.pausePreview": "Mettre la lecture en pause", | ||
| "recorder.aria.progress": "Progression du téléversement", | ||
| "recorder.aria.done": "Téléversement terminé", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, s = { | ||
| "action.retry": "Reintentar", | ||
| "action.reload": "Recargar", | ||
| "player.notify.loadFailed": "No se pudo cargar el reproductor.", | ||
| "player.notify.sessionExpired": "Tu sesión ha expirado.", | ||
| "player.notify.noSession": "No hay sesión de reproducción disponible", | ||
| "player.notify.trackLoadFailed": "No se pudo cargar esta pista.", | ||
| "player.notify.playFailed": "No se pudo reproducir esta pista.", | ||
| "player.aria.loading": "Cargando el reproductor de audio", | ||
| "player.loadingText": "Cargando el reproductor de audio…", | ||
| "player.aria.region": "Reproductor de audio", | ||
| "player.status.playbackError": "Error de reproducción", | ||
| "player.status.buffering": "Almacenando en búfer", | ||
| "player.status.nowPlaying": "Reproduciendo: {title}", | ||
| "playButton.retry": "Reintentar", | ||
| "playButton.loading": "Cargando", | ||
| "playButton.pause": "Pausa", | ||
| "playButton.play": "Reproducir", | ||
| "progress.aria.label": "Progreso de reproducción", | ||
| "progress.aria.valueText": "{current} de {total}", | ||
| "playTime.aria": "Tiempo de reproducción: {elapsed} de {total}", | ||
| "volume.aria": "Volumen", | ||
| "settings.aria": "Más opciones", | ||
| "settings.download": "Descargar {label}", | ||
| "settings.notDownloadable": "Esta pista no se puede descargar.", | ||
| "settings.output.menuLabel": "Dispositivo de salida", | ||
| "settings.output.unnamed": "Altavoz {n}", | ||
| "trackTitle.none": "Ninguna pista seleccionada", | ||
| "coverArt.none": "Sin carátula", | ||
| "coverArt.alt": "Carátula", | ||
| "tracklist.aria": "Lista de pistas", | ||
| "waveform.aria": "Forma de onda de audio", | ||
| "notification.dismiss": "Descartar notificación", | ||
| "uploader.notify.sessionExpired": "Tu sesión de subida ha expirado.", | ||
| "uploader.notify.uploadSuccess": "{filename} subido correctamente", | ||
| "uploader.notify.uploadFailed": "{filename}: error al subir", | ||
| "uploader.notify.networkError": "{filename}: error de red", | ||
| "uploader.notify.uploadFailedDetail": "{filename}: {error}", | ||
| "uploader.notify.noAudioFiles": "No se detectaron archivos de audio. Selecciona archivos de audio.", | ||
| "uploader.notify.limitExceeded": "Solo puedes subir {limit} archivo(s).", | ||
| "uploader.error.tryAgain": "Intentar de nuevo", | ||
| "uploader.aria.loading": "Cargando el cargador", | ||
| "uploader.loadingText": "Cargando…", | ||
| "uploader.aria.fileArea": "Área de subida de archivos", | ||
| "uploader.dropHeading": "Suelta pistas de audio en la colección", | ||
| "uploader.or": "o", | ||
| "uploader.browseFiles": "Explorar archivos", | ||
| "uploader.aria.selectFiles": "Selecciona archivos de audio para subir", | ||
| "uploader.aria.totalProgress": "Progreso total de subida", | ||
| "uploader.totalProgressText": "{percent}% en total", | ||
| "uploader.aria.queue": "Cola de subida", | ||
| "uploader.aria.fileProgress": "Progreso de subida de {filename}", | ||
| "uploader.aria.retryFile": "Reintentar la subida de {filename}", | ||
| "uploader.aria.cancelUpload": "Cancelar la subida de {filename}", | ||
| "uploader.aria.removeFile": "Quitar el archivo {filename}", | ||
| "recorder.notify.sessionExpired": "Tu sesión de subida ha expirado.", | ||
| "recorder.notify.uploadSuccess": "Grabación subida correctamente", | ||
| "recorder.notify.uploadFailed": "Error al subir", | ||
| "recorder.notify.networkError": "Error de red durante la subida", | ||
| "recorder.notify.uploadFailedDetail": "Error al subir: {error}", | ||
| "recorder.notify.micDenied": "Se denegó el acceso al micrófono.", | ||
| "recorder.notify.micUnavailable": "El micrófono no está disponible.", | ||
| "recorder.notify.maxDuration": "Se alcanzó la duración máxima de grabación.", | ||
| "recorder.error.tryAgain": "Intentar de nuevo", | ||
| "recorder.aria.loading": "Cargando el grabador", | ||
| "recorder.loadingText": "Cargando…", | ||
| "recorder.aria.region": "Grabador de voz", | ||
| "recorder.aria.start": "Iniciar grabación", | ||
| "recorder.aria.pause": "Pausar grabación", | ||
| "recorder.aria.resume": "Reanudar grabación", | ||
| "recorder.aria.stop": "Detener grabación", | ||
| "recorder.aria.discard": "Descartar grabación", | ||
| "recorder.aria.send": "Confirmar grabación", | ||
| "recorder.aria.cancelCountdown": "Cancelar cuenta atrás", | ||
| "recorder.idle.hint": "Toca para grabar", | ||
| "recorder.countdown.hint": "Prepárate…", | ||
| "recorder.aria.selectMic": "Seleccionar micrófono", | ||
| "recorder.device.unnamed": "Micrófono {n}", | ||
| "recorder.device.menuLabel": "Micrófonos", | ||
| "recorder.aria.moreOptions": "Más opciones", | ||
| "recorder.menu.preview": "Escuchar", | ||
| "recorder.menu.stopPreview": "Detener escucha", | ||
| "recorder.menu.delete": "Eliminar", | ||
| "recorder.menu.stopUpload": "Detener subida", | ||
| "recorder.aria.cancelUpload": "Cancelar subida", | ||
| "recorder.aria.play": "Reproducir grabación", | ||
| "recorder.aria.pausePreview": "Pausar reproducción", | ||
| "recorder.aria.progress": "Progreso de subida", | ||
| "recorder.aria.done": "Subida completa", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, c = { | ||
| "action.retry": "Wiederholen", | ||
| "action.reload": "Neu laden", | ||
| "player.notify.loadFailed": "Player konnte nicht geladen werden.", | ||
| "player.notify.sessionExpired": "Ihre Sitzung ist abgelaufen.", | ||
| "player.notify.noSession": "Keine Wiedergabesitzung verfügbar", | ||
| "player.notify.trackLoadFailed": "Dieser Titel konnte nicht geladen werden.", | ||
| "player.notify.playFailed": "Dieser Titel konnte nicht abgespielt werden.", | ||
| "player.aria.loading": "Audio-Player wird geladen", | ||
| "player.loadingText": "Audio-Player wird geladen…", | ||
| "player.aria.region": "Audio-Player", | ||
| "player.status.playbackError": "Wiedergabefehler", | ||
| "player.status.buffering": "Puffern", | ||
| "player.status.nowPlaying": "Wird abgespielt: {title}", | ||
| "playButton.retry": "Wiederholen", | ||
| "playButton.loading": "Wird geladen", | ||
| "playButton.pause": "Pause", | ||
| "playButton.play": "Abspielen", | ||
| "progress.aria.label": "Wiedergabefortschritt", | ||
| "progress.aria.valueText": "{current} von {total}", | ||
| "playTime.aria": "Wiedergabezeit: {elapsed} von {total}", | ||
| "volume.aria": "Lautstärke", | ||
| "settings.aria": "Weitere Optionen", | ||
| "settings.download": "{label} herunterladen", | ||
| "settings.notDownloadable": "Dieser Titel kann nicht heruntergeladen werden.", | ||
| "settings.output.menuLabel": "Ausgabegerät", | ||
| "settings.output.unnamed": "Lautsprecher {n}", | ||
| "trackTitle.none": "Kein Titel ausgewählt", | ||
| "coverArt.none": "Kein Cover", | ||
| "coverArt.alt": "Cover", | ||
| "tracklist.aria": "Titelliste", | ||
| "waveform.aria": "Audio-Wellenform", | ||
| "notification.dismiss": "Benachrichtigung schließen", | ||
| "uploader.notify.sessionExpired": "Ihre Upload-Sitzung ist abgelaufen.", | ||
| "uploader.notify.uploadSuccess": "{filename} erfolgreich hochgeladen", | ||
| "uploader.notify.uploadFailed": "{filename}: Upload fehlgeschlagen", | ||
| "uploader.notify.networkError": "{filename}: Netzwerkfehler", | ||
| "uploader.notify.uploadFailedDetail": "{filename}: {error}", | ||
| "uploader.notify.noAudioFiles": "Keine Audiodateien erkannt. Bitte wählen Sie Audiodateien aus.", | ||
| "uploader.notify.limitExceeded": "Sie können höchstens {limit} Datei(en) hochladen.", | ||
| "uploader.error.tryAgain": "Erneut versuchen", | ||
| "uploader.aria.loading": "Uploader wird geladen", | ||
| "uploader.loadingText": "Wird geladen…", | ||
| "uploader.aria.fileArea": "Datei-Upload-Bereich", | ||
| "uploader.dropHeading": "Audiotitel in die Sammlung ziehen", | ||
| "uploader.or": "oder", | ||
| "uploader.browseFiles": "Dateien durchsuchen", | ||
| "uploader.aria.selectFiles": "Audiodateien zum Hochladen auswählen", | ||
| "uploader.aria.totalProgress": "Gesamter Upload-Fortschritt", | ||
| "uploader.totalProgressText": "{percent}% gesamt", | ||
| "uploader.aria.queue": "Upload-Warteschlange", | ||
| "uploader.aria.fileProgress": "Upload-Fortschritt für {filename}", | ||
| "uploader.aria.retryFile": "Upload für {filename} wiederholen", | ||
| "uploader.aria.cancelUpload": "Upload für {filename} abbrechen", | ||
| "uploader.aria.removeFile": "Datei {filename} entfernen", | ||
| "recorder.notify.sessionExpired": "Ihre Upload-Sitzung ist abgelaufen.", | ||
| "recorder.notify.uploadSuccess": "Aufnahme erfolgreich hochgeladen", | ||
| "recorder.notify.uploadFailed": "Upload fehlgeschlagen", | ||
| "recorder.notify.networkError": "Netzwerkfehler während des Uploads", | ||
| "recorder.notify.uploadFailedDetail": "Upload fehlgeschlagen: {error}", | ||
| "recorder.notify.micDenied": "Mikrofonzugriff wurde verweigert.", | ||
| "recorder.notify.micUnavailable": "Mikrofon ist nicht verfügbar.", | ||
| "recorder.notify.maxDuration": "Maximale Aufnahmedauer erreicht.", | ||
| "recorder.error.tryAgain": "Erneut versuchen", | ||
| "recorder.aria.loading": "Recorder wird geladen", | ||
| "recorder.loadingText": "Wird geladen…", | ||
| "recorder.aria.region": "Sprachrekorder", | ||
| "recorder.aria.start": "Aufnahme starten", | ||
| "recorder.aria.pause": "Aufnahme pausieren", | ||
| "recorder.aria.resume": "Aufnahme fortsetzen", | ||
| "recorder.aria.stop": "Aufnahme beenden", | ||
| "recorder.aria.discard": "Aufnahme verwerfen", | ||
| "recorder.aria.send": "Aufnahme bestätigen", | ||
| "recorder.aria.cancelCountdown": "Countdown abbrechen", | ||
| "recorder.idle.hint": "Tippen zum Aufnehmen", | ||
| "recorder.countdown.hint": "Bereit machen…", | ||
| "recorder.aria.selectMic": "Mikrofon auswählen", | ||
| "recorder.device.unnamed": "Mikrofon {n}", | ||
| "recorder.device.menuLabel": "Mikrofone", | ||
| "recorder.aria.moreOptions": "Weitere Optionen", | ||
| "recorder.menu.preview": "Anhören", | ||
| "recorder.menu.stopPreview": "Anhören stoppen", | ||
| "recorder.menu.delete": "Löschen", | ||
| "recorder.menu.stopUpload": "Upload stoppen", | ||
| "recorder.aria.cancelUpload": "Upload abbrechen", | ||
| "recorder.aria.play": "Aufnahme abspielen", | ||
| "recorder.aria.pausePreview": "Wiedergabe pausieren", | ||
| "recorder.aria.progress": "Upload-Fortschritt", | ||
| "recorder.aria.done": "Upload abgeschlossen", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, u = { en: n, fr: d, es: s, de: c }; | ||
| function p(r) { | ||
| if (!r) return "en"; | ||
| const e = r.toLowerCase().split("-")[0]; | ||
| return l.includes(e ?? "") ? e : "en"; | ||
| } | ||
| function f(r, e, a) { | ||
| const t = p(r ?? void 0); | ||
| let o = u[t][e] ?? n[e] ?? e; | ||
| if (a) | ||
| for (const i of Object.keys(a)) | ||
| o = o.split(`{${i}}`).join(String(a[i])); | ||
| return o; | ||
| } | ||
| export { | ||
| f as t | ||
| }; |
| class u { | ||
| #e; | ||
| constructor(n) { | ||
| this.#e = n; | ||
| } | ||
| get(n) { | ||
| const t = this.#e.getItem(n); | ||
| if (!t) return; | ||
| const i = JSON.parse(t); | ||
| if (i) { | ||
| if (i.expires && i.expires <= Date.now()) { | ||
| this.remove(n); | ||
| return; | ||
| } | ||
| return i.data; | ||
| } | ||
| } | ||
| set(n, t, i = 6e4) { | ||
| const o = {}; | ||
| o.data = t, i && (i === !0 ? i = Date.now() : i = Date.now() + i, o.expires = i), this.#e.setItem(n, JSON.stringify(o)); | ||
| } | ||
| remove(n) { | ||
| return this.#e.removeItem(n); | ||
| } | ||
| } | ||
| function d(e) { | ||
| return new u(e); | ||
| } | ||
| const p = "adn-inputchange", v = "adn-outputchange", s = "audioInputDeviceId", a = "audioOutputDeviceId"; | ||
| function r() { | ||
| if (!(typeof sessionStorage > "u")) | ||
| return d(sessionStorage); | ||
| } | ||
| function c() { | ||
| return typeof HTMLMediaElement < "u" && typeof HTMLMediaElement.prototype.setSinkId == "function"; | ||
| } | ||
| async function f(e) { | ||
| if (typeof navigator > "u" || !navigator.mediaDevices?.enumerateDevices) | ||
| return []; | ||
| try { | ||
| return (await navigator.mediaDevices.enumerateDevices()).filter((t) => t.kind === e && t.deviceId).map((t) => ({ deviceId: t.deviceId, label: t.label || "" })); | ||
| } catch { | ||
| return []; | ||
| } | ||
| } | ||
| function I() { | ||
| return f("audiooutput"); | ||
| } | ||
| function g() { | ||
| const e = r()?.get(s); | ||
| return typeof e == "string" ? e : ""; | ||
| } | ||
| function l(e) { | ||
| r()?.set(s, e, !1); | ||
| } | ||
| function m() { | ||
| const e = r()?.get(a); | ||
| return typeof e == "string" ? e : ""; | ||
| } | ||
| function S(e) { | ||
| r()?.set(a, e, !1); | ||
| } | ||
| async function y(e, n) { | ||
| if (!e || !n || !c()) return; | ||
| const t = e; | ||
| if (typeof t.setSinkId == "function") | ||
| try { | ||
| await t.setSinkId(n); | ||
| } catch { | ||
| } | ||
| } | ||
| export { | ||
| p as I, | ||
| v as O, | ||
| y as a, | ||
| m as b, | ||
| c, | ||
| d, | ||
| I as e, | ||
| S as f, | ||
| g, | ||
| l as s | ||
| }; |
| import { n as l, r as E, i as V, a as X, b as N, t as j } from "./lit-DpNjQO9d.js"; | ||
| import { t as L } from "./i18n-BI0dP23M.js"; | ||
| function q(t) { | ||
| if (t === void 0) return "--:--"; | ||
| const i = Math.floor(t / 60) || 0, o = Math.round(t % 60) || 0; | ||
| return `${i}:${("" + o).padStart(2, "0")}`; | ||
| } | ||
| function et(t) { | ||
| if (t === void 0) return "0s"; | ||
| const i = Math.floor(t / 60) || 0, o = Math.round(t % 60) || 0; | ||
| return [ | ||
| i && i + "m", | ||
| o && o + "s" | ||
| ].join(" "); | ||
| } | ||
| function it(t, i = 2) { | ||
| if (!+t) return "0 Bytes"; | ||
| const o = 1e3, s = i < 0 ? 0 : i, e = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], r = Math.floor(Math.log(t) / Math.log(o)); | ||
| return `${parseFloat((t / Math.pow(o, r)).toFixed(s))} ${e[r]}`; | ||
| } | ||
| let z, _, P, M, W, $, R, C, S; | ||
| const T = []; | ||
| function I(t, i) { | ||
| return _ = window.pageXOffset, M = window.pageYOffset, $ = window.innerHeight, C = window.innerWidth, P === void 0 && (P = _), W === void 0 && (W = M), S === void 0 && (S = C), R === void 0 && (R = $), (i || M !== W || _ !== P || $ !== R || C !== S) && (Y(t), P = _, W = M, R = $, S = C), requestAnimationFrame(I); | ||
| } | ||
| function Y(t) { | ||
| for (const i of T) | ||
| i({ x: _, y: M, px: P, py: W, vh: $, pvh: R, vw: C, pvw: S }, t); | ||
| } | ||
| function G(t) { | ||
| return T.indexOf(t) < 0 && T.push(t), z = z || I(performance.now()), { | ||
| update() { | ||
| return I(performance.now(), !0), this; | ||
| }, | ||
| destroy() { | ||
| T.splice(T.indexOf(t), 1); | ||
| } | ||
| }; | ||
| } | ||
| var U = Object.defineProperty, K = Object.getOwnPropertyDescriptor, a = (t, i, o, s) => { | ||
| for (var e = s > 1 ? void 0 : s ? K(i, o) : i, r = t.length - 1, c; r >= 0; r--) | ||
| (c = t[r]) && (e = (s ? c(i, o, e) : c(e)) || e); | ||
| return s && e && U(i, o, e), e; | ||
| }; | ||
| let n = class extends X { | ||
| constructor() { | ||
| super(...arguments), this.levels = [], this.height = 120, this.lineColor = "#888888", this.lineWidth = 2, this.gap = 3, this.variant = "vertical", this.locale = "en", this.scaleStrength = 0.4, this.reflectionAngle = 45, this.reflectionSize = 0.25, this.reflectionOpacity = 0.55, this.highlightFrom = 0, this.highlightWidth = 1, this.min = 0, this.max = 1, this.duration = 0, this.progress = 0, this.data = new Float32Array(), this.hoverPosition = null, this.containerWidth = 0, this.canvas = null, this.ctx = null, this._srrafHandle = null, this._drawScheduled = !1, this._hoverRafId = null, this._cachedRect = null, this.draw = () => { | ||
| if (!this.canvas || !this.ctx) return; | ||
| const { lineWidth: t, gap: i, height: o, variant: s } = this, e = this.ctx, r = Math.max(1, window.devicePixelRatio || 1), c = this.canvas.clientWidth || this.getRect().width, v = Math.max(1, Math.round(c * r)), h = Math.max(1, Math.round(o * r)); | ||
| this.canvas.width = v, this.canvas.height = h; | ||
| const u = t + i, O = Math.floor( | ||
| (c - t - (s === "wavy" ? u : 0)) / u | ||
| ) + 1, b = []; | ||
| for (let d = 0; d < O; d++) { | ||
| const p = Math.round(d / O * this.data.length); | ||
| b.push(this.data[p]); | ||
| } | ||
| e.clearRect(0, 0, v, h), e.fillStyle = this.lineColor, e.strokeStyle = this.lineColor; | ||
| const k = Math.max(1, Math.round(t * r)), D = u * r; | ||
| if (s === "vertical") | ||
| b.forEach((d, p) => { | ||
| if (!d) return; | ||
| const g = Math.round(p * D), f = Math.round(d * h), y = Math.round((h - f) / 2); | ||
| e.fillRect(g, y, k, f); | ||
| }); | ||
| else if (s === "reflection") { | ||
| const d = Math.max(0, this.reflectionSize), p = Math.round(h / (1 + d)), g = h - p, f = p, m = (0.5 - Math.max(0, Math.min(1, this.progress))) * 2 * (this.reflectionAngle * Math.PI / 180), A = Math.tan(m); | ||
| e.fillStyle = this.lineColor, b.forEach((w, H) => { | ||
| if (!w) return; | ||
| const F = Math.round(H * D), x = Math.round(w * p); | ||
| e.fillRect(F, f - x, k, x); | ||
| }); | ||
| const B = e.createLinearGradient(0, f, 0, f + g); | ||
| B.addColorStop(0, this.colorToRgba(this.lineColor, this.reflectionOpacity)), B.addColorStop(0.75, this.colorToRgba(this.lineColor, this.reflectionOpacity * 0.5)), B.addColorStop(1, this.colorToRgba(this.lineColor, 0)), e.strokeStyle = B, e.lineWidth = k, b.forEach((w, H) => { | ||
| if (!w) return; | ||
| const F = Math.round(H * D) + k / 2, x = w * g; | ||
| e.beginPath(), e.moveTo(F, f), e.lineTo(F + A * x, f + x), e.stroke(); | ||
| }); | ||
| } else if (s === "wavy") { | ||
| e.scale(r, r), e.lineWidth = this.lineWidth, e.save(); | ||
| const d = o / 2; | ||
| e.translate(0, d); | ||
| const p = c / b.length; | ||
| for (const [g, f] of b.entries()) { | ||
| if (!f) continue; | ||
| const y = g * u + Math.ceil(t / 2) + 0.5; | ||
| let m = f * (d - this.lineWidth * 2); | ||
| m < 0 ? m = 0 : m > d - this.lineWidth * 2 && (m = d - this.lineWidth * 2); | ||
| const A = (g + 1) % 2 ? m : -m; | ||
| e.beginPath(), e.moveTo(y, 0), e.lineTo(y, A), e.arc( | ||
| y + p / 2, | ||
| A, | ||
| Math.min(p / 2, Math.min(p / 2, m)), | ||
| Math.PI, | ||
| 0, | ||
| !!((g + 1) % 2) | ||
| ), e.lineTo(y + p, 0), e.stroke(); | ||
| } | ||
| e.restore(); | ||
| } | ||
| }; | ||
| } | ||
| connectedCallback() { | ||
| super.connectedCallback(), this.updateLineColor(), this._srrafHandle = G(({ vw: t, pvw: i }) => { | ||
| t !== i && (this._cachedRect = null, this.computeWaveformWidth(), this.scheduleDraw()); | ||
| }); | ||
| } | ||
| disconnectedCallback() { | ||
| super.disconnectedCallback(), this._srrafHandle?.destroy(), this._srrafHandle = null, this._hoverRafId !== null && (cancelAnimationFrame(this._hoverRafId), this._hoverRafId = null); | ||
| } | ||
| willUpdate(t) { | ||
| this.style.setProperty("--_playheadPosition", this.progress * 100 + "%"), this.style.setProperty("--_playheadVisible", this.progress > 0 ? "1" : "0"), this.style.setProperty("--_hoverPosition", this.hoverPosition !== null ? this.hoverPosition * 100 + "%" : "0%"), this.style.setProperty("--_hoverVisible", this.hoverPosition !== null ? "1" : "0"), this.style.setProperty("--_highlightFrom", `${this.highlightFrom}px`), this.style.setProperty("--_maskWidth", `${Math.floor(this.containerWidth * this.highlightWidth)}px`), this.updateLineColor(), this.levels && t.has("levels") && this.processData(); | ||
| } | ||
| render() { | ||
| return Z.call(this); | ||
| } | ||
| firstUpdated() { | ||
| this.canvas = this.renderRoot.querySelector("canvas"), this.canvas && (this.ctx = this.canvas.getContext("2d")); | ||
| } | ||
| updated() { | ||
| this.style.setProperty("--_pre-progress", `${this.min * 100}%`), this.max < 1 ? this.style.setProperty("--_width", `${this.max * 100}%`) : this.style.setProperty("--_width", `${this.progress * 100}%`), this.computeWaveformWidth(), this.scheduleDraw(); | ||
| } | ||
| getRect() { | ||
| return this._cachedRect || (this._cachedRect = this.getBoundingClientRect()), this._cachedRect; | ||
| } | ||
| handleEvent(t) { | ||
| const i = t.currentTarget; | ||
| if (t.type === "mouseenter") { | ||
| i.style.setProperty("--_transitionSpeed", "0"); | ||
| return; | ||
| } | ||
| if (t.type === "mouseleave") { | ||
| i.style.setProperty("--_transitionSpeed", "100ms"), this.hoverPosition = null; | ||
| return; | ||
| } | ||
| const o = this.getRect(), s = t.clientX - o.left; | ||
| if (s < 0 || s > this.containerWidth) { | ||
| this.hoverPosition = null; | ||
| return; | ||
| } | ||
| const e = Math.max(0, Math.min(1, s / this.containerWidth)); | ||
| if (t.type === "mousemove") { | ||
| if (this._hoverRafId !== null) return; | ||
| this._hoverRafId = requestAnimationFrame(() => { | ||
| this._hoverRafId = null, this.hoverPosition = e; | ||
| }); | ||
| } | ||
| t.type === "click" && this.dispatchEvent( | ||
| new CustomEvent("adni-seek", { | ||
| detail: { percent: e }, | ||
| bubbles: !0 | ||
| }) | ||
| ); | ||
| } | ||
| handleTouch(t) { | ||
| if (!(!t.touches.length && t.type !== "touchend")) { | ||
| if (t.type === "touchstart" || t.type === "touchmove") { | ||
| t.preventDefault(); | ||
| const i = t.touches[0]; | ||
| if (!i) return; | ||
| const o = this.getRect(), s = i.clientX - o.left, e = Math.max(0, Math.min(1, s / this.containerWidth)); | ||
| this.hoverPosition = e; | ||
| } | ||
| t.type === "touchend" && (this.hoverPosition !== null && this.dispatchEvent( | ||
| new CustomEvent("adni-seek", { | ||
| detail: { percent: this.hoverPosition }, | ||
| bubbles: !0 | ||
| }) | ||
| ), this.hoverPosition = null); | ||
| } | ||
| } | ||
| computeWaveformWidth() { | ||
| this._cachedRect = null, this.containerWidth = this.getRect().width; | ||
| } | ||
| processData() { | ||
| const { levels: t, scaleStrength: i } = this; | ||
| if (!t || t.length === 0) { | ||
| this.data = new Float32Array(); | ||
| return; | ||
| } | ||
| const o = Math.min(...t), e = Math.max(...t) - o; | ||
| let r = e === 0 ? t.map(() => 0.5) : t.map((h) => (h - o) / e), c = r.reduce((h, u) => h + u, 0) / t.length, v = 0; | ||
| for (; c > 1 - i && v < 10; ) | ||
| r = r.map((h) => h * h), c = r.reduce((h, u) => h + u, 0) / t.length, v += 1; | ||
| this.data = new Float32Array(r); | ||
| } | ||
| // Normalize any CSS color to rgba() with the given alpha (via the canvas' | ||
| // own color parsing) so the reflection gradient can fade to transparent. | ||
| colorToRgba(t, i) { | ||
| const o = this.ctx; | ||
| if (!o) return `rgba(136, 136, 136, ${i})`; | ||
| o.fillStyle = "#000", o.fillStyle = t; | ||
| const s = o.fillStyle; | ||
| if (s.startsWith("#")) { | ||
| let r = s.slice(1); | ||
| r.length === 3 && (r = r.split("").map((u) => u + u).join("")); | ||
| const c = parseInt(r.slice(0, 2), 16), v = parseInt(r.slice(2, 4), 16), h = parseInt(r.slice(4, 6), 16); | ||
| return `rgba(${c}, ${v}, ${h}, ${i})`; | ||
| } | ||
| const e = s.match(/rgba?\(([^)]+)\)/); | ||
| if (e && e[1]) { | ||
| const [r, c, v] = e[1].split(",").map((h) => h.trim()); | ||
| return `rgba(${r}, ${c}, ${v}, ${i})`; | ||
| } | ||
| return `rgba(136, 136, 136, ${i})`; | ||
| } | ||
| updateLineColor() { | ||
| const t = getComputedStyle(this), i = t.getPropertyValue("--adn-waveform-color-fg"), o = t.getPropertyValue("--adn-color-accent"); | ||
| this.lineColor = i || o || t.getPropertyValue("--_color-accent"); | ||
| } | ||
| scheduleDraw() { | ||
| this._drawScheduled || (this._drawScheduled = !0, requestAnimationFrame(() => { | ||
| this._drawScheduled = !1, this.draw(); | ||
| })); | ||
| } | ||
| }; | ||
| n.styles = J(); | ||
| a([ | ||
| l({ type: Array }) | ||
| ], n.prototype, "levels", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "height", 2); | ||
| a([ | ||
| l({ type: String, attribute: "line-color" }) | ||
| ], n.prototype, "lineColor", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "line-width" }) | ||
| ], n.prototype, "lineWidth", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "gap", 2); | ||
| a([ | ||
| l({ type: String }) | ||
| ], n.prototype, "variant", 2); | ||
| a([ | ||
| l({ type: String, attribute: "locale" }) | ||
| ], n.prototype, "locale", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "scale-strength" }) | ||
| ], n.prototype, "scaleStrength", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "reflection-angle" }) | ||
| ], n.prototype, "reflectionAngle", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "reflection-size" }) | ||
| ], n.prototype, "reflectionSize", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "reflection-opacity" }) | ||
| ], n.prototype, "reflectionOpacity", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "highlight-from" }) | ||
| ], n.prototype, "highlightFrom", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "highlight-width" }) | ||
| ], n.prototype, "highlightWidth", 2); | ||
| a([ | ||
| l() | ||
| ], n.prototype, "min", 2); | ||
| a([ | ||
| l() | ||
| ], n.prototype, "max", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "duration", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "progress", 2); | ||
| a([ | ||
| E() | ||
| ], n.prototype, "data", 2); | ||
| a([ | ||
| E() | ||
| ], n.prototype, "hoverPosition", 2); | ||
| n = a([ | ||
| j("audiodn-waveform") | ||
| ], n); | ||
| function Z() { | ||
| const t = this.hoverPosition !== null && this.duration > 0 ? q(this.hoverPosition * this.duration) : null; | ||
| return N` | ||
| <div class="waveform-container" | ||
| @mouseenter=${this} @mouseleave=${this} @mousemove=${this} | ||
| @touchstart=${(i) => this.handleTouch(i)} | ||
| @touchmove=${(i) => this.handleTouch(i)} | ||
| @touchend=${(i) => this.handleTouch(i)} | ||
| > | ||
| <canvas @click=${this} role="img" aria-label=${L(this.locale, "waveform.aria")}></canvas> | ||
| <div class="playhead progress-playhead"></div> | ||
| <div class="playhead hover-playhead"></div> | ||
| ${t !== null ? N` | ||
| <div class="hover-tooltip" style="left: ${this.hoverPosition * 100}%">${t}</div> | ||
| ` : ""} | ||
| </div> | ||
| `; | ||
| } | ||
| function J() { | ||
| return V` | ||
| :host { | ||
| width: 100%; | ||
| position: relative; | ||
| display: flex; | ||
| justify-content: center; | ||
| height: 100%; | ||
| box-sizing: border-box; | ||
| background: var(--adn-waveform-bg); | ||
| border: var(--adn-waveform-border); | ||
| border-radius: var(--adn-waveform-radius); | ||
| padding: var(--adn-waveform-padding); | ||
| } | ||
| .waveform-container { | ||
| width: 100%; | ||
| position: relative; | ||
| --_transitionSpeed: 100ms; | ||
| touch-action: none; | ||
| } | ||
| .click-overlay { | ||
| position: absolute; | ||
| inset: 0; | ||
| height: 100%; | ||
| cursor: pointer; | ||
| z-index: 1000; | ||
| } | ||
| canvas { | ||
| width: 100%; | ||
| height: 100%; | ||
| mask: linear-gradient(to right, | ||
| rgba(255 255 255 / 0.5) var(--_pre-progress), | ||
| rgba(255 255 255 / 1) var(--_pre-progress), | ||
| rgba(255 255 255 / 1) var(--_width), | ||
| rgba(255 255 255 / 0.5) var(--_width) | ||
| ); | ||
| } | ||
| .playhead { | ||
| width: var(--adn-waveform-playhead-width, 1px); | ||
| background: var(--adn-waveform-color-playhead, var(--_color-font)); | ||
| height: 100%; | ||
| position: absolute; | ||
| inset-block: 0; | ||
| pointer-events: none; | ||
| } | ||
| .progress-playhead { | ||
| left: var(--_playheadPosition); | ||
| opacity: var(--_playheadVisible, 0); | ||
| } | ||
| .hover-playhead { | ||
| left: var(--_hoverPosition); | ||
| opacity: calc(0.5 * var(--_hoverVisible, 0)); | ||
| } | ||
| .hover-tooltip { | ||
| position: absolute; | ||
| top: -24px; | ||
| transform: translateX(-50%); | ||
| background: rgba(0, 0, 0, 0.85); | ||
| color: #fff; | ||
| font-size: 11px; | ||
| padding: 2px 6px; | ||
| border-radius: 3px; | ||
| pointer-events: none; | ||
| white-space: nowrap; | ||
| font-family: sans-serif; | ||
| } | ||
| `; | ||
| } | ||
| export { | ||
| n as A, | ||
| et as a, | ||
| it as b, | ||
| q as f | ||
| }; |
@@ -12,2 +12,6 @@ import { LitElement } from 'lit'; | ||
| buffering: boolean; | ||
| /** Playback progress (0..1) for the optional ring. Only shown when `showProgress`. */ | ||
| progress: number; | ||
| /** When true, draw a circular progress ring around the button (inline player). */ | ||
| showProgress: boolean; | ||
| locale: Locale; | ||
@@ -14,0 +18,0 @@ static styles: import("lit").CSSResult; |
| import { LitElement } from 'lit'; | ||
| import { type Locale } from '../lib/i18n.js'; | ||
| import { type AudioDevice } from '../lib/media-devices.js'; | ||
| import type { CSSResult, TemplateResult } from 'lit'; | ||
@@ -13,4 +14,8 @@ import type { TrackVariant } from '../lib/track.js'; | ||
| protected isOpen: boolean; | ||
| protected outputs: AudioDevice[]; | ||
| protected selectedOutputId: string; | ||
| static styles: CSSResult; | ||
| private get variantCount(); | ||
| get showOutputPicker(): boolean; | ||
| get showVariantSection(): boolean; | ||
| get hasMenu(): boolean; | ||
@@ -21,3 +26,8 @@ render(): TemplateResult; | ||
| updated(changedProperties: Map<string, unknown>): void; | ||
| connectedCallback(): void; | ||
| disconnectedCallback(): void; | ||
| refreshOutputs(): Promise<void>; | ||
| private readonly onDeviceChange; | ||
| private readonly onOutputChange; | ||
| outputLabel(device: AudioDevice, index: number): string; | ||
| handleEvent(event: Event): void; | ||
@@ -24,0 +34,0 @@ protected handleKeydown(e: KeyboardEvent): void; |
+1
-1
| import { AudioDnPlayer as e } from "./player.js"; | ||
| import { AudiodnUploader as f } from "./uploader.js"; | ||
| import { A as p } from "./shared/waveform-DjrtM6Eb.js"; | ||
| import { A as p } from "./shared/waveform-BkawXg58.js"; | ||
| import { AudiodnRecorder as a } from "./recorder.js"; | ||
@@ -5,0 +5,0 @@ export { |
| export declare const LOCALES: readonly ["en", "fr", "es", "de"]; | ||
| export type Locale = (typeof LOCALES)[number]; | ||
| export declare const DEFAULT_LOCALE: Locale; | ||
| export type MessageKey = 'action.retry' | 'action.reload' | 'player.notify.loadFailed' | 'player.notify.sessionExpired' | 'player.notify.noSession' | 'player.notify.trackLoadFailed' | 'player.notify.playFailed' | 'player.aria.loading' | 'player.loadingText' | 'player.aria.region' | 'player.status.playbackError' | 'player.status.buffering' | 'player.status.nowPlaying' | 'playButton.retry' | 'playButton.loading' | 'playButton.pause' | 'playButton.play' | 'progress.aria.label' | 'progress.aria.valueText' | 'playTime.aria' | 'volume.aria' | 'settings.aria' | 'settings.download' | 'settings.notDownloadable' | 'trackTitle.none' | 'coverArt.none' | 'coverArt.alt' | 'tracklist.aria' | 'waveform.aria' | 'notification.dismiss' | 'uploader.notify.sessionExpired' | 'uploader.notify.uploadSuccess' | 'uploader.notify.uploadFailed' | 'uploader.notify.networkError' | 'uploader.notify.uploadFailedDetail' | 'uploader.notify.noAudioFiles' | 'uploader.notify.limitExceeded' | 'uploader.error.tryAgain' | 'uploader.aria.loading' | 'uploader.loadingText' | 'uploader.aria.fileArea' | 'uploader.dropHeading' | 'uploader.or' | 'uploader.browseFiles' | 'uploader.aria.selectFiles' | 'uploader.aria.totalProgress' | 'uploader.totalProgressText' | 'uploader.aria.queue' | 'uploader.aria.fileProgress' | 'uploader.aria.retryFile' | 'uploader.aria.cancelUpload' | 'uploader.aria.removeFile' | 'recorder.notify.sessionExpired' | 'recorder.notify.uploadSuccess' | 'recorder.notify.uploadFailed' | 'recorder.notify.networkError' | 'recorder.notify.uploadFailedDetail' | 'recorder.notify.micDenied' | 'recorder.notify.micUnavailable' | 'recorder.notify.maxDuration' | 'recorder.error.tryAgain' | 'recorder.aria.loading' | 'recorder.loadingText' | 'recorder.aria.region' | 'recorder.aria.start' | 'recorder.aria.pause' | 'recorder.aria.resume' | 'recorder.aria.stop' | 'recorder.aria.discard' | 'recorder.aria.send' | 'recorder.aria.cancelUpload' | 'recorder.aria.play' | 'recorder.aria.pausePreview' | 'recorder.aria.progress' | 'recorder.aria.done' | 'recorder.aria.cancelCountdown' | 'recorder.timer.preview' | 'recorder.idle.hint' | 'recorder.countdown.hint' | 'recorder.aria.selectMic' | 'recorder.device.unnamed' | 'recorder.device.menuLabel' | 'recorder.aria.moreOptions' | 'recorder.menu.preview' | 'recorder.menu.stopPreview' | 'recorder.menu.delete' | 'recorder.menu.stopUpload'; | ||
| export type MessageKey = 'action.retry' | 'action.reload' | 'player.notify.loadFailed' | 'player.notify.sessionExpired' | 'player.notify.noSession' | 'player.notify.trackLoadFailed' | 'player.notify.playFailed' | 'player.aria.loading' | 'player.loadingText' | 'player.aria.region' | 'player.status.playbackError' | 'player.status.buffering' | 'player.status.nowPlaying' | 'playButton.retry' | 'playButton.loading' | 'playButton.pause' | 'playButton.play' | 'progress.aria.label' | 'progress.aria.valueText' | 'playTime.aria' | 'volume.aria' | 'settings.aria' | 'settings.download' | 'settings.notDownloadable' | 'settings.output.menuLabel' | 'settings.output.unnamed' | 'trackTitle.none' | 'coverArt.none' | 'coverArt.alt' | 'tracklist.aria' | 'waveform.aria' | 'notification.dismiss' | 'uploader.notify.sessionExpired' | 'uploader.notify.uploadSuccess' | 'uploader.notify.uploadFailed' | 'uploader.notify.networkError' | 'uploader.notify.uploadFailedDetail' | 'uploader.notify.noAudioFiles' | 'uploader.notify.limitExceeded' | 'uploader.error.tryAgain' | 'uploader.aria.loading' | 'uploader.loadingText' | 'uploader.aria.fileArea' | 'uploader.dropHeading' | 'uploader.or' | 'uploader.browseFiles' | 'uploader.aria.selectFiles' | 'uploader.aria.totalProgress' | 'uploader.totalProgressText' | 'uploader.aria.queue' | 'uploader.aria.fileProgress' | 'uploader.aria.retryFile' | 'uploader.aria.cancelUpload' | 'uploader.aria.removeFile' | 'recorder.notify.sessionExpired' | 'recorder.notify.uploadSuccess' | 'recorder.notify.uploadFailed' | 'recorder.notify.networkError' | 'recorder.notify.uploadFailedDetail' | 'recorder.notify.micDenied' | 'recorder.notify.micUnavailable' | 'recorder.notify.maxDuration' | 'recorder.error.tryAgain' | 'recorder.aria.loading' | 'recorder.loadingText' | 'recorder.aria.region' | 'recorder.aria.start' | 'recorder.aria.pause' | 'recorder.aria.resume' | 'recorder.aria.stop' | 'recorder.aria.discard' | 'recorder.aria.send' | 'recorder.aria.cancelUpload' | 'recorder.aria.play' | 'recorder.aria.pausePreview' | 'recorder.aria.progress' | 'recorder.aria.done' | 'recorder.aria.cancelCountdown' | 'recorder.timer.preview' | 'recorder.idle.hint' | 'recorder.countdown.hint' | 'recorder.aria.selectMic' | 'recorder.device.unnamed' | 'recorder.device.menuLabel' | 'recorder.aria.moreOptions' | 'recorder.menu.preview' | 'recorder.menu.stopPreview' | 'recorder.menu.delete' | 'recorder.menu.stopUpload'; | ||
| type Messages = Record<MessageKey, string>; | ||
@@ -6,0 +6,0 @@ export declare const catalogs: Readonly<Record<Locale, Readonly<Messages>>>; |
+8
-0
@@ -26,2 +26,5 @@ import './components/cover-art.js'; | ||
| size: string; | ||
| variant: 'default' | 'inline'; | ||
| /** Play-button size (px) for the `inline` variant. Ignored otherwise. */ | ||
| height?: number; | ||
| theme: Theme; | ||
@@ -70,2 +73,6 @@ locale: Locale; | ||
| protected updated(changedProperties: Map<string, unknown>): void; | ||
| /** Square play-button edge (px) for the inline variant, clamped to a sane minimum. */ | ||
| inlineButtonSize(): number; | ||
| /** Absolute playback fraction (0..1) of the active track, for the inline ring. */ | ||
| inlineProgress(): number; | ||
| private getEffectiveTheme; | ||
@@ -102,2 +109,3 @@ private loadSession; | ||
| handleUIChangeVolume(event: CustomEvent): void; | ||
| handleUISelectOutput(event: CustomEvent<string>): void; | ||
| protected handleKeydown(e: KeyboardEvent): void; | ||
@@ -104,0 +112,0 @@ calculateCurrentTime(desiredTime: number | undefined, rawTime: boolean): number; |
+16
-14
@@ -8,3 +8,3 @@ import { LitElement } from 'lit'; | ||
| export type Theme = 'auto' | 'dark' | 'light'; | ||
| export type RecorderVariant = 'panel' | 'regular' | 'tiny'; | ||
| export type RecorderVariant = 'panel' | 'regular' | 'inline'; | ||
| export type RecorderMode = 'idle' | 'countdown' | 'recording' | 'preview' | 'uploading' | 'done'; | ||
@@ -37,3 +37,3 @@ declare global { | ||
| variant: RecorderVariant; | ||
| /** Button size (px) for the `tiny` variant. Buttons are square (width = height). */ | ||
| /** Button size (px) for the `inline` variant. Buttons are square (width = height). */ | ||
| height: number; | ||
@@ -64,4 +64,4 @@ sessionData?: UploadSessionData; | ||
| _deviceMenuOpen: boolean; | ||
| /** Transient failure flag: shows a red warning glyph in the tiny variant. */ | ||
| _tinyError: boolean; | ||
| /** Transient failure flag: shows a red warning glyph in the inline variant. */ | ||
| _inlineError: boolean; | ||
| private _mediaStream; | ||
@@ -78,3 +78,3 @@ private _mediaRecorder; | ||
| private _doneTimer?; | ||
| private _tinyErrorTimer?; | ||
| private _inlineErrorTimer?; | ||
| private _maxDurationTimer?; | ||
@@ -85,2 +85,4 @@ private _sessionTimer; | ||
| private _onDeviceChange; | ||
| private _onInputChange; | ||
| private _onOutputChange; | ||
| private _onDocPointerDown; | ||
@@ -121,16 +123,16 @@ private _onRepositionDeviceMenu; | ||
| /** True for the compact, two-button layout. */ | ||
| isTiny(): boolean; | ||
| /** Square button edge (px) for the tiny variant, clamped to a sane minimum. */ | ||
| tinyButtonSize(): number; | ||
| isInline(): boolean; | ||
| /** Square button edge (px) for the inline variant, clamped to a sane minimum. */ | ||
| inlineButtonSize(): number; | ||
| /** True when more than one mic is available and we are idle (picker is interactive). */ | ||
| showDevicePicker(): boolean; | ||
| /** True when the tiny variant shows its contextual menu (preview or upload). */ | ||
| /** True when the inline variant shows its contextual menu (preview or upload). */ | ||
| showContextMenu(): boolean; | ||
| /** Any state in which the popover menu is allowed to open. */ | ||
| canOpenMenu(): boolean; | ||
| /** Close the menu, then toggle preview playback (tiny contextual action). */ | ||
| /** Close the menu, then toggle preview playback (inline contextual action). */ | ||
| menuTogglePreview(): void; | ||
| /** Close the menu, then discard the recording (tiny contextual action). */ | ||
| /** Close the menu, then discard the recording (inline contextual action). */ | ||
| menuDelete(): void; | ||
| /** Close the menu, then cancel the in-flight upload (tiny contextual action). */ | ||
| /** Close the menu, then cancel the in-flight upload (inline contextual action). */ | ||
| menuCancelUpload(): void; | ||
@@ -196,6 +198,6 @@ deviceLabel(device: { | ||
| /** | ||
| * Show a transient red warning glyph in the tiny variant (which suppresses the | ||
| * Show a transient red warning glyph in the inline variant (which suppresses the | ||
| * notification banner because it's too small to read inside a compact control). | ||
| */ | ||
| private flashTinyError; | ||
| private flashInlineError; | ||
| private resetToIdle; | ||
@@ -202,0 +204,0 @@ handleMicClick(): void; |
+2
-2
| import { n as c, r as h, i as m, a as v, b as d, t as g } from "./shared/lit-DpNjQO9d.js"; | ||
| import { t as f, S as b, a as y, p as _, i as x, g as w, q as u, b as k, d as $, r as E, n as T, o as S } from "./shared/color-C5w9LHXC.js"; | ||
| import { t as a } from "./shared/i18n-CIM9pdy9.js"; | ||
| import { t as f, S as b, a as y, p as _, i as x, g as w, q as u, b as k, d as $, r as E, n as T, o as S } from "./shared/color-BrgTYjY_.js"; | ||
| import { t as a } from "./shared/i18n-BI0dP23M.js"; | ||
| var C = Object.defineProperty, U = Object.getOwnPropertyDescriptor, l = (e, r, t, i) => { | ||
@@ -5,0 +5,0 @@ for (var o = i > 1 ? void 0 : i ? U(r, t) : r, n = e.length - 1, p; n >= 0; n--) |
+2
-2
| import "./shared/lit-DpNjQO9d.js"; | ||
| import { A as p } from "./shared/waveform-DjrtM6Eb.js"; | ||
| import "./shared/i18n-CIM9pdy9.js"; | ||
| import { A as p } from "./shared/waveform-BkawXg58.js"; | ||
| import "./shared/i18n-BI0dP23M.js"; | ||
| export { | ||
| p as AudioDnWaveform | ||
| }; |
+1
-1
| { | ||
| "name": "@audiodn/components", | ||
| "version": "0.3.1", | ||
| "version": "0.4.0", | ||
| "description": "Custom web components for Audio Delivery Network", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+5
-3
@@ -110,3 +110,5 @@ # AudioDN Components | ||
| | `variants` | string | `""` | Comma-separated variant indexes to request, in priority order — the **first is selected by default**. e.g. `"hq,lq"`. | | ||
| | `size` | string | `large` | Layout preset. Values: `small`, `regular`, `large`. | | ||
| | `size` | string | `large` | Layout preset for the `default` variant. Values: `small`, `regular`, `large`. | | ||
| | `variant` | string | `default` | Layout variant. `default` is the full player (cover art, title, waveform, controls, tracklist). `inline` is a compact play/pause button — with a circular progress ring that fills clockwise from the top — plus the settings menu, and shows no track information (surface it yourself). | | ||
| | `height` | number | `56` | `inline` variant only. Edge size (px) of the square play/pause button. | | ||
| | `locale` | string | `en` | UI language. Values: `en`, `fr`, `es`, `de`. | | ||
@@ -233,4 +235,4 @@ | `volume` | number | `0.7` | Initial volume, `0`–`1`. Persisted to `sessionStorage` after the user changes it. | | ||
| | `auto-hide` | boolean | `false` | After a successful upload, sets the host to `display: none`. | | ||
| | `variant` | string | `panel` | Layout preset. `panel` (a.k.a. `regular`) is the full panel with waveform, timers, and separate controls. `tiny` is a compact two-button layout: a record button (with a source menu when more than one mic is available) that animates while recording, then a confirm button plus a contextual preview/delete menu. | | ||
| | `height` | number | `56` | `tiny` variant only. Edge size (px) of the square icon buttons; all tiny buttons share this size. | | ||
| | `variant` | string | `panel` | Layout preset. `panel` (a.k.a. `regular`) is the full panel with waveform, timers, and separate controls. `inline` is a compact two-button layout: a record button (with a source menu when more than one mic is available) that animates while recording, then a confirm button plus a contextual preview/delete menu. | | ||
| | `height` | number | `56` | `inline` variant only. Edge size (px) of the square icon buttons; all inline buttons share this size. | | ||
@@ -237,0 +239,0 @@ ### Events |
| import { w as d, n as E, r as U, i as b, a as I, b as y, t as R } from "./lit-DpNjQO9d.js"; | ||
| import { t as V } from "./i18n-CIM9pdy9.js"; | ||
| function D(t) { | ||
| if (!t || typeof t != "object") return !1; | ||
| const e = t.url; | ||
| return !(typeof e != "string" || !e.trim() || /\/(null|undefined)(?:\/|$)/i.test(e)); | ||
| } | ||
| function A(t) { | ||
| if (!t || typeof t != "object") return; | ||
| const e = t, n = {}; | ||
| let o = !1; | ||
| for (const r of ["icon", "small", "regular", "large"]) { | ||
| const i = e[r]; | ||
| D(i) && (n[r] = { | ||
| height: Number(i.height) || 0, | ||
| type: String(i.type || ""), | ||
| url: i.url.trim(), | ||
| width: Number(i.width) || 0 | ||
| }, o = !0); | ||
| } | ||
| return o ? n : void 0; | ||
| } | ||
| const ct = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>`, lt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>`, pt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 5V2L7 7l5 5V8a5 5 0 1 1-4.9 6h-2.05A7 7 0 1 0 12 5z"/></svg>`, dt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l9.5 16.5H2.5L12 3z"/><path d="M12 10v4"/><path d="M12 17.5v.01"/></svg>`, ut = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M475.8 175.3c3 8 .4 16.8-5.9 22.5l-39.6 36a176.6 176.6 0 0 1 0 46.5l39.6 36a20.7 20.7 0 0 1 5.9 22.5c-4 10.9-9 21.3-14.5 31.3l-4.3 7.4c-6 10.1-12.8 19.6-20.2 28.6a20.8 20.8 0 0 1-22.5 6.2l-51-16.2a176.3 176.3 0 0 1-40.3 23.2l-11.4 52.2a20.7 20.7 0 0 1-16.7 16.3 237 237 0 0 1-77.9 0c-8.4-1.4-14.8-8-16.6-16.3l-11.5-52.2a179 179 0 0 1-40.3-23.2l-51 16.3a21 21 0 0 1-22.4-6.2c-7.4-9-14.2-18.5-20.2-28.6l-4.3-7.4a234 234 0 0 1-14.5-31.3c-3-8-.4-16.9 5.9-22.5l39.6-36a179 179 0 0 1 0-46.6l-39.6-36a20.7 20.7 0 0 1-5.9-22.5c4-10.9 9-21.3 14.5-31.3l4.3-7.5c6-10 12.8-19.5 20.2-28.5a20.8 20.8 0 0 1 22.5-6.2l51 16.2A176.3 176.3 0 0 1 189 94.8l11.4-52.2a20.7 20.7 0 0 1 16.7-16.3 227.5 227.5 0 0 1 77.9-.1c8.4 1.4 14.8 8 16.6 16.3l11.5 52.2a179 179 0 0 1 40.3 23.2l51-16.2c8-2.5 17-.3 22.4 6.2 7.5 9 14.2 18.5 20.3 28.6l4.3 7.4c5.6 10 10.4 20.4 14.5 31.3l-.1.1ZM256 330a73 73 0 1 0 0-146 73 73 0 0 0 0 146Z"/></svg>`, mt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M267.6 64.4A27.8 27.8 0 0 1 284 89.7v332.6a27.8 27.8 0 0 1-46.1 20.7L121 339H62.4A55.5 55.5 0 0 1 7 283.7v-55.4a55.5 55.5 0 0 1 55.4-55.5h58.7L237.9 69c8.1-7.3 19.8-9 29.7-4.6Zm107.8 114.7 47.6 47.6 47.6-47.6a20.8 20.8 0 0 1 29.3 29.3L452.3 256l47.6 47.6a20.8 20.8 0 0 1-29.3 29.3L423 285.3 375.4 333a20.8 20.8 0 0 1-29.3-29.3l47.6-47.6-47.6-47.6a20.8 20.8 0 0 1 29.3-29.3Z"/></svg>`, ft = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M279.8 64.4A27.8 27.8 0 0 1 296 89.7v332.6a28 28 0 0 1-16.2 25.3 27.3 27.3 0 0 1-29.6-4.6l-116-104H76c-30.3 0-55-24.8-55-55.4v-55.4a55.3 55.3 0 0 1 55-55.5h58.3L250.2 69c8-7.3 19.7-9 29.6-4.6Zm149 62.3a166 166 0 0 1 0 257.6 20.8 20.8 0 0 1-26.1-32.2 124.4 124.4 0 0 0 0-193.2 20.8 20.8 0 0 1 26.1-32.2Zm-52.6 65a82.7 82.7 0 0 1 0 128.6 21 21 0 0 1-29.5-3c-7.3-8.9-6-22 3-29.2a41.2 41.2 0 0 0 0-64.3 20.7 20.7 0 0 1-3-29.2 21.1 21.1 0 0 1 29.5-3v.1Z"/></svg>`, ht = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M280.8 64.4A27.8 27.8 0 0 1 297 89.7v332.6a28 28 0 0 1-16.2 25.3 27.3 27.3 0 0 1-29.6-4.6l-116-104H77c-30.3 0-55-24.8-55-55.4v-55.4a55.3 55.3 0 0 1 55-55.5h58.3L251.2 69c8-7.3 19.7-9 29.6-4.6Zm96.4 127.3a82.7 82.7 0 0 1 0 128.6 21 21 0 0 1-29.5-3c-7.3-8.9-6-22 3-29.2a41.2 41.2 0 0 0 0-64.3 20.7 20.7 0 0 1-3-29.2 21.1 21.1 0 0 1 29.5-3v.1Z"/></svg>`, gt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M96 480a32 32 0 1 1 0-64h320a32 32 0 1 1 0 64H96Zm182.6-137.4a32 32 0 0 1-45.3 0l-128-128a32 32 0 0 1 45.3-45.3l73.4 73.4V64a32 32 0 1 1 64 0v178.7l73.4-73.4a32 32 0 0 1 45.3 45.3l-128 128h-.1Z"/></svg>`, vt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M242.7 165.4h.1a22 22 0 0 1 6.5 4.6l45.4 45.2a22 22 0 0 1-31.1 31.2l-7.8-7.8v83.6a22 22 0 0 1-44 0v-83.6l-7.8 7.8a22 22 0 0 1-30.8.2l-.3-.3a22 22 0 0 1 0-31l45.3-45.3a22.1 22.1 0 0 1 .7-.7h.1l.4-.5h.2c1.6-1.5 3.4-2.6 5.3-3.4l.3-.1a22.2 22.2 0 0 1 7.6-1.7h.1a17.8 17.8 0 0 1 1.2 0h-.3a22.4 22.4 0 0 1 .9 0h.7c2.6.2 5 .8 7.3 1.8Z"/><path d="M199.1 21c68.5 0 131 35 167.3 91.1l.1.3h2a153.7 153.7 0 0 1 143.5 151v2.5c0 46.4-20.7 89.6-55.8 118.6a28.5 28.5 0 0 1-36.3-43.8A96.8 96.8 0 0 0 358.4 169c-15 0-29-7.9-36.7-20.9A142 142 0 0 0 57 220.3 142 142 0 0 0 98.5 321 28.4 28.4 0 1 1 58 361 199.2 199.2 0 0 1 199 21Z"/></svg>`, wt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.49 6-3.31 6-6.72h-1.7z"/></svg>`, xt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6 6h12v12H6z"/></svg>`, yt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>`; | ||
| d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>`; | ||
| const bt = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`, _t = d`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/></svg>`, H = { VITE_API_URL: "https://api.audiodelivery.net" }, F = H, f = F?.VITE_API_URL; | ||
| class m extends Error { | ||
| constructor(e, n) { | ||
| super(e), this.name = "ApiError", this.status = n; | ||
| } | ||
| } | ||
| const S = 1, N = 1e3; | ||
| async function h(t, e) { | ||
| let n = null; | ||
| for (let o = 0; o <= S; o++) | ||
| try { | ||
| return await fetch(t, e); | ||
| } catch (r) { | ||
| n = r instanceof Error ? r : new Error(String(r)), o < S && await new Promise((i) => setTimeout(i, N * Math.pow(2, o))); | ||
| } | ||
| throw n || new m("Network request failed", 0); | ||
| } | ||
| async function g(t, e, n) { | ||
| return n(); | ||
| } | ||
| function v(t, e = {}) { | ||
| return t ? { | ||
| ...e, | ||
| headers: { | ||
| ...e.headers, | ||
| "Accept-Language": t | ||
| } | ||
| } : e; | ||
| } | ||
| async function Z(t, e, n, o, r, i, s) { | ||
| const a = `/v1/play_session/${e}`; | ||
| return g("POST", a, async () => { | ||
| const l = `${f}${a}`, c = await h(l, v(i, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${t}` | ||
| }, | ||
| body: JSON.stringify({ | ||
| [`${e}_id`]: n, | ||
| variants: o, | ||
| ...r && { expires_in: r }, | ||
| // Requested download intent; the API key is the authoritative gate and | ||
| // the server stores (key AND this) on the session. | ||
| ...s && { is_downloadable: !0 } | ||
| }) | ||
| })), p = await c.json(); | ||
| if (!c.ok || !p.ok) | ||
| throw new m(p.message || "Failed to create play session", c.status); | ||
| if (!p.tracks?.length) | ||
| throw new m("No tracks found in session", c.status); | ||
| const x = { | ||
| ok: p.ok, | ||
| playSessionId: p.play_session_id, | ||
| expiresAt: new Date(p.expires_at), | ||
| playSession: u(p.play_session), | ||
| tracks: [] | ||
| }; | ||
| x.playSession.expiresAt = new Date(x.playSession.expiresAt); | ||
| for (const O of p.tracks) | ||
| x.tracks.push(u(O)); | ||
| return p.first_track && (x.firstTrack = B(p.first_track)), x; | ||
| }); | ||
| } | ||
| async function G(t, e) { | ||
| const n = `/v1/play_session/${t}`; | ||
| return g("GET", n, async () => { | ||
| const o = `${f}${n}`, r = await h(o, v(e)), i = await r.json(); | ||
| if (!r.ok || !i.ok) | ||
| throw new m(i.message || "Failed to fetch play session", r.status); | ||
| if (!i.tracks?.length) | ||
| throw new m("No tracks found in session", r.status); | ||
| const s = { | ||
| ok: i.ok, | ||
| playSessionId: i.play_session_id, | ||
| expiresAt: new Date(i.expires_at || i.play_session.expires_at), | ||
| playSession: u(i.play_session), | ||
| tracks: [] | ||
| }; | ||
| s.playSession.expiresAt = new Date(s.playSession.expiresAt); | ||
| for (const a of i.tracks) | ||
| s.tracks.push(u(a)); | ||
| return i.first_track && (s.firstTrack = B(i.first_track)), s; | ||
| }); | ||
| } | ||
| async function kt(t, e, n) { | ||
| const o = `/v1/play/${t}/${e}`; | ||
| return g("GET", o, async () => { | ||
| const r = `${f}${o}`, i = await h(r, v(n)), s = await i.json(); | ||
| if (!i.ok || !s.ok) | ||
| throw new m(s.message || "Failed to fetch track data", i.status); | ||
| return { | ||
| ok: s.ok, | ||
| playSessionId: s.play_session_id, | ||
| trackId: s.track_id, | ||
| playSession: u(s.play_session), | ||
| track: u(s.track), | ||
| levels: u(s.levels), | ||
| variants: z(s.variants), | ||
| coverImage: A(u(s.cover_image)) | ||
| }; | ||
| }); | ||
| } | ||
| async function St(t, e, n, o) { | ||
| const r = `/v1/play/${t}/${e}/${encodeURIComponent(String(n).toLowerCase())}/download`; | ||
| return g("GET", r, async () => { | ||
| const i = `${f}${r}`, s = await h(i, v(o)), a = await s.json(); | ||
| if (!s.ok || !a?.ok) | ||
| throw new m(a?.message || "Failed to fetch download URL", s.status); | ||
| return a; | ||
| }); | ||
| } | ||
| async function Tt(t, e, n) { | ||
| const o = "/v1/upload_session"; | ||
| return g("POST", o, async () => { | ||
| const r = `${f}${o}`, i = {}; | ||
| e && (i.collection_id = e); | ||
| const s = await h(r, v(n, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${t}` | ||
| }, | ||
| body: JSON.stringify(i) | ||
| })), a = await s.json(); | ||
| if (!s.ok || !a?.ok) | ||
| throw new m(a?.message || "Failed to create upload session", s.status); | ||
| return a; | ||
| }); | ||
| } | ||
| async function $t(t, e, n, o, r) { | ||
| const i = "/v1/upload_session"; | ||
| return g("POST", i, async () => { | ||
| const s = `${f}${i}`, a = { file_name: n }; | ||
| o?.player_title && (a.player_title = o.player_title), o?.player_subtitle && (a.player_subtitle = o.player_subtitle), o?.player_color && (a.player_color = o.player_color), o?.metadata && (a.metadata = o.metadata), o?.organization_index && (a.organization_index = o.organization_index); | ||
| const l = { track: a }; | ||
| e && (l.collection_id = e); | ||
| const c = await h(s, v(r, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${t}` | ||
| }, | ||
| body: JSON.stringify(l) | ||
| })), p = await c.json(); | ||
| if (!c.ok || !p?.ok) | ||
| throw new m(p?.message || "Failed to create upload session with track", c.status); | ||
| if (!p.track_id || !p.track_upload?.upload_url) | ||
| throw new m("Upload session created but track upload URL was missing", c.status); | ||
| return p; | ||
| }); | ||
| } | ||
| async function Ct(t, e) { | ||
| const n = `/v1/upload_session/${t}`; | ||
| return g("GET", n, async () => { | ||
| const o = `${f}${n}`, r = await h(o, v(e)), i = await r.json(); | ||
| if (!r.ok || !i?.ok) | ||
| throw new m(i?.message || "Failed to fetch upload session", r.status); | ||
| return i; | ||
| }); | ||
| } | ||
| async function Mt(t, e, n, o) { | ||
| const r = `/v1/upload/${t}/track`; | ||
| return g("POST", r, async () => { | ||
| const i = `${f}${r}`, s = await h(i, v(o, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json" | ||
| }, | ||
| body: JSON.stringify({ | ||
| file_name: e, | ||
| file_size: n | ||
| }) | ||
| })), a = await s.json(); | ||
| if (!s.ok || !a?.ok) | ||
| throw new m(a?.message || "Failed to get upload URL", s.status); | ||
| return a; | ||
| }); | ||
| } | ||
| function z(t) { | ||
| return t.map((e) => { | ||
| const n = u(e); | ||
| return e.data !== null && (n.isPreview = !0, n.preview = { | ||
| offsetStart: e.data.capture_start, | ||
| offsetEnd: e.data.capture_end, | ||
| duration: e.data.duration | ||
| }), n; | ||
| }); | ||
| } | ||
| function B(t) { | ||
| return { | ||
| ok: !0, | ||
| playSessionId: "", | ||
| trackId: t.track_id, | ||
| playSession: {}, | ||
| track: u(t.track), | ||
| levels: u(t.levels), | ||
| variants: z(t.variants), | ||
| coverImage: A(u(t.cover_image)) | ||
| }; | ||
| } | ||
| function T(t) { | ||
| return t.toLowerCase().replace(/([-_][a-z])/g, function(e) { | ||
| return e.toUpperCase().replace("-", "").replace("_", ""); | ||
| }); | ||
| } | ||
| function u(t) { | ||
| if (t == null) return t; | ||
| const e = {}; | ||
| for (const [n, o] of Object.entries(t)) { | ||
| if (o != null && o.constructor === Object) { | ||
| e[T(n)] = u(o); | ||
| continue; | ||
| } | ||
| Object.hasOwn(t, n) && (e[T(n)] = o); | ||
| } | ||
| return e; | ||
| } | ||
| var W = Object.defineProperty, Y = Object.getOwnPropertyDescriptor, _ = (t, e, n, o) => { | ||
| for (var r = o > 1 ? void 0 : o ? Y(e, n) : e, i = t.length - 1, s; i >= 0; i--) | ||
| (s = t[i]) && (r = (o ? s(e, n, r) : s(r)) || r); | ||
| return o && r && W(e, n, r), r; | ||
| }; | ||
| const P = 180, J = { | ||
| error: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M15 9l-6 6M9 9l6 6"/></svg>`, | ||
| warning: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9.5 16.5H2.5L12 3z"/><path d="M12 10v4"/><path d="M12 17.5v.01"/></svg>`, | ||
| info: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 11v5"/><path d="M12 8v.01"/></svg>`, | ||
| success: d`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M8.5 12.5l2.5 2.5 4.5-5"/></svg>` | ||
| }; | ||
| let w = class extends I { | ||
| constructor() { | ||
| super(...arguments), this.duration = 5e3, this.locale = "en", this.notifications = [], this.nextId = 0; | ||
| } | ||
| add(t, e, n = {}) { | ||
| const o = n.duration ?? (t === "error" || t === "warning" ? 0 : this.duration), r = this.notifications.find((c) => !c.dismissing && c.type === t && c.message === e); | ||
| if (r) | ||
| return r.timeout && clearTimeout(r.timeout), r.action = n.action, o > 0 && (r.timeout = setTimeout(() => this.dismiss(r.id), o)), this.notifications = [...this.notifications], r.id; | ||
| const i = this.nextId++, s = { id: i, type: t, message: e, action: n.action }; | ||
| o > 0 && (s.timeout = setTimeout(() => this.dismiss(i), o)); | ||
| const a = [...this.notifications, s]; | ||
| this.notifications = a.length > 4 ? a.slice(a.length - 4) : a; | ||
| const l = t === "error" ? "adn-error" : t === "success" ? "adn-success" : `adn-${t}`; | ||
| return this.dispatchEvent(new CustomEvent(l, { | ||
| detail: { message: e }, | ||
| bubbles: !0, | ||
| composed: !0 | ||
| })), i; | ||
| } | ||
| dismiss(t) { | ||
| const e = this.notifications.find((n) => n.id === t); | ||
| !e || e.dismissing || (e.timeout && clearTimeout(e.timeout), e.dismissing = !0, this.notifications = [...this.notifications], setTimeout(() => { | ||
| this.notifications = this.notifications.filter((n) => n.id !== t); | ||
| }, P)); | ||
| } | ||
| clear() { | ||
| for (const t of this.notifications) | ||
| t.timeout && clearTimeout(t.timeout); | ||
| this.notifications = []; | ||
| } | ||
| runAction(t) { | ||
| t.action?.onClick(), this.dismiss(t.id); | ||
| } | ||
| disconnectedCallback() { | ||
| super.disconnectedCallback(), this.clear(); | ||
| } | ||
| render() { | ||
| return this.notifications.length === 0 ? y`` : y` | ||
| <div class="notification-stack"> | ||
| ${[...this.notifications].reverse().map((t) => y` | ||
| <div | ||
| class="notification notification-${t.type} ${t.dismissing ? "is-dismissing" : ""}" | ||
| role=${t.type === "error" || t.type === "warning" ? "alert" : "status"} | ||
| aria-live=${t.type === "error" || t.type === "warning" ? "assertive" : "polite"} | ||
| > | ||
| <span class="notification-icon">${J[t.type]}</span> | ||
| <span class="notification-message">${t.message}</span> | ||
| ${t.action ? y` | ||
| <button class="notification-action" @click=${() => this.runAction(t)}>${t.action.label}</button> | ||
| ` : ""} | ||
| <button class="notification-dismiss" @click=${() => this.dismiss(t.id)} aria-label=${V(this.locale, "notification.dismiss")}> | ||
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg> | ||
| </button> | ||
| </div> | ||
| `)} | ||
| </div> | ||
| `; | ||
| } | ||
| }; | ||
| w.styles = q(); | ||
| _([ | ||
| E({ type: Number }) | ||
| ], w.prototype, "duration", 2); | ||
| _([ | ||
| E({ type: String, attribute: "locale" }) | ||
| ], w.prototype, "locale", 2); | ||
| _([ | ||
| U() | ||
| ], w.prototype, "notifications", 2); | ||
| w = _([ | ||
| R("audiodn-notification") | ||
| ], w); | ||
| function q() { | ||
| return b` | ||
| .notification-stack { | ||
| position: absolute; | ||
| top: 0; | ||
| left: 0; | ||
| right: 0; | ||
| z-index: 9999; | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: var(--adn-notification-gap, 6px); | ||
| padding: var(--adn-notification-padding, 6px); | ||
| pointer-events: none; | ||
| } | ||
| .notification { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 8px; | ||
| padding: 8px 10px; | ||
| border-radius: var(--adn-notification-radius, 8px); | ||
| font-size: var(--adn-notification-font-size, var(--step--1, 0.833rem)); | ||
| font-family: var(--adn-font-family, sans-serif); | ||
| line-height: 1.3; | ||
| color: var(--_notif-fg, #fff); | ||
| background: var(--_notif-bg); | ||
| box-shadow: var(--adn-notification-box-shadow, 0 4px 14px rgba(0, 0, 0, 0.35)); | ||
| pointer-events: auto; | ||
| animation: notif-in 200ms cubic-bezier(0.16, 1, 0.3, 1); | ||
| } | ||
| .notification.is-dismissing { | ||
| animation: notif-out ${P}ms ease-in forwards; | ||
| pointer-events: none; | ||
| } | ||
| .notification-error { | ||
| --_notif-bg: var(--adn-notification-bg-error, #dc2626); | ||
| } | ||
| .notification-warning { | ||
| --_notif-bg: var(--adn-notification-bg-warning, #d97706); | ||
| } | ||
| .notification-info { | ||
| --_notif-bg: var(--adn-notification-bg-info, #2563eb); | ||
| } | ||
| .notification-success { | ||
| --_notif-bg: var(--adn-notification-bg-success, #16a34a); | ||
| } | ||
| .notification-icon { | ||
| display: inline-flex; | ||
| flex-shrink: 0; | ||
| } | ||
| .notification-icon svg { | ||
| width: 1.15em; | ||
| height: 1.15em; | ||
| } | ||
| .notification-message { | ||
| flex: 1; | ||
| min-width: 0; | ||
| } | ||
| .notification-action { | ||
| flex-shrink: 0; | ||
| appearance: none; | ||
| border: 1px solid currentColor; | ||
| background: transparent; | ||
| color: inherit; | ||
| font: inherit; | ||
| font-weight: 600; | ||
| padding: 3px 10px; | ||
| border-radius: 999px; | ||
| cursor: pointer; | ||
| opacity: 0.95; | ||
| transition: background-color 120ms ease, opacity 120ms ease; | ||
| } | ||
| .notification-action:hover { | ||
| background: rgba(255, 255, 255, 0.18); | ||
| opacity: 1; | ||
| } | ||
| .notification-dismiss { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| flex-shrink: 0; | ||
| appearance: none; | ||
| border: none; | ||
| background: transparent; | ||
| color: inherit; | ||
| cursor: pointer; | ||
| padding: 2px; | ||
| opacity: 0.7; | ||
| transition: opacity 120ms ease; | ||
| } | ||
| .notification-dismiss svg { | ||
| width: 1em; | ||
| height: 1em; | ||
| } | ||
| .notification-dismiss:hover { | ||
| opacity: 1; | ||
| } | ||
| @keyframes notif-in { | ||
| from { opacity: 0; transform: translateY(-8px); } | ||
| to { opacity: 1; transform: translateY(0); } | ||
| } | ||
| @keyframes notif-out { | ||
| from { opacity: 1; transform: translateY(0); } | ||
| to { opacity: 0; transform: translateY(-8px); } | ||
| } | ||
| @media (prefers-reduced-motion: reduce) { | ||
| .notification, | ||
| .notification.is-dismissing { | ||
| animation-duration: 1ms; | ||
| } | ||
| } | ||
| `; | ||
| } | ||
| const Et = b` | ||
| /* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,18,1.25,5,3,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ | ||
| /* Step -3: 9.2593px → 9.216px */ | ||
| --step--3: clamp(0.576rem, 0.5796rem + -0.0047vw, 0.5787rem); | ||
| /* Step -2: 11.1111px → 11.52px */ | ||
| --step--2: clamp(0.6944rem, 0.6856rem + 0.0444vw, 0.72rem); | ||
| /* Step -1: 13.3333px → 14.4px */ | ||
| --step--1: clamp(0.8333rem, 0.8101rem + 0.1159vw, 0.9rem); | ||
| /* Step 0: 16px → 18px */ | ||
| --step-0: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); | ||
| /* Step 1: 19.2px → 22.5px */ | ||
| --step-1: clamp(1.2rem, 1.1283rem + 0.3587vw, 1.4063rem); | ||
| /* Step 2: 23.04px → 28.125px */ | ||
| --step-2: clamp(1.44rem, 1.3295rem + 0.5527vw, 1.7578rem); | ||
| /* Step 3: 27.648px → 35.1563px */ | ||
| --step-3: clamp(1.728rem, 1.5648rem + 0.8161vw, 2.1973rem); | ||
| /* @link https://utopia.fyi/space/calculator?c=320,16,1.2,1240,18,1.25,5,1,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ | ||
| /* Space 3xs: 4px → 5px */ | ||
| --space-3xs: clamp(0.25rem, 0.2283rem + 0.1087vw, 0.3125rem); | ||
| /* Space 2xs: 8px → 9px */ | ||
| --space-2xs: clamp(0.5rem, 0.4783rem + 0.1087vw, 0.5625rem); | ||
| /* Space xs: 12px → 14px */ | ||
| --space-xs: clamp(0.75rem, 0.7065rem + 0.2174vw, 0.875rem); | ||
| /* Space s: 16px → 18px */ | ||
| --space-s: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); | ||
| /* Space m: 24px → 27px */ | ||
| --space-m: clamp(1.5rem, 1.4348rem + 0.3261vw, 1.6875rem); | ||
| /* Space l: 32px → 36px */ | ||
| --space-l: clamp(2rem, 1.913rem + 0.4348vw, 2.25rem); | ||
| /* Space xl: 48px → 54px */ | ||
| --space-xl: clamp(3rem, 2.8696rem + 0.6522vw, 3.375rem); | ||
| /* Space 2xl: 64px → 72px */ | ||
| --space-2xl: clamp(4rem, 3.8261rem + 0.8696vw, 4.5rem); | ||
| /* Space 3xl: 96px → 108px */ | ||
| --space-3xl: clamp(6rem, 5.7391rem + 1.3043vw, 6.75rem); | ||
| /* One-up pairs */ | ||
| /* Space 3xs-2xs: 4px → 9px */ | ||
| --space-3xs-2xs: clamp(0.25rem, 0.1413rem + 0.5435vw, 0.5625rem); | ||
| /* Space 2xs-xs: 8px → 14px */ | ||
| --space-2xs-xs: clamp(0.5rem, 0.3696rem + 0.6522vw, 0.875rem); | ||
| /* Space xs-s: 12px → 18px */ | ||
| --space-xs-s: clamp(0.75rem, 0.6196rem + 0.6522vw, 1.125rem); | ||
| /* Space s-m: 16px → 27px */ | ||
| --space-s-m: clamp(1rem, 0.7609rem + 1.1957vw, 1.6875rem); | ||
| /* Space m-l: 24px → 36px */ | ||
| --space-m-l: clamp(1.5rem, 1.2391rem + 1.3043vw, 2.25rem); | ||
| /* Space l-xl: 32px → 54px */ | ||
| --space-l-xl: clamp(2rem, 1.5217rem + 2.3913vw, 3.375rem); | ||
| /* Space xl-2xl: 48px → 72px */ | ||
| --space-xl-2xl: clamp(3rem, 2.4783rem + 2.6087vw, 4.5rem); | ||
| /* Space 2xl-3xl: 64px → 108px */ | ||
| --space-2xl-3xl: clamp(4rem, 3.0435rem + 4.7826vw, 6.75rem); | ||
| /* Custom pairs */ | ||
| /* Space s-l: 16px → 36px */ | ||
| --space-s-l: clamp(1rem, 0.5652rem + 2.1739vw, 2.25rem); | ||
| /* --adn-volume-width: clamp(3.125rem, -0.4464rem + 17.8571vw, 6.25rem); */ | ||
| `, At = b` | ||
| :host([theme="light"]) { | ||
| --_bg: var(--adn-bg, #f4f4f5); | ||
| --_bg-light: var(--adn-bg-light, #e4e4e7); | ||
| --_color-font: var(--adn-color-font, #1c1c1e); | ||
| --_color-font-muted: var(--adn-color-font-muted, #52525b); | ||
| --_border-color: var(--adn-border-color, #d4d4d8); | ||
| --_color-highlight: var(--adn-color-highlight, rgba(0, 0, 0, 0.06)); | ||
| /* Darker greyscale accent so controls read on the light background. */ | ||
| --_color-accent: var(--adn-color-accent, #52525b); | ||
| --_color-accent-rgb: var(--adn-color-accent-rgb, 82, 82, 91); | ||
| } | ||
| @media (prefers-color-scheme: light) { | ||
| :host([theme="auto"]) { | ||
| --_bg: var(--adn-bg, #f4f4f5); | ||
| --_bg-light: var(--adn-bg-light, #e4e4e7); | ||
| --_color-font: var(--adn-color-font, #1c1c1e); | ||
| --_color-font-muted: var(--adn-color-font-muted, #52525b); | ||
| --_border-color: var(--adn-border-color, #d4d4d8); | ||
| --_color-highlight: var(--adn-color-highlight, rgba(0, 0, 0, 0.06)); | ||
| --_color-accent: var(--adn-color-accent, #52525b); | ||
| --_color-accent-rgb: var(--adn-color-accent-rgb, 82, 82, 91); | ||
| } | ||
| } | ||
| `, zt = b` | ||
| *, *:before, *:after { | ||
| box-sizing: border-box; | ||
| } | ||
| @media (prefers-reduced-motion: no-preference) { | ||
| interpolate-size: allow-keywords; | ||
| } | ||
| img,canvas, svg { | ||
| display: block; | ||
| max-width: 100%; | ||
| } | ||
| input, button { | ||
| font: inherit; | ||
| } | ||
| `, X = 3e4; | ||
| async function Bt({ | ||
| playSessionId: t, | ||
| id: e, | ||
| apiKey: n, | ||
| scope: o, | ||
| variants: r, | ||
| sessionTtl: i, | ||
| locale: s, | ||
| downloadable: a | ||
| }) { | ||
| if (t) | ||
| try { | ||
| const c = await G(t, s); | ||
| if (c) | ||
| return c; | ||
| } catch (c) { | ||
| if (!(n && o && e)) | ||
| throw new Error("failed to fetch session", { cause: c }); | ||
| } | ||
| if (!n) | ||
| throw new Error("apiKey must be provided"); | ||
| if (!o) | ||
| throw new Error("scope must be provided"); | ||
| if (!e) | ||
| throw new Error("id must be provided"); | ||
| if (!r.length) | ||
| throw new Error("no variants provided"); | ||
| const l = await Z(n, o, e, r, i, s, a); | ||
| if (!l) | ||
| throw new Error("failed to load session data"); | ||
| return l.tracks = l.tracks.sort((c, p) => c.order - p.order).map((c, p) => (c.order = p + 1, c)), l; | ||
| } | ||
| class Pt { | ||
| constructor() { | ||
| this._warningTimer = null, this._expiryTimer = null; | ||
| } | ||
| schedule(e, n) { | ||
| this.clear(); | ||
| const o = Date.now(), i = e.getTime() - o, s = i - X; | ||
| if (i <= 0) { | ||
| n.onExpiry(); | ||
| return; | ||
| } | ||
| s <= 0 ? n.onWarning() : this._warningTimer = setTimeout(n.onWarning, s), this._expiryTimer = setTimeout(n.onExpiry, i); | ||
| } | ||
| clear() { | ||
| this._warningTimer !== null && (clearTimeout(this._warningTimer), this._warningTimer = null), this._expiryTimer !== null && (clearTimeout(this._expiryTimer), this._expiryTimer = null); | ||
| } | ||
| } | ||
| const K = { r: 244, g: 244, b: 245 }, Q = { r: 0, g: 0, b: 0 }, $ = 3, tt = 0.02, L = (t, e, n) => Math.min(n, Math.max(e, t)); | ||
| function j(t) { | ||
| if (typeof t != "string") return null; | ||
| let e = t.trim().replace(/^#/, ""); | ||
| return e.length === 3 && (e = e.split("").map((n) => n + n).join("")), /^[0-9a-fA-F]{6}$/.test(e) ? { | ||
| r: parseInt(e.substring(0, 2), 16), | ||
| g: parseInt(e.substring(2, 4), 16), | ||
| b: parseInt(e.substring(4, 6), 16) | ||
| } : null; | ||
| } | ||
| function et({ r: t, g: e, b: n }) { | ||
| const o = (r) => L(Math.round(r), 0, 255).toString(16).padStart(2, "0"); | ||
| return `#${o(t)}${o(e)}${o(n)}`; | ||
| } | ||
| function ot({ r: t, g: e, b: n }) { | ||
| const o = t / 255, r = e / 255, i = n / 255, s = Math.max(o, r, i), a = Math.min(o, r, i), l = s - a; | ||
| let c = 0; | ||
| l !== 0 && (s === o ? c = (r - i) / l % 6 : s === r ? c = (i - o) / l + 2 : c = (o - r) / l + 4, c *= 60, c < 0 && (c += 360)); | ||
| const p = s === 0 ? 0 : l / s; | ||
| return { h: c, s: p, v: s }; | ||
| } | ||
| function C({ h: t, s: e, v: n }) { | ||
| const o = n * e, r = o * (1 - Math.abs(t / 60 % 2 - 1)), i = n - o; | ||
| let s = 0, a = 0, l = 0; | ||
| return t < 60 ? (s = o, a = r, l = 0) : t < 120 ? (s = r, a = o, l = 0) : t < 180 ? (s = 0, a = o, l = r) : t < 240 ? (s = 0, a = r, l = o) : t < 300 ? (s = r, a = 0, l = o) : (s = o, a = 0, l = r), { | ||
| r: (s + i) * 255, | ||
| g: (a + i) * 255, | ||
| b: (l + i) * 255 | ||
| }; | ||
| } | ||
| function k({ r: t, g: e, b: n }) { | ||
| const o = [t / 255, e / 255, n / 255].map((r) => r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4)); | ||
| return 0.2126 * o[0] + 0.7152 * o[1] + 0.0722 * o[2]; | ||
| } | ||
| function M(t, e) { | ||
| const n = k(t), o = k(e), r = Math.max(n, o), i = Math.min(n, o); | ||
| return (r + 0.05) / (i + 0.05); | ||
| } | ||
| function Lt(t, e = 0.179) { | ||
| const n = j(t); | ||
| return n ? k(n) <= e : !0; | ||
| } | ||
| function nt(t, e, n) { | ||
| let { v: o } = t, r = C({ ...t, v: o }); | ||
| if (M(r, e) >= $) return r; | ||
| for (let i = 0; i < 60 && (o = L(o + n * tt, 0, 1), r = C({ ...t, v: o }), !(M(r, e) >= $ || o === 0 || o === 1)); i++) | ||
| ; | ||
| return r; | ||
| } | ||
| function rt(t, e) { | ||
| const n = j(t); | ||
| if (!n) return null; | ||
| const o = ot(n); | ||
| return et(nt(o, e === "light" ? K : Q, e === "light" ? -1 : 1)); | ||
| } | ||
| const it = "#71717a"; | ||
| function jt(t) { | ||
| return rt(it, t) ?? (t === "light" ? "#52525b" : "#a1a1aa"); | ||
| } | ||
| export { | ||
| gt as A, | ||
| Bt as B, | ||
| m as C, | ||
| kt as D, | ||
| jt as E, | ||
| Pt as S, | ||
| rt as a, | ||
| Mt as b, | ||
| $t as c, | ||
| dt as d, | ||
| bt as e, | ||
| xt as f, | ||
| Ct as g, | ||
| wt as h, | ||
| Lt as i, | ||
| yt as j, | ||
| ct as k, | ||
| lt as l, | ||
| _t as m, | ||
| zt as n, | ||
| Et as o, | ||
| j as p, | ||
| Tt as q, | ||
| vt as r, | ||
| D as s, | ||
| At as t, | ||
| pt as u, | ||
| mt as v, | ||
| ft as w, | ||
| ht as x, | ||
| St as y, | ||
| ut as z | ||
| }; |
| const d = ["en", "fr", "es", "de"]; | ||
| const n = { | ||
| "action.retry": "Retry", | ||
| "action.reload": "Reload", | ||
| "player.notify.loadFailed": "Couldn’t load the player.", | ||
| "player.notify.sessionExpired": "Your session expired.", | ||
| "player.notify.noSession": "No play session available", | ||
| "player.notify.trackLoadFailed": "Couldn’t load this track.", | ||
| "player.notify.playFailed": "Couldn’t play this track.", | ||
| "player.aria.loading": "Loading audio player", | ||
| "player.loadingText": "Loading audio player…", | ||
| "player.aria.region": "Audio player", | ||
| "player.status.playbackError": "Playback error", | ||
| "player.status.buffering": "Buffering", | ||
| "player.status.nowPlaying": "Now playing: {title}", | ||
| "playButton.retry": "Retry", | ||
| "playButton.loading": "Loading", | ||
| "playButton.pause": "Pause", | ||
| "playButton.play": "Play", | ||
| "progress.aria.label": "Playback progress", | ||
| "progress.aria.valueText": "{current} of {total}", | ||
| "playTime.aria": "Playback time: {elapsed} of {total}", | ||
| "volume.aria": "Volume", | ||
| "settings.aria": "Settings", | ||
| "settings.download": "Download {label}", | ||
| "settings.notDownloadable": "This track isn’t downloadable.", | ||
| "trackTitle.none": "No track selected", | ||
| "coverArt.none": "No cover art", | ||
| "coverArt.alt": "Cover art", | ||
| "tracklist.aria": "Track list", | ||
| "waveform.aria": "Audio waveform", | ||
| "notification.dismiss": "Dismiss notification", | ||
| "uploader.notify.sessionExpired": "Your upload session expired.", | ||
| "uploader.notify.uploadSuccess": "{filename} uploaded successfully", | ||
| "uploader.notify.uploadFailed": "{filename}: upload failed", | ||
| "uploader.notify.networkError": "{filename}: network error", | ||
| "uploader.notify.uploadFailedDetail": "{filename}: {error}", | ||
| "uploader.notify.noAudioFiles": "No audio files detected. Please select audio files.", | ||
| "uploader.notify.limitExceeded": "You can upload at most {limit} file(s).", | ||
| "uploader.error.tryAgain": "Try again", | ||
| "uploader.aria.loading": "Loading uploader", | ||
| "uploader.loadingText": "Loading…", | ||
| "uploader.aria.fileArea": "File upload area", | ||
| "uploader.dropHeading": "Drop Audio Tracks To Collection", | ||
| "uploader.or": "or", | ||
| "uploader.browseFiles": "Browse Files", | ||
| "uploader.aria.selectFiles": "Select audio files to upload", | ||
| "uploader.aria.totalProgress": "Total upload progress", | ||
| "uploader.totalProgressText": "{percent}% total", | ||
| "uploader.aria.queue": "Upload queue", | ||
| "uploader.aria.fileProgress": "Upload progress for {filename}", | ||
| "uploader.aria.retryFile": "Retry upload for {filename}", | ||
| "uploader.aria.cancelUpload": "Cancel upload for {filename}", | ||
| "uploader.aria.removeFile": "Remove file {filename}", | ||
| "recorder.notify.sessionExpired": "Your upload session expired.", | ||
| "recorder.notify.uploadSuccess": "Recording uploaded successfully", | ||
| "recorder.notify.uploadFailed": "Upload failed", | ||
| "recorder.notify.networkError": "Network error during upload", | ||
| "recorder.notify.uploadFailedDetail": "Upload failed: {error}", | ||
| "recorder.notify.micDenied": "Microphone access was denied.", | ||
| "recorder.notify.micUnavailable": "Microphone is not available.", | ||
| "recorder.notify.maxDuration": "Maximum recording length reached.", | ||
| "recorder.error.tryAgain": "Try again", | ||
| "recorder.aria.loading": "Loading recorder", | ||
| "recorder.loadingText": "Loading…", | ||
| "recorder.aria.region": "Voice recorder", | ||
| "recorder.aria.start": "Start recording", | ||
| "recorder.aria.pause": "Pause recording", | ||
| "recorder.aria.resume": "Resume recording", | ||
| "recorder.aria.stop": "Stop recording", | ||
| "recorder.aria.discard": "Discard recording", | ||
| "recorder.aria.send": "Confirm recording", | ||
| "recorder.aria.cancelCountdown": "Cancel countdown", | ||
| "recorder.idle.hint": "Tap to record", | ||
| "recorder.countdown.hint": "Get ready…", | ||
| "recorder.aria.selectMic": "Select microphone", | ||
| "recorder.device.unnamed": "Microphone {n}", | ||
| "recorder.device.menuLabel": "Microphones", | ||
| "recorder.aria.moreOptions": "More options", | ||
| "recorder.menu.preview": "Preview", | ||
| "recorder.menu.stopPreview": "Stop preview", | ||
| "recorder.menu.delete": "Delete", | ||
| "recorder.menu.stopUpload": "Stop upload", | ||
| "recorder.aria.cancelUpload": "Cancel upload", | ||
| "recorder.aria.play": "Play recording", | ||
| "recorder.aria.pausePreview": "Pause playback", | ||
| "recorder.aria.progress": "Upload progress", | ||
| "recorder.aria.done": "Upload complete", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, t = { | ||
| "action.retry": "Réessayer", | ||
| "action.reload": "Recharger", | ||
| "player.notify.loadFailed": "Impossible de charger le lecteur.", | ||
| "player.notify.sessionExpired": "Votre session a expiré.", | ||
| "player.notify.noSession": "Aucune session de lecture disponible", | ||
| "player.notify.trackLoadFailed": "Impossible de charger cette piste.", | ||
| "player.notify.playFailed": "Impossible de lire cette piste.", | ||
| "player.aria.loading": "Chargement du lecteur audio", | ||
| "player.loadingText": "Chargement du lecteur audio…", | ||
| "player.aria.region": "Lecteur audio", | ||
| "player.status.playbackError": "Erreur de lecture", | ||
| "player.status.buffering": "Mise en mémoire tampon", | ||
| "player.status.nowPlaying": "Lecture en cours : {title}", | ||
| "playButton.retry": "Réessayer", | ||
| "playButton.loading": "Chargement", | ||
| "playButton.pause": "Pause", | ||
| "playButton.play": "Lecture", | ||
| "progress.aria.label": "Progression de la lecture", | ||
| "progress.aria.valueText": "{current} sur {total}", | ||
| "playTime.aria": "Temps de lecture : {elapsed} sur {total}", | ||
| "volume.aria": "Volume", | ||
| "settings.aria": "Paramètres", | ||
| "settings.download": "Télécharger {label}", | ||
| "settings.notDownloadable": "Cette piste n’est pas téléchargeable.", | ||
| "trackTitle.none": "Aucune piste sélectionnée", | ||
| "coverArt.none": "Pas de pochette", | ||
| "coverArt.alt": "Pochette", | ||
| "tracklist.aria": "Liste des pistes", | ||
| "waveform.aria": "Forme d’onde audio", | ||
| "notification.dismiss": "Ignorer la notification", | ||
| "uploader.notify.sessionExpired": "Votre session de téléversement a expiré.", | ||
| "uploader.notify.uploadSuccess": "{filename} téléversé avec succès", | ||
| "uploader.notify.uploadFailed": "{filename} : échec du téléversement", | ||
| "uploader.notify.networkError": "{filename} : erreur réseau", | ||
| "uploader.notify.uploadFailedDetail": "{filename} : {error}", | ||
| "uploader.notify.noAudioFiles": "Aucun fichier audio détecté. Veuillez sélectionner des fichiers audio.", | ||
| "uploader.notify.limitExceeded": "Vous ne pouvez téléverser que {limit} fichier(s).", | ||
| "uploader.error.tryAgain": "Réessayer", | ||
| "uploader.aria.loading": "Chargement du téléverseur", | ||
| "uploader.loadingText": "Chargement…", | ||
| "uploader.aria.fileArea": "Zone de téléversement de fichiers", | ||
| "uploader.dropHeading": "Déposez des pistes audio dans la collection", | ||
| "uploader.or": "ou", | ||
| "uploader.browseFiles": "Parcourir les fichiers", | ||
| "uploader.aria.selectFiles": "Sélectionner des fichiers audio à téléverser", | ||
| "uploader.aria.totalProgress": "Progression totale du téléversement", | ||
| "uploader.totalProgressText": "{percent}% au total", | ||
| "uploader.aria.queue": "File de téléversement", | ||
| "uploader.aria.fileProgress": "Progression du téléversement pour {filename}", | ||
| "uploader.aria.retryFile": "Réessayer le téléversement pour {filename}", | ||
| "uploader.aria.cancelUpload": "Annuler le téléversement pour {filename}", | ||
| "uploader.aria.removeFile": "Retirer le fichier {filename}", | ||
| "recorder.notify.sessionExpired": "Votre session de téléversement a expiré.", | ||
| "recorder.notify.uploadSuccess": "Enregistrement téléversé avec succès", | ||
| "recorder.notify.uploadFailed": "Échec du téléversement", | ||
| "recorder.notify.networkError": "Erreur réseau pendant le téléversement", | ||
| "recorder.notify.uploadFailedDetail": "Échec du téléversement : {error}", | ||
| "recorder.notify.micDenied": "L’accès au microphone a été refusé.", | ||
| "recorder.notify.micUnavailable": "Le microphone n’est pas disponible.", | ||
| "recorder.notify.maxDuration": "Durée maximale d’enregistrement atteinte.", | ||
| "recorder.error.tryAgain": "Réessayer", | ||
| "recorder.aria.loading": "Chargement de l’enregistreur", | ||
| "recorder.loadingText": "Chargement…", | ||
| "recorder.aria.region": "Enregistreur vocal", | ||
| "recorder.aria.start": "Démarrer l’enregistrement", | ||
| "recorder.aria.pause": "Mettre en pause", | ||
| "recorder.aria.resume": "Reprendre l’enregistrement", | ||
| "recorder.aria.stop": "Arrêter l’enregistrement", | ||
| "recorder.aria.discard": "Supprimer l’enregistrement", | ||
| "recorder.aria.send": "Confirmer l’enregistrement", | ||
| "recorder.aria.cancelCountdown": "Annuler le compte à rebours", | ||
| "recorder.idle.hint": "Appuyez pour enregistrer", | ||
| "recorder.countdown.hint": "Préparez-vous…", | ||
| "recorder.aria.selectMic": "Choisir le microphone", | ||
| "recorder.device.unnamed": "Microphone {n}", | ||
| "recorder.device.menuLabel": "Microphones", | ||
| "recorder.aria.moreOptions": "Plus d’options", | ||
| "recorder.menu.preview": "Écouter", | ||
| "recorder.menu.stopPreview": "Arrêter l’écoute", | ||
| "recorder.menu.delete": "Supprimer", | ||
| "recorder.menu.stopUpload": "Arrêter l’envoi", | ||
| "recorder.aria.cancelUpload": "Annuler le téléversement", | ||
| "recorder.aria.play": "Lire l’enregistrement", | ||
| "recorder.aria.pausePreview": "Mettre la lecture en pause", | ||
| "recorder.aria.progress": "Progression du téléversement", | ||
| "recorder.aria.done": "Téléversement terminé", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, s = { | ||
| "action.retry": "Reintentar", | ||
| "action.reload": "Recargar", | ||
| "player.notify.loadFailed": "No se pudo cargar el reproductor.", | ||
| "player.notify.sessionExpired": "Tu sesión ha expirado.", | ||
| "player.notify.noSession": "No hay sesión de reproducción disponible", | ||
| "player.notify.trackLoadFailed": "No se pudo cargar esta pista.", | ||
| "player.notify.playFailed": "No se pudo reproducir esta pista.", | ||
| "player.aria.loading": "Cargando el reproductor de audio", | ||
| "player.loadingText": "Cargando el reproductor de audio…", | ||
| "player.aria.region": "Reproductor de audio", | ||
| "player.status.playbackError": "Error de reproducción", | ||
| "player.status.buffering": "Almacenando en búfer", | ||
| "player.status.nowPlaying": "Reproduciendo: {title}", | ||
| "playButton.retry": "Reintentar", | ||
| "playButton.loading": "Cargando", | ||
| "playButton.pause": "Pausa", | ||
| "playButton.play": "Reproducir", | ||
| "progress.aria.label": "Progreso de reproducción", | ||
| "progress.aria.valueText": "{current} de {total}", | ||
| "playTime.aria": "Tiempo de reproducción: {elapsed} de {total}", | ||
| "volume.aria": "Volumen", | ||
| "settings.aria": "Ajustes", | ||
| "settings.download": "Descargar {label}", | ||
| "settings.notDownloadable": "Esta pista no se puede descargar.", | ||
| "trackTitle.none": "Ninguna pista seleccionada", | ||
| "coverArt.none": "Sin carátula", | ||
| "coverArt.alt": "Carátula", | ||
| "tracklist.aria": "Lista de pistas", | ||
| "waveform.aria": "Forma de onda de audio", | ||
| "notification.dismiss": "Descartar notificación", | ||
| "uploader.notify.sessionExpired": "Tu sesión de subida ha expirado.", | ||
| "uploader.notify.uploadSuccess": "{filename} subido correctamente", | ||
| "uploader.notify.uploadFailed": "{filename}: error al subir", | ||
| "uploader.notify.networkError": "{filename}: error de red", | ||
| "uploader.notify.uploadFailedDetail": "{filename}: {error}", | ||
| "uploader.notify.noAudioFiles": "No se detectaron archivos de audio. Selecciona archivos de audio.", | ||
| "uploader.notify.limitExceeded": "Solo puedes subir {limit} archivo(s).", | ||
| "uploader.error.tryAgain": "Intentar de nuevo", | ||
| "uploader.aria.loading": "Cargando el cargador", | ||
| "uploader.loadingText": "Cargando…", | ||
| "uploader.aria.fileArea": "Área de subida de archivos", | ||
| "uploader.dropHeading": "Suelta pistas de audio en la colección", | ||
| "uploader.or": "o", | ||
| "uploader.browseFiles": "Explorar archivos", | ||
| "uploader.aria.selectFiles": "Selecciona archivos de audio para subir", | ||
| "uploader.aria.totalProgress": "Progreso total de subida", | ||
| "uploader.totalProgressText": "{percent}% en total", | ||
| "uploader.aria.queue": "Cola de subida", | ||
| "uploader.aria.fileProgress": "Progreso de subida de {filename}", | ||
| "uploader.aria.retryFile": "Reintentar la subida de {filename}", | ||
| "uploader.aria.cancelUpload": "Cancelar la subida de {filename}", | ||
| "uploader.aria.removeFile": "Quitar el archivo {filename}", | ||
| "recorder.notify.sessionExpired": "Tu sesión de subida ha expirado.", | ||
| "recorder.notify.uploadSuccess": "Grabación subida correctamente", | ||
| "recorder.notify.uploadFailed": "Error al subir", | ||
| "recorder.notify.networkError": "Error de red durante la subida", | ||
| "recorder.notify.uploadFailedDetail": "Error al subir: {error}", | ||
| "recorder.notify.micDenied": "Se denegó el acceso al micrófono.", | ||
| "recorder.notify.micUnavailable": "El micrófono no está disponible.", | ||
| "recorder.notify.maxDuration": "Se alcanzó la duración máxima de grabación.", | ||
| "recorder.error.tryAgain": "Intentar de nuevo", | ||
| "recorder.aria.loading": "Cargando el grabador", | ||
| "recorder.loadingText": "Cargando…", | ||
| "recorder.aria.region": "Grabador de voz", | ||
| "recorder.aria.start": "Iniciar grabación", | ||
| "recorder.aria.pause": "Pausar grabación", | ||
| "recorder.aria.resume": "Reanudar grabación", | ||
| "recorder.aria.stop": "Detener grabación", | ||
| "recorder.aria.discard": "Descartar grabación", | ||
| "recorder.aria.send": "Confirmar grabación", | ||
| "recorder.aria.cancelCountdown": "Cancelar cuenta atrás", | ||
| "recorder.idle.hint": "Toca para grabar", | ||
| "recorder.countdown.hint": "Prepárate…", | ||
| "recorder.aria.selectMic": "Seleccionar micrófono", | ||
| "recorder.device.unnamed": "Micrófono {n}", | ||
| "recorder.device.menuLabel": "Micrófonos", | ||
| "recorder.aria.moreOptions": "Más opciones", | ||
| "recorder.menu.preview": "Escuchar", | ||
| "recorder.menu.stopPreview": "Detener escucha", | ||
| "recorder.menu.delete": "Eliminar", | ||
| "recorder.menu.stopUpload": "Detener subida", | ||
| "recorder.aria.cancelUpload": "Cancelar subida", | ||
| "recorder.aria.play": "Reproducir grabación", | ||
| "recorder.aria.pausePreview": "Pausar reproducción", | ||
| "recorder.aria.progress": "Progreso de subida", | ||
| "recorder.aria.done": "Subida completa", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, c = { | ||
| "action.retry": "Wiederholen", | ||
| "action.reload": "Neu laden", | ||
| "player.notify.loadFailed": "Player konnte nicht geladen werden.", | ||
| "player.notify.sessionExpired": "Ihre Sitzung ist abgelaufen.", | ||
| "player.notify.noSession": "Keine Wiedergabesitzung verfügbar", | ||
| "player.notify.trackLoadFailed": "Dieser Titel konnte nicht geladen werden.", | ||
| "player.notify.playFailed": "Dieser Titel konnte nicht abgespielt werden.", | ||
| "player.aria.loading": "Audio-Player wird geladen", | ||
| "player.loadingText": "Audio-Player wird geladen…", | ||
| "player.aria.region": "Audio-Player", | ||
| "player.status.playbackError": "Wiedergabefehler", | ||
| "player.status.buffering": "Puffern", | ||
| "player.status.nowPlaying": "Wird abgespielt: {title}", | ||
| "playButton.retry": "Wiederholen", | ||
| "playButton.loading": "Wird geladen", | ||
| "playButton.pause": "Pause", | ||
| "playButton.play": "Abspielen", | ||
| "progress.aria.label": "Wiedergabefortschritt", | ||
| "progress.aria.valueText": "{current} von {total}", | ||
| "playTime.aria": "Wiedergabezeit: {elapsed} von {total}", | ||
| "volume.aria": "Lautstärke", | ||
| "settings.aria": "Einstellungen", | ||
| "settings.download": "{label} herunterladen", | ||
| "settings.notDownloadable": "Dieser Titel kann nicht heruntergeladen werden.", | ||
| "trackTitle.none": "Kein Titel ausgewählt", | ||
| "coverArt.none": "Kein Cover", | ||
| "coverArt.alt": "Cover", | ||
| "tracklist.aria": "Titelliste", | ||
| "waveform.aria": "Audio-Wellenform", | ||
| "notification.dismiss": "Benachrichtigung schließen", | ||
| "uploader.notify.sessionExpired": "Ihre Upload-Sitzung ist abgelaufen.", | ||
| "uploader.notify.uploadSuccess": "{filename} erfolgreich hochgeladen", | ||
| "uploader.notify.uploadFailed": "{filename}: Upload fehlgeschlagen", | ||
| "uploader.notify.networkError": "{filename}: Netzwerkfehler", | ||
| "uploader.notify.uploadFailedDetail": "{filename}: {error}", | ||
| "uploader.notify.noAudioFiles": "Keine Audiodateien erkannt. Bitte wählen Sie Audiodateien aus.", | ||
| "uploader.notify.limitExceeded": "Sie können höchstens {limit} Datei(en) hochladen.", | ||
| "uploader.error.tryAgain": "Erneut versuchen", | ||
| "uploader.aria.loading": "Uploader wird geladen", | ||
| "uploader.loadingText": "Wird geladen…", | ||
| "uploader.aria.fileArea": "Datei-Upload-Bereich", | ||
| "uploader.dropHeading": "Audiotitel in die Sammlung ziehen", | ||
| "uploader.or": "oder", | ||
| "uploader.browseFiles": "Dateien durchsuchen", | ||
| "uploader.aria.selectFiles": "Audiodateien zum Hochladen auswählen", | ||
| "uploader.aria.totalProgress": "Gesamter Upload-Fortschritt", | ||
| "uploader.totalProgressText": "{percent}% gesamt", | ||
| "uploader.aria.queue": "Upload-Warteschlange", | ||
| "uploader.aria.fileProgress": "Upload-Fortschritt für {filename}", | ||
| "uploader.aria.retryFile": "Upload für {filename} wiederholen", | ||
| "uploader.aria.cancelUpload": "Upload für {filename} abbrechen", | ||
| "uploader.aria.removeFile": "Datei {filename} entfernen", | ||
| "recorder.notify.sessionExpired": "Ihre Upload-Sitzung ist abgelaufen.", | ||
| "recorder.notify.uploadSuccess": "Aufnahme erfolgreich hochgeladen", | ||
| "recorder.notify.uploadFailed": "Upload fehlgeschlagen", | ||
| "recorder.notify.networkError": "Netzwerkfehler während des Uploads", | ||
| "recorder.notify.uploadFailedDetail": "Upload fehlgeschlagen: {error}", | ||
| "recorder.notify.micDenied": "Mikrofonzugriff wurde verweigert.", | ||
| "recorder.notify.micUnavailable": "Mikrofon ist nicht verfügbar.", | ||
| "recorder.notify.maxDuration": "Maximale Aufnahmedauer erreicht.", | ||
| "recorder.error.tryAgain": "Erneut versuchen", | ||
| "recorder.aria.loading": "Recorder wird geladen", | ||
| "recorder.loadingText": "Wird geladen…", | ||
| "recorder.aria.region": "Sprachrekorder", | ||
| "recorder.aria.start": "Aufnahme starten", | ||
| "recorder.aria.pause": "Aufnahme pausieren", | ||
| "recorder.aria.resume": "Aufnahme fortsetzen", | ||
| "recorder.aria.stop": "Aufnahme beenden", | ||
| "recorder.aria.discard": "Aufnahme verwerfen", | ||
| "recorder.aria.send": "Aufnahme bestätigen", | ||
| "recorder.aria.cancelCountdown": "Countdown abbrechen", | ||
| "recorder.idle.hint": "Tippen zum Aufnehmen", | ||
| "recorder.countdown.hint": "Bereit machen…", | ||
| "recorder.aria.selectMic": "Mikrofon auswählen", | ||
| "recorder.device.unnamed": "Mikrofon {n}", | ||
| "recorder.device.menuLabel": "Mikrofone", | ||
| "recorder.aria.moreOptions": "Weitere Optionen", | ||
| "recorder.menu.preview": "Anhören", | ||
| "recorder.menu.stopPreview": "Anhören stoppen", | ||
| "recorder.menu.delete": "Löschen", | ||
| "recorder.menu.stopUpload": "Upload stoppen", | ||
| "recorder.aria.cancelUpload": "Upload abbrechen", | ||
| "recorder.aria.play": "Aufnahme abspielen", | ||
| "recorder.aria.pausePreview": "Wiedergabe pausieren", | ||
| "recorder.aria.progress": "Upload-Fortschritt", | ||
| "recorder.aria.done": "Upload abgeschlossen", | ||
| "recorder.timer.preview": "{current}/{total}" | ||
| }, u = { en: n, fr: t, es: s, de: c }; | ||
| function p(r) { | ||
| if (!r) return "en"; | ||
| const e = r.toLowerCase().split("-")[0]; | ||
| return d.includes(e ?? "") ? e : "en"; | ||
| } | ||
| function f(r, e, a) { | ||
| const l = p(r ?? void 0); | ||
| let o = u[l][e] ?? n[e] ?? e; | ||
| if (a) | ||
| for (const i of Object.keys(a)) | ||
| o = o.split(`{${i}}`).join(String(a[i])); | ||
| return o; | ||
| } | ||
| export { | ||
| f as t | ||
| }; |
| import { n as l, r as E, i as V, a as X, b as N, t as j } from "./lit-DpNjQO9d.js"; | ||
| import { t as L } from "./i18n-CIM9pdy9.js"; | ||
| function q(t) { | ||
| if (t === void 0) return "--:--"; | ||
| const i = Math.floor(t / 60) || 0, o = Math.round(t % 60) || 0; | ||
| return `${i}:${("" + o).padStart(2, "0")}`; | ||
| } | ||
| function et(t) { | ||
| if (t === void 0) return "0s"; | ||
| const i = Math.floor(t / 60) || 0, o = Math.round(t % 60) || 0; | ||
| return [ | ||
| i && i + "m", | ||
| o && o + "s" | ||
| ].join(" "); | ||
| } | ||
| function it(t, i = 2) { | ||
| if (!+t) return "0 Bytes"; | ||
| const o = 1e3, s = i < 0 ? 0 : i, e = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], r = Math.floor(Math.log(t) / Math.log(o)); | ||
| return `${parseFloat((t / Math.pow(o, r)).toFixed(s))} ${e[r]}`; | ||
| } | ||
| let z, _, P, M, W, $, R, C, S; | ||
| const T = []; | ||
| function I(t, i) { | ||
| return _ = window.pageXOffset, M = window.pageYOffset, $ = window.innerHeight, C = window.innerWidth, P === void 0 && (P = _), W === void 0 && (W = M), S === void 0 && (S = C), R === void 0 && (R = $), (i || M !== W || _ !== P || $ !== R || C !== S) && (Y(t), P = _, W = M, R = $, S = C), requestAnimationFrame(I); | ||
| } | ||
| function Y(t) { | ||
| for (const i of T) | ||
| i({ x: _, y: M, px: P, py: W, vh: $, pvh: R, vw: C, pvw: S }, t); | ||
| } | ||
| function G(t) { | ||
| return T.indexOf(t) < 0 && T.push(t), z = z || I(performance.now()), { | ||
| update() { | ||
| return I(performance.now(), !0), this; | ||
| }, | ||
| destroy() { | ||
| T.splice(T.indexOf(t), 1); | ||
| } | ||
| }; | ||
| } | ||
| var U = Object.defineProperty, K = Object.getOwnPropertyDescriptor, a = (t, i, o, s) => { | ||
| for (var e = s > 1 ? void 0 : s ? K(i, o) : i, r = t.length - 1, c; r >= 0; r--) | ||
| (c = t[r]) && (e = (s ? c(i, o, e) : c(e)) || e); | ||
| return s && e && U(i, o, e), e; | ||
| }; | ||
| let n = class extends X { | ||
| constructor() { | ||
| super(...arguments), this.levels = [], this.height = 120, this.lineColor = "#888888", this.lineWidth = 2, this.gap = 3, this.variant = "vertical", this.locale = "en", this.scaleStrength = 0.4, this.reflectionAngle = 45, this.reflectionSize = 0.25, this.reflectionOpacity = 0.55, this.highlightFrom = 0, this.highlightWidth = 1, this.min = 0, this.max = 1, this.duration = 0, this.progress = 0, this.data = new Float32Array(), this.hoverPosition = null, this.containerWidth = 0, this.canvas = null, this.ctx = null, this._srrafHandle = null, this._drawScheduled = !1, this._hoverRafId = null, this._cachedRect = null, this.draw = () => { | ||
| if (!this.canvas || !this.ctx) return; | ||
| const { lineWidth: t, gap: i, height: o, variant: s } = this, e = this.ctx, r = Math.max(1, window.devicePixelRatio || 1), c = this.canvas.clientWidth || this.getRect().width, v = Math.max(1, Math.round(c * r)), h = Math.max(1, Math.round(o * r)); | ||
| this.canvas.width = v, this.canvas.height = h; | ||
| const u = t + i, O = Math.floor( | ||
| (c - t - (s === "wavy" ? u : 0)) / u | ||
| ) + 1, b = []; | ||
| for (let d = 0; d < O; d++) { | ||
| const p = Math.round(d / O * this.data.length); | ||
| b.push(this.data[p]); | ||
| } | ||
| e.clearRect(0, 0, v, h), e.fillStyle = this.lineColor, e.strokeStyle = this.lineColor; | ||
| const k = Math.max(1, Math.round(t * r)), D = u * r; | ||
| if (s === "vertical") | ||
| b.forEach((d, p) => { | ||
| if (!d) return; | ||
| const g = Math.round(p * D), f = Math.round(d * h), y = Math.round((h - f) / 2); | ||
| e.fillRect(g, y, k, f); | ||
| }); | ||
| else if (s === "reflection") { | ||
| const d = Math.max(0, this.reflectionSize), p = Math.round(h / (1 + d)), g = h - p, f = p, m = (0.5 - Math.max(0, Math.min(1, this.progress))) * 2 * (this.reflectionAngle * Math.PI / 180), A = Math.tan(m); | ||
| e.fillStyle = this.lineColor, b.forEach((w, H) => { | ||
| if (!w) return; | ||
| const F = Math.round(H * D), x = Math.round(w * p); | ||
| e.fillRect(F, f - x, k, x); | ||
| }); | ||
| const B = e.createLinearGradient(0, f, 0, f + g); | ||
| B.addColorStop(0, this.colorToRgba(this.lineColor, this.reflectionOpacity)), B.addColorStop(0.75, this.colorToRgba(this.lineColor, this.reflectionOpacity * 0.5)), B.addColorStop(1, this.colorToRgba(this.lineColor, 0)), e.strokeStyle = B, e.lineWidth = k, b.forEach((w, H) => { | ||
| if (!w) return; | ||
| const F = Math.round(H * D) + k / 2, x = w * g; | ||
| e.beginPath(), e.moveTo(F, f), e.lineTo(F + A * x, f + x), e.stroke(); | ||
| }); | ||
| } else if (s === "wavy") { | ||
| e.scale(r, r), e.lineWidth = this.lineWidth, e.save(); | ||
| const d = o / 2; | ||
| e.translate(0, d); | ||
| const p = c / b.length; | ||
| for (const [g, f] of b.entries()) { | ||
| if (!f) continue; | ||
| const y = g * u + Math.ceil(t / 2) + 0.5; | ||
| let m = f * (d - this.lineWidth * 2); | ||
| m < 0 ? m = 0 : m > d - this.lineWidth * 2 && (m = d - this.lineWidth * 2); | ||
| const A = (g + 1) % 2 ? m : -m; | ||
| e.beginPath(), e.moveTo(y, 0), e.lineTo(y, A), e.arc( | ||
| y + p / 2, | ||
| A, | ||
| Math.min(p / 2, Math.min(p / 2, m)), | ||
| Math.PI, | ||
| 0, | ||
| !!((g + 1) % 2) | ||
| ), e.lineTo(y + p, 0), e.stroke(); | ||
| } | ||
| e.restore(); | ||
| } | ||
| }; | ||
| } | ||
| connectedCallback() { | ||
| super.connectedCallback(), this.updateLineColor(), this._srrafHandle = G(({ vw: t, pvw: i }) => { | ||
| t !== i && (this._cachedRect = null, this.computeWaveformWidth(), this.scheduleDraw()); | ||
| }); | ||
| } | ||
| disconnectedCallback() { | ||
| super.disconnectedCallback(), this._srrafHandle?.destroy(), this._srrafHandle = null, this._hoverRafId !== null && (cancelAnimationFrame(this._hoverRafId), this._hoverRafId = null); | ||
| } | ||
| willUpdate(t) { | ||
| this.style.setProperty("--_playheadPosition", this.progress * 100 + "%"), this.style.setProperty("--_playheadVisible", this.progress > 0 ? "1" : "0"), this.style.setProperty("--_hoverPosition", this.hoverPosition !== null ? this.hoverPosition * 100 + "%" : "0%"), this.style.setProperty("--_hoverVisible", this.hoverPosition !== null ? "1" : "0"), this.style.setProperty("--_highlightFrom", `${this.highlightFrom}px`), this.style.setProperty("--_maskWidth", `${Math.floor(this.containerWidth * this.highlightWidth)}px`), this.updateLineColor(), this.levels && t.has("levels") && this.processData(); | ||
| } | ||
| render() { | ||
| return Z.call(this); | ||
| } | ||
| firstUpdated() { | ||
| this.canvas = this.renderRoot.querySelector("canvas"), this.canvas && (this.ctx = this.canvas.getContext("2d")); | ||
| } | ||
| updated() { | ||
| this.style.setProperty("--_pre-progress", `${this.min * 100}%`), this.max < 1 ? this.style.setProperty("--_width", `${this.max * 100}%`) : this.style.setProperty("--_width", `${this.progress * 100}%`), this.computeWaveformWidth(), this.scheduleDraw(); | ||
| } | ||
| getRect() { | ||
| return this._cachedRect || (this._cachedRect = this.getBoundingClientRect()), this._cachedRect; | ||
| } | ||
| handleEvent(t) { | ||
| const i = t.currentTarget; | ||
| if (t.type === "mouseenter") { | ||
| i.style.setProperty("--_transitionSpeed", "0"); | ||
| return; | ||
| } | ||
| if (t.type === "mouseleave") { | ||
| i.style.setProperty("--_transitionSpeed", "100ms"), this.hoverPosition = null; | ||
| return; | ||
| } | ||
| const o = this.getRect(), s = t.clientX - o.left; | ||
| if (s < 0 || s > this.containerWidth) { | ||
| this.hoverPosition = null; | ||
| return; | ||
| } | ||
| const e = Math.max(0, Math.min(1, s / this.containerWidth)); | ||
| if (t.type === "mousemove") { | ||
| if (this._hoverRafId !== null) return; | ||
| this._hoverRafId = requestAnimationFrame(() => { | ||
| this._hoverRafId = null, this.hoverPosition = e; | ||
| }); | ||
| } | ||
| t.type === "click" && this.dispatchEvent( | ||
| new CustomEvent("adni-seek", { | ||
| detail: { percent: e }, | ||
| bubbles: !0 | ||
| }) | ||
| ); | ||
| } | ||
| handleTouch(t) { | ||
| if (!(!t.touches.length && t.type !== "touchend")) { | ||
| if (t.type === "touchstart" || t.type === "touchmove") { | ||
| t.preventDefault(); | ||
| const i = t.touches[0]; | ||
| if (!i) return; | ||
| const o = this.getRect(), s = i.clientX - o.left, e = Math.max(0, Math.min(1, s / this.containerWidth)); | ||
| this.hoverPosition = e; | ||
| } | ||
| t.type === "touchend" && (this.hoverPosition !== null && this.dispatchEvent( | ||
| new CustomEvent("adni-seek", { | ||
| detail: { percent: this.hoverPosition }, | ||
| bubbles: !0 | ||
| }) | ||
| ), this.hoverPosition = null); | ||
| } | ||
| } | ||
| computeWaveformWidth() { | ||
| this._cachedRect = null, this.containerWidth = this.getRect().width; | ||
| } | ||
| processData() { | ||
| const { levels: t, scaleStrength: i } = this; | ||
| if (!t || t.length === 0) { | ||
| this.data = new Float32Array(); | ||
| return; | ||
| } | ||
| const o = Math.min(...t), e = Math.max(...t) - o; | ||
| let r = e === 0 ? t.map(() => 0.5) : t.map((h) => (h - o) / e), c = r.reduce((h, u) => h + u, 0) / t.length, v = 0; | ||
| for (; c > 1 - i && v < 10; ) | ||
| r = r.map((h) => h * h), c = r.reduce((h, u) => h + u, 0) / t.length, v += 1; | ||
| this.data = new Float32Array(r); | ||
| } | ||
| // Normalize any CSS color to rgba() with the given alpha (via the canvas' | ||
| // own color parsing) so the reflection gradient can fade to transparent. | ||
| colorToRgba(t, i) { | ||
| const o = this.ctx; | ||
| if (!o) return `rgba(136, 136, 136, ${i})`; | ||
| o.fillStyle = "#000", o.fillStyle = t; | ||
| const s = o.fillStyle; | ||
| if (s.startsWith("#")) { | ||
| let r = s.slice(1); | ||
| r.length === 3 && (r = r.split("").map((u) => u + u).join("")); | ||
| const c = parseInt(r.slice(0, 2), 16), v = parseInt(r.slice(2, 4), 16), h = parseInt(r.slice(4, 6), 16); | ||
| return `rgba(${c}, ${v}, ${h}, ${i})`; | ||
| } | ||
| const e = s.match(/rgba?\(([^)]+)\)/); | ||
| if (e && e[1]) { | ||
| const [r, c, v] = e[1].split(",").map((h) => h.trim()); | ||
| return `rgba(${r}, ${c}, ${v}, ${i})`; | ||
| } | ||
| return `rgba(136, 136, 136, ${i})`; | ||
| } | ||
| updateLineColor() { | ||
| const t = getComputedStyle(this), i = t.getPropertyValue("--adn-waveform-color-fg"), o = t.getPropertyValue("--adn-color-accent"); | ||
| this.lineColor = i || o || t.getPropertyValue("--_color-accent"); | ||
| } | ||
| scheduleDraw() { | ||
| this._drawScheduled || (this._drawScheduled = !0, requestAnimationFrame(() => { | ||
| this._drawScheduled = !1, this.draw(); | ||
| })); | ||
| } | ||
| }; | ||
| n.styles = J(); | ||
| a([ | ||
| l({ type: Array }) | ||
| ], n.prototype, "levels", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "height", 2); | ||
| a([ | ||
| l({ type: String, attribute: "line-color" }) | ||
| ], n.prototype, "lineColor", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "line-width" }) | ||
| ], n.prototype, "lineWidth", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "gap", 2); | ||
| a([ | ||
| l({ type: String }) | ||
| ], n.prototype, "variant", 2); | ||
| a([ | ||
| l({ type: String, attribute: "locale" }) | ||
| ], n.prototype, "locale", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "scale-strength" }) | ||
| ], n.prototype, "scaleStrength", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "reflection-angle" }) | ||
| ], n.prototype, "reflectionAngle", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "reflection-size" }) | ||
| ], n.prototype, "reflectionSize", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "reflection-opacity" }) | ||
| ], n.prototype, "reflectionOpacity", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "highlight-from" }) | ||
| ], n.prototype, "highlightFrom", 2); | ||
| a([ | ||
| l({ type: Number, attribute: "highlight-width" }) | ||
| ], n.prototype, "highlightWidth", 2); | ||
| a([ | ||
| l() | ||
| ], n.prototype, "min", 2); | ||
| a([ | ||
| l() | ||
| ], n.prototype, "max", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "duration", 2); | ||
| a([ | ||
| l({ type: Number }) | ||
| ], n.prototype, "progress", 2); | ||
| a([ | ||
| E() | ||
| ], n.prototype, "data", 2); | ||
| a([ | ||
| E() | ||
| ], n.prototype, "hoverPosition", 2); | ||
| n = a([ | ||
| j("audiodn-waveform") | ||
| ], n); | ||
| function Z() { | ||
| const t = this.hoverPosition !== null && this.duration > 0 ? q(this.hoverPosition * this.duration) : null; | ||
| return N` | ||
| <div class="waveform-container" | ||
| @mouseenter=${this} @mouseleave=${this} @mousemove=${this} | ||
| @touchstart=${(i) => this.handleTouch(i)} | ||
| @touchmove=${(i) => this.handleTouch(i)} | ||
| @touchend=${(i) => this.handleTouch(i)} | ||
| > | ||
| <canvas @click=${this} role="img" aria-label=${L(this.locale, "waveform.aria")}></canvas> | ||
| <div class="playhead progress-playhead"></div> | ||
| <div class="playhead hover-playhead"></div> | ||
| ${t !== null ? N` | ||
| <div class="hover-tooltip" style="left: ${this.hoverPosition * 100}%">${t}</div> | ||
| ` : ""} | ||
| </div> | ||
| `; | ||
| } | ||
| function J() { | ||
| return V` | ||
| :host { | ||
| width: 100%; | ||
| position: relative; | ||
| display: flex; | ||
| justify-content: center; | ||
| height: 100%; | ||
| box-sizing: border-box; | ||
| background: var(--adn-waveform-bg); | ||
| border: var(--adn-waveform-border); | ||
| border-radius: var(--adn-waveform-radius); | ||
| padding: var(--adn-waveform-padding); | ||
| } | ||
| .waveform-container { | ||
| width: 100%; | ||
| position: relative; | ||
| --_transitionSpeed: 100ms; | ||
| touch-action: none; | ||
| } | ||
| .click-overlay { | ||
| position: absolute; | ||
| inset: 0; | ||
| height: 100%; | ||
| cursor: pointer; | ||
| z-index: 1000; | ||
| } | ||
| canvas { | ||
| width: 100%; | ||
| height: 100%; | ||
| mask: linear-gradient(to right, | ||
| rgba(255 255 255 / 0.5) var(--_pre-progress), | ||
| rgba(255 255 255 / 1) var(--_pre-progress), | ||
| rgba(255 255 255 / 1) var(--_width), | ||
| rgba(255 255 255 / 0.5) var(--_width) | ||
| ); | ||
| } | ||
| .playhead { | ||
| width: var(--adn-waveform-playhead-width, 1px); | ||
| background: var(--adn-waveform-color-playhead, var(--_color-font)); | ||
| height: 100%; | ||
| position: absolute; | ||
| inset-block: 0; | ||
| pointer-events: none; | ||
| } | ||
| .progress-playhead { | ||
| left: var(--_playheadPosition); | ||
| opacity: var(--_playheadVisible, 0); | ||
| } | ||
| .hover-playhead { | ||
| left: var(--_hoverPosition); | ||
| opacity: calc(0.5 * var(--_hoverVisible, 0)); | ||
| } | ||
| .hover-tooltip { | ||
| position: absolute; | ||
| top: -24px; | ||
| transform: translateX(-50%); | ||
| background: rgba(0, 0, 0, 0.85); | ||
| color: #fff; | ||
| font-size: 11px; | ||
| padding: 2px 6px; | ||
| border-radius: 3px; | ||
| pointer-events: none; | ||
| white-space: nowrap; | ||
| font-family: sans-serif; | ||
| } | ||
| `; | ||
| } | ||
| export { | ||
| n as A, | ||
| et as a, | ||
| it as b, | ||
| q as f | ||
| }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
333823
4.84%39
5.41%7988
4.46%587
0.34%