nixamp 0.28.2 → 0.28.4

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.
Files changed (159) hide show
  1. package/README.md +2 -2
  2. package/backtoschool/dist/assets/ar-qWtdkIOw.js +1 -0
  3. package/backtoschool/dist/assets/cs-O-6iUq7L.js +1 -0
  4. package/backtoschool/dist/assets/da-CtdhUqOq.js +1 -0
  5. package/backtoschool/dist/assets/de-DpIL8Ees.js +1 -0
  6. package/backtoschool/dist/assets/es-SiEP0g18.js +1 -0
  7. package/backtoschool/dist/assets/fi-DFexxTi-.js +1 -0
  8. package/backtoschool/dist/assets/fr-BHMNLR57.js +1 -0
  9. package/backtoschool/dist/assets/hi-Bbvbrvch.js +1 -0
  10. package/backtoschool/dist/assets/hu-WxKh5kIZ.js +1 -0
  11. package/backtoschool/dist/assets/id-BMS_sYt_.js +1 -0
  12. package/backtoschool/dist/assets/index-BTxRE5f2.js +113 -0
  13. package/backtoschool/dist/assets/index-CAxBxaVm.css +1 -0
  14. package/backtoschool/dist/assets/it-D5A6m68v.js +1 -0
  15. package/backtoschool/dist/assets/nl-6C2ukGHx.js +1 -0
  16. package/backtoschool/dist/assets/ru-DBAi8Upl.js +1 -0
  17. package/backtoschool/dist/assets/sv-DwuCaxjv.js +1 -0
  18. package/backtoschool/dist/assets/uk-DKZMfSc9.js +1 -0
  19. package/backtoschool/dist/assets/vi-CEACVAuf.js +1 -0
  20. package/backtoschool/dist/assets/zh-yfl-mwgz.js +1 -0
  21. package/backtoschool/dist/index.html +21 -3
  22. package/backtoschool/dist/platform-icons/LICENSE.txt +29 -0
  23. package/backtoschool/dist/platform-icons/amazon.svg +4 -0
  24. package/backtoschool/dist/platform-icons/apple.svg +4 -0
  25. package/backtoschool/dist/platform-icons/google-play.svg +3 -0
  26. package/backtoschool/dist/platform-icons/pwa.svg +1 -0
  27. package/dist/directory.d.ts +2 -0
  28. package/dist/directory.js +3 -0
  29. package/dist/locales/ar.d.ts +15 -0
  30. package/dist/locales/ar.js +2 -0
  31. package/dist/locales/cs.d.ts +15 -0
  32. package/dist/locales/cs.js +2 -0
  33. package/dist/locales/da.d.ts +15 -0
  34. package/dist/locales/da.js +2 -0
  35. package/dist/locales/de.d.ts +15 -0
  36. package/dist/locales/de.js +2 -0
  37. package/dist/locales/en.d.ts +17 -2
  38. package/dist/locales/en.js +2 -0
  39. package/dist/locales/es.d.ts +15 -0
  40. package/dist/locales/es.js +2 -0
  41. package/dist/locales/fi.d.ts +15 -0
  42. package/dist/locales/fi.js +2 -0
  43. package/dist/locales/fr.d.ts +15 -0
  44. package/dist/locales/fr.js +2 -0
  45. package/dist/locales/hi.d.ts +15 -0
  46. package/dist/locales/hi.js +2 -0
  47. package/dist/locales/hu.d.ts +15 -0
  48. package/dist/locales/hu.js +2 -0
  49. package/dist/locales/id.d.ts +15 -0
  50. package/dist/locales/id.js +2 -0
  51. package/dist/locales/it.d.ts +15 -0
  52. package/dist/locales/it.js +2 -0
  53. package/dist/locales/nl.d.ts +15 -0
  54. package/dist/locales/nl.js +2 -0
  55. package/dist/locales/platforms.d.ts +18 -0
  56. package/dist/locales/platforms.js +18 -0
  57. package/dist/locales/ru.d.ts +15 -0
  58. package/dist/locales/ru.js +2 -0
  59. package/dist/locales/sv.d.ts +15 -0
  60. package/dist/locales/sv.js +2 -0
  61. package/dist/locales/uk.d.ts +15 -0
  62. package/dist/locales/uk.js +2 -0
  63. package/dist/locales/vi.d.ts +15 -0
  64. package/dist/locales/vi.js +2 -0
  65. package/dist/locales/zh.d.ts +15 -0
  66. package/dist/locales/zh.js +2 -0
  67. package/dist/owner.js +2 -0
  68. package/dist/server.js +75 -1
  69. package/dist/translation-passes.d.ts +2 -7
  70. package/dist/translation-passes.js +2 -3
  71. package/dist/upgrade-allowance.d.ts +1 -1
  72. package/dist/upgrade-allowance.js +6 -3
  73. package/package.json +1 -1
  74. package/src/directory.ts +5 -0
  75. package/src/locales/ar.ts +2 -0
  76. package/src/locales/cs.ts +2 -0
  77. package/src/locales/da.ts +2 -0
  78. package/src/locales/de.ts +2 -0
  79. package/src/locales/en.ts +2 -0
  80. package/src/locales/es.ts +2 -0
  81. package/src/locales/fi.ts +2 -0
  82. package/src/locales/fr.ts +2 -0
  83. package/src/locales/hi.ts +2 -0
  84. package/src/locales/hu.ts +2 -0
  85. package/src/locales/id.ts +2 -0
  86. package/src/locales/it.ts +2 -0
  87. package/src/locales/nl.ts +2 -0
  88. package/src/locales/platforms.ts +18 -0
  89. package/src/locales/ru.ts +2 -0
  90. package/src/locales/sv.ts +2 -0
  91. package/src/locales/uk.ts +2 -0
  92. package/src/locales/vi.ts +2 -0
  93. package/src/locales/zh.ts +2 -0
  94. package/src/owner.ts +1 -0
  95. package/src/server.ts +65 -1
  96. package/src/translation-passes.ts +2 -3
  97. package/src/upgrade-allowance.ts +6 -3
  98. package/web/dist/assets/ar-BM4HXbrr.js +1 -0
  99. package/web/dist/assets/cs-BPFPXPrG.js +1 -0
  100. package/web/dist/assets/da-BbjtxWrB.js +1 -0
  101. package/web/dist/assets/de-Dtz3Bhp_.js +1 -0
  102. package/web/dist/assets/es-BrlLPN-y.js +1 -0
  103. package/web/dist/assets/fi-CTtU6ffD.js +1 -0
  104. package/web/dist/assets/fr-B3y13c6l.js +1 -0
  105. package/web/dist/assets/hi-BmiLJVyo.js +1 -0
  106. package/web/dist/assets/{hls-3VKVEQE3-Cw5UD-5P.js → hls-3VKVEQE3-CvgC0LL8.js} +1 -1
  107. package/web/dist/assets/hu-cxF2GmF7.js +1 -0
  108. package/web/dist/assets/id-B8_X34fY.js +1 -0
  109. package/web/dist/assets/index-CiCiA-iK.js +3 -0
  110. package/web/dist/assets/index-DQcsiztI.css +1 -0
  111. package/web/dist/assets/it-BpEyHjHd.js +1 -0
  112. package/web/dist/assets/{mpegts-a5NkXKRN.js → mpegts-Djd5Q1R0.js} +1 -1
  113. package/web/dist/assets/{mpegts-LO6RVLD6-DS0PXyu3.js → mpegts-LO6RVLD6-YKZ0YjK4.js} +1 -1
  114. package/web/dist/assets/nl-B5a5pbea.js +1 -0
  115. package/web/dist/assets/ru-CVFemmuD.js +1 -0
  116. package/web/dist/assets/sv-CNh9vHHz.js +1 -0
  117. package/web/dist/assets/uk-DZ0hiYwz.js +1 -0
  118. package/web/dist/assets/vi-NT9brx3v.js +1 -0
  119. package/web/dist/assets/zh-DhgGtbYp.js +1 -0
  120. package/web/dist/index.html +36 -30
  121. package/web/dist/sw.js +23 -23
  122. package/backtoschool/dist/assets/ar-D-Ld5vpy.js +0 -1
  123. package/backtoschool/dist/assets/cs-_3DVOugI.js +0 -1
  124. package/backtoschool/dist/assets/da-tGj_pE2V.js +0 -1
  125. package/backtoschool/dist/assets/de-vZHKX4Ec.js +0 -1
  126. package/backtoschool/dist/assets/es-DXYBTMqx.js +0 -1
  127. package/backtoschool/dist/assets/fi-3Awdi4xT.js +0 -1
  128. package/backtoschool/dist/assets/fr-ChJB95FS.js +0 -1
  129. package/backtoschool/dist/assets/hi-OutMojZO.js +0 -1
  130. package/backtoschool/dist/assets/hu-fhESdEDW.js +0 -1
  131. package/backtoschool/dist/assets/id-DEiYuHM3.js +0 -1
  132. package/backtoschool/dist/assets/index-D06NfY1L.css +0 -1
  133. package/backtoschool/dist/assets/index-DBZjqzOv.js +0 -93
  134. package/backtoschool/dist/assets/it-BWr9AXgr.js +0 -1
  135. package/backtoschool/dist/assets/nl-CRyTjXF_.js +0 -1
  136. package/backtoschool/dist/assets/ru-B9x7d0z_.js +0 -1
  137. package/backtoschool/dist/assets/sv-Bj-BJsv_.js +0 -1
  138. package/backtoschool/dist/assets/uk-C1-8NwOQ.js +0 -1
  139. package/backtoschool/dist/assets/vi-z6CDEBrS.js +0 -1
  140. package/backtoschool/dist/assets/zh-DHLUyAFs.js +0 -1
  141. package/web/dist/assets/ar-D-Ld5vpy.js +0 -1
  142. package/web/dist/assets/cs-_3DVOugI.js +0 -1
  143. package/web/dist/assets/da-tGj_pE2V.js +0 -1
  144. package/web/dist/assets/de-vZHKX4Ec.js +0 -1
  145. package/web/dist/assets/es-DXYBTMqx.js +0 -1
  146. package/web/dist/assets/fi-3Awdi4xT.js +0 -1
  147. package/web/dist/assets/fr-ChJB95FS.js +0 -1
  148. package/web/dist/assets/hi-OutMojZO.js +0 -1
  149. package/web/dist/assets/hu-fhESdEDW.js +0 -1
  150. package/web/dist/assets/id-DEiYuHM3.js +0 -1
  151. package/web/dist/assets/index-BKyAT0fX.css +0 -1
  152. package/web/dist/assets/index-BqcDIh2Q.js +0 -3
  153. package/web/dist/assets/it-BWr9AXgr.js +0 -1
  154. package/web/dist/assets/nl-CRyTjXF_.js +0 -1
  155. package/web/dist/assets/ru-B9x7d0z_.js +0 -1
  156. package/web/dist/assets/sv-Bj-BJsv_.js +0 -1
  157. package/web/dist/assets/uk-C1-8NwOQ.js +0 -1
  158. package/web/dist/assets/vi-z6CDEBrS.js +0 -1
  159. package/web/dist/assets/zh-DHLUyAFs.js +0 -1
