Files
kindle-calendar/calendar/scripts/generate-dashboard-manifest.mjs
2026-03-17 10:37:27 +08:00

132 lines
3.9 KiB
JavaScript

import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const currentDir = path.dirname(fileURLToPath(import.meta.url));
const distDir = path.resolve(currentDir, '../dist');
const manifestPath = path.join(distDir, 'dashboard-manifest.json');
const clockRegionPath = path.join(distDir, 'clock-region.json');
const themesSourcePath = path.resolve(currentDir, '../config/themes.json');
const themesDistPath = path.join(distDir, 'themes.json');
const themesDir = path.join(distDir, 'themes');
const dashboardBaseUrl = 'https://shell.biboer.cn:20001';
const themesSource = JSON.parse(fs.readFileSync(themesSourcePath, 'utf8'));
const generatedAt = new Date().toISOString();
const defaultVariant = themesSource.themes.find((theme) => theme.id === themesSource.defaultThemeId)?.variants?.[themesSource.defaultOrientation];
const defaultDeviceClock = defaultVariant ? toDeviceClock(defaultVariant, themesSource.defaultOrientation) : null;
const defaultClockRegion = defaultVariant
? {
x: defaultDeviceClock.x,
y: defaultDeviceClock.y,
width: defaultDeviceClock.width,
height: defaultDeviceClock.height,
}
: {
x: 313,
y: 0,
width: 220,
height: 220,
};
const clockRegion = fs.existsSync(clockRegionPath)
? {
...defaultClockRegion,
...JSON.parse(fs.readFileSync(clockRegionPath, 'utf8')),
}
: defaultClockRegion;
const manifest = {
theme: {
id: themesSource.defaultThemeId,
orientation: themesSource.defaultOrientation,
themesUrl: `${dashboardBaseUrl}/themes.json`,
},
background: {
path: 'kindlebg.png',
url: `${dashboardBaseUrl}/kindlebg.png`,
updatedAt: generatedAt,
refreshIntervalMinutes: 120,
},
clockRegion,
clockFace: {
path: 'assets/clock-face.png',
managedOnKindle: true,
designWidth: 220,
designHeight: 220,
},
clockHands: {
hourPattern: 'assets/hour-hand/%03d.png',
minutePattern: 'assets/minute-hand/%02d.png',
refreshIntervalMinutes: 1,
networkRequired: false,
anchorMode: 'baked-into-patch',
scaleWithClockFace: false,
},
};
const themesIndex = {
updatedAt: generatedAt,
defaultThemeId: themesSource.defaultThemeId,
defaultOrientation: themesSource.defaultOrientation,
themes: themesSource.themes.map((theme) => ({
id: theme.id,
label: theme.label,
configUrl: `${dashboardBaseUrl}/themes/${theme.id}.json`,
orientations: Object.keys(theme.variants),
})),
};
function toDeviceClock(variant, orientation) {
if (orientation !== 'landscape') {
return {
...variant.clock,
rotationDegrees: 0,
};
}
return {
...variant.clock,
x: variant.viewport.height - (variant.clock.y + variant.clock.height),
y: variant.clock.x,
width: variant.clock.height,
height: variant.clock.width,
rotationDegrees: 90,
};
}
function buildThemeConfig(theme) {
return {
id: theme.id,
label: theme.label,
updatedAt: generatedAt,
variants: Object.fromEntries(
Object.entries(theme.variants).map(([orientation, variant]) => [
orientation,
{
devicePlacement: variant.devicePlacement,
background: {
path: variant.backgroundPath,
url: `${dashboardBaseUrl}/${variant.backgroundPath}`,
refreshIntervalMinutes: 120,
},
clock: toDeviceClock(variant, orientation),
},
]),
),
};
}
fs.mkdirSync(distDir, { recursive: true });
fs.mkdirSync(themesDir, { recursive: true });
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
fs.writeFileSync(themesDistPath, `${JSON.stringify(themesIndex, null, 2)}\n`, 'utf8');
for (const theme of themesSource.themes) {
const themePath = path.join(themesDir, `${theme.id}.json`);
fs.writeFileSync(themePath, `${JSON.stringify(buildThemeConfig(theme), null, 2)}\n`, 'utf8');
}
console.log(`Wrote ${manifestPath}`);
console.log(`Wrote ${themesDistPath}`);