nixamp 0.28.2 → 0.28.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/directory.d.ts +2 -0
- package/dist/directory.js +3 -0
- package/dist/owner.js +2 -0
- package/dist/server.js +66 -1
- package/dist/translation-passes.d.ts +2 -7
- package/dist/translation-passes.js +2 -3
- package/dist/upgrade-allowance.d.ts +1 -1
- package/dist/upgrade-allowance.js +6 -3
- package/package.json +1 -1
- package/src/directory.ts +5 -0
- package/src/owner.ts +1 -0
- package/src/server.ts +57 -1
- package/src/translation-passes.ts +2 -3
- package/src/upgrade-allowance.ts +6 -3
- package/web/dist/assets/{hls-3VKVEQE3-Cw5UD-5P.js → hls-3VKVEQE3-B4Sk5BbY.js} +1 -1
- package/web/dist/assets/index-B33hHbmF.js +3 -0
- package/web/dist/assets/{mpegts-a5NkXKRN.js → mpegts-CoCC1wqt.js} +1 -1
- package/web/dist/assets/{mpegts-LO6RVLD6-DS0PXyu3.js → mpegts-LO6RVLD6-Ct0Biz5E.js} +1 -1
- package/web/dist/index.html +13 -6
- package/web/dist/sw.js +5 -5
- package/web/dist/assets/index-BqcDIh2Q.js +0 -3
package/README.md
CHANGED
|
@@ -574,7 +574,7 @@ uses its direct model; it does not first translate the audio into English.
|
|
|
574
574
|
|
|
575
575
|
### Hear it in your language
|
|
576
576
|
|
|
577
|
-
Every signed-in account gets **
|
|
577
|
+
Every signed-in account gets **ten free live-use sessions per UTC day**, shared
|
|
578
578
|
across Nixamp's paid panels and upgrades. There is no timed cutoff: a session
|
|
579
579
|
continues while its listener remains, within the existing API usage limits.
|
|
580
580
|
Reconnects to the same session within 90 seconds reuse it. A stopped session
|
|
@@ -614,7 +614,7 @@ multiplied by five. Credentials and balances never travel in checkout URLs.
|
|
|
614
614
|
New checkout creation is capped at five per account and fifty per account server
|
|
615
615
|
per UTC day, plus IP and request throttles; retries reuse the original invoice.
|
|
616
616
|
|
|
617
|
-
After the
|
|
617
|
+
After the ten free sessions, new sessions require purchased credit. Configure `COINPAY_X402_KEY`
|
|
618
618
|
with `payments:create` permission and at least one business wallet; the scoped
|
|
619
619
|
key supplies the merchant identity. Free sessions and existing credit still work during a
|
|
620
620
|
checkout outage. A self-hosted operator explicitly sponsoring API usage may set
|
package/dist/directory.d.ts
CHANGED
|
@@ -141,6 +141,8 @@ export interface Announcement {
|
|
|
141
141
|
export interface LineupEntry {
|
|
142
142
|
id: string;
|
|
143
143
|
name: string;
|
|
144
|
+
/** Account that put this channel on the air, when known. */
|
|
145
|
+
startedBy?: string;
|
|
144
146
|
kind: "audio" | "video";
|
|
145
147
|
art: string;
|
|
146
148
|
about: string;
|
package/dist/directory.js
CHANGED
|
@@ -112,6 +112,9 @@ export function parseLineupEntry(input) {
|
|
|
112
112
|
return {
|
|
113
113
|
id,
|
|
114
114
|
name,
|
|
115
|
+
...(typeof record["startedBy"] === "string" && /^[a-zA-Z0-9_-]{1,64}$/.test(record["startedBy"])
|
|
116
|
+
? { startedBy: record["startedBy"] }
|
|
117
|
+
: {}),
|
|
115
118
|
kind: record["kind"] === "video" ? "video" : "audio",
|
|
116
119
|
// A picture is somewhere a crawler can go, or nothing: a data: URL is a
|
|
117
120
|
// page in a tag, and javascript: is a page in a tag that runs.
|
package/dist/owner.js
CHANGED
|
@@ -132,6 +132,8 @@ export function needsAdmin(path, method = "GET") {
|
|
|
132
132
|
export function needsMember(path, method = "GET") {
|
|
133
133
|
if (method === "POST" && /^\/api\/tracks\/\d+\/live$/.test(path))
|
|
134
134
|
return true;
|
|
135
|
+
if (method === "POST" && path === "/api/folders/live")
|
|
136
|
+
return true;
|
|
135
137
|
if (method === "POST" && /^\/api\/catalogs\/[^/]+\/entries\/[^/]+\/live$/.test(path))
|
|
136
138
|
return true;
|
|
137
139
|
if (method === "POST" && /^\/api\/channels\/[^/]+\/keep$/.test(path))
|
package/dist/server.js
CHANGED
|
@@ -1009,6 +1009,7 @@ export function lineupEntry(listenLink, info) {
|
|
|
1009
1009
|
return {
|
|
1010
1010
|
id: info.id,
|
|
1011
1011
|
name: info.name,
|
|
1012
|
+
...(info.startedBy ? { startedBy: info.startedBy } : {}),
|
|
1012
1013
|
kind: info.kind ?? "audio",
|
|
1013
1014
|
art: absoluteArtOf(listenLink, info),
|
|
1014
1015
|
about: info.about ?? "",
|
|
@@ -3568,7 +3569,15 @@ export function createHandler(engine, options) {
|
|
|
3568
3569
|
redials: one.redials ?? 0,
|
|
3569
3570
|
error: one.error ?? "",
|
|
3570
3571
|
// For a list: how long it is, and which entry is on, from 0.
|
|
3571
|
-
...(one.playlist ? {
|
|
3572
|
+
...(one.playlist ? {
|
|
3573
|
+
entries: one.playlist.length,
|
|
3574
|
+
entry: one.playlistAt ?? 0,
|
|
3575
|
+
playlist: one.playlist.map((source) => {
|
|
3576
|
+
const parts = source.split(/[\\/]/).filter(Boolean);
|
|
3577
|
+
return parts.length > 1 ? parts.slice(-2).join(" / ") : (parts[0] || "Untitled");
|
|
3578
|
+
}),
|
|
3579
|
+
live: one.live !== false,
|
|
3580
|
+
} : {}),
|
|
3572
3581
|
// The member who put it on, when one did: theirs to take off.
|
|
3573
3582
|
startedBy: one.startedBy ?? "",
|
|
3574
3583
|
// A picture of it, and a line about it, where there is one.
|
|
@@ -4031,6 +4040,62 @@ export function createHandler(engine, options) {
|
|
|
4031
4040
|
* do and which made two files at once impossible for anybody. The owner
|
|
4032
4041
|
* and any member may; the caps and the throttle above say how much.
|
|
4033
4042
|
*/
|
|
4043
|
+
if (path === "/api/folders/live" && request.method === "POST") {
|
|
4044
|
+
if (!options.channels) {
|
|
4045
|
+
json(response, 503, { error: "this server cannot carry channels" });
|
|
4046
|
+
return;
|
|
4047
|
+
}
|
|
4048
|
+
let body = {};
|
|
4049
|
+
try {
|
|
4050
|
+
body = JSON.parse(await readBody(request));
|
|
4051
|
+
}
|
|
4052
|
+
catch {
|
|
4053
|
+
json(response, 400, { error: "bad JSON" });
|
|
4054
|
+
return;
|
|
4055
|
+
}
|
|
4056
|
+
const indices = Array.isArray(body.indices)
|
|
4057
|
+
? [...new Set(body.indices.filter((one) => Number.isInteger(one) && one >= 0))]
|
|
4058
|
+
: [];
|
|
4059
|
+
if (indices.length === 0 || indices.length > 10_000) {
|
|
4060
|
+
json(response, 400, { error: "choose a folder with playable files" });
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
const tracks = engine.snapshot().tracks ?? [];
|
|
4064
|
+
const selected = indices
|
|
4065
|
+
.map((index) => ({ index, track: tracks[index], source: engine.trackPath(index) }))
|
|
4066
|
+
.filter((one) => Boolean(one.track && one.source && !isRemote(one.source)));
|
|
4067
|
+
if (selected.length !== indices.length) {
|
|
4068
|
+
json(response, 404, { error: "one or more folder files are no longer available" });
|
|
4069
|
+
return;
|
|
4070
|
+
}
|
|
4071
|
+
selected.sort((a, b) => String(a.track.title ?? a.source).localeCompare(String(b.track.title ?? b.source), undefined, { numeric: true, sensitivity: "base" }));
|
|
4072
|
+
const sources = selected.map((one) => one.source);
|
|
4073
|
+
const channelId = cleanId(`folder-${sha("sha1").update(sources.join("\n")).digest("hex").slice(0, 12)}`);
|
|
4074
|
+
const name = typeof body.name === "string" && body.name.trim() !== ""
|
|
4075
|
+
? body.name.trim().slice(0, 120)
|
|
4076
|
+
: selected[0]?.track.folder || "folder";
|
|
4077
|
+
if (liveBy && !options.channels.has(channelId)) {
|
|
4078
|
+
const refusal = memberLiveRefusal(options.channels, liveBy);
|
|
4079
|
+
if (refusal) {
|
|
4080
|
+
json(response, 429, { error: refusal });
|
|
4081
|
+
return;
|
|
4082
|
+
}
|
|
4083
|
+
}
|
|
4084
|
+
if (!options.channels.has(channelId)) {
|
|
4085
|
+
const started = await pullChannel(options.channels, options.ffprobe ?? ["ffprobe"], channelId, name, sources[0], [], "", { playlist: sources, live: true });
|
|
4086
|
+
if (!started) {
|
|
4087
|
+
json(response, 409, { error: "that folder is already going on the air" });
|
|
4088
|
+
return;
|
|
4089
|
+
}
|
|
4090
|
+
if (liveBy)
|
|
4091
|
+
options.channels.info(channelId).startedBy = liveBy;
|
|
4092
|
+
}
|
|
4093
|
+
options.channels.keep(channelId);
|
|
4094
|
+
options.rememberChannels?.(rememberedNow(options.channels));
|
|
4095
|
+
void options.live?.announce?.();
|
|
4096
|
+
json(response, 200, { channel: channelId, name, video: options.channels.kindOf(channelId) !== "audio" });
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
4034
4099
|
const trackLive = /^\/api\/tracks\/(\d+)\/live$/.exec(path);
|
|
4035
4100
|
if (trackLive && request.method === "POST") {
|
|
4036
4101
|
if (!options.channels) {
|
|
@@ -5,17 +5,12 @@ export declare const TRANSLATION_PLANS: readonly [{
|
|
|
5
5
|
readonly id: "day";
|
|
6
6
|
readonly name: "Day";
|
|
7
7
|
readonly days: 1;
|
|
8
|
-
readonly priceCents:
|
|
9
|
-
}, {
|
|
10
|
-
readonly id: "week";
|
|
11
|
-
readonly name: "Week";
|
|
12
|
-
readonly days: 7;
|
|
13
|
-
readonly priceCents: 2500;
|
|
8
|
+
readonly priceCents: 100;
|
|
14
9
|
}, {
|
|
15
10
|
readonly id: "month";
|
|
16
11
|
readonly name: "Month";
|
|
17
12
|
readonly days: 30;
|
|
18
|
-
readonly priceCents:
|
|
13
|
+
readonly priceCents: 500;
|
|
19
14
|
}];
|
|
20
15
|
export type TranslationPlan = typeof TRANSLATION_PLANS[number];
|
|
21
16
|
export type TranslationUsage = "transcription" | "voice";
|
|
@@ -5,9 +5,8 @@ import { SpeechError } from "./speech.js";
|
|
|
5
5
|
import { UpgradeAllowances } from "./upgrade-allowance.js";
|
|
6
6
|
export const TRANSLATION_MULTIPLIER = 5;
|
|
7
7
|
export const TRANSLATION_PLANS = [
|
|
8
|
-
{ id: "day", name: "Day", days: 1, priceCents:
|
|
9
|
-
{ id: "
|
|
10
|
-
{ id: "month", name: "Month", days: 30, priceCents: 10000 },
|
|
8
|
+
{ id: "day", name: "Day", days: 1, priceCents: 100 },
|
|
9
|
+
{ id: "month", name: "Month", days: 30, priceCents: 500 },
|
|
11
10
|
];
|
|
12
11
|
const COINS = ["USDC_POL", "USDC_SOL", "SOL", "POL", "BTC", "ETH", "USDC_ETH", "BCH", "DOGE"];
|
|
13
12
|
const ID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Claim only on explicit use, never from balance polling or provider chunks. */
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { SpeechError } from "./speech.js";
|
|
5
|
-
export const FREE_UPGRADE_SESSIONS =
|
|
5
|
+
export const FREE_UPGRADE_SESSIONS = 10;
|
|
6
6
|
export const FREE_UPGRADE_RECONNECT_SECONDS = 90;
|
|
7
7
|
const DAY = 86_400_000;
|
|
8
8
|
export class UpgradeAllowances {
|
|
@@ -16,8 +16,11 @@ export class UpgradeAllowances {
|
|
|
16
16
|
async ensure() {
|
|
17
17
|
this.schema ??= this.db.query(`CREATE TABLE IF NOT EXISTS upgrade_daily_uses (
|
|
18
18
|
by_account TEXT NOT NULL, day BIGINT NOT NULL,
|
|
19
|
-
uses INTEGER NOT NULL CHECK (uses
|
|
20
|
-
sessions JSONB NOT NULL, PRIMARY KEY (by_account, day))`)
|
|
19
|
+
uses INTEGER NOT NULL CHECK (uses >= 1),
|
|
20
|
+
sessions JSONB NOT NULL, PRIMARY KEY (by_account, day))`)
|
|
21
|
+
.then(() => this.db.query(`ALTER TABLE upgrade_daily_uses DROP CONSTRAINT IF EXISTS upgrade_daily_uses_uses_check`))
|
|
22
|
+
.then(() => this.db.query(`ALTER TABLE upgrade_daily_uses ADD CONSTRAINT upgrade_daily_uses_uses_check CHECK (uses BETWEEN 1 AND 10)`))
|
|
23
|
+
.then(() => undefined)
|
|
21
24
|
.catch(error => { this.schema = null; throw error; });
|
|
22
25
|
await this.schema;
|
|
23
26
|
}
|
package/package.json
CHANGED
package/src/directory.ts
CHANGED
|
@@ -149,6 +149,8 @@ export interface Announcement {
|
|
|
149
149
|
export interface LineupEntry {
|
|
150
150
|
id: string;
|
|
151
151
|
name: string;
|
|
152
|
+
/** Account that put this channel on the air, when known. */
|
|
153
|
+
startedBy?: string;
|
|
152
154
|
kind: "audio" | "video";
|
|
153
155
|
art: string;
|
|
154
156
|
about: string;
|
|
@@ -247,6 +249,9 @@ export function parseLineupEntry(input: unknown): LineupEntry | null {
|
|
|
247
249
|
return {
|
|
248
250
|
id,
|
|
249
251
|
name,
|
|
252
|
+
...(typeof record["startedBy"] === "string" && /^[a-zA-Z0-9_-]{1,64}$/.test(record["startedBy"])
|
|
253
|
+
? { startedBy: record["startedBy"] }
|
|
254
|
+
: {}),
|
|
250
255
|
kind: record["kind"] === "video" ? "video" : "audio",
|
|
251
256
|
// A picture is somewhere a crawler can go, or nothing: a data: URL is a
|
|
252
257
|
// page in a tag, and javascript: is a page in a tag that runs.
|
package/src/owner.ts
CHANGED
|
@@ -146,6 +146,7 @@ export function needsAdmin(path: string, method = "GET"): boolean {
|
|
|
146
146
|
*/
|
|
147
147
|
export function needsMember(path: string, method = "GET"): boolean {
|
|
148
148
|
if (method === "POST" && /^\/api\/tracks\/\d+\/live$/.test(path)) return true;
|
|
149
|
+
if (method === "POST" && path === "/api/folders/live") return true;
|
|
149
150
|
if (method === "POST" && /^\/api\/catalogs\/[^/]+\/entries\/[^/]+\/live$/.test(path)) return true;
|
|
150
151
|
if (method === "POST" && /^\/api\/channels\/[^/]+\/keep$/.test(path)) return true;
|
|
151
152
|
if (method === "POST" && /^\/api\/channels\/[^/]+\/(?:start|stop|restart)$/.test(path)) return true;
|
package/src/server.ts
CHANGED
|
@@ -1253,6 +1253,7 @@ export function lineupEntry(listenLink: string, info: ChannelInfo): LineupEntry
|
|
|
1253
1253
|
return {
|
|
1254
1254
|
id: info.id,
|
|
1255
1255
|
name: info.name,
|
|
1256
|
+
...(info.startedBy ? { startedBy: info.startedBy } : {}),
|
|
1256
1257
|
kind: info.kind ?? "audio",
|
|
1257
1258
|
art: absoluteArtOf(listenLink, info),
|
|
1258
1259
|
about: info.about ?? "",
|
|
@@ -4014,7 +4015,15 @@ export function createHandler(engine: Engine, options: HandlerOptions) {
|
|
|
4014
4015
|
redials: one.redials ?? 0,
|
|
4015
4016
|
error: one.error ?? "",
|
|
4016
4017
|
// For a list: how long it is, and which entry is on, from 0.
|
|
4017
|
-
...(one.playlist ? {
|
|
4018
|
+
...(one.playlist ? {
|
|
4019
|
+
entries: one.playlist.length,
|
|
4020
|
+
entry: one.playlistAt ?? 0,
|
|
4021
|
+
playlist: one.playlist.map((source) => {
|
|
4022
|
+
const parts = source.split(/[\\/]/).filter(Boolean);
|
|
4023
|
+
return parts.length > 1 ? parts.slice(-2).join(" / ") : (parts[0] || "Untitled");
|
|
4024
|
+
}),
|
|
4025
|
+
live: one.live !== false,
|
|
4026
|
+
} : {}),
|
|
4018
4027
|
// The member who put it on, when one did: theirs to take off.
|
|
4019
4028
|
startedBy: one.startedBy ?? "",
|
|
4020
4029
|
// A picture of it, and a line about it, where there is one.
|
|
@@ -4492,6 +4501,53 @@ export function createHandler(engine: Engine, options: HandlerOptions) {
|
|
|
4492
4501
|
* do and which made two files at once impossible for anybody. The owner
|
|
4493
4502
|
* and any member may; the caps and the throttle above say how much.
|
|
4494
4503
|
*/
|
|
4504
|
+
if (path === "/api/folders/live" && request.method === "POST") {
|
|
4505
|
+
if (!options.channels) {
|
|
4506
|
+
json(response, 503, { error: "this server cannot carry channels" });
|
|
4507
|
+
return;
|
|
4508
|
+
}
|
|
4509
|
+
let body: { indices?: unknown; name?: unknown } = {};
|
|
4510
|
+
try { body = JSON.parse(await readBody(request)) as typeof body; } catch {
|
|
4511
|
+
json(response, 400, { error: "bad JSON" });
|
|
4512
|
+
return;
|
|
4513
|
+
}
|
|
4514
|
+
const indices = Array.isArray(body.indices)
|
|
4515
|
+
? [...new Set(body.indices.filter((one): one is number => Number.isInteger(one) && one >= 0))]
|
|
4516
|
+
: [];
|
|
4517
|
+
if (indices.length === 0 || indices.length > 10_000) {
|
|
4518
|
+
json(response, 400, { error: "choose a folder with playable files" });
|
|
4519
|
+
return;
|
|
4520
|
+
}
|
|
4521
|
+
const tracks = engine.snapshot().tracks ?? [];
|
|
4522
|
+
const selected = indices
|
|
4523
|
+
.map((index) => ({ index, track: tracks[index], source: engine.trackPath(index) }))
|
|
4524
|
+
.filter((one): one is { index: number; track: (typeof tracks)[number]; source: string } => Boolean(one.track && one.source && !isRemote(one.source)));
|
|
4525
|
+
if (selected.length !== indices.length) {
|
|
4526
|
+
json(response, 404, { error: "one or more folder files are no longer available" });
|
|
4527
|
+
return;
|
|
4528
|
+
}
|
|
4529
|
+
selected.sort((a, b) => String(a.track.title ?? a.source).localeCompare(String(b.track.title ?? b.source), undefined, { numeric: true, sensitivity: "base" }));
|
|
4530
|
+
const sources = selected.map((one) => one.source);
|
|
4531
|
+
const channelId = cleanId(`folder-${sha("sha1").update(sources.join("\n")).digest("hex").slice(0, 12)}`);
|
|
4532
|
+
const name = typeof body.name === "string" && body.name.trim() !== ""
|
|
4533
|
+
? body.name.trim().slice(0, 120)
|
|
4534
|
+
: selected[0]?.track.folder || "folder";
|
|
4535
|
+
if (liveBy && !options.channels.has(channelId)) {
|
|
4536
|
+
const refusal = memberLiveRefusal(options.channels, liveBy);
|
|
4537
|
+
if (refusal) { json(response, 429, { error: refusal }); return; }
|
|
4538
|
+
}
|
|
4539
|
+
if (!options.channels.has(channelId)) {
|
|
4540
|
+
const started = await pullChannel(options.channels, options.ffprobe ?? ["ffprobe"], channelId, name, sources[0]!, [], "", { playlist: sources, live: true });
|
|
4541
|
+
if (!started) { json(response, 409, { error: "that folder is already going on the air" }); return; }
|
|
4542
|
+
if (liveBy) options.channels.info(channelId)!.startedBy = liveBy;
|
|
4543
|
+
}
|
|
4544
|
+
options.channels.keep(channelId);
|
|
4545
|
+
options.rememberChannels?.(rememberedNow(options.channels));
|
|
4546
|
+
void options.live?.announce?.();
|
|
4547
|
+
json(response, 200, { channel: channelId, name, video: options.channels.kindOf(channelId) !== "audio" });
|
|
4548
|
+
return;
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4495
4551
|
const trackLive = /^\/api\/tracks\/(\d+)\/live$/.exec(path);
|
|
4496
4552
|
if (trackLive && request.method === "POST") {
|
|
4497
4553
|
if (!options.channels) {
|
|
@@ -7,9 +7,8 @@ import { UpgradeAllowances, type UpgradeAllowance } from "./upgrade-allowance.ts
|
|
|
7
7
|
|
|
8
8
|
export const TRANSLATION_MULTIPLIER = 5;
|
|
9
9
|
export const TRANSLATION_PLANS = [
|
|
10
|
-
{ id: "day", name: "Day", days: 1, priceCents:
|
|
11
|
-
{ id: "
|
|
12
|
-
{ id: "month", name: "Month", days: 30, priceCents: 10000 },
|
|
10
|
+
{ id: "day", name: "Day", days: 1, priceCents: 100 },
|
|
11
|
+
{ id: "month", name: "Month", days: 30, priceCents: 500 },
|
|
13
12
|
] as const;
|
|
14
13
|
export type TranslationPlan = typeof TRANSLATION_PLANS[number];
|
|
15
14
|
export type TranslationUsage = "transcription" | "voice";
|
package/src/upgrade-allowance.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { createHash } from "node:crypto";
|
|
|
4
4
|
import type { Queryable } from "./follows.ts";
|
|
5
5
|
import { SpeechError } from "./speech.ts";
|
|
6
6
|
|
|
7
|
-
export const FREE_UPGRADE_SESSIONS =
|
|
7
|
+
export const FREE_UPGRADE_SESSIONS = 10;
|
|
8
8
|
export const FREE_UPGRADE_RECONNECT_SECONDS = 90;
|
|
9
9
|
const DAY = 86_400_000;
|
|
10
10
|
export interface UpgradeAllowance {
|
|
@@ -18,8 +18,11 @@ export class UpgradeAllowances {
|
|
|
18
18
|
async ensure(): Promise<void> {
|
|
19
19
|
this.schema ??= this.db.query(`CREATE TABLE IF NOT EXISTS upgrade_daily_uses (
|
|
20
20
|
by_account TEXT NOT NULL, day BIGINT NOT NULL,
|
|
21
|
-
uses INTEGER NOT NULL CHECK (uses
|
|
22
|
-
sessions JSONB NOT NULL, PRIMARY KEY (by_account, day))`)
|
|
21
|
+
uses INTEGER NOT NULL CHECK (uses >= 1),
|
|
22
|
+
sessions JSONB NOT NULL, PRIMARY KEY (by_account, day))`)
|
|
23
|
+
.then(() => this.db.query(`ALTER TABLE upgrade_daily_uses DROP CONSTRAINT IF EXISTS upgrade_daily_uses_uses_check`))
|
|
24
|
+
.then(() => this.db.query(`ALTER TABLE upgrade_daily_uses ADD CONSTRAINT upgrade_daily_uses_uses_check CHECK (uses BETWEEN 1 AND 10)`))
|
|
25
|
+
.then(() => undefined)
|
|
23
26
|
.catch(error => { this.schema = null; throw error; });
|
|
24
27
|
await this.schema;
|
|
25
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./index-
|
|
1
|
+
import{t as e}from"./index-B33hHbmF.js";var t=3;async function n(n){let{media:r,src:i,isTv:a}=n,{default:o}=await e(async()=>{let{default:e}=await import(`./hls-n74Cnh8A.js`);return{default:e}},[]);if(!o.isSupported())return n.onError(`This browser cannot play HLS streams.`),{destroy:()=>void 0,levels:()=>[]};let s=new o({...a?{maxBufferLength:60,maxMaxBufferLength:120,backBufferLength:30,liveSyncDurationCount:4}:{backBufferLength:90},enableWorker:!0}),c=0,l=!1;s.on(o.Events.ERROR,(e,r)=>{if(!l&&r.fatal){if(c>=t){n.onError(`This stream kept failing and has been stopped.`),s.destroy();return}switch(c+=1,r.type){case o.ErrorTypes.NETWORK_ERROR:n.onNotice(`Reconnecting…`),s.startLoad();break;case o.ErrorTypes.MEDIA_ERROR:n.onNotice(`Recovering…`),s.recoverMediaError();break;default:n.onError(`This stream could not be played.`),s.destroy()}}}),s.on(o.Events.MANIFEST_PARSED,()=>{l||(n.onNotice(null),n.onReady?.({live:s.levels.length>0&&!Number.isFinite(r.duration),levels:u()}))}),s.on(o.Events.LEVEL_LOADED,(e,t)=>{l||n.onReady?.({live:t.details.live,levels:u()})}),s.on(o.Events.FRAG_BUFFERED,()=>{l||n.onNotice(null)});function u(){return s.levels.map((e,t)=>({index:t,height:e.height||null,bitrate:e.bitrate||null,label:e.height?`${String(e.height)}p`:`${String(Math.round((e.bitrate||0)/1e3))}k`}))}return s.loadSource(i),s.attachMedia(r),{destroy(){l=!0,s.destroy()},levels:u,setLevel(e){s.currentLevel=e},currentLevel:()=>s.autoLevelEnabled?-1:s.currentLevel}}export{n as createHlsEngine};
|