178 lines
5.5 KiB
JavaScript
178 lines
5.5 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 kindleBackgroundsDir = path.resolve(currentDir, '../kindle-backgrounds');
|
|
const dashboardBaseUrl = 'https://shell.biboer.cn:20001';
|
|
|
|
const themesSource = JSON.parse(fs.readFileSync(themesSourcePath, 'utf8'));
|
|
const generatedAt = new Date().toISOString();
|
|
const defaultTheme = themesSource.themes.find((theme) => theme.id === themesSource.defaultThemeId);
|
|
const defaultVariant = defaultTheme?.variants?.[themesSource.defaultOrientation];
|
|
const defaultDeviceClock = defaultVariant ? buildRuntimeClock(defaultTheme.id, themesSource.defaultOrientation, defaultVariant) : 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 resolveVariantClock(themeId, orientation, variant) {
|
|
const regionPath = path.join(distDir, 'themes', themeId, orientation, 'kindlebg.clock-region.json');
|
|
const exportedRegion = fs.existsSync(regionPath)
|
|
? JSON.parse(fs.readFileSync(regionPath, 'utf8'))
|
|
: null;
|
|
|
|
return {
|
|
...variant,
|
|
clock: {
|
|
...variant.clock,
|
|
...(exportedRegion
|
|
? {
|
|
x: exportedRegion.x,
|
|
y: exportedRegion.y,
|
|
width: exportedRegion.width,
|
|
height: exportedRegion.height,
|
|
}
|
|
: {}),
|
|
},
|
|
};
|
|
}
|
|
|
|
function buildRuntimeClock(themeId, orientation, variant) {
|
|
const resolvedVariant = resolveVariantClock(themeId, orientation, variant);
|
|
const hasExportedRegion =
|
|
resolvedVariant.clock.x !== variant.clock.x ||
|
|
resolvedVariant.clock.y !== variant.clock.y ||
|
|
resolvedVariant.clock.width !== variant.clock.width ||
|
|
resolvedVariant.clock.height !== variant.clock.height;
|
|
|
|
if (orientation === 'landscape' && hasExportedRegion) {
|
|
return {
|
|
...resolvedVariant.clock,
|
|
rotationDegrees: 90,
|
|
};
|
|
}
|
|
|
|
return toDeviceClock(resolvedVariant, orientation);
|
|
}
|
|
|
|
function buildThemeConfig(theme) {
|
|
return {
|
|
id: theme.id,
|
|
label: theme.label,
|
|
updatedAt: generatedAt,
|
|
variants: Object.fromEntries(
|
|
Object.entries(theme.variants).map(([orientation, variant]) => {
|
|
return [
|
|
orientation,
|
|
{
|
|
devicePlacement: variant.devicePlacement,
|
|
background: {
|
|
// Kindle 端统一走扁平目录,避免设备侧自己拼主题子目录规则。
|
|
path: `kindle-backgrounds/${theme.id}-${orientation}.png`,
|
|
url: `${dashboardBaseUrl}/kindle-backgrounds/${theme.id}-${orientation}.png`,
|
|
refreshIntervalMinutes: 120,
|
|
},
|
|
clock: buildRuntimeClock(theme.id, orientation, variant),
|
|
},
|
|
];
|
|
}),
|
|
),
|
|
};
|
|
}
|
|
|
|
fs.mkdirSync(distDir, { recursive: true });
|
|
fs.mkdirSync(themesDir, { recursive: true });
|
|
fs.mkdirSync(kindleBackgroundsDir, { 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}`);
|