@@ -1,4 +1,19 @@
1
1
  declare const _default: {
2
+ "Supported platforms": string;
3
+ "In review": string;
4
+ "Not available": string;
5
+ "Install PWA": string;
6
+ "PWA installed": string;
7
+ "Web app": string;
8
+ "Install the web app": string;
9
+ "Keep BackToSchool on your home screen or desktop. No app store needed.": string;
10
+ "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.": string;
11
+ "Android: open your browser menu and choose Install app or Add to Home screen.": string;
12
+ "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.": string;
13
+ "You can also keep using BackToSchool in this browser.": string;
14
+ "The web app is installed. You can keep learning here.": string;
15
+ "Continue learning": string;
16
+ "The install prompt could not open. Select Web app again for installation instructions.": string;
2
17
  "No parties live right now.": string;
3
18
  "Could not refresh parties.": string;
4
19
  "Pick a server in the directory, or paste its link here.": string;
@@ -1,4 +1,6 @@
1
+ import platformMessages from "./platforms.js";
1
2
  export default {
3
+ ...platformMessages,
2
4
  "No parties live right now.": "Сейчас нет вечеринок в эфире.",
3
5
  "Could not refresh parties.": "Не удалось обновить список вечеринок.",
4
6
  "Pick a server in the directory, or paste its link here.": "Выберите сервер в каталоге или вставьте его ссылку сюда.",
@@ -1,4 +1,19 @@
1
1
  declare const _default: {
2
+ "Supported platforms": string;
3
+ "In review": string;
4
+ "Not available": string;
5
+ "Install PWA": string;
6
+ "PWA installed": string;
7
+ "Web app": string;
8
+ "Install the web app": string;
9
+ "Keep BackToSchool on your home screen or desktop. No app store needed.": string;
10
+ "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.": string;
11
+ "Android: open your browser menu and choose Install app or Add to Home screen.": string;
12
+ "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.": string;
13
+ "You can also keep using BackToSchool in this browser.": string;
14
+ "The web app is installed. You can keep learning here.": string;
15
+ "Continue learning": string;
16
+ "The install prompt could not open. Select Web app again for installation instructions.": string;
2
17
  "No parties live right now.": string;
3
18
  "Could not refresh parties.": string;
4
19
  "Pick a server in the directory, or paste its link here.": string;
@@ -1,4 +1,6 @@
1
+ import platformMessages from "./platforms.js";
1
2
  export default {
3
+ ...platformMessages,
2
4
  "No parties live right now.": "Inga partyn är live just nu.",
3
5
  "Could not refresh parties.": "Kunde inte uppdatera partyn.",
4
6
  "Pick a server in the directory, or paste its link here.": "Välj en server i katalogen eller klistra in dess länk här.",
@@ -1,4 +1,19 @@
1
1
  declare const _default: {
2
+ "Supported platforms": string;
3
+ "In review": string;
4
+ "Not available": string;
5
+ "Install PWA": string;
6
+ "PWA installed": string;
7
+ "Web app": string;
8
+ "Install the web app": string;
9
+ "Keep BackToSchool on your home screen or desktop. No app store needed.": string;
10
+ "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.": string;
11
+ "Android: open your browser menu and choose Install app or Add to Home screen.": string;
12
+ "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.": string;
13
+ "You can also keep using BackToSchool in this browser.": string;
14
+ "The web app is installed. You can keep learning here.": string;
15
+ "Continue learning": string;
16
+ "The install prompt could not open. Select Web app again for installation instructions.": string;
2
17
  "No parties live right now.": string;
3
18
  "Could not refresh parties.": string;
4
19
  "Pick a server in the directory, or paste its link here.": string;
@@ -1,4 +1,6 @@
1
+ import platformMessages from "./platforms.js";
1
2
  export default {
3
+ ...platformMessages,
2
4
  "No parties live right now.": "Зараз немає вечірок наживо.",
3
5
  "Could not refresh parties.": "Не вдалося оновити список вечірок.",
4
6
  "Pick a server in the directory, or paste its link here.": "Виберіть сервер у каталозі або вставте його посилання сюди.",
@@ -1,4 +1,19 @@
1
1
  declare const _default: {
2
+ "Supported platforms": string;
3
+ "In review": string;
4
+ "Not available": string;
5
+ "Install PWA": string;
6
+ "PWA installed": string;
7
+ "Web app": string;
8
+ "Install the web app": string;
9
+ "Keep BackToSchool on your home screen or desktop. No app store needed.": string;
10
+ "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.": string;
11
+ "Android: open your browser menu and choose Install app or Add to Home screen.": string;
12
+ "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.": string;
13
+ "You can also keep using BackToSchool in this browser.": string;
14
+ "The web app is installed. You can keep learning here.": string;
15
+ "Continue learning": string;
16
+ "The install prompt could not open. Select Web app again for installation instructions.": string;
2
17
  "No parties live right now.": string;
3
18
  "Could not refresh parties.": string;
4
19
  "Pick a server in the directory, or paste its link here.": string;
@@ -1,4 +1,6 @@
1
+ import platformMessages from "./platforms.js";
1
2
  export default {
3
+ ...platformMessages,
2
4
  "No parties live right now.": "Hiện không có buổi xem chung nào trực tiếp.",
3
5
  "Could not refresh parties.": "Không thể cập nhật các buổi xem chung.",
4
6
  "Pick a server in the directory, or paste its link here.": "Chọn máy chủ trong danh bạ hoặc dán liên kết vào đây.",
@@ -1,4 +1,19 @@
1
1
  declare const _default: {
2
+ "Supported platforms": string;
3
+ "In review": string;
4
+ "Not available": string;
5
+ "Install PWA": string;
6
+ "PWA installed": string;
7
+ "Web app": string;
8
+ "Install the web app": string;
9
+ "Keep BackToSchool on your home screen or desktop. No app store needed.": string;
10
+ "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.": string;
11
+ "Android: open your browser menu and choose Install app or Add to Home screen.": string;
12
+ "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.": string;
13
+ "You can also keep using BackToSchool in this browser.": string;
14
+ "The web app is installed. You can keep learning here.": string;
15
+ "Continue learning": string;
16
+ "The install prompt could not open. Select Web app again for installation instructions.": string;
2
17
  "No parties live right now.": string;
3
18
  "Could not refresh parties.": string;
4
19
  "Pick a server in the directory, or paste its link here.": string;
@@ -1,4 +1,6 @@
1
+ import platformMessages from "./platforms.js";
1
2
  export default {
3
+ ...platformMessages,
2
4
  "No parties live right now.": "目前没有正在直播的派对。",
3
5
  "Could not refresh parties.": "无法刷新派对列表。",
4
6
  "Pick a server in the directory, or paste its link here.": "从目录中选择服务器,或在此粘贴其链接。",
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
@@ -18,6 +18,7 @@ import { spawn, spawnSync } from "node:child_process";
18
18
  import { readFileSync } from "node:fs";
19
19
  import { Readable } from "node:stream";
20
20
  import { pipeline as pipeStream } from "node:stream/promises";
21
+ import { relative } from "node:path";
21
22
  import { SharedTranslations } from "./shared-translation.js";
22
23
  import { TranslationPasses } from "./translation-passes.js";
23
24
  import { LiveVoice, LIVE_VOICE_LANGUAGES, LIVE_VOICE_MODEL } from "./live-voice.js";
@@ -1009,6 +1010,7 @@ export function lineupEntry(listenLink, info) {
1009
1010
  return {
1010
1011
  id: info.id,
1011
1012
  name: info.name,
1013
+ ...(info.startedBy ? { startedBy: info.startedBy } : {}),
1012
1014
  kind: info.kind ?? "audio",
1013
1015
  art: absoluteArtOf(listenLink, info),
1014
1016
  about: info.about ?? "",
@@ -3568,7 +3570,21 @@ export function createHandler(engine, options) {
3568
3570
  redials: one.redials ?? 0,
3569
3571
  error: one.error ?? "",
3570
3572
  // For a list: how long it is, and which entry is on, from 0.
3571
- ...(one.playlist ? { entries: one.playlist.length, entry: one.playlistAt ?? 0 } : {}),
3573
+ ...(one.playlist ? {
3574
+ entries: one.playlist.length,
3575
+ entry: one.playlistAt ?? 0,
3576
+ playlist: one.playlist.map((source) => {
3577
+ const root = engine.snapshot(false).root;
3578
+ if (root && !isRemote(source)) {
3579
+ const served = relative(root, source).replaceAll("\\", "/");
3580
+ if (served && !served.startsWith("../"))
3581
+ return served;
3582
+ }
3583
+ const parts = source.split(/[\\/]/).filter(Boolean);
3584
+ return parts.length > 1 ? parts.slice(-2).join(" / ") : (parts[0] || "Untitled");
3585
+ }),
3586
+ live: one.live !== false,
3587
+ } : {}),
3572
3588
  // The member who put it on, when one did: theirs to take off.
3573
3589
  startedBy: one.startedBy ?? "",
3574
3590
  // A picture of it, and a line about it, where there is one.
@@ -4031,6 +4047,64 @@ export function createHandler(engine, options) {
4031
4047
  * do and which made two files at once impossible for anybody. The owner
4032
4048
  * and any member may; the caps and the throttle above say how much.
4033
4049
  */
4050
+ if (path === "/api/folders/live" && request.method === "POST") {
4051
+ if (!options.channels) {
4052
+ json(response, 503, { error: "this server cannot carry channels" });
4053
+ return;
4054
+ }
4055
+ let body = {};
4056
+ try {
4057
+ body = JSON.parse(await readBody(request));
4058
+ }
4059
+ catch {
4060
+ json(response, 400, { error: "bad JSON" });
4061
+ return;
4062
+ }
4063
+ const indices = Array.isArray(body.indices)
4064
+ ? [...new Set(body.indices.filter((one) => Number.isInteger(one) && one >= 0))]
4065
+ : [];
4066
+ if (indices.length === 0 || indices.length > 10_000) {
4067
+ json(response, 400, { error: "choose a folder with playable files" });
4068
+ return;
4069
+ }
4070
+ const tracks = engine.snapshot().tracks ?? [];
4071
+ const selected = indices
4072
+ .map((index) => ({ index, track: tracks[index], source: engine.trackPath(index) }))
4073
+ .filter((one) => Boolean(one.track && one.source && !isRemote(one.source)));
4074
+ if (selected.length !== indices.length) {
4075
+ json(response, 404, { error: "one or more folder files are no longer available" });
4076
+ return;
4077
+ }
4078
+ // `indices` already follows the server's depth-first library order.
4079
+ // Keep it intact: sorting these paths by title flattens nested folders
4080
+ // and makes a folder live start the wrong file.
4081
+ const sources = selected.map((one) => one.source);
4082
+ const channelId = cleanId(`folder-${sha("sha1").update(sources.join("\n")).digest("hex").slice(0, 12)}`);
4083
+ const name = typeof body.name === "string" && body.name.trim() !== ""
4084
+ ? body.name.trim().slice(0, 120)
4085
+ : selected[0]?.track.folder || "folder";
4086
+ if (liveBy && !options.channels.has(channelId)) {
4087
+ const refusal = memberLiveRefusal(options.channels, liveBy);
4088
+ if (refusal) {
4089
+ json(response, 429, { error: refusal });
4090
+ return;
4091
+ }
4092
+ }
4093
+ if (!options.channels.has(channelId)) {
4094
+ const started = await pullChannel(options.channels, options.ffprobe ?? ["ffprobe"], channelId, name, sources[0], [], "", { playlist: sources, live: true });
4095
+ if (!started) {
4096
+ json(response, 409, { error: "that folder is already going on the air" });
4097
+ return;
4098
+ }
4099
+ if (liveBy)
4100
+ options.channels.info(channelId).startedBy = liveBy;
4101
+ }
4102
+ options.channels.keep(channelId);
4103
+ options.rememberChannels?.(rememberedNow(options.channels));
4104
+ void options.live?.announce?.();
4105
+ json(response, 200, { channel: channelId, name, video: options.channels.kindOf(channelId) !== "audio" });
4106
+ return;
4107
+ }
4034
4108
  const trackLive = /^\/api\/tracks\/(\d+)\/live$/.exec(path);
4035
4109
  if (trackLive && request.method === "POST") {
4036
4110
  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: 500;
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: 10000;
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: 500 },
9
- { id: "week", name: "Week", days: 7, priceCents: 2500 },
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;
@@ -1,5 +1,5 @@
1
1
  import type { Queryable } from "./follows.ts";
2
- export declare const FREE_UPGRADE_SESSIONS = 5;
2
+ export declare const FREE_UPGRADE_SESSIONS = 10;
3
3
  export declare const FREE_UPGRADE_RECONNECT_SECONDS = 90;
4
4
  export interface UpgradeAllowance {
5
5
  limit: number;
@@ -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;
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 BETWEEN 1 AND 5),
20
- sessions JSONB NOT NULL, PRIMARY KEY (by_account, day))`).then(() => undefined)
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nixamp",
3
- "version": "0.28.2",
3
+ "version": "0.28.4",
4
4
  "description": "It really whips the terminal's ass. A Winamp-shaped audio player for your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
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/locales/ar.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "لا توجد جلسات مباشرة الآن.",
4
6
  "Could not refresh parties.": "تعذر تحديث الجلسات.",
5
7
  "Pick a server in the directory, or paste its link here.": "اختر خادمًا من الدليل أو الصق رابطه هنا.",
package/src/locales/cs.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Právě neprobíhají žádné párty.",
4
6
  "Could not refresh parties.": "Párty se nepodařilo aktualizovat.",
5
7
  "Pick a server in the directory, or paste its link here.": "Vyberte server v seznamu nebo sem vložte jeho odkaz.",
package/src/locales/da.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Ingen fester er live lige nu.",
4
6
  "Could not refresh parties.": "Kunne ikke opdatere festerne.",
5
7
  "Pick a server in the directory, or paste its link here.": "Vælg en server i oversigten, eller indsæt dens link her.",
package/src/locales/de.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Gerade sind keine Partys live.",
4
6
  "Could not refresh parties.": "Partys konnten nicht aktualisiert werden.",
5
7
  "Pick a server in the directory, or paste its link here.": "Wähle einen Server im Verzeichnis oder füge seinen Link hier ein.",
package/src/locales/en.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  /* Shared UI messages. English is both the default and the fallback. */
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "No parties live right now.",
4
6
  "Could not refresh parties.": "Could not refresh parties.",
5
7
  "Pick a server in the directory, or paste its link here.": "Pick a server in the directory, or paste its link here.",
package/src/locales/es.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "No hay fiestas en directo ahora.",
4
6
  "Could not refresh parties.": "No se pudieron actualizar las fiestas.",
5
7
  "Pick a server in the directory, or paste its link here.": "Elige un servidor del directorio o pega su enlace aquí.",
package/src/locales/fi.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Yhtään katselubilettä ei ole nyt käynnissä.",
4
6
  "Could not refresh parties.": "Katselubileitä ei voitu päivittää.",
5
7
  "Pick a server in the directory, or paste its link here.": "Valitse palvelin hakemistosta tai liitä sen linkki tähän.",
package/src/locales/fr.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Aucune soirée en direct pour le moment.",
4
6
  "Could not refresh parties.": "Impossible d’actualiser les soirées.",
5
7
  "Pick a server in the directory, or paste its link here.": "Choisissez un serveur dans l’annuaire ou collez son lien ici.",
package/src/locales/hi.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "अभी कोई पार्टी लाइव नहीं है।",
4
6
  "Could not refresh parties.": "पार्टियाँ अपडेट नहीं हो सकीं।",
5
7
  "Pick a server in the directory, or paste its link here.": "डायरेक्टरी में सर्वर चुनें या उसका लिंक यहाँ पेस्ट करें।",
package/src/locales/hu.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Jelenleg nincs élő közös nézés.",
4
6
  "Could not refresh parties.": "Nem sikerült frissíteni a közös nézéseket.",
5
7
  "Pick a server in the directory, or paste its link here.": "Válassz egy szervert a listából, vagy illeszd be ide a hivatkozását.",
package/src/locales/id.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Belum ada pesta yang sedang live.",
4
6
  "Could not refresh parties.": "Tidak dapat memperbarui pesta.",
5
7
  "Pick a server in the directory, or paste its link here.": "Pilih server di direktori atau tempel tautannya di sini.",
package/src/locales/it.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Nessun party in diretta al momento.",
4
6
  "Could not refresh parties.": "Impossibile aggiornare i party.",
5
7
  "Pick a server in the directory, or paste its link here.": "Scegli un server dalla directory o incolla qui il suo link.",
package/src/locales/nl.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Er zijn nu geen feestjes live.",
4
6
  "Could not refresh parties.": "Feestjes konden niet worden bijgewerkt.",
5
7
  "Pick a server in the directory, or paste its link here.": "Kies een server in de lijst of plak hier de link.",
@@ -0,0 +1,18 @@
1
+ /* English fallback for BackToSchool platform and installation messages. */
2
+ export default {
3
+ "Supported platforms": "Supported platforms",
4
+ "In review": "In review",
5
+ "Not available": "Not available",
6
+ "Install PWA": "Install PWA",
7
+ "PWA installed": "PWA installed",
8
+ "Web app": "Web app",
9
+ "Install the web app": "Install the web app",
10
+ "Keep BackToSchool on your home screen or desktop. No app store needed.": "Keep BackToSchool on your home screen or desktop. No app store needed.",
11
+ "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.": "iPhone or iPad: open this site in Safari, tap Share, then Add to Home Screen.",
12
+ "Android: open your browser menu and choose Install app or Add to Home screen.": "Android: open your browser menu and choose Install app or Add to Home screen.",
13
+ "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.": "Desktop: look for Install in the address bar or browser menu. The option depends on your browser.",
14
+ "You can also keep using BackToSchool in this browser.": "You can also keep using BackToSchool in this browser.",
15
+ "The web app is installed. You can keep learning here.": "The web app is installed. You can keep learning here.",
16
+ "Continue learning": "Continue learning",
17
+ "The install prompt could not open. Select Web app again for installation instructions.": "The install prompt could not open. Select Web app again for installation instructions.",
18
+ };
package/src/locales/ru.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Сейчас нет вечеринок в эфире.",
4
6
  "Could not refresh parties.": "Не удалось обновить список вечеринок.",
5
7
  "Pick a server in the directory, or paste its link here.": "Выберите сервер в каталоге или вставьте его ссылку сюда.",
package/src/locales/sv.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Inga partyn är live just nu.",
4
6
  "Could not refresh parties.": "Kunde inte uppdatera partyn.",
5
7
  "Pick a server in the directory, or paste its link here.": "Välj en server i katalogen eller klistra in dess länk här.",
package/src/locales/uk.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Зараз немає вечірок наживо.",
4
6
  "Could not refresh parties.": "Не вдалося оновити список вечірок.",
5
7
  "Pick a server in the directory, or paste its link here.": "Виберіть сервер у каталозі або вставте його посилання сюди.",
package/src/locales/vi.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "Hiện không có buổi xem chung nào trực tiếp.",
4
6
  "Could not refresh parties.": "Không thể cập nhật các buổi xem chung.",
5
7
  "Pick a server in the directory, or paste its link here.": "Chọn máy chủ trong danh bạ hoặc dán liên kết vào đây.",
package/src/locales/zh.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import platformMessages from "./platforms.ts";
1
2
  import type { Catalogue } from "../i18n.ts";
2
3
  export default {
4
+ ...platformMessages,
3
5
  "No parties live right now.": "目前没有正在直播的派对。",
4
6
  "Could not refresh parties.": "无法刷新派对列表。",
5
7
  "Pick a server in the directory, or paste its link here.": "从目录中选择服务器,或在此粘贴其链接。",
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;