windsor-bot 0.2.1 → 0.2.5
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/dist/bot.js +4 -1
- package/dist/printer.js +9 -1
- package/dist/printing/cups.js +9 -1
- package/dist/printing/escp.js +9 -1
- package/dist/printing/imagefeed.js +9 -1
- package/dist/server.js +10 -6
- package/package.json +2 -1
package/dist/bot.js
CHANGED
|
@@ -94,7 +94,10 @@ async function removeReactionSafe(message, emoji) {
|
|
|
94
94
|
}
|
|
95
95
|
async function reactSafe(message, emoji, clearThinking = true) {
|
|
96
96
|
try {
|
|
97
|
-
|
|
97
|
+
// Retries can encounter the same pending reaction repeatedly while offline.
|
|
98
|
+
if (!message.reactions.cache.get(emoji)?.me) {
|
|
99
|
+
await message.react(emoji);
|
|
100
|
+
}
|
|
98
101
|
if (emoji !== Reaction.thinking && clearThinking) {
|
|
99
102
|
await removeReactionSafe(message, Reaction.thinking);
|
|
100
103
|
}
|
package/dist/printer.js
CHANGED
|
@@ -56,6 +56,14 @@ function chooseFontForLines(totalLines) {
|
|
|
56
56
|
return { fontSize: FONT_NORMAL, charsPerLine: CHARS_NORMAL };
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
function countLayoutLines(lines) {
|
|
60
|
+
const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
61
|
+
return longestLine > CHARS_DOUBLE
|
|
62
|
+
? 9
|
|
63
|
+
: lines.length <= 2
|
|
64
|
+
? 2
|
|
65
|
+
: lines.length;
|
|
66
|
+
}
|
|
59
67
|
export async function getConnectedPrinter() {
|
|
60
68
|
// Try CUPS first
|
|
61
69
|
try {
|
|
@@ -95,7 +103,7 @@ export async function formatPrintJob(job) {
|
|
|
95
103
|
parts.push(INIT);
|
|
96
104
|
// Determine content lines count for font sizing
|
|
97
105
|
const rawLines = job.lines;
|
|
98
|
-
const previewFontLines = rawLines
|
|
106
|
+
const previewFontLines = countLayoutLines(rawLines);
|
|
99
107
|
const { fontSize, charsPerLine } = chooseFontForLines(previewFontLines);
|
|
100
108
|
// Header
|
|
101
109
|
if (job.header) {
|
package/dist/printing/cups.js
CHANGED
|
@@ -14,6 +14,14 @@ function chooseFontSize(totalLines) {
|
|
|
14
14
|
return FONT_BODY_LARGE;
|
|
15
15
|
return FONT_BODY_NORMAL;
|
|
16
16
|
}
|
|
17
|
+
function countLayoutLines(lines) {
|
|
18
|
+
const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
19
|
+
return longestLine > 24
|
|
20
|
+
? 9
|
|
21
|
+
: lines.length <= 2
|
|
22
|
+
? 2
|
|
23
|
+
: lines.length;
|
|
24
|
+
}
|
|
17
25
|
export async function buildPdfBuffer(job, paperSize) {
|
|
18
26
|
return new Promise((resolve, reject) => {
|
|
19
27
|
const chunks = [];
|
|
@@ -26,7 +34,7 @@ export async function buildPdfBuffer(job, paperSize) {
|
|
|
26
34
|
doc.on('data', (chunk) => chunks.push(chunk));
|
|
27
35
|
doc.on('end', () => resolve(Buffer.concat(chunks)));
|
|
28
36
|
doc.on('error', reject);
|
|
29
|
-
const bodyFontSize = chooseFontSize(job.lines
|
|
37
|
+
const bodyFontSize = chooseFontSize(countLayoutLines(job.lines));
|
|
30
38
|
// Header
|
|
31
39
|
if (job.header) {
|
|
32
40
|
doc.fontSize(FONT_HEADER).font('Helvetica-Bold').text(job.header, { align: 'center', lineGap: LINE_GAP });
|
package/dist/printing/escp.js
CHANGED
|
@@ -34,10 +34,18 @@ function chooseFontForLines(totalLines) {
|
|
|
34
34
|
return { fontSize: 'normal', cols: COLS_NORMAL };
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
function countLayoutLines(lines) {
|
|
38
|
+
const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
39
|
+
return longestLine > COLS_DOUBLE
|
|
40
|
+
? 9
|
|
41
|
+
: lines.length <= 2
|
|
42
|
+
? 2
|
|
43
|
+
: lines.length;
|
|
44
|
+
}
|
|
37
45
|
export async function buildEscpBuffer(job) {
|
|
38
46
|
const conn = new InMemory();
|
|
39
47
|
const printer = await Printer.CONNECT('TM-T20', conn);
|
|
40
|
-
const { fontSize, cols } = chooseFontForLines(job.lines
|
|
48
|
+
const { fontSize, cols } = chooseFontForLines(countLayoutLines(job.lines));
|
|
41
49
|
// Header
|
|
42
50
|
if (job.header) {
|
|
43
51
|
const headerLines = wrapText(job.header, COLS_DOUBLE);
|
|
@@ -21,6 +21,14 @@ function chooseLineHeight(totalLines) {
|
|
|
21
21
|
return { lineHeight: LINE_HEIGHT_LARGE, fontPath: FONT_32 };
|
|
22
22
|
return { lineHeight: LINE_HEIGHT_NORMAL, fontPath: FONT_16 };
|
|
23
23
|
}
|
|
24
|
+
function countLayoutLines(lines) {
|
|
25
|
+
const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
26
|
+
return longestLine > 24
|
|
27
|
+
? 9
|
|
28
|
+
: lines.length <= 2
|
|
29
|
+
? 2
|
|
30
|
+
: lines.length;
|
|
31
|
+
}
|
|
24
32
|
function wrapText(text, font, maxWidth) {
|
|
25
33
|
if (!text)
|
|
26
34
|
return [''];
|
|
@@ -48,7 +56,7 @@ async function renderQrCode(url) {
|
|
|
48
56
|
return Jimp.fromBuffer(pngBuf);
|
|
49
57
|
}
|
|
50
58
|
export async function renderJobToPng(job) {
|
|
51
|
-
const totalLines = job.lines
|
|
59
|
+
const totalLines = countLayoutLines(job.lines);
|
|
52
60
|
const { lineHeight, fontPath } = chooseLineHeight(totalLines);
|
|
53
61
|
const fontNormal = await loadFont(FONT_16);
|
|
54
62
|
const fontLarge = await loadFont(FONT_32);
|
package/dist/server.js
CHANGED
|
@@ -76,17 +76,21 @@ async function updateGlobalBot() {
|
|
|
76
76
|
'/usr/local/bin/npm',
|
|
77
77
|
'/opt/homebrew/bin/npm',
|
|
78
78
|
'/usr/bin/npm',
|
|
79
|
+
'npm',
|
|
79
80
|
]
|
|
80
81
|
.filter((candidate) => Boolean(candidate))
|
|
81
|
-
.map(candidate => (
|
|
82
|
-
|
|
83
|
-
args: candidate.endsWith('.js') ? [candidate] : [],
|
|
84
|
-
}));
|
|
82
|
+
.map(candidate => candidate.trim())
|
|
83
|
+
.filter((candidate, index, candidates) => candidates.indexOf(candidate) === index);
|
|
85
84
|
let npmCommand;
|
|
86
85
|
for (const candidate of npmCandidates) {
|
|
86
|
+
const command = candidate.endsWith('.js')
|
|
87
|
+
? { path: process.execPath, args: [candidate] }
|
|
88
|
+
: { path: candidate, args: [] };
|
|
87
89
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
// Validate the script itself, not just the Node executable used to run it.
|
|
91
|
+
if (candidate !== 'npm')
|
|
92
|
+
await access(candidate);
|
|
93
|
+
npmCommand = command;
|
|
90
94
|
break;
|
|
91
95
|
}
|
|
92
96
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "windsor-bot",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Self-hosted Discord bot automation for household list and todo printing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"prepare": "npm run build",
|
|
9
9
|
"build": "tsc && node scripts/build-web.mjs",
|
|
10
10
|
"clean": "node scripts/clean.mjs",
|
|
11
|
+
"deploy": "git push origin 'refs/tags/v*:refs/tags/v*'",
|
|
11
12
|
"dev": "node src/index.ts",
|
|
12
13
|
"test": "node --test src/tests/*.test.ts",
|
|
13
14
|
"generate-wordsearches": "node scripts/generate-wordsearches.mjs",
|