fluncle 0.201.0 → 0.203.0

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 (2) hide show
  1. package/bin/fluncle.mjs +126 -56
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -367,6 +367,55 @@ var require_main = __commonJS((exports, module) => {
367
367
  module.exports = DotenvModule;
368
368
  });
369
369
 
370
+ // src/env.ts
371
+ import { homedir } from "node:os";
372
+ import { join } from "node:path";
373
+ function loadEnv(keys) {
374
+ loadConfig();
375
+ const result = {};
376
+ const missing = [];
377
+ for (const key of keys) {
378
+ const value = process.env[key];
379
+ if (value === undefined) {
380
+ missing.push(key);
381
+ continue;
382
+ }
383
+ result[key] = value;
384
+ }
385
+ if (missing.length > 0) {
386
+ throw new Error(`Missing required env vars: ${missing.join(", ")}`);
387
+ }
388
+ return result;
389
+ }
390
+ function getApiBaseUrl() {
391
+ loadConfig();
392
+ return (process.env.FLUNCLE_API_BASE_URL ?? "https://www.fluncle.com").replace(/\/+$/, "");
393
+ }
394
+ function loadConfig() {
395
+ const profile = getEnvProfile();
396
+ if (loadedProfile === profile) {
397
+ return;
398
+ }
399
+ loadedProfile = profile;
400
+ if (false) {}
401
+ import_dotenv2.config({ path: join(homedir(), `.config/fluncle/.env.${profile}`), quiet: true });
402
+ }
403
+ function getEnvProfile() {
404
+ const profile = process.env.FLUNCLE_ENV ?? defaultEnvProfile;
405
+ if (!isEnvProfile2(profile)) {
406
+ throw new Error(`Unknown env profile: ${profile}. Expected local or production.`);
407
+ }
408
+ return profile;
409
+ }
410
+ function isEnvProfile2(value) {
411
+ return envProfiles2.includes(value);
412
+ }
413
+ var import_dotenv2, envProfiles2, defaultEnvProfile = "production", loadedProfile;
414
+ var init_env = __esm(() => {
415
+ import_dotenv2 = __toESM(require_main(), 1);
416
+ envProfiles2 = ["local", "production"];
417
+ });
418
+
370
419
  // ../../packages/contracts/src/util.ts
