libroadcast-cli 2.3.0 → 2.4.1

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.
@@ -1,41 +1,37 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.checkTokenScopes = exports.translateRoundsToFix = exports.handleApiResponse = exports.msgCommonErrorHelp = exports.sleep = exports.client = exports.commands = exports.Command = exports.packageJson = exports.args = exports.LICHESS_TOKEN = void 0;
7
- const node_process_1 = require("node:process");
8
- const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
9
- const colors_1 = __importDefault(require("./colors"));
10
- const node_fs_1 = require("node:fs");
11
- const node_path_1 = require("node:path");
12
- const delay_1 = require("../cmd/delay");
13
- const setPGN_1 = require("../cmd/setPGN");
14
- const setPGNMulti_1 = require("../cmd/setPGNMulti");
15
- const setLichessGames_1 = require("../cmd/setLichessGames");
16
- const fixSchedule_1 = require("../cmd/fixSchedule");
17
- const startsPrevious_1 = require("../cmd/startsPrevious");
18
- const period_1 = require("../cmd/period");
19
- const score_1 = require("../cmd/score");
20
- const push_1 = require("../cmd/push");
21
- const login_1 = require("../cmd/login");
22
- const credentials_1 = require("./credentials");
1
+ import { argv } from "node:process";
2
+ import createClient from "openapi-fetch";
3
+ import cl from "./colors.js";
4
+ const __dirname = import.meta.dirname;
5
+ import { readFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { delayCommand } from "../cmd/delay.js";
8
+ import { setPGNCommand } from "../cmd/setPGN.js";
9
+ import { setPGNMultiCommand } from "../cmd/setPGNMulti.js";
10
+ import { setLichessGamesCommand } from "../cmd/setLichessGames.js";
11
+ import { fixScheduleCommand } from "../cmd/fixSchedule.js";
12
+ import { startsPreviousCommand } from "../cmd/startsPrevious.js";
13
+ import { periodCommand } from "../cmd/period.js";
14
+ import { scoreCommand } from "../cmd/score.js";
15
+ import { pushCommand } from "../cmd/push.js";
16
+ import { pushFilterIDCommand } from "../cmd/pushFilterID.js";
17
+ import { loginCommand } from "../cmd/login.js";
18
+ import { getStoredCredentials } from "./credentials.js";
23
19
  const getToken = () => {
24
- const stored = (0, credentials_1.getStoredCredentials)();
20
+ const stored = getStoredCredentials();
25
21
  return stored?.lichessToken;
26
22
  };
27
23
  const getDomain = () => {
28
- const stored = (0, credentials_1.getStoredCredentials)();
24
+ const stored = getStoredCredentials();
29
25
  if (stored?.lichessDomain) {
30
26
  return stored.lichessDomain.replace(/\/$/, "") + "/";
31
27
  }
32
28
  return "https://lichess.org/";
33
29
  };
34
- exports.LICHESS_TOKEN = getToken();
30
+ export const LICHESS_TOKEN = getToken();
35
31
  const LICHESS_DOMAIN = getDomain();
36
- exports.args = node_process_1.argv.slice(2);
37
- exports.packageJson = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "../../package.json"), "utf-8"));
38
- var Command;
32
+ export const args = argv.slice(2);
33
+ export const packageJson = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
34
+ export var Command;
39
35
  (function (Command) {
40
36
  Command["Login"] = "login";
41
37
  Command["Delay"] = "delay";
@@ -47,50 +43,49 @@ var Command;
47
43
  Command["Period"] = "period";
48
44
  Command["Score"] = "score";
49
45
  Command["Push"] = "push";
50
- })(Command || (exports.Command = Command = {}));
51
- exports.commands = new Map([
52
- [Command.Login, login_1.loginCommand],
53
- [Command.Delay, delay_1.delayCommand],
54
- [Command.SetPGN, setPGN_1.setPGNCommand],
55
- [Command.SetPGNMulti, setPGNMulti_1.setPGNMultiCommand],
56
- [Command.SetLichessGames, setLichessGames_1.setLichessGamesCommand],
57
- [Command.FixSchedule, fixSchedule_1.fixScheduleCommand],
58
- [Command.StartsPrevious, startsPrevious_1.startsPreviousCommand],
59
- [Command.Period, period_1.periodCommand],
60
- [Command.Score, score_1.scoreCommand],
61
- [Command.Push, push_1.pushCommand],
46
+ Command["PushFilterID"] = "pushFilterID";
47
+ })(Command || (Command = {}));
48
+ export const commands = new Map([
49
+ [Command.Login, loginCommand],
50
+ [Command.Delay, delayCommand],
51
+ [Command.SetPGN, setPGNCommand],
52
+ [Command.SetPGNMulti, setPGNMultiCommand],
53
+ [Command.SetLichessGames, setLichessGamesCommand],
54
+ [Command.FixSchedule, fixScheduleCommand],
55
+ [Command.StartsPrevious, startsPreviousCommand],
56
+ [Command.Period, periodCommand],
57
+ [Command.Score, scoreCommand],
58
+ [Command.Push, pushCommand],
59
+ [Command.PushFilterID, pushFilterIDCommand],
62
60
  ]);
