Add editable weather captions and manage Threads scheduling with PM2

This commit is contained in:
2026-11-02 04:07:40 +09:00
parent 8c2113a323
commit 6ce32d33fe
17 changed files with 305 additions and 50 deletions
+28
View File
@@ -0,0 +1,28 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { loadCaptions, weatherKey, renderCaption } from '../server/threads/captions.ts';
const sample = { cloudCover: 10, visibility: 10000, rain: 0, snowfall: 0 };
test('caption weather uses precipitation first and does not assume missing data means clear', () => {
const config = loadCaptions();
assert.equal(weatherKey({ ...sample, rain: 1, snowfall: 1 }, config), 'snow');
assert.equal(weatherKey({ ...sample, rain: 1, visibility: 100 }, config), 'rain');
assert.equal(weatherKey({ ...sample, visibility: 500 }, config), 'fog');
assert.equal(weatherKey({ ...sample, cloudCover: 90 }, config), 'cloudy');
assert.equal(weatherKey({ ...sample, cloudCover: 50 }, config), 'partlyCloudy');
assert.equal(weatherKey(sample, config), 'clear');
assert.equal(weatherKey(null, config), 'unknown');
assert.equal(weatherKey({ ...sample, rain: null }, config), 'unknown');
});
test('editable caption expands Korean date/time and test marker without publishing', () => {
const config = loadCaptions();
config.template = ['{message}', '{date} {time} / {sunrise}', '{url}'];
config.messages.rain = ['비 오는 날이야 ☔'];
const result = renderCaption(config, { weather: { ...sample, rain: 1 }, capturedAt: '2026-11-01T18:00:00Z',
sunrise: '2026-11-01T21:53:00Z', url: 'https://sunrise.horoli.kr', test: true });
assert.ok(result.text.includes('비 오는 날이야 ☔'));
assert.ok(result.text.includes('2026-11-02 03:00 / 06:53'));
assert.ok(result.text.startsWith(config.testPrefix));
assert.equal(result.condition, 'rain');
});
+10
View File
@@ -0,0 +1,10 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { nextRunAt } from '../server/threads/schedule.ts';
test('PM2 scheduler prepares at 03:00 Korea time regardless of host timezone', () => {
assert.equal(nextRunAt(new Date('2026-11-01T17:00:00Z')).toISOString(), '2026-11-01T18:00:00.000Z');
assert.equal(nextRunAt(new Date('2026-11-01T20:00:00Z')).toISOString(), '2026-11-01T20:00:00.000Z');
assert.equal(nextRunAt(new Date('2026-11-01T20:00:00Z'), '2026-11-02').toISOString(), '2026-11-02T18:00:00.000Z');
assert.equal(nextRunAt(new Date('2026-12-31T20:00:00Z'), '2027-01-01').toISOString(), '2027-01-01T18:00:00.000Z');
});