@adaptive-ds/assets-optimizer 0.2.0 → 0.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/changelogs/2026-04-18_v0.2.1.md +5 -0
- package/changelogs/2026-04-18_v0.3.0.md +6 -0
- package/dist/AssetsOptimizeOptions.d.ts +17 -0
- package/dist/AssetsOptimizeOptions.d.ts.map +1 -0
- package/dist/AssetsOptimizeOptions.js +1 -0
- package/dist/AssetsOptimizeResult.d.ts +12 -0
- package/dist/AssetsOptimizeResult.d.ts.map +1 -0
- package/dist/AssetsOptimizeResult.js +1 -0
- package/dist/assetsOptimize.d.ts +4 -0
- package/dist/assetsOptimize.d.ts.map +1 -0
- package/dist/assetsOptimize.js +60 -0
- package/dist/image/ExpectedImage.d.ts +5 -0
- package/dist/image/ExpectedImage.d.ts.map +1 -0
- package/dist/image/ExpectedImage.js +1 -0
- package/dist/image/ImageFormat.d.ts +2 -0
- package/dist/image/ImageFormat.d.ts.map +1 -0
- package/dist/image/ImageFormat.js +1 -0
- package/dist/image/OptimizeImagesOptions.d.ts +10 -0
- package/dist/image/OptimizeImagesOptions.d.ts.map +1 -0
- package/dist/image/OptimizeImagesOptions.js +1 -0
- package/dist/image/ProcessImagesOptions.d.ts +10 -0
- package/dist/image/ProcessImagesOptions.d.ts.map +1 -0
- package/dist/image/ProcessImagesOptions.js +1 -0
- package/dist/image/TransformSpec.d.ts +8 -0
- package/dist/image/TransformSpec.d.ts.map +1 -0
- package/dist/image/TransformSpec.js +1 -0
- package/dist/image/buildExpectedImages.d.ts +4 -0
- package/dist/image/buildExpectedImages.d.ts.map +1 -0
- package/dist/image/buildExpectedImages.js +89 -0
- package/dist/image/createOutputHash.d.ts +2 -0
- package/dist/image/createOutputHash.d.ts.map +1 -0
- package/dist/image/createOutputHash.js +4 -0
- package/dist/image/createOutputHashForFile.d.ts +2 -0
- package/dist/image/createOutputHashForFile.d.ts.map +1 -0
- package/dist/image/createOutputHashForFile.js +14 -0
- package/dist/image/createRootImageTransform.d.ts +3 -0
- package/dist/image/createRootImageTransform.d.ts.map +1 -0
- package/dist/image/createRootImageTransform.js +33 -0
- package/dist/image/defaultQuality.d.ts +2 -0
- package/dist/image/defaultQuality.d.ts.map +1 -0
- package/dist/image/defaultQuality.js +1 -0
- package/dist/image/imageFormats.d.ts +3 -0
- package/dist/image/imageFormats.d.ts.map +1 -0
- package/dist/image/imageFormats.js +1 -0
- package/dist/image/isImageFormat.d.ts +3 -0
- package/dist/image/isImageFormat.d.ts.map +1 -0
- package/dist/image/isImageFormat.js +5 -0
- package/dist/image/optimizeImages.d.ts +4 -0
- package/dist/image/optimizeImages.d.ts.map +1 -0
- package/dist/image/optimizeImages.js +35 -0
- package/dist/image/parseTransformSpec.d.ts +3 -0
- package/dist/image/parseTransformSpec.d.ts.map +1 -0
- package/dist/image/parseTransformSpec.js +26 -0
- package/dist/image/processImage.d.ts +3 -0
- package/dist/image/processImage.d.ts.map +1 -0
- package/dist/image/processImage.js +28 -0
- package/dist/image/processImages.d.ts +3 -0
- package/dist/image/processImages.d.ts.map +1 -0
- package/dist/image/processImages.js +19 -0
- package/dist/image/supportedSourceExtensions.d.ts +2 -0
- package/dist/image/supportedSourceExtensions.d.ts.map +1 -0
- package/dist/image/supportedSourceExtensions.js +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/list/AssetListTypes.d.ts +13 -0
- package/dist/list/AssetListTypes.d.ts.map +1 -0
- package/dist/list/AssetListTypes.js +1 -0
- package/dist/list/formatGeneratedCodeFile.d.ts +3 -0
- package/dist/list/formatGeneratedCodeFile.d.ts.map +1 -0
- package/dist/list/formatGeneratedCodeFile.js +32 -0
- package/dist/list/generateImageList.d.ts +3 -0
- package/dist/list/generateImageList.d.ts.map +1 -0
- package/dist/list/generateImageList.js +85 -0
- package/dist/list/generateVideoList.d.ts +3 -0
- package/dist/list/generateVideoList.d.ts.map +1 -0
- package/dist/list/generateVideoList.js +87 -0
- package/dist/list/getAssetKey.d.ts +2 -0
- package/dist/list/getAssetKey.d.ts.map +1 -0
- package/dist/list/getAssetKey.js +10 -0
- package/dist/list/loadExistingAssetList.d.ts +2 -0
- package/dist/list/loadExistingAssetList.d.ts.map +1 -0
- package/dist/list/loadExistingAssetList.js +23 -0
- package/dist/list/sortAssetMap.d.ts +2 -0
- package/dist/list/sortAssetMap.d.ts.map +1 -0
- package/dist/list/sortAssetMap.js +8 -0
- package/dist/rclone/bisync.d.ts +9 -0
- package/dist/rclone/bisync.d.ts.map +1 -0
- package/dist/rclone/bisync.js +25 -0
- package/dist/rclone/runRclone.d.ts +2 -0
- package/dist/rclone/runRclone.d.ts.map +1 -0
- package/dist/rclone/runRclone.js +13 -0
- package/dist/shared/assertNever.d.ts +2 -0
- package/dist/shared/assertNever.d.ts.map +1 -0
- package/dist/shared/assertNever.js +3 -0
- package/dist/shared/dirExists.d.ts +2 -0
- package/dist/shared/dirExists.d.ts.map +1 -0
- package/dist/shared/dirExists.js +10 -0
- package/dist/shared/getOwnPackageName.d.ts +2 -0
- package/dist/shared/getOwnPackageName.d.ts.map +1 -0
- package/dist/shared/getOwnPackageName.js +21 -0
- package/dist/shared/isMissingDirError.d.ts +2 -0
- package/dist/shared/isMissingDirError.d.ts.map +1 -0
- package/dist/shared/isMissingDirError.js +3 -0
- package/dist/shared/listLocalFiles.d.ts +2 -0
- package/dist/shared/listLocalFiles.d.ts.map +1 -0
- package/dist/shared/listLocalFiles.js +13 -0
- package/dist/shared/logger.d.ts +13 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/logger.js +47 -0
- package/dist/shared/printSummary.d.ts +4 -0
- package/dist/shared/printSummary.d.ts.map +1 -0
- package/dist/shared/printSummary.js +25 -0
- package/dist/shared/walkFiles.d.ts +2 -0
- package/dist/shared/walkFiles.d.ts.map +1 -0
- package/dist/shared/walkFiles.js +17 -0
- package/dist/video/OptimizeVideosOptions.d.ts +10 -0
- package/dist/video/OptimizeVideosOptions.d.ts.map +1 -0
- package/dist/video/OptimizeVideosOptions.js +1 -0
- package/dist/video/ProcessVideosOptions.d.ts +11 -0
- package/dist/video/ProcessVideosOptions.d.ts.map +1 -0
- package/dist/video/ProcessVideosOptions.js +1 -0
- package/dist/video/createVideoArgs.d.ts +3 -0
- package/dist/video/createVideoArgs.d.ts.map +1 -0
- package/dist/video/createVideoArgs.js +77 -0
- package/dist/video/createVideoPreviewArgs.d.ts +2 -0
- package/dist/video/createVideoPreviewArgs.d.ts.map +1 -0
- package/dist/video/createVideoPreviewArgs.js +18 -0
- package/dist/video/createVideoPreviewPath.d.ts +2 -0
- package/dist/video/createVideoPreviewPath.d.ts.map +1 -0
- package/dist/video/createVideoPreviewPath.js +3 -0
- package/dist/video/ensureVideoPreviews.d.ts +4 -0
- package/dist/video/ensureVideoPreviews.d.ts.map +1 -0
- package/dist/video/ensureVideoPreviews.js +30 -0
- package/dist/video/getAvailableVideoEncoders.d.ts +3 -0
- package/dist/video/getAvailableVideoEncoders.d.ts.map +1 -0
- package/dist/video/getAvailableVideoEncoders.js +36 -0
- package/dist/video/optimizeVideos.d.ts +4 -0
- package/dist/video/optimizeVideos.d.ts.map +1 -0
- package/dist/video/optimizeVideos.js +81 -0
- package/dist/video/processLocalVideos.d.ts +4 -0
- package/dist/video/processLocalVideos.d.ts.map +1 -0
- package/dist/video/processLocalVideos.js +26 -0
- package/dist/video/processVideos.d.ts +3 -0
- package/dist/video/processVideos.d.ts.map +1 -0
- package/dist/video/processVideos.js +10 -0
- package/dist/video/runFfmpeg.d.ts +3 -0
- package/dist/video/runFfmpeg.d.ts.map +1 -0
- package/dist/video/runFfmpeg.js +26 -0
- package/dist/video/supportedVideoSourceExtensions.d.ts +2 -0
- package/dist/video/supportedVideoSourceExtensions.d.ts.map +1 -0
- package/dist/video/supportedVideoSourceExtensions.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,kCAAkC,CAAA;AAChD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sCAAsC,CAAA;AACpD,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kCAAkC,CAAA;AAChD,cAAc,mCAAmC,CAAA;AACjD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export * from "./AssetsOptimizeOptions.js";
|
|
2
|
+
export * from "./AssetsOptimizeResult.js";
|
|
3
|
+
export * from "./image/OptimizeImagesOptions.js";
|
|
4
|
+
export * from "./image/buildExpectedImages.js";
|
|
5
|
+
export * from "./image/createOutputHash.js";
|
|
6
|
+
export * from "./image/defaultQuality.js";
|
|
7
|
+
export * from "./image/ExpectedImage.js";
|
|
8
|
+
export * from "./image/ImageFormat.js";
|
|
9
|
+
export * from "./image/optimizeImages.js";
|
|
10
|
+
export * from "./image/parseTransformSpec.js";
|
|
11
|
+
export * from "./image/processImage.js";
|
|
12
|
+
export * from "./image/processImages.js";
|
|
13
|
+
export * from "./image/ProcessImagesOptions.js";
|
|
14
|
+
export * from "./image/supportedSourceExtensions.js";
|
|
15
|
+
export * from "./image/TransformSpec.js";
|
|
16
|
+
export * from "./list/AssetListTypes.js";
|
|
17
|
+
export * from "./list/generateImageList.js";
|
|
18
|
+
export * from "./list/generateVideoList.js";
|
|
19
|
+
export * from "./assetsOptimize.js";
|
|
20
|
+
export * from "./rclone/bisync.js";
|
|
21
|
+
export * from "./rclone/runRclone.js";
|
|
22
|
+
export * from "./shared/listLocalFiles.js";
|
|
23
|
+
export * from "./shared/printSummary.js";
|
|
24
|
+
export * from "./shared/walkFiles.js";
|
|
25
|
+
export * from "./video/OptimizeVideosOptions.js";
|
|
26
|
+
export * from "./video/createVideoPreviewPath.js";
|
|
27
|
+
export * from "./video/ensureVideoPreviews.js";
|
|
28
|
+
export * from "./video/optimizeVideos.js";
|
|
29
|
+
export * from "./video/processVideos.js";
|
|
30
|
+
export * from "./video/ProcessVideosOptions.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ImageType {
|
|
2
|
+
path: string;
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
alt: string;
|
|
6
|
+
mimeType?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface VideoType {
|
|
9
|
+
path: string;
|
|
10
|
+
mimeType?: string;
|
|
11
|
+
image: ImageType;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=AssetListTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetListTypes.d.ts","sourceRoot":"","sources":["../../src/list/AssetListTypes.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,SAAS,CAAA;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatGeneratedCodeFile.d.ts","sourceRoot":"","sources":["../../src/list/formatGeneratedCodeFile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,wBAAsB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiChG"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export async function formatGeneratedCodeFile(outputPath, logger) {
|
|
2
|
+
const command = ["bunx", "biome", "check", "--write", outputPath];
|
|
3
|
+
logger?.cli(command.join(" "));
|
|
4
|
+
const process = Bun.spawn(command, {
|
|
5
|
+
stdout: "pipe",
|
|
6
|
+
stderr: "pipe",
|
|
7
|
+
});
|
|
8
|
+
const exitCode = await process.exited;
|
|
9
|
+
if (exitCode !== 0) {
|
|
10
|
+
const stderr = await new Response(process.stderr).text();
|
|
11
|
+
const message = `Failed to format generated file ${outputPath}: ${stderr}`;
|
|
12
|
+
if (logger) {
|
|
13
|
+
logger.warn(message);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
console.warn(message);
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (logger?.isEnabled(3)) {
|
|
21
|
+
const [stdout, stderr] = await Promise.all([
|
|
22
|
+
new Response(process.stdout).text(),
|
|
23
|
+
new Response(process.stderr).text(),
|
|
24
|
+
]);
|
|
25
|
+
if (stdout.trim()) {
|
|
26
|
+
logger.verbose(stdout.trim());
|
|
27
|
+
}
|
|
28
|
+
if (stderr.trim()) {
|
|
29
|
+
logger.verbose(stderr.trim());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateImageList.d.ts","sourceRoot":"","sources":["../../src/list/generateImageList.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAUjD,wBAAsB,iBAAiB,CACrC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAWf"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { imageSize } from "image-size";
|
|
4
|
+
import { getOwnPackageName } from "../shared/getOwnPackageName.js";
|
|
5
|
+
import { walkFiles } from "../shared/walkFiles.js";
|
|
6
|
+
import { formatGeneratedCodeFile } from "./formatGeneratedCodeFile.js";
|
|
7
|
+
import { getAssetKey } from "./getAssetKey.js";
|
|
8
|
+
import { loadExistingAssetList } from "./loadExistingAssetList.js";
|
|
9
|
+
import { sortAssetMap } from "./sortAssetMap.js";
|
|
10
|
+
const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".avif", ".tiff", ".svg"]);
|
|
11
|
+
export async function generateImageList(imageDirectory, outputPath, imageTypeImportPath, logger) {
|
|
12
|
+
const resolvedImageTypeImportPath = imageTypeImportPath ?? (await getOwnPackageName(import.meta.url));
|
|
13
|
+
const existingImages = await loadExistingAssetList(outputPath, "imageList");
|
|
14
|
+
const imageMap = await processImageFiles(imageDirectory, existingImages, logger);
|
|
15
|
+
const sorted = sortAssetMap(imageMap);
|
|
16
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
17
|
+
await Bun.write(outputPath, createGeneratedImageListContent(sorted, resolvedImageTypeImportPath));
|
|
18
|
+
await formatGeneratedCodeFile(outputPath, logger);
|
|
19
|
+
logger?.files(`generated image list: ${outputPath}`);
|
|
20
|
+
logger?.summary(`Generated ${Object.keys(sorted).length} images to ${outputPath}`);
|
|
21
|
+
}
|
|
22
|
+
async function processImageFiles(directory, existingImages, logger) {
|
|
23
|
+
const imageMap = {};
|
|
24
|
+
for (const filePath of await walkFiles(directory)) {
|
|
25
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
26
|
+
if (!IMAGE_EXTENSIONS.has(extension)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const buffer = await fs.readFile(filePath);
|
|
31
|
+
const dimensions = imageSize(buffer);
|
|
32
|
+
if (!dimensions.width || !dimensions.height) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const relativePath = path.relative(directory, filePath);
|
|
36
|
+
const key = normalizeGeneratedImageKey(getAssetKey(filePath));
|
|
37
|
+
const fileName = path.basename(filePath, extension);
|
|
38
|
+
imageMap[key] = {
|
|
39
|
+
path: relativePath,
|
|
40
|
+
width: dimensions.width,
|
|
41
|
+
height: dimensions.height,
|
|
42
|
+
alt: existingImages[key]?.alt || formatGeneratedImageAlt(fileName),
|
|
43
|
+
mimeType: getImageMimeType(extension),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger?.error(`Error processing ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return imageMap;
|
|
51
|
+
}
|
|
52
|
+
function normalizeGeneratedImageKey(key) {
|
|
53
|
+
return key.replace(/_[0-9a-f]{8}$/i, "");
|
|
54
|
+
}
|
|
55
|
+
function formatGeneratedImageAlt(fileName) {
|
|
56
|
+
return normalizeGeneratedImageKey(fileName).replace(/[-_]/g, " ");
|
|
57
|
+
}
|
|
58
|
+
function createGeneratedImageListContent(imageMap, imageTypeImportPath) {
|
|
59
|
+
return `import type { ImageType } from "${imageTypeImportPath}"
|
|
60
|
+
|
|
61
|
+
// Auto-generated, manual changes will be lost, generated by optimizeAssets from @adaptive-ds/assets-optimizer
|
|
62
|
+
export const imageList = ${JSON.stringify(imageMap, null, 2)} as const satisfies Record<string, ImageType>
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
function getImageMimeType(extension) {
|
|
66
|
+
switch (extension) {
|
|
67
|
+
case ".jpg":
|
|
68
|
+
case ".jpeg":
|
|
69
|
+
return "image/jpeg";
|
|
70
|
+
case ".png":
|
|
71
|
+
return "image/png";
|
|
72
|
+
case ".gif":
|
|
73
|
+
return "image/gif";
|
|
74
|
+
case ".webp":
|
|
75
|
+
return "image/webp";
|
|
76
|
+
case ".avif":
|
|
77
|
+
return "image/avif";
|
|
78
|
+
case ".tiff":
|
|
79
|
+
return "image/tiff";
|
|
80
|
+
case ".svg":
|
|
81
|
+
return "image/svg+xml";
|
|
82
|
+
default:
|
|
83
|
+
return "application/octet-stream";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateVideoList.d.ts","sourceRoot":"","sources":["../../src/list/generateVideoList.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAUjD,wBAAsB,iBAAiB,CACrC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAUf"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { imageSize } from "image-size";
|
|
4
|
+
import { getOwnPackageName } from "../shared/getOwnPackageName.js";
|
|
5
|
+
import { isMissingDirError } from "../shared/isMissingDirError.js";
|
|
6
|
+
import { walkFiles } from "../shared/walkFiles.js";
|
|
7
|
+
import { createVideoPreviewPath } from "../video/createVideoPreviewPath.js";
|
|
8
|
+
import { supportedVideoSourceExtensions } from "../video/supportedVideoSourceExtensions.js";
|
|
9
|
+
import { formatGeneratedCodeFile } from "./formatGeneratedCodeFile.js";
|
|
10
|
+
import { getAssetKey } from "./getAssetKey.js";
|
|
11
|
+
import { loadExistingAssetList } from "./loadExistingAssetList.js";
|
|
12
|
+
import { sortAssetMap } from "./sortAssetMap.js";
|
|
13
|
+
export async function generateVideoList(videosDirectory, outputPath, videoTypeImportPath, logger) {
|
|
14
|
+
const resolvedVideoTypeImportPath = videoTypeImportPath ?? (await getOwnPackageName(import.meta.url));
|
|
15
|
+
const existingVideos = await loadExistingAssetList(outputPath, "videoList");
|
|
16
|
+
const videoMap = sortAssetMap(await processVideoFiles(videosDirectory, existingVideos));
|
|
17
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
18
|
+
await Bun.write(outputPath, createGeneratedVideoListContent(videoMap, resolvedVideoTypeImportPath));
|
|
19
|
+
await formatGeneratedCodeFile(outputPath, logger);
|
|
20
|
+
logger?.files(`generated video list: ${outputPath}`);
|
|
21
|
+
logger?.summary(`Generated ${Object.keys(videoMap).length} videos to ${outputPath}`);
|
|
22
|
+
}
|
|
23
|
+
async function processVideoFiles(directory, existingVideos) {
|
|
24
|
+
const videoMap = {};
|
|
25
|
+
let filePaths;
|
|
26
|
+
try {
|
|
27
|
+
filePaths = await walkFiles(directory);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (isMissingDirError(error)) {
|
|
31
|
+
return videoMap;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
for (const filePath of filePaths) {
|
|
36
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
37
|
+
if (!supportedVideoSourceExtensions.has(extension)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const relativePath = path.relative(directory, filePath);
|
|
41
|
+
const key = getAssetKey(filePath);
|
|
42
|
+
const previewPath = createVideoPreviewPath(filePath);
|
|
43
|
+
const previewBuffer = await fs.readFile(previewPath);
|
|
44
|
+
const previewDimensions = imageSize(previewBuffer);
|
|
45
|
+
if (!previewDimensions.width || !previewDimensions.height) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const fileName = path.basename(filePath, extension);
|
|
49
|
+
const existingPreview = existingVideos[key]?.image;
|
|
50
|
+
videoMap[key] = {
|
|
51
|
+
path: relativePath,
|
|
52
|
+
mimeType: getVideoMimeType(extension),
|
|
53
|
+
image: {
|
|
54
|
+
path: path.relative(directory, previewPath),
|
|
55
|
+
width: previewDimensions.width,
|
|
56
|
+
height: previewDimensions.height,
|
|
57
|
+
alt: existingPreview?.alt || fileName.replace(/[-_]/g, " "),
|
|
58
|
+
mimeType: "image/jpeg",
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return videoMap;
|
|
63
|
+
}
|
|
64
|
+
function createGeneratedVideoListContent(videoMap, videoTypeImportPath) {
|
|
65
|
+
return `import type { VideoType } from "${videoTypeImportPath}"
|
|
66
|
+
|
|
67
|
+
// Auto-generated, manual changes will be lost, generated by optimizeAssets from @adaptive-ds/assets-optimizer
|
|
68
|
+
export const videoList = ${JSON.stringify(videoMap, null, 2)} as const satisfies Record<string, VideoType>
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
function getVideoMimeType(extension) {
|
|
72
|
+
switch (extension) {
|
|
73
|
+
case ".mp4":
|
|
74
|
+
case ".m4v":
|
|
75
|
+
return "video/mp4";
|
|
76
|
+
case ".mov":
|
|
77
|
+
return "video/quicktime";
|
|
78
|
+
case ".webm":
|
|
79
|
+
return "video/webm";
|
|
80
|
+
case ".avi":
|
|
81
|
+
return "video/x-msvideo";
|
|
82
|
+
case ".mkv":
|
|
83
|
+
return "video/x-matroska";
|
|
84
|
+
default:
|
|
85
|
+
return "application/octet-stream";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getAssetKey.d.ts","sourceRoot":"","sources":["../../src/list/getAssetKey.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUpD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function getAssetKey(filePath) {
|
|
3
|
+
const extension = path.extname(filePath);
|
|
4
|
+
const fileName = path.basename(filePath, extension);
|
|
5
|
+
let key = fileName.replace(/-/g, "_");
|
|
6
|
+
if (/^\d/.test(key)) {
|
|
7
|
+
key = `i${key}`;
|
|
8
|
+
}
|
|
9
|
+
return key;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadExistingAssetList.d.ts","sourceRoot":"","sources":["../../src/list/loadExistingAssetList.ts"],"names":[],"mappings":"AAGA,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAgB/G"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
export async function loadExistingAssetList(filePath, exportName) {
|
|
4
|
+
try {
|
|
5
|
+
await fs.access(filePath);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const moduleUrl = `${pathToFileURL(filePath).href}?t=${Date.now()}`;
|
|
12
|
+
const existingModule = (await import(moduleUrl));
|
|
13
|
+
const existingList = existingModule[exportName];
|
|
14
|
+
return isRecord(existingList) ? existingList : {};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.warn(`Failed to load existing ${exportName} from ${filePath}:`, error);
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return typeof value === "object" && value !== null;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortAssetMap.d.ts","sourceRoot":"","sources":["../../src/list/sortAssetMap.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAU9E"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface BisyncOptions {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
resync?: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* https://rclone.org/bisync/#limitations
|
|
7
|
+
*/
|
|
8
|
+
export declare function bisync(localPath: string, remotePath: string, options?: BisyncOptions): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=bisync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bisync.d.ts","sourceRoot":"","sources":["../../src/rclone/bisync.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB9G"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { dirExists } from "../shared/dirExists.js";
|
|
3
|
+
import { runRclone } from "./runRclone.js";
|
|
4
|
+
/**
|
|
5
|
+
* https://rclone.org/bisync/#limitations
|
|
6
|
+
*/
|
|
7
|
+
export async function bisync(localPath, remotePath, options = {}) {
|
|
8
|
+
const cwd = options.cwd ?? process.cwd();
|
|
9
|
+
const localDirExists = await dirExists(localPath);
|
|
10
|
+
await fs.mkdir(localPath, { recursive: true });
|
|
11
|
+
await runRclone(["mkdir", remotePath], cwd);
|
|
12
|
+
const args = [
|
|
13
|
+
"bisync",
|
|
14
|
+
localPath,
|
|
15
|
+
remotePath,
|
|
16
|
+
"--create-empty-src-dirs",
|
|
17
|
+
"--resilient",
|
|
18
|
+
"--recover",
|
|
19
|
+
"--ignore-listing",
|
|
20
|
+
];
|
|
21
|
+
if (options.resync === true || !localDirExists) {
|
|
22
|
+
args.push("--resync");
|
|
23
|
+
}
|
|
24
|
+
await runRclone(args, cwd);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runRclone.d.ts","sourceRoot":"","sources":["../../src/rclone/runRclone.ts"],"names":[],"mappings":"AAAA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAclF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export async function runRclone(args, cwd = process.cwd()) {
|
|
2
|
+
const command = ["rclone", ...args];
|
|
3
|
+
console.log(command.join(" "));
|
|
4
|
+
const proc = Bun.spawn(command, {
|
|
5
|
+
cwd,
|
|
6
|
+
stdout: "inherit",
|
|
7
|
+
stderr: "inherit",
|
|
8
|
+
});
|
|
9
|
+
const exitCode = await proc.exited;
|
|
10
|
+
if (exitCode !== 0) {
|
|
11
|
+
throw new Error(`rclone ${args.join(" ")} failed with exit code ${exitCode}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertNever.d.ts","sourceRoot":"","sources":["../../src/shared/assertNever.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dirExists.d.ts","sourceRoot":"","sources":["../../src/shared/dirExists.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getOwnPackageName.d.ts","sourceRoot":"","sources":["../../src/shared/getOwnPackageName.ts"],"names":[],"mappings":"AAIA,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB1E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export async function getOwnPackageName(moduleUrl) {
|
|
5
|
+
let currentDir = path.dirname(fileURLToPath(moduleUrl));
|
|
6
|
+
while (true) {
|
|
7
|
+
const packageJsonPath = path.join(currentDir, "package.json");
|
|
8
|
+
try {
|
|
9
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
|
|
10
|
+
if (packageJson.name) {
|
|
11
|
+
return packageJson.name;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
15
|
+
const parentDir = path.dirname(currentDir);
|
|
16
|
+
if (parentDir === currentDir) {
|
|
17
|
+
throw new Error(`Could not resolve package name for ${moduleUrl}`);
|
|
18
|
+
}
|
|
19
|
+
currentDir = parentDir;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isMissingDirError.d.ts","sourceRoot":"","sources":["../../src/shared/isMissingDirError.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAEhF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listLocalFiles.d.ts","sourceRoot":"","sources":["../../src/shared/listLocalFiles.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUnE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isMissingDirError } from "./isMissingDirError.js";
|
|
2
|
+
import { walkFiles } from "./walkFiles.js";
|
|
3
|
+
export async function listLocalFiles(dir) {
|
|
4
|
+
try {
|
|
5
|
+
return await walkFiles(dir);
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
if (isMissingDirError(error)) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type LogLevel = 0 | 1 | 2 | 3;
|
|
2
|
+
export interface Logger {
|
|
3
|
+
readonly level: LogLevel;
|
|
4
|
+
isEnabled(level: LogLevel): boolean;
|
|
5
|
+
summary(message: string): void;
|
|
6
|
+
files(message: string): void;
|
|
7
|
+
cli(message: string): void;
|
|
8
|
+
verbose(message: string): void;
|
|
9
|
+
warn(message: string): void;
|
|
10
|
+
error(message: string): void;
|
|
11
|
+
}
|
|
12
|
+
export declare function createLogger(logLevel: number | undefined): Logger;
|
|
13
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/shared/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAEpC,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAA;IACnC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAiCjE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function createLogger(logLevel) {
|
|
2
|
+
const level = normalizeLogLevel(logLevel);
|
|
3
|
+
const log = (minimumLevel, message, write = console.log) => {
|
|
4
|
+
if (level >= minimumLevel) {
|
|
5
|
+
write(message);
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
return {
|
|
9
|
+
level,
|
|
10
|
+
isEnabled(minimumLevel) {
|
|
11
|
+
return level >= minimumLevel;
|
|
12
|
+
},
|
|
13
|
+
summary(message) {
|
|
14
|
+
log(1, message);
|
|
15
|
+
},
|
|
16
|
+
files(message) {
|
|
17
|
+
log(1, message);
|
|
18
|
+
},
|
|
19
|
+
cli(message) {
|
|
20
|
+
log(2, message);
|
|
21
|
+
},
|
|
22
|
+
verbose(message) {
|
|
23
|
+
log(3, message);
|
|
24
|
+
},
|
|
25
|
+
warn(message) {
|
|
26
|
+
log(1, message, console.warn);
|
|
27
|
+
},
|
|
28
|
+
error(message) {
|
|
29
|
+
log(1, message, console.error);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function normalizeLogLevel(logLevel) {
|
|
34
|
+
if (logLevel == null) {
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
if (logLevel <= 0) {
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
if (logLevel === 1) {
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
if (logLevel === 2) {
|
|
44
|
+
return 2;
|
|
45
|
+
}
|
|
46
|
+
return 3;
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printSummary.d.ts","sourceRoot":"","sources":["../../src/shared/printSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,wBAAgB,YAAY,CAAC,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA6B/E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function printSummary(result, logger) {
|
|
2
|
+
logger.summary(`Processed ${result.processed.length} new optimized images`);
|
|
3
|
+
logger.summary(`Skipped ${result.skippedExisting.length} existing optimized images`);
|
|
4
|
+
logger.summary(`Skipped ${result.skippedRootFiles.length} root original files`);
|
|
5
|
+
logger.summary(`Deleted ${result.deletedLocal.length} stale local optimized images`);
|
|
6
|
+
logger.summary(`Processed ${result.processedVideos.length} new optimized videos`);
|
|
7
|
+
logger.summary(`Skipped ${result.skippedExistingVideos.length} existing processed videos`);
|
|
8
|
+
logger.summary(`Generated ${result.processedVideoPreviews.length} new video previews`);
|
|
9
|
+
logger.summary(`Skipped ${result.skippedExistingVideoPreviews.length} existing video previews`);
|
|
10
|
+
for (const fileName of result.processed) {
|
|
11
|
+
logger.files(`processed image: ${fileName}`);
|
|
12
|
+
}
|
|
13
|
+
for (const fileName of result.deletedLocal) {
|
|
14
|
+
logger.files(`deleted local image: ${fileName}`);
|
|
15
|
+
}
|
|
16
|
+
for (const fileName of result.processedVideos) {
|
|
17
|
+
logger.files(`processed video: ${fileName}`);
|
|
18
|
+
}
|
|
19
|
+
for (const fileName of result.processedVideoPreviews) {
|
|
20
|
+
logger.files(`generated preview: ${fileName}`);
|
|
21
|
+
}
|
|
22
|
+
for (const warning of result.warnings) {
|
|
23
|
+
logger.warn(warning);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walkFiles.d.ts","sourceRoot":"","sources":["../../src/shared/walkFiles.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiB9D"}
|