libroadcast-cli 2.1.0 → 2.3.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.
package/README.md CHANGED
@@ -76,6 +76,12 @@ Commands:
76
76
  Options:
77
77
  --rounds <roundsToFix> Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.
78
78
 
79
+ push <roundId> <PGNFromPathOrUrl> [--loop <intervalInSeconds>]
80
+ Upload a PGN file from a local path or URL to the specified broadcast round.
81
+ Note: The PGN file must be accessible from the provided path or URL.
82
+ Options:
83
+ --loop <intervalInSeconds> Continuously push the PGN file at the specified interval in seconds.
84
+
79
85
 
80
86
  Examples:
81
87
  # Login with your Lichess token (interactive)
@@ -100,4 +106,6 @@ Examples:
100
106
  $ period bcast123 10
101
107
  # Set custom scoring for all rounds in a broadcast
102
108
  $ score bcast123 1.0 0.5 1.0 0.5
109
+ # Push a PGN file in loop mode every 60 seconds
110
+ $ push round456 /path/to/localfile.pgn --loop 60
103
111
  ```
@@ -0,0 +1,107 @@
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.pushCommand = void 0;
7
+ const node_process_1 = require("node:process");
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const commandHandler_1 = require("../utils/commandHandler");
11
+ const getInfoBroadcast_1 = require("../utils/getInfoBroadcast");
12
+ const colors_1 = __importDefault(require("../utils/colors"));
13
+ const pushPGN = async (round, pgn) => {
14
+ try {
15
+ const res = await commandHandler_1.client
16
+ .POST("/api/broadcast/round/{broadcastRoundId}/push", {
17
+ params: {
18
+ path: { broadcastRoundId: round.id },
19
+ },
20
+ body: pgn,
21
+ bodySerializer: (body) => body,
22
+ })
23
+ .then((response) => response.data);
24
+ console.log(colors_1.default.green(`✓ Successfully pushed PGN for round ${colors_1.default.whiteBold(round.id)}.`));
25
+ console.table(res?.games.map((game, i) => {
26
+ return {
27
+ "Game #": i + 1,
28
+ "White Player": game.tags["White"] || "Unknown",
29
+ "Black Player": game.tags["Black"] || "Unknown",
30
+ Result: game.tags["Result"] || "Unknown",
31
+ "Ply Count": game.moves || "Unknown",
32
+ Error: game.error || "None",
33
+ };
34
+ }));
35
+ }
36
+ catch (error) {
37
+ console.error(colors_1.default.red(`Error pushing PGN for round ${colors_1.default.whiteBold(round.id)}:`), error);
38
+ }
39
+ };
40
+ const readPGNFromURL = async (pgnURL) => {
41
+ if (pgnURL.startsWith("http://") || pgnURL.startsWith("https://")) {
42
+ const response = await fetch(pgnURL, {
43
+ method: "GET",
44
+ headers: {
45
+ "User-Agent": commandHandler_1.packageJson.name + "/" + commandHandler_1.packageJson.version,
46
+ },
47
+ });
48
+ if (!response.ok) {
49
+ console.error(colors_1.default.red(`Failed to fetch PGN from URL: ${response.statusText}`));
50
+ return undefined;
51
+ }
52
+ const pgnText = await response.text();
53
+ return pgnText;
54
+ }
55
+ else {
56
+ const resolvedPath = node_path_1.default.resolve(pgnURL);
57
+ const stats = await (0, promises_1.readFile)(resolvedPath, { encoding: "utf-8" }).catch((err) => {
58
+ console.error(colors_1.default.red(`Failed to read PGN file: ${err.message}`));
59
+ return undefined;
60
+ });
61
+ if (!stats)
62
+ return undefined;
63
+ return stats.toString();
64
+ }
65
+ };
66
+ const loop = async (roundInfo, pgnPath, loopTimer) => {
67
+ while (true) {
68
+ const pgnContent = await readPGNFromURL(pgnPath);
69
+ if (pgnContent)
70
+ await pushPGN(roundInfo, pgnContent);
71
+ await (0, commandHandler_1.sleep)(loopTimer * 1000);
72
+ }
73
+ };
74
+ const pushCommand = async (args) => {
75
+ await (0, commandHandler_1.checkTokenScopes)();
76
+ const [roundId, pgnPath] = args.slice(0, 2);
77
+ if (!roundId || !pgnPath) {
78
+ (0, commandHandler_1.msgCommonErrorHelp)("Round ID and PGN are required.");
79
+ (0, node_process_1.exit)(1);
80
+ }
81
+ const roundInfo = await (0, getInfoBroadcast_1.getBroadcastRound)(roundId);
82
+ if (!roundInfo) {
83
+ console.error(colors_1.default.red("Round not found."));
84
+ (0, node_process_1.exit)(1);
85
+ }
86
+ const loopArgIndex = args.findIndex((arg) => arg === "--loop");
87
+ let loopTimer = undefined;
88
+ if (loopArgIndex !== -1 && loopArgIndex + 1 < args.length) {
89
+ const loopTimerStr = args[loopArgIndex + 1];
90
+ loopTimer = parseInt(loopTimerStr, 10);
91
+ if (isNaN(loopTimer) || loopTimer <= 0) {
92
+ console.error(colors_1.default.red("Loop timer must be a positive integer."));
93
+ (0, node_process_1.exit)(1);
94
+ }
95
+ }
96
+ if (loopTimer) {
97
+ console.log(colors_1.default.green(`Starting loop to push PGN every ${colors_1.default.whiteBold(loopTimer.toString())} seconds...`));
98
+ console.log(colors_1.default.blue("Press Ctrl+C to stop."));
99
+ await loop(roundInfo, pgnPath, loopTimer);
100
+ }
101
+ else {
102
+ const pgnContent = await readPGNFromURL(pgnPath);
103
+ if (pgnContent)
104
+ await pushPGN(roundInfo, pgnContent);
105
+ }
106
+ };
107
+ exports.pushCommand = pushCommand;
package/dist/index.js CHANGED
@@ -5,15 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const node_process_1 = require("node:process");
8
- const node_fs_1 = require("node:fs");
9
- const node_path_1 = require("node:path");
10
8
  const commandHandler_1 = require("./utils/commandHandler");
11
9
  const help_1 = require("./utils/help");
12
10
  const colors_1 = __importDefault(require("./utils/colors"));
13
11
  (async () => {
14
12
  if (commandHandler_1.args.includes("--version") || commandHandler_1.args.includes("-v")) {
15
- const packageJson = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "../package.json"), "utf-8"));
16
- console.log(`${colors_1.default.whiteBold("libroadcast-cli")} ${colors_1.default.underItalic(`v${packageJson.version}`)}`);
13
+ console.log(`${colors_1.default.whiteBold(commandHandler_1.packageJson.name)} ${colors_1.default.underItalic(`v${commandHandler_1.packageJson.version}`)}`);
17
14
  (0, node_process_1.exit)(0);
18
15
  }
19
16
  if (commandHandler_1.args.length === 0 || (0, help_1.includeHelp)(commandHandler_1.args[0])) {
@@ -3,10 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
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.args = exports.LICHESS_TOKEN = void 0;
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
7
  const node_process_1 = require("node:process");
8
8
  const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
9
9
  const colors_1 = __importDefault(require("./colors"));
10
+ const node_fs_1 = require("node:fs");
11
+ const node_path_1 = require("node:path");
10
12
  const delay_1 = require("../cmd/delay");
11
13
  const setPGN_1 = require("../cmd/setPGN");
12
14
  const setPGNMulti_1 = require("../cmd/setPGNMulti");
@@ -15,6 +17,7 @@ const fixSchedule_1 = require("../cmd/fixSchedule");
15
17
  const startsPrevious_1 = require("../cmd/startsPrevious");
16
18
  const period_1 = require("../cmd/period");
17
19
  const score_1 = require("../cmd/score");
20
+ const push_1 = require("../cmd/push");
18
21
  const login_1 = require("../cmd/login");
19
22
  const credentials_1 = require("./credentials");
20
23
  const getToken = () => {
@@ -31,6 +34,7 @@ const getDomain = () => {
31
34
  exports.LICHESS_TOKEN = getToken();
32
35
  const LICHESS_DOMAIN = getDomain();
33
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"));
34
38
  var Command;
35
39
  (function (Command) {
36
40
  Command["Login"] = "login";
@@ -42,6 +46,7 @@ var Command;
42
46
  Command["StartsPrevious"] = "startsPrevious";
43
47
  Command["Period"] = "period";
44
48
  Command["Score"] = "score";
49
+ Command["Push"] = "push";
45
50
  })(Command || (exports.Command = Command = {}));
46
51
  exports.commands = new Map([
47
52
  [Command.Login, login_1.loginCommand],
@@ -53,12 +58,14 @@ exports.commands = new Map([
53
58
  [Command.StartsPrevious, startsPrevious_1.startsPreviousCommand],
54
59
  [Command.Period, period_1.periodCommand],
55
60
  [Command.Score, score_1.scoreCommand],
61
+ [Command.Push, push_1.pushCommand],
56
62
  ]);
57
63
  exports.client = (0, openapi_fetch_1.default)({
58
64
  baseUrl: LICHESS_DOMAIN,
59
65
  headers: {
60
66
  Authorization: `Bearer ${exports.LICHESS_TOKEN}`,
61
67
  Accept: "application/json",
68
+ "User-Agent": exports.packageJson.name + "/" + exports.packageJson.version,
62
69
  },
63
70
  });
64
71
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -74,6 +74,13 @@ const helpScore = [
74
74
  ` ${colors_1.default.bold("Options:")}`,
75
75
  ` --rounds <roundsToFix> ${colors_1.default.gray("Specify which rounds to fix using formats like '1-4', '8+', '3,5,7', etc.")}`,
76
76
  ].join("\n");
77
+ 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.")}`,
83
+ ].join("\n");
77
84
  const msg = [
78
85
  `${colors_1.default.boldYellow("Usage:")} ${colors_1.default.underItalic("<command> [options]")}`,
79
86
  ``,
@@ -97,6 +104,8 @@ const msg = [
97
104
  ``,
98
105
  helpScore,
99
106
  ``,
107
+ helpPush,
108
+ ``,
100
109
  ``,
101
110
  `${colors_1.default.boldYellow("Examples:")}`,
102
111
  ` ${colors_1.default.gray("# Login with your Lichess token (interactive)")}`,
@@ -121,6 +130,8 @@ const msg = [
121
130
  ` $ ${colors_1.default.underItalic("period")} ${colors_1.default.italic("bcast123 10")}`,
122
131
  ` ${colors_1.default.gray("# Set custom scoring for all rounds in a broadcast")}`,
123
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")}`,
124
135
  ];
125
136
  const showHelp = (cmd) => {
126
137
  const ranges = {
@@ -133,6 +144,7 @@ const showHelp = (cmd) => {
133
144
  [commandHandler_1.Command.StartsPrevious]: helpStartsPrevious,
134
145
  [commandHandler_1.Command.Period]: helpSetPeriod,
135
146
  [commandHandler_1.Command.Score]: helpScore,
147
+ [commandHandler_1.Command.Push]: helpPush,
136
148
  };
137
149
  const range = cmd ? ranges[cmd] : undefined;
138
150
  console.info(range ? range : msg.join("\n"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libroadcast-cli",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "CLI to help with broadcast maintenance on Lichess",
5
5
  "main": "dist/index.js",
6
6
  "keywords": [