63
- exports.client = (0, openapi_fetch_1.default)({
61
+ export const client = createClient({
64
62
  baseUrl: LICHESS_DOMAIN,
65
63
  headers: {
66
- Authorization: `Bearer ${exports.LICHESS_TOKEN}`,
64
+ Authorization: `Bearer ${LICHESS_TOKEN}`,
67
65
  Accept: "application/json",
68
- "User-Agent": exports.packageJson.name + "/" + exports.packageJson.version,
66
+ "User-Agent": packageJson.name + "/" + packageJson.version,
69
67
  },
70
68
  });
71
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
72
- exports.sleep = sleep;
73
- const msgCommonErrorHelp = (msg) => {
74
- console.error(colors_1.default.red(msg));
75
- console.info(colors_1.default.blue("Use --help to see usage."));
69
+ export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
70
+ export const msgCommonErrorHelp = (msg) => {
71
+ console.error(cl.red(msg));
72
+ console.info(cl.blue("Use --help to see usage."));
76
73
  };
77
- exports.msgCommonErrorHelp = msgCommonErrorHelp;
78
- const handleApiResponse = async (promise, successMsg, errorContext) => {
74
+ export const handleApiResponse = async (promise, successMsg, errorContext) => {
79
75
  try {
80
76
  const response = await promise;
81
77
  if (response.response.ok) {
82
- console.log(colors_1.default.green(successMsg));
78
+ console.log(cl.green(successMsg));
83
79
  }
84
80
  else {
85
- console.error(colors_1.default.red(`${errorContext}: ${colors_1.default.whiteBold(response.response.statusText)}`));
81
+ console.error(cl.red(`${errorContext}: ${cl.whiteBold(response.response.statusText)}`));
86
82
  }
87
83
  }
88
84
  catch (error) {
89
- console.error(colors_1.default.red(errorContext), error);
85
+ console.error(cl.red(errorContext), error);
90
86
  }
91
87
  };
92
- exports.handleApiResponse = handleApiResponse;
93
- const translateRoundsToFix = (arg) => {
88
+ export const translateRoundsToFix = (arg) => {
94
89
  const rounds = [];
95
90
  const parts = arg.split(",");
96
91
  for (const part of parts) {
@@ -121,32 +116,30 @@ const translateRoundsToFix = (arg) => {
121
116
  }
122
117
  return [...new Set(rounds)];
123
118
  };
124
- exports.translateRoundsToFix = translateRoundsToFix;
125
- const checkTokenScopes = async (modRequired) => {
119
+ export const checkTokenScopes = async (modRequired) => {
126
120
  const requiredScopes = ["study:read", "study:write"];
127
121
  if (modRequired)
128
122
  requiredScopes.push("web:mod");
129
- const stored = (0, credentials_1.getStoredCredentials)();
123
+ const stored = getStoredCredentials();
130
124
  let scopes = [];
131
125
  if (stored?.scopes) {
132
126
  scopes = stored.scopes;
133
127
  }
134
128
  else {
135
- const response = await exports.client.POST("/api/token/test", {
129
+ const response = await client.POST("/api/token/test", {
136
130
  headers: {
137
131
  "Content-Type": "text/plain",
138
132
  },
139
- body: exports.LICHESS_TOKEN,
133
+ body: LICHESS_TOKEN,
140
134
  bodySerializer: (body) => body,
141
135
  });
142
136
  const data = await response.data;
143
- const scopesStr = data?.[exports.LICHESS_TOKEN]?.scopes;
137
+ const scopesStr = data?.[LICHESS_TOKEN]?.scopes;
144
138
  scopes = scopesStr ? scopesStr.split(",").map((s) => s.trim()) : [];
145
139
  }
146
140
  const missingScopes = requiredScopes.filter((scope) => !scopes.includes(scope));
147
141
  if (missingScopes.length > 0) {
148
- console.error(colors_1.default.red(`Error: Missing required token scopes: ${missingScopes.join(", ")}`));
142
+ console.error(cl.red(`Error: Missing required token scopes: ${missingScopes.join(", ")}`));
149
143
  process.exit(1);
150
144
  }
151
145
  };
152
- exports.checkTokenScopes = checkTokenScopes;
@@ -1,45 +1,39 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchTokenScopes = exports.clearCredentials = exports.saveCredentials = exports.getStoredCredentials = void 0;
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
- const node_os_1 = require("node:os");
7
- const CONFIG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".libroadcast");
8
- const CREDENTIALS_FILE = (0, node_path_1.join)(CONFIG_DIR, "credentials.json");
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const CONFIG_DIR = join(homedir(), ".libroadcast");
5
+ const CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
9
6
  const ensureConfigDir = () => {
10
- if (!(0, node_fs_1.existsSync)(CONFIG_DIR)) {
11
- (0, node_fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
7
+ if (!existsSync(CONFIG_DIR)) {
8
+ mkdirSync(CONFIG_DIR, { recursive: true });
12
9
  }
13
10
  };
14
- const getStoredCredentials = () => {
11
+ export const getStoredCredentials = () => {
15
12
  try {
16
- if (!(0, node_fs_1.existsSync)(CREDENTIALS_FILE)) {
13
+ if (!existsSync(CREDENTIALS_FILE)) {
17
14
  return null;
18
15
  }
19
- const content = (0, node_fs_1.readFileSync)(CREDENTIALS_FILE, "utf-8");
16
+ const content = readFileSync(CREDENTIALS_FILE, "utf-8");
20
17
  return JSON.parse(content);
21
18
  }
22
19
  catch (error) {
23
20
  return null;
24
21
  }
25
22
  };
26
- exports.getStoredCredentials = getStoredCredentials;
27
- const saveCredentials = (credentials) => {
23
+ export const saveCredentials = (credentials) => {
28
24
  ensureConfigDir();
29
- (0, node_fs_1.writeFileSync)(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), "utf-8");
25
+ writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), "utf-8");
30
26
  };
31
- exports.saveCredentials = saveCredentials;
32
- const clearCredentials = () => {
27
+ export const clearCredentials = () => {
33
28
  try {
34
- if ((0, node_fs_1.existsSync)(CREDENTIALS_FILE)) {
35
- (0, node_fs_1.unlinkSync)(CREDENTIALS_FILE);
29
+ if (existsSync(CREDENTIALS_FILE)) {
30
+ unlinkSync(CREDENTIALS_FILE);
36
31
  }
37
32
  }
38
33
  catch (error) {
39
34
  }
40
35
  };
41
- exports.clearCredentials = clearCredentials;
42
- const fetchTokenScopes = async (token, domain) => {
36
+ export const fetchTokenScopes = async (token, domain) => {
43
37
  try {
44
38
  const normalizedDomain = domain.replace(/\/$/, "") + "/";
45
39
  const url = `${normalizedDomain}api/token/test`;
@@ -61,4 +55,3 @@ const fetchTokenScopes = async (token, domain) => {
61
55
  throw new Error(`Failed to fetch token scopes: ${error instanceof Error ? error.message : String(error)}`);
62
56
  }
63
57
  };
64
- exports.fetchTokenScopes = fetchTokenScopes;
@@ -1,12 +1,6 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getBroadcastRound = exports.getBroadcast = void 0;
7
- const commandHandler_1 = require("./commandHandler");
8
- const colors_1 = __importDefault(require("./colors"));
9
- const getBroadcast = (broadcastId) => commandHandler_1.client
1
+ import { client } from "./commandHandler.js";
2
+ import cl from "./colors.js";
3
+ export const getBroadcast = (broadcastId) => client
10
4
  .GET("/api/broadcast/{broadcastTournamentId}", {
11
5
  params: {
12
6
  path: { broadcastTournamentId: broadcastId },
@@ -14,11 +8,10 @@ const getBroadcast = (broadcastId) => commandHandler_1.client
14
8
  })
15
9
  .then((response) => response.data)
16
10
  .catch((error) => {
17
- console.error(colors_1.default.red("Error fetching broadcast:"), error);
11
+ console.error(cl.red("Error fetching broadcast:"), error);
18
12
  return null;
19
13
  });
20
- exports.getBroadcast = getBroadcast;
21
- const getBroadcastRound = (roundId) => commandHandler_1.client
14
+ export const getBroadcastRound = (roundId) => client
22
15
  .GET("/api/broadcast/{broadcastTournamentSlug}/{broadcastRoundSlug}/{broadcastRoundId}", {
23
16
  params: {
24
17
  path: {
@@ -30,7 +23,6 @@ const getBroadcastRound = (roundId) => commandHandler_1.client
30
23
  })
31
24
  .then((response) => response.data?.round)
32
25
  .catch((error) => {
33
- console.error(colors_1.default.red("Error fetching broadcast round:"), error);
26
+ console.error(cl.red("Error fetching broadcast round:"), error);
34
27
  return null;
35
28
  });
36
- exports.getBroadcastRound = getBroadcastRound;
@@ -1,91 +1,92 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.includeHelp = exports.showHelp = void 0;
7
- const commandHandler_1 = require("./commandHandler");
8
- const colors_1 = __importDefault(require("./colors"));
1
+ import { Command } from "./commandHandler.js";
2
+ import cl from "./colors.js";
9
3
  const helpLogin = [
10
- ` ${colors_1.default.underItalic("login [--logout]")}`,
11
- ` ${colors_1.default.gray("Save your Lichess token and domain for future use.")}`,
12
- ` ${colors_1.default.gray("This allows you to use the CLI without setting environment variables.")}`,
13
- ` ${colors_1.default.bold("Options:")}`,
14
- ` --logout (-lo) ${colors_1.default.gray("Clear saved credentials and log out.")}`,
4
+ ` ${cl.underItalic("login [--logout]")}`,
5
+ ` ${cl.gray("Save your Lichess token and domain for future use.")}`,
6
+ ` ${cl.gray("This allows you to use the CLI without setting environment variables.")}`,
7
+ ` ${cl.bold("Options:")}`,
8
+ ` --logout (-lo) ${cl.gray("Clear saved credentials and log out.")}`,
15
9
  ].join("\n");
16
10
  const helpDelay = [
17
- ` ${colors_1.default.underItalic("delay <broadcastId> <delayInSeconds> [--onlyDelay] [--noDelay] [--rounds <roundsToFix>]")} `,
18
- ` ${colors_1.default.gray("Sets the delay for all rounds in the specified broadcast.")}`,
19
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray("The delay is specified in seconds. (max 3600 seconds = 1 hour)")}`,
20
- ` ${colors_1.default.bold("Options:")}`,
21
- ` --onlyDelay ${colors_1.default.gray("Set only the delay without changing the start time.")}`,
22
- ` --noDelay ${colors_1.default.gray("Do not modify the delay, only adjust the start time.")}`,
23
- ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
11
+ ` ${cl.underItalic("delay <broadcastId> <delayInSeconds> [--onlyDelay] [--noDelay] [--rounds <roundsToFix>]")} `,
12
+ ` ${cl.gray("Sets the delay for all rounds in the specified broadcast.")}`,
13
+ ` ${cl.bold("Note:")} ${cl.gray("The delay is specified in seconds. (max 3600 seconds = 1 hour)")}`,
14
+ ` ${cl.bold("Options:")}`,
15
+ ` --onlyDelay ${cl.gray("Set only the delay without changing the start time.")}`,
16
+ ` --noDelay ${cl.gray("Do not modify the delay, only adjust the start time.")}`,
17
+ ` --rounds <roundsToFix> ${cl.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
24
18
  ].join("\n");
25
19
  const helpSetPGN = [
26
- ` ${colors_1.default.underItalic("setPGN <broadcastId> <sourcePGNUrl> [--withFilter] [--slice <sliceFilter>] [--rounds <roundsToFix>]")}`,
27
- ` ${colors_1.default.gray("Sets the source PGN URL for all rounds in the specified broadcast.")}`,
28
- ` ${colors_1.default.italic("(optional)")} ${colors_1.default.gray('Use "{}" in the URL as a placeholder for the round number.')}`,
29
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray('For livechesscloud URLs, please ensure it ends with "/{}".')}`,
30
- ` ${colors_1.default.bold("Options:")}`,
31
- ` --withFilter ${colors_1.default.gray("Apply round number filtering based on round number.")}`,
32
- ` --slice <sliceFilter> ${colors_1.default.gray("Apply slice filtering using the provided filter string.")}`,
33
- ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
20
+ ` ${cl.underItalic("setPGN <broadcastId> <sourcePGNUrl> [--withFilter] [--slice <sliceFilter>] [--rounds <roundsToFix>]")}`,
21
+ ` ${cl.gray("Sets the source PGN URL for all rounds in the specified broadcast.")}`,
22
+ ` ${cl.italic("(optional)")} ${cl.gray('Use "{}" in the URL as a placeholder for the round number.')}`,
23
+ ` ${cl.bold("Note:")} ${cl.gray('For livechesscloud URLs, please ensure it ends with "/{}".')}`,
24
+ ` ${cl.bold("Options:")}`,
25
+ ` --withFilter ${cl.gray("Apply round number filtering based on round number.")}`,
26
+ ` --slice <sliceFilter> ${cl.gray("Apply slice filtering using the provided filter string.")}`,
27
+ ` --rounds <roundsToFix> ${cl.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
34
28
  ].join("\n");
35
29
  const helpSetPGNMulti = [
36
- ` ${colors_1.default.underItalic("setPGNMulti <broadcastId> <sourcePGNUrl> <gamesNum> [--withFilter] [--onlyGames <sliceFilter>] [--rounds <roundsToFix>]")}`,
37
- ` ${colors_1.default.gray("Sets the source PGN URLs for all rounds in the specified broadcast.")}`,
38
- ` ${colors_1.default.gray("Use {r} in the URL as a placeholder for the round number and {g} for the game number.")}`,
39
- ` ${colors_1.default.gray("Use the gamesNum parameter to specify how many games per round.")}`,
40
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray('For broadcasts with multiple rounds, the source PGN URLs must include the "{g}" placeholder for round numbers.')}`,
41
- ` ${colors_1.default.bold("Options:")}`,
42
- ` --withFilter ${colors_1.default.gray("Apply round number filtering based on round number.")}`,
43
- ` --onlyGames <sliceFilter> ${colors_1.default.gray("Apply slice filtering using the provided filter string.")}`,
44
- ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
30
+ ` ${cl.underItalic("setPGNMulti <broadcastId> <sourcePGNUrl> <gamesNum> [--withFilter] [--onlyGames <sliceFilter>] [--rounds <roundsToFix>]")}`,
31
+ ` ${cl.gray("Sets the source PGN URLs for all rounds in the specified broadcast.")}`,
32
+ ` ${cl.gray("Use {r} in the URL as a placeholder for the round number and {g} for the game number.")}`,
33
+ ` ${cl.gray("Use the gamesNum parameter to specify how many games per round.")}`,
34
+ ` ${cl.bold("Note:")} ${cl.gray('For broadcasts with multiple rounds, the source PGN URLs must include the "{g}" placeholder for round numbers.')}`,
35
+ ` ${cl.bold("Options:")}`,
36
+ ` --withFilter ${cl.gray("Apply round number filtering based on round number.")}`,
37
+ ` --onlyGames <sliceFilter> ${cl.gray("Apply slice filtering using the provided filter string.")}`,
38
+ ` --rounds <roundsToFix> ${cl.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
45
39
  ].join("\n");
46
40
  const helpSetLichessGames = [
47
- ` ${colors_1.default.underItalic("setLichessGames <broadcastRoundId> <gameIds...>")}`,
48
- ` ${colors_1.default.gray("Sets the games for the specified broadcast round using Lichess game IDs.")}`,
49
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray("Maximum of 64 game IDs can be provided.")}`,
41
+ ` ${cl.underItalic("setLichessGames <broadcastRoundId> <gameIds...>")}`,
42
+ ` ${cl.gray("Sets the games for the specified broadcast round using Lichess game IDs.")}`,
43
+ ` ${cl.bold("Note:")} ${cl.gray("Maximum of 64 game IDs can be provided.")}`,
50
44
  ].join("\n");
51
45
  const helpFixSchedule = [
52
- ` ${colors_1.default.underItalic("fixSchedule <broadcastId> <timeDiff> [--rounds <roundsToFix>]")}`,
53
- ` ${colors_1.default.gray("Fixes the schedule of rounds in the specified broadcast by applying a time difference.")}`,
54
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray('The time difference should be in a format like "1h", "30m", "15s", etc.')}`,
55
- ` ${colors_1.default.bold("Options:")}`,
56
- ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
46
+ ` ${cl.underItalic("fixSchedule <broadcastId> <timeDiff> [--rounds <roundsToFix>]")}`,
47
+ ` ${cl.gray("Fixes the schedule of rounds in the specified broadcast by applying a time difference.")}`,
48
+ ` ${cl.bold("Note:")} ${cl.gray('The time difference should be in a format like "1h", "30m", "15s", etc.')}`,
49
+ ` ${cl.bold("Options:")}`,
50
+ ` --rounds <roundsToFix> ${cl.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
57
51
  ].join("\n");
58
52
  const helpStartsPrevious = [
59
- ` ${colors_1.default.underItalic("startsPrevious <broadcastId> <startsPrevious>")}`,
60
- ` ${colors_1.default.gray("Sets the startsAfterPrevious flag for all rounds in the specified broadcast.")}`,
53
+ ` ${cl.underItalic("startsPrevious <broadcastId> <startsPrevious>")}`,
54
+ ` ${cl.gray("Sets the startsAfterPrevious flag for all rounds in the specified broadcast.")}`,
61
55
  ].join("\n");
62
56
  const helpSetPeriod = [
63
- ` ${colors_1.default.underItalic("period <broadcastId> <periodInSeconds>")}`,
64
- ` ${colors_1.default.gray("Sets the period between polling for all rounds in the specified broadcast.")}`,
65
- ` ${colors_1.default.redBold("Required:")} ${colors_1.default.gray(`Your Lichess token needs the ${colors_1.default.whiteBold("web:mod")} scope to use this command. (Broadcast/Study Admin perm required)`)}`,
66
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray("The period is specified in seconds.")}`,
67
- ` ${colors_1.default.bold("Options:")}`,
68
- ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
57
+ ` ${cl.underItalic("period <broadcastId> <periodInSeconds>")}`,
58
+ ` ${cl.gray("Sets the period between polling for all rounds in the specified broadcast.")}`,
59
+ ` ${cl.redBold("Required:")} ${cl.gray(`Your Lichess token needs the ${cl.whiteBold("web:mod")} scope to use this command. (Broadcast/Study Admin perm required)`)}`,
60
+ ` ${cl.bold("Note:")} ${cl.gray("The period is specified in seconds.")}`,
61
+ ` ${cl.bold("Options:")}`,
62
+ ` --rounds <roundsToFix> ${cl.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
69
63
  ].join("\n");
70
64
  const helpScore = [
71
- ` ${colors_1.default.underItalic("score <broadcastId> <whiteWin> <whiteDraw> <blackWin> <blackDraw> [--rounds <roundsToFix>]")}`,
72
- ` ${colors_1.default.gray("Sets the custom scoring for all rounds in the specified broadcast.")}`,
73
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray("Scores must be numbers between 0 and 10.")}`,
74
- ` ${colors_1.default.bold("Options:")}`,
75
- ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
65
+ ` ${cl.underItalic("score <broadcastId> <whiteWin> <whiteDraw> <blackWin> <blackDraw> [--rounds <roundsToFix>]")}`,
66
+ ` ${cl.gray("Sets the custom scoring for all rounds in the specified broadcast.")}`,
67
+ ` ${cl.bold("Note:")} ${cl.gray("Scores must be numbers between 0 and 10.")}`,
68
+ ` ${cl.bold("Options:")}`,
69
+ ` --rounds <roundsToFix> ${cl.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
76
70
  ].join("\n");
77
71
  const helpPush = [
78
- ` ${colors_1.default.underItalic("push <roundId> <PGNFromPathOrUrl> [--loop <intervalInSeconds>]")}`,
79
- ` ${colors_1.default.gray("Upload a PGN file from a local path or URL to the specified broadcast round.")}`,
80
- ` ${colors_1.default.bold("Note:")} ${colors_1.default.gray("The PGN file must be accessible from the provided path or URL.")}`,
81
- ` ${colors_1.default.bold("Options:")}`,
82
- ` --loop <intervalInSeconds> ${colors_1.default.gray("Continuously push the PGN file at the specified interval in seconds.")}`,
72
+ ` ${cl.underItalic("push <roundId> <PGNFromPathOrUrl> [--loop <intervalInSeconds>]")}`,
73
+ ` ${cl.gray("Upload a PGN file from a local path or URL to the specified broadcast round.")}`,
74
+ ` ${cl.bold("Note:")} ${cl.gray("The PGN file must be accessible from the provided path or URL.")}`,
75
+ ` ${cl.bold("Options:")}`,
76
+ ` --loop <intervalInSeconds> ${cl.gray("Continuously push the PGN file at the specified interval in seconds.")}`,
77
+ ].join("\n");
78
+ const helpPushFilterID = [
79
+ ` ${cl.underItalic("pushFilterID <roundId> <PGNFromPathOrUrl> <FideIds...> [--loop <intervalInSeconds>]")}`,
80
+ ` ${cl.gray("Upload a PGN file from a local path or URL to the specified broadcast round, filtering games by FIDE ID.")}`,
81
+ ` ${cl.bold("Note:")} ${cl.gray("The PGN file must be accessible from the provided path or URL.")}`,
82
+ ` ${cl.bold("Options:")}`,
83
+ ` --loop <intervalInSeconds> ${cl.gray("Continuously push the PGN file at the specified interval in seconds.")}`,
83
84
  ].join("\n");
84
85
  const msg = [
85
- `${colors_1.default.boldYellow("Usage:")} ${colors_1.default.underItalic("<command> [options]")}`,
86
+ `${cl.boldYellow("Usage:")} ${cl.underItalic("<command> [options]")}`,
86
87
  ``,
87
88
  ``,
88
- `${colors_1.default.boldYellow("Commands:")}`,
89
+ `${cl.boldYellow("Commands:")}`,
89
90
  helpLogin,
90
91
  ``,
91
92
  helpDelay,
@@ -106,49 +107,52 @@ const msg = [
106
107
  ``,
107
108
  helpPush,
108
109
  ``,
110
+ helpPushFilterID,
111
+ ``,
109
112
  ``,
110
- `${colors_1.default.boldYellow("Examples:")}`,
111
- ` ${colors_1.default.gray("# Login with your Lichess token (interactive)")}`,
112
- ` $ ${colors_1.default.underItalic("login")}`,
113
- ` ${colors_1.default.gray("# Login with token as argument")}`,
114
- ` $ ${colors_1.default.underItalic("login")} ${colors_1.default.italic("lip_yourtoken https://lichess.org")}`,
115
- ` ${colors_1.default.gray("# Logout and clear saved credentials")}`,
116
- ` $ ${colors_1.default.underItalic("login")} ${colors_1.default.italic("--logout")}`,
117
- ` ${colors_1.default.gray("# Set a 5-minute delay without changing start time")}`,
118
- ` $ ${colors_1.default.underItalic("delay")} ${colors_1.default.italic("bcast123 300 --onlyDelay")}`,
119
- ` ${colors_1.default.gray("# Set source PGN URL with round and slice filters")}`,
120
- ` $ ${colors_1.default.underItalic("setPGN")} ${colors_1.default.italic('bcast123 https://example.com/pgns/round-{}/game.pgn --withFilter --slice "1-5,7,9-12"')}`,
121
- ` ${colors_1.default.gray("# Set source PGN URLs for multiple games per round")}`,
122
- ` $ ${colors_1.default.underItalic("setPGNMulti")} ${colors_1.default.italic('bcast123 https://example.com/pgns/round-{r}/game-{g}.pgn 12 --withFilter --onlyGames "1-5,7,9-12"')}`,
123
- ` ${colors_1.default.gray("# Set Lichess games for a broadcast round")}`,
124
- ` $ ${colors_1.default.underItalic("setLichessGames")} ${colors_1.default.italic("round456 gameId1 gameId2 gameId3")}`,
125
- ` ${colors_1.default.gray("# Fix schedule of rounds 1 to 4 and all rounds after 8 by adding 15 minutes")}`,
126
- ` $ ${colors_1.default.underItalic("fixSchedule")} ${colors_1.default.italic("bcast123 15m --rounds 1-4,8+")}`,
127
- ` ${colors_1.default.gray("# Set startsAfterPrevious to true for all rounds in a broadcast")}`,
128
- ` $ ${colors_1.default.underItalic("startsPrevious")} ${colors_1.default.italic("bcast123 true")}`,
129
- ` ${colors_1.default.gray("# Set polling period to 10 seconds for all rounds in a broadcast")}`,
130
- ` $ ${colors_1.default.underItalic("period")} ${colors_1.default.italic("bcast123 10")}`,
131
- ` ${colors_1.default.gray("# Set custom scoring for all rounds in a broadcast")}`,
132
- ` $ ${colors_1.default.underItalic("score")} ${colors_1.default.italic("bcast123 1.0 0.5 1.0 0.5")}`,
133
- ` ${colors_1.default.gray("# Push a PGN file in loop mode every 60 seconds")}`,
134
- ` $ ${colors_1.default.underItalic("push")} ${colors_1.default.italic("round456 /path/to/localfile.pgn --loop 60")}`,
113
+ `${cl.boldYellow("Examples:")}`,
114
+ ` ${cl.gray("# Login with your Lichess token (interactive)")}`,
115
+ ` $ ${cl.underItalic("login")}`,
116
+ ` ${cl.gray("# Login with token as argument")}`,
117
+ ` $ ${cl.underItalic("login")} ${cl.italic("lip_yourtoken https://lichess.org")}`,
118
+ ` ${cl.gray("# Logout and clear saved credentials")}`,
119
+ ` $ ${cl.underItalic("login")} ${cl.italic("--logout")}`,
120
+ ` ${cl.gray("# Set a 5-minute delay without changing start time")}`,
121
+ ` $ ${cl.underItalic("delay")} ${cl.italic("bcast123 300 --onlyDelay")}`,
122
+ ` ${cl.gray("# Set source PGN URL with round and slice filters")}`,
123
+ ` $ ${cl.underItalic("setPGN")} ${cl.italic('bcast123 https://example.com/pgns/round-{}/game.pgn --withFilter --slice "1-5,7,9-12"')}`,
124
+ ` ${cl.gray("# Set source PGN URLs for multiple games per round")}`,
125
+ ` $ ${cl.underItalic("setPGNMulti")} ${cl.italic('bcast123 https://example.com/pgns/round-{r}/game-{g}.pgn 12 --withFilter --onlyGames "1-5,7,9-12"')}`,
126
+ ` ${cl.gray("# Set Lichess games for a broadcast round")}`,
127
+ ` $ ${cl.underItalic("setLichessGames")} ${cl.italic("round456 gameId1 gameId2 gameId3")}`,
128
+ ` ${cl.gray("# Fix schedule of rounds 1 to 4 and all rounds after 8 by adding 15 minutes")}`,
129
+ ` $ ${cl.underItalic("fixSchedule")} ${cl.italic("bcast123 15m --rounds 1-4,8+")}`,
130
+ ` ${cl.gray("# Set startsAfterPrevious to true for all rounds in a broadcast")}`,
131
+ ` $ ${cl.underItalic("startsPrevious")} ${cl.italic("bcast123 true")}`,
132
+ ` ${cl.gray("# Set polling period to 10 seconds for all rounds in a broadcast")}`,
133
+ ` $ ${cl.underItalic("period")} ${cl.italic("bcast123 10")}`,
134
+ ` ${cl.gray("# Set custom scoring for all rounds in a broadcast")}`,
135
+ ` $ ${cl.underItalic("score")} ${cl.italic("bcast123 1.0 0.5 1.0 0.5")}`,
136
+ ` ${cl.gray("# Push a PGN file in loop mode every 60 seconds")}`,
137
+ ` $ ${cl.underItalic("push")} ${cl.italic("round456 /path/to/localfile.pgn --loop 60")}`,
138
+ ` ${cl.gray("# Push a PGN file from URL filtering by FIDE IDs in loop mode every 120 seconds")}`,
139
+ ` $ ${cl.underItalic("pushFilterID")} ${cl.italic("round456 https://example.com/games.pgn 12345 67890 --loop 120")}`,
135
140
  ];
136
- const showHelp = (cmd) => {
141
+ export const showHelp = (cmd) => {
137
142
  const ranges = {
138
- [commandHandler_1.Command.Login]: helpLogin,
139
- [commandHandler_1.Command.Delay]: helpDelay,
140
- [commandHandler_1.Command.SetPGN]: helpSetPGN,
141
- [commandHandler_1.Command.SetPGNMulti]: helpSetPGNMulti,
142
- [commandHandler_1.Command.SetLichessGames]: helpSetLichessGames,
143
- [commandHandler_1.Command.FixSchedule]: helpFixSchedule,
144
- [commandHandler_1.Command.StartsPrevious]: helpStartsPrevious,
145
- [commandHandler_1.Command.Period]: helpSetPeriod,
146
- [commandHandler_1.Command.Score]: helpScore,
147
- [commandHandler_1.Command.Push]: helpPush,
143
+ [Command.Login]: helpLogin,
144
+ [Command.Delay]: helpDelay,
145
+ [Command.SetPGN]: helpSetPGN,
146
+ [Command.SetPGNMulti]: helpSetPGNMulti,
147
+ [Command.SetLichessGames]: helpSetLichessGames,
148
+ [Command.FixSchedule]: helpFixSchedule,
149
+ [Command.StartsPrevious]: helpStartsPrevious,
150
+ [Command.Period]: helpSetPeriod,
151
+ [Command.Score]: helpScore,
152
+ [Command.Push]: helpPush,
153
+ [Command.PushFilterID]: helpPushFilterID,
148
154
  };
149
155
  const range = cmd ? ranges[cmd] : undefined;
150
156
  console.info(range ? range : msg.join("\n"));
151
157
  };
152
- exports.showHelp = showHelp;
153
- const includeHelp = (str) => ["--help", "-h"].includes(str);
154
- exports.includeHelp = includeHelp;
158
+ export const includeHelp = (str) => ["--help", "-h"].includes(str);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libroadcast-cli",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "CLI to help with broadcast maintenance on Lichess",
5
5
  "main": "dist/index.js",
6
6
  "keywords": [
@@ -10,15 +10,16 @@
10
10
  ],
11
11
  "author": "Sérgio Glórias",
12
12
  "license": "MIT",
13
- "type": "commonjs",
13
+ "type": "module",
14
14
  "dependencies": {
15
15
  "@lichess-org/types": "^2.0.109",
16
16
  "@types/node": "~24.10.4",
17
+ "chessops": "^0.15.0",
17
18
  "ms": "3.0.0-canary.202508261828",
18
19
  "openapi-fetch": "^0.15.0"
19
20
  },
20
21
  "devDependencies": {
21
- "prettier": "3.7.4",
22
+ "prettier": "3.8.1",
22
23
  "typescript": "^5.9.3"
23
24
  },
24
25
  "engines": {