371
420
  function formatDuration(durationMs) {
372
421
  const totalSeconds = Math.round(durationMs / 1000);
@@ -561,7 +610,7 @@ function parseVersion(version) {
561
610
  var currentVersion;
562
611
  var init_version = __esm(() => {
563
612
  init_output();
564
- currentVersion = "0.201.0".trim() ? "0.201.0".trim() : "0.1.0";
613
+ currentVersion = "0.203.0".trim() ? "0.203.0".trim() : "0.1.0";
565
614
  });
566
615
 
567
616
  // src/update-notifier.ts
@@ -573,8 +622,8 @@ __export(exports_update_notifier, {
573
622
  detectInstallMethod: () => detectInstallMethod
574
623
  });
575
624
  import { mkdir, readFile, writeFile } from "node:fs/promises";
576
- import { homedir, platform } from "node:os";
577
- import { dirname, join, sep } from "node:path";
625
+ import { homedir as homedir2, platform } from "node:os";
626
+ import { dirname, join as join2, sep } from "node:path";
578
627
  import { fileURLToPath } from "node:url";
579
628
  async function notifyIfUpdateAvailable(args) {
580
629
  try {
@@ -686,8 +735,8 @@ async function writeCache(state) {
686
735
  } catch {}
687
736
  }
688
737
  function cacheFilePath() {
689
- const base = process.env.XDG_CACHE_HOME?.trim() || platform() === "win32" && process.env.LOCALAPPDATA?.trim() || join(homedir(), ".config");
690
- return join(base, "fluncle", "update-check.json");
738
+ const base = process.env.XDG_CACHE_HOME?.trim() || platform() === "win32" && process.env.LOCALAPPDATA?.trim() || join2(homedir2(), ".config");
739
+ return join2(base, "fluncle", "update-check.json");
691
740
  }
692
741
  function buildNotice(current, latest) {
693
742
  const method = detectInstallMethod({ entry: entryPath(), execPath: process.execPath || "" });
@@ -747,55 +796,6 @@ var init_update_notifier = __esm(() => {
747
796
  cacheTtlMs = 24 * 60 * 60 * 1000;
748
797
  });
749
798
 
750
- // src/env.ts
751
- import { homedir as homedir2 } from "node:os";
752
- import { join as join2 } from "node:path";
753
- function loadEnv(keys) {
754
- loadConfig();
755
- const result = {};
756
- const missing = [];
757
- for (const key of keys) {
758
- const value = process.env[key];
759
- if (value === undefined) {
760
- missing.push(key);
761
- continue;
762
- }
763
- result[key] = value;
764
- }
765
- if (missing.length > 0) {
766
- throw new Error(`Missing required env vars: ${missing.join(", ")}`);
767
- }
768
- return result;
769
- }
770
- function getApiBaseUrl() {
771
- loadConfig();
772
- return (process.env.FLUNCLE_API_BASE_URL ?? "https://www.fluncle.com").replace(/\/+$/, "");
773
- }
774
- function loadConfig() {
775
- const profile = getEnvProfile();
776
- if (loadedProfile === profile) {
777
- return;
778
- }
779
- loadedProfile = profile;
780
- if (false) {}
781
- import_dotenv2.config({ path: join2(homedir2(), `.config/fluncle/.env.${profile}`), quiet: true });
782
- }
783
- function getEnvProfile() {
784
- const profile = process.env.FLUNCLE_ENV ?? defaultEnvProfile;
785
- if (!isEnvProfile2(profile)) {
786
- throw new Error(`Unknown env profile: ${profile}. Expected local or production.`);
787
- }
788
- return profile;
789
- }
790
- function isEnvProfile2(value) {
791
- return envProfiles2.includes(value);
792
- }
793
- var import_dotenv2, envProfiles2, defaultEnvProfile = "production", loadedProfile;
794
- var init_env = __esm(() => {
795
- import_dotenv2 = __toESM(require_main(), 1);
796
- envProfiles2 = ["local", "production"];
797
- });
798
-
799
799
  // src/user-token.ts
800
800
  import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
801
801
  import { homedir as homedir3 } from "node:os";
@@ -2452,7 +2452,7 @@ function parseVersion2(version) {
2452
2452
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
2453
2453
  var init_version2 = __esm(() => {
2454
2454
  init_output();
2455
- currentVersion2 = "0.201.0".trim() ? "0.201.0".trim() : "0.1.0";
2455
+ currentVersion2 = "0.203.0".trim() ? "0.203.0".trim() : "0.1.0";
2456
2456
  });
2457
2457
 
2458
2458
  // ../../packages/registry/src/index.ts
@@ -3258,7 +3258,7 @@ var init_src = __esm(() => {
3258
3258
  {
3259
3259
  command: "ssh rave.fluncle.com",
3260
3260
  exposedContent: [
3261
- "the rave terminal TUI: Latest bangers, Fresh releases, Artist archive, Sonic galaxies, Mixtape archive, Random banger, Submit, Subscribe, Install CLI, System status, About",
3261
+ "the rave terminal TUI: Latest findings, Fresh releases, Artist archive, Sonic galaxies, Mixtape archive, Random banger, Submit, Subscribe, Install CLI, System status, About",
3262
3262
  "deep-register one-shots: `ssh rave.fluncle.com latest|fresh|random`"
3263
3263
  ],
3264
3264
  kind: "ssh",
@@ -6710,6 +6710,7 @@ __export(exports_admin_catalogue, {
6710
6710
  verifyCaptureCommand: () => verifyCaptureCommand,
6711
6711
  setTrackDismissedCommand: () => setTrackDismissedCommand,
6712
6712
  requeueUnmatchedCommand: () => requeueUnmatchedCommand,
6713
+ requeueAnchorCommand: () => requeueAnchorCommand,
6713
6714
  listUnverifiedCapturesCommand: () => listUnverifiedCapturesCommand,
6714
6715
  forceCaptureCommand: () => forceCaptureCommand,
6715
6716
  flagWrongAudioCommand: () => flagWrongAudioCommand,
@@ -6749,6 +6750,11 @@ async function clearWrongAudioCommand(trackId) {
6749
6750
  async function requeueUnmatchedCommand() {
6750
6751
  return adminApiPost("/api/v1/admin/catalogue/captures/requeue-unmatched", {});
6751
6752
  }
6753
+ async function requeueAnchorCommand(trackIds) {
6754
+ return adminApiPost("/api/v1/admin/catalogue/anchor/requeue", {
6755
+ trackIds
6756
+ });
6757
+ }
6752
6758
  async function forceCaptureCommand(trackId) {
6753
6759
  return adminApiPost("/api/v1/admin/catalogue/force-capture", {
6754
6760
  trackId
@@ -9362,6 +9368,60 @@ function isEnvProfile(value) {
9362
9368
  var spotifyPlaylistUrl = "https://open.spotify.com/playlist/1m5LADqpLjiBERdtqrIiL0";
9363
9369
  var telegramUrl = "https://t.me/fluncle";
9364
9370
 
9371
+ // src/live.ts
9372
+ init_env();
9373
+ var NEBULA_VIOLET = "\x1B[38;2;171;123;255m";
9374
+ var RESET = "\x1B[0m";
9375
+ var TIMEOUT_MS = 1500;
9376
+ function shouldSkip(args) {
9377
+ if (process.env.FLUNCLE_NO_LIVE_CALLOUT === "1") {
9378
+ return true;
9379
+ }
9380
+ if (process.env.CI) {
9381
+ return true;
9382
+ }
9383
+ if (args.length === 0) {
9384
+ return true;
9385
+ }
9386
+ const first = args[0];
9387
+ if (first === "admin" || first === "help") {
9388
+ return true;
9389
+ }
9390
+ return args.some((arg) => arg === "--json" || arg === "--help" || arg === "-h" || arg === "--version" || arg === "-V");
9391
+ }
9392
+ function displayUrl(url) {
9393
+ return url.replace(/^https?:\/\/(www\.)?/, "");
9394
+ }
9395
+ async function maybePrintLiveCallout(args) {
9396
+ if (shouldSkip(args) || process.stdout.isTTY !== true) {
9397
+ return;
9398
+ }
9399
+ try {
9400
+ const controller = new AbortController;
9401
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
9402
+ let data;
9403
+ try {
9404
+ const response = await fetch(`${getApiBaseUrl()}/api/v1/status`, {
9405
+ signal: controller.signal
9406
+ });
9407
+ if (!response.ok) {
9408
+ return;
9409
+ }
9410
+ data = await response.json();
9411
+ } finally {
9412
+ clearTimeout(timer);
9413
+ }
9414
+ const live = data.live;
9415
+ if (!live?.on) {
9416
+ return;
9417
+ }
9418
+ const text = `On the decks, live now: ${displayUrl(live.url)}`;
9419
+ const line = process.env.NO_COLOR ? text : `${NEBULA_VIOLET}${text}${RESET}`;
9420
+ console.log(`${line}
9421
+ `);
9422
+ } catch {}
9423
+ }
9424
+
9365
9425
  // src/output.ts
9366
9426
  import { writeSync } from "node:fs";
9367
9427
  var EAGAIN_WAIT = new Int32Array(new SharedArrayBuffer(4));
@@ -9440,6 +9500,7 @@ async function main(args = process.argv.slice(2)) {
9440
9500
  program2.outputHelp();
9441
9501
  return;
9442
9502
  }
9503
+ await maybePrintLiveCallout(args);
9443
9504
  try {
9444
9505
  assertParseArgsCompatiblePositionals(args);
9445
9506
  assertParseArgsCompatibleOptionValues(args);
@@ -10082,6 +10143,15 @@ function addAdminCommands(program2) {
10082
10143
  }
10083
10144
  console.log(cleared ? `Kept ${trackId}. Its audio re-embeds and rejoins the ranking on the next sweep.` : `${trackId} was not quarantined \u2014 nothing to clear.`);
10084
10145
  });
10146
+ catalogue.command("requeue-anchor").description("Clear rows' anchor re-ask backoff so the next tick retries them (operator)").argument("<trackIds...>", "The catalogue track id(s) to requeue (up to 250)").option("--json", "Print JSON", false).action(async (trackIds, options) => {
10147
+ const { requeueAnchorCommand: requeueAnchorCommand2 } = await Promise.resolve().then(() => (init_admin_catalogue(), exports_admin_catalogue));
10148
+ const { requeued } = await requeueAnchorCommand2(trackIds);
10149
+ if (options.json) {
10150
+ printJson({ ok: true, requeued });
10151
+ return;
10152
+ }
10153
+ console.log(`Re-queued ${requeued} of ${trackIds.length} row(s) \u2014 the next anchor tick picks them up at their real priority.`);
10154
+ });
10085
10155
  catalogue.command("requeue-unmatched").description("Re-queue terminal-unmatched captures after a matcher improvement (operator)").option("--json", "Print JSON", false).action(async (options) => {
10086
10156
  const { requeueUnmatchedCommand: requeueUnmatchedCommand2 } = await Promise.resolve().then(() => (init_admin_catalogue(), exports_admin_catalogue));
10087
10157
  const { requeued, skippedVetoed } = await requeueUnmatchedCommand2();
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "url": "git+https://github.com/mauricekleine/fluncle.git"
32
32
  },
33
33
  "type": "module",
34
- "version": "0.201.0"
34
+ "version": "0.203.0"
35
35
  }