dev-toolkit-cli 1.0.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.
@@ -0,0 +1,13 @@
1
+ import { Resolution } from "../lib/constants";
2
+ export declare const FileType: readonly ["image", "video"];
3
+ type FileType = (typeof FileType)[number];
4
+ export type CompressFileArgs = {
5
+ verbose: number;
6
+ type: FileType;
7
+ resolution: Resolution;
8
+ force: boolean;
9
+ horizontal: boolean;
10
+ };
11
+ export declare function file(pathname: string, { verbose, type, resolution, force, horizontal }: CompressFileArgs): Promise<void>;
12
+ export {};
13
+ //# sourceMappingURL=action-compress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-compress.d.ts","sourceRoot":"","sources":["../../src/actions/action-compress.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAa9C,eAAO,MAAM,QAAQ,6BAA8B,CAAC;AACpD,KAAK,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAU1C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAsB,IAAI,CACxB,QAAQ,EAAE,MAAM,EAChB,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,gBAAgB,iBA+CnE"}
@@ -0,0 +1,83 @@
1
+ import { CommanderError } from "commander";
2
+ import fs from "fs/promises";
3
+ import mime from "mime";
4
+ import path from "path";
5
+ import sharp from "sharp";
6
+ import { addFilenamePrefix, getAvailablePathname, getDirectory, getFilename, getFolderFiles, normalizeFilename, removeFilenamePrefix, replaceFilenameExtension, } from "../lib/utils/index.js";
7
+ import { check_dependencies, ffmpeg_video_compress } from "../lib/bash.js";
8
+ export const FileType = ["image", "video"];
9
+ const unsupportedFormats = {
10
+ image: ["image/webp", "image/gif", "image/svg+xml"],
11
+ video: [],
12
+ };
13
+ const compressedFlagPrefix = "compressed_";
14
+ const compressTempPrefix = "temp.";
15
+ export async function file(pathname, { verbose, type, resolution, force, horizontal }) {
16
+ await check_dependencies(["ffmpeg"]);
17
+ if (force)
18
+ console.warn("⚠️ Ignoring already compressed files");
19
+ if (horizontal)
20
+ console.warn("⚠️ Forcing horizontal aspect ratio 16x9");
21
+ let verbose_title = "";
22
+ const filePathList = await getFolderFiles(pathname, true);
23
+ for (let filePath of filePathList) {
24
+ const mimetype = mime.getType(filePath);
25
+ if (!mimetype)
26
+ continue;
27
+ const fileType = mimetype.split("/")[0];
28
+ if (!(type ? [type] : FileType).includes(fileType) ||
29
+ (unsupportedFormats[fileType] || []).includes(mimetype) ||
30
+ (!force &&
31
+ [compressedFlagPrefix, compressTempPrefix].some((pf) => getFilename(filePath).startsWith(pf))))
32
+ continue;
33
+ const title = filePath
34
+ .substring(pathname.length)
35
+ .split("/")
36
+ .slice(1, 1 + verbose)
37
+ .join("/");
38
+ if (title !== verbose_title)
39
+ console.log(`Compressing ${fileType} at:`, title);
40
+ verbose_title = title;
41
+ try {
42
+ if (fileType === "image")
43
+ await compressImage(filePath);
44
+ else if (fileType === "video")
45
+ await compressVideo(filePath, resolution, horizontal);
46
+ }
47
+ catch (err) {
48
+ console.error(" Error compressing", `"${filePath}"`);
49
+ // console.error("Error compressing", `"${filePath}"`, err.message);
50
+ }
51
+ }
52
+ console.log("\nCompression successfully finished 🚀");
53
+ }
54
+ async function compressImage(filePath) {
55
+ await sharp(filePath)
56
+ .webp()
57
+ .toFile(replaceFilenameExtension(filePath, "webp"));
58
+ await fs.rm(filePath);
59
+ }
60
+ async function compressVideo(filePath, resolution, force) {
61
+ const directory = getDirectory(filePath);
62
+ let filename = getFilename(filePath);
63
+ const normalizedFilename = normalizeFilename(filename);
64
+ if (filename !== normalizedFilename) {
65
+ const oldPathname = path.join(directory, filename);
66
+ const newPathname = await getAvailablePathname(path.join(directory, normalizedFilename));
67
+ if (!newPathname) {
68
+ throw new CommanderError(1, "P003", "Could not find a new file destination");
69
+ }
70
+ const newFilename = getFilename(newPathname);
71
+ console.log(" File renamed. From:", `'${filename.trim()}'`, "to:", `'${newFilename.trim()}'`);
72
+ await fs.rename(oldPathname, newPathname);
73
+ filename = newFilename;
74
+ }
75
+ const input = path.join(directory, filename);
76
+ const output = addFilenamePrefix(input, compressTempPrefix);
77
+ await ffmpeg_video_compress(input, output, resolution, force).catch(async (err) => {
78
+ await fs.rm(output);
79
+ throw err;
80
+ });
81
+ await fs.rm(input);
82
+ await fs.rename(output, addFilenamePrefix(removeFilenamePrefix(input, compressedFlagPrefix), compressedFlagPrefix));
83
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-compress.js","sourceRoot":"","sources":["../../src/actions/action-compress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * as compress from "./action-compress.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1 @@
1
+ export * as compress from "./action-compress.js";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Resolution } from "./constants.js";
2
+ export declare const execAsync: (command: string) => Promise<unknown>;
3
+ export declare function check_dependencies(dependencies?: string[]): Promise<void>;
4
+ export declare function ffmpeg_video_compress(input: string, output: string, resolution?: Resolution, forceResolution?: boolean): Promise<unknown>;
5
+ //# sourceMappingURL=bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/lib/bash.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAqB,MAAM,gBAAgB,CAAC;AAG/D,eAAO,MAAM,SAAS,YAAa,MAAM,qBAMrC,CAAC;AAUL,wBAAsB,kBAAkB,CAAC,YAAY,WAAqB,iBAczE;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,UAAmB,EAC/B,eAAe,CAAC,EAAE,OAAO,oBAS1B"}
@@ -0,0 +1,33 @@
1
+ import { exec } from "child_process";
2
+ import { resolutionMapping } from "./constants.js";
3
+ import { CommanderError } from "commander";
4
+ export const execAsync = (command) => new Promise((resolve, reject) => {
5
+ exec(command, (error, stdout, stderr) => {
6
+ if (error)
7
+ reject(new Error(stderr));
8
+ else
9
+ resolve(stdout);
10
+ });
11
+ });
12
+ const globalDependencies = ["ffmpeg"];
13
+ async function check_dependency(dependency) {
14
+ return execAsync(`${dependency} -h`)
15
+ .then(() => true)
16
+ .catch(() => false);
17
+ }
18
+ export async function check_dependencies(dependencies = globalDependencies) {
19
+ const missing_dependencies = [];
20
+ for (let dep of dependencies) {
21
+ if (!(await check_dependency(dep)))
22
+ missing_dependencies.push(dep);
23
+ }
24
+ if (missing_dependencies.length > 0) {
25
+ throw new CommanderError(1, "missing_dependencies", missing_dependencies.map((dep) => `'${dep}'`).join(", "));
26
+ }
27
+ }
28
+ export async function ffmpeg_video_compress(input, output, resolution = "480p", forceResolution) {
29
+ const { w, h } = resolutionMapping[resolution];
30
+ return execAsync(forceResolution
31
+ ? `ffmpeg -i "${input}" -s ${w}x${h} -acodec copy -y "${output}"`
32
+ : `ffmpeg -i "${input}" -filter:v scale=-1:${h} -acodec copy -y "${output}"`);
33
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/lib/bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAc,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAe,EAAE,EAAE,CAC3C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,KAAK;YAAE,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;;YAChC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,MAAM,kBAAkB,GAAG,CAAC,QAAQ,CAAC,CAAC;AAEtC,KAAK,UAAU,gBAAgB,CAAC,UAAkB;IAChD,OAAO,SAAS,CAAC,GAAG,UAAU,KAAK,CAAC;SACjC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;SAChB,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,YAAY,GAAG,kBAAkB;IACxE,MAAM,oBAAoB,GAAG,EAAE,CAAC;IAEhC,KAAK,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAAE,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,cAAc,CACtB,CAAC,EACD,sBAAsB,EACtB,oBAAoB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACzD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAa,EACb,MAAc,EACd,aAAyB,MAAM,EAC/B,eAAyB;IAEzB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAE/C,OAAO,SAAS,CACd,eAAe;QACb,CAAC,CAAC,cAAc,KAAK,QAAQ,CAAC,IAAI,CAAC,qBAAqB,MAAM,GAAG;QACjE,CAAC,CAAC,cAAc,KAAK,wBAAwB,CAAC,qBAAqB,MAAM,GAAG,CAC/E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ export declare const resolutionMapping: {
2
+ readonly "4320p": {
3
+ readonly w: 7680;
4
+ readonly h: 4320;
5
+ };
6
+ readonly "2160p": {
7
+ readonly w: 3840;
8
+ readonly h: 2160;
9
+ };
10
+ readonly "1440p": {
11
+ readonly w: 2560;
12
+ readonly h: 1440;
13
+ };
14
+ readonly "1080p": {
15
+ readonly w: 1920;
16
+ readonly h: 1080;
17
+ };
18
+ readonly "720p": {
19
+ readonly w: 1280;
20
+ readonly h: 720;
21
+ };
22
+ readonly "480p": {
23
+ readonly w: 854;
24
+ readonly h: 480;
25
+ };
26
+ readonly "360p": {
27
+ readonly w: 640;
28
+ readonly h: 360;
29
+ };
30
+ readonly "240p": {
31
+ readonly w: 426;
32
+ readonly h: 240;
33
+ };
34
+ };
35
+ export declare const Resolution: readonly ["4320p", "2160p", "1440p", "1080p", "720p", "480p", "360p", "240p"];
36
+ export type Resolution = (typeof Resolution)[number];
37
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCpB,CAAC;AAEX,eAAO,MAAM,UAAU,+EASb,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ export const resolutionMapping = {
2
+ "4320p": {
3
+ w: 7680,
4
+ h: 4320,
5
+ },
6
+ "2160p": {
7
+ w: 3840,
8
+ h: 2160,
9
+ },
10
+ "1440p": {
11
+ w: 2560,
12
+ h: 1440,
13
+ },
14
+ "1080p": {
15
+ w: 1920,
16
+ h: 1080,
17
+ },
18
+ "720p": {
19
+ w: 1280,
20
+ h: 720,
21
+ },
22
+ "480p": {
23
+ w: 854,
24
+ h: 480,
25
+ },
26
+ "360p": {
27
+ w: 640,
28
+ h: 360,
29
+ },
30
+ "240p": {
31
+ w: 426,
32
+ h: 240,
33
+ },
34
+ };
35
+ export const Resolution = [
36
+ "4320p",
37
+ "2160p",
38
+ "1440p",
39
+ "1080p",
40
+ "720p",
41
+ "480p",
42
+ "360p",
43
+ "240p",
44
+ ];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE;QACP,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,IAAI;KACR;IACD,OAAO,EAAE;QACP,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,IAAI;KACR;IACD,OAAO,EAAE;QACP,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,IAAI;KACR;IACD,OAAO,EAAE;QACP,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,IAAI;KACR;IACD,MAAM,EAAE;QACN,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,GAAG;KACP;IACD,MAAM,EAAE;QACN,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,GAAG;KACP;IACD,MAAM,EAAE;QACN,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,GAAG;KACP;IACD,MAAM,EAAE;QACN,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,GAAG;KACP;CACO,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACE,CAAC"}
@@ -0,0 +1,13 @@
1
+ export declare function getFolderFiles(pathname: string, recursive?: boolean): Promise<Array<string>>;
2
+ export declare function getFolderList(pathname: string): Promise<string[]>;
3
+ export declare function getFilenameExtension(filename: string): string | undefined;
4
+ export declare function replaceFilenameExtension(filename: string, newExtension: string): string;
5
+ export declare function addFilenameSuffix(pathname: string, suffix: string): string;
6
+ export declare function addFilenamePrefix(pathname: string, prefix: string): string;
7
+ export declare function removeFilenamePrefix(pathname: string, prefix: string): string;
8
+ export declare function getFilenameWithoutExtension(filename: string): string;
9
+ export declare function getAvailablePathname(pathname: string): Promise<string | null>;
10
+ export declare function getFilename(pathname: string): string;
11
+ export declare function getDirectory(pathname: string): string;
12
+ export declare function normalizeFilename(filename: string): string;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/index.ts"],"names":[],"mappings":"AAMA,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,UAAQ,GAChB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CA4BxB;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,qBAWnD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,sBAIpD;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,UAGrB;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UASjE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAIjE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAKpE;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,UAK3D;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,0BAQ1D;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,UAE3C;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,UAE5C;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,UAoBjD"}
@@ -0,0 +1,89 @@
1
+ import fs from "fs/promises";
2
+ import fsSync from "fs";
3
+ import path from "path";
4
+ export async function getFolderFiles(pathname, recursive = false) {
5
+ const list = await fs.readdir(pathname);
6
+ let { folder_list, file_list } = await list.reduce(async (_acc, name) => {
7
+ const acc = await _acc;
8
+ const is_directory = (await fs.lstat(path.join(pathname, name))).isDirectory();
9
+ if (is_directory)
10
+ acc.folder_list.push(name);
11
+ else
12
+ acc.file_list.push(name);
13
+ return acc;
14
+ }, Promise.resolve({ folder_list: [], file_list: [] }));
15
+ file_list = file_list.map((name) => path.join(pathname, name));
16
+ if (!recursive)
17
+ return file_list;
18
+ const subfolder_file_list = await Promise.all(folder_list.map((folder_name) => getFolderFiles(path.join(pathname, folder_name), recursive))).then((l) => l.flatMap((l) => l));
19
+ file_list.push(...subfolder_file_list);
20
+ return file_list;
21
+ }
22
+ export async function getFolderList(pathname) {
23
+ return Promise.all((await fs.readdir(pathname)).map(async (name) => {
24
+ const is_directory = (await fs.lstat(path.join(pathname, name))).isDirectory();
25
+ return { name, is_directory };
26
+ })).then((result) => result.filter((it) => it.is_directory).map((it) => it.name));
27
+ }
28
+ export function getFilenameExtension(filename) {
29
+ return ((filename.includes(".") && filename.split(".").slice(-1)[0]) || undefined);
30
+ }
31
+ export function replaceFilenameExtension(filename, newExtension) {
32
+ return `${getFilenameWithoutExtension(filename)}.${newExtension}`;
33
+ }
34
+ export function addFilenameSuffix(pathname, suffix) {
35
+ const directory = getDirectory(pathname);
36
+ const filename = getFilename(pathname);
37
+ const extension = getFilenameExtension(filename);
38
+ const filenameWithoutExtension = getFilenameWithoutExtension(filename);
39
+ return path.join(directory, `${filenameWithoutExtension}${suffix}.${extension}`);
40
+ }
41
+ export function addFilenamePrefix(pathname, prefix) {
42
+ const directory = getDirectory(pathname);
43
+ const filename = getFilename(pathname);
44
+ return path.join(directory, `${prefix}${filename}`);
45
+ }
46
+ export function removeFilenamePrefix(pathname, prefix) {
47
+ const directory = getDirectory(pathname);
48
+ const filename = getFilename(pathname);
49
+ if (!filename.startsWith(prefix))
50
+ return pathname;
51
+ return path.join(directory, filename.substring(prefix.length));
52
+ }
53
+ export function getFilenameWithoutExtension(filename) {
54
+ return ((filename.includes(".") && filename.split(".").slice(0, -1).join(".")) ||
55
+ filename);
56
+ }
57
+ export async function getAvailablePathname(pathname) {
58
+ for (let i = 0; i < Number.MAX_SAFE_INTEGER; i++) {
59
+ const availablePathname = i === 0 ? pathname : addFilenameSuffix(pathname, ` (${i})`);
60
+ if (!fsSync.existsSync(availablePathname))
61
+ return availablePathname;
62
+ }
63
+ return null;
64
+ }
65
+ export function getFilename(pathname) {
66
+ return pathname.split("/").slice(-1)[0];
67
+ }
68
+ export function getDirectory(pathname) {
69
+ return pathname.split("/").slice(0, -1).join("/");
70
+ }
71
+ export function normalizeFilename(filename) {
72
+ return (filename
73
+ .normalize("NFD")
74
+ .replace(/[\u0300-\u036f]/g, "")
75
+ // Avoid multiple characters
76
+ .replace(/[ ]{2,}/g, " ")
77
+ .replace(/[.]{2,}/g, ".")
78
+ .replace(/[-]{2,}/g, "-")
79
+ // Replace ' - ' to '-'
80
+ .replace(/[ ][-][ ]/g, "-")
81
+ .replace(/[-][ ]/g, "-")
82
+ .replace(/[ ][-]/g, "-")
83
+ // Replace space to '_'
84
+ .replace(/[ ]/g, "_")
85
+ // Remove all not allowed characters
86
+ .replace(/[^-.0-9_a-zA-Z[]]/g, "")
87
+ // Remove all not alphanumeric characters on start
88
+ .replace(/^[^0-9a-zA-Z]/g, ""));
89
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,MAAM,MAAM,IAAI,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AAIxB,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,SAAS,GAAG,KAAK;IAEjB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAExC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACtE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC;QACvB,MAAM,YAAY,GAAG,CACnB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAC1C,CAAC,WAAW,EAAE,CAAC;QAEhB,IAAI,YAAY;YAAE,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YACxC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE9B,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAmB,CAAC,CAAC,CAAC;IAEzE,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/D,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAEjC,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,GAAG,CAC3C,WAAW,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAC9B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,SAAS,CAAC,CAC5D,CACF,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnC,SAAS,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,CAAC;IAEvC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,OAAO,OAAO,CAAC,GAAG,CAChB,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC9C,MAAM,YAAY,GAAG,CACnB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAC1C,CAAC,WAAW,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAChC,CAAC,CAAC,CACH,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAChB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,OAAO,CACL,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAC1E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,QAAgB,EAChB,YAAoB;IAEpB,OAAO,GAAG,2BAA2B,CAAC,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,MAAM,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,wBAAwB,GAAG,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IACvE,OAAO,IAAI,CAAC,IAAI,CACd,SAAS,EACT,GAAG,wBAAwB,GAAG,MAAM,IAAI,SAAS,EAAE,CACpD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,MAAM,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAc;IACnE,MAAM,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IAClD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAgB;IAC1D,OAAO,CACL,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtE,QAAQ,CACT,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,iBAAiB,GACrB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC;YAAE,OAAO,iBAAiB,CAAC;IACtE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,OAAO,CACL,QAAQ;SACL,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAChC,4BAA4B;SAC3B,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;QACzB,uBAAuB;SACtB,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC;SAC1B,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;QACxB,uBAAuB;SACtB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;QACrB,oCAAoC;SACnC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC;QAClC,kDAAkD;SACjD,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CACjC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,89 @@
1
+ import fs from "fs/promises";
2
+ import fsSync from "fs";
3
+ import path from "path";
4
+ export async function getFolderFiles(pathname, recursive = false) {
5
+ const list = await fs.readdir(pathname);
6
+ let { folder_list, file_list } = await list.reduce(async (_acc, name) => {
7
+ const acc = await _acc;
8
+ const is_directory = (await fs.lstat(path.join(pathname, name))).isDirectory();
9
+ if (is_directory)
10
+ acc.folder_list.push(name);
11
+ else
12
+ acc.file_list.push(name);
13
+ return acc;
14
+ }, Promise.resolve({ folder_list: [], file_list: [] }));
15
+ file_list = file_list.map((name) => path.join(pathname, name));
16
+ if (!recursive)
17
+ return file_list;
18
+ const subfolder_file_list = await Promise.all(folder_list.map((folder_name) => getFolderFiles(path.join(pathname, folder_name), recursive))).then((l) => l.flatMap((l) => l));
19
+ file_list.push(...subfolder_file_list);
20
+ return file_list;
21
+ }
22
+ export async function getFolderList(pathname) {
23
+ return Promise.all((await fs.readdir(pathname)).map(async (name) => {
24
+ const is_directory = (await fs.lstat(path.join(pathname, name))).isDirectory();
25
+ return { name, is_directory };
26
+ })).then((result) => result.filter((it) => it.is_directory).map((it) => it.name));
27
+ }
28
+ export function getFilenameExtension(filename) {
29
+ return ((filename.includes(".") && filename.split(".").slice(-1)[0]) || undefined);
30
+ }
31
+ export function replaceFilenameExtension(filename, newExtension) {
32
+ return `${getFilenameWithoutExtension(filename)}.${newExtension}`;
33
+ }
34
+ export function addFilenameSuffix(pathname, suffix) {
35
+ const directory = getDirectory(pathname);
36
+ const filename = getFilename(pathname);
37
+ const extension = getFilenameExtension(filename);
38
+ const filenameWithoutExtension = getFilenameWithoutExtension(filename);
39
+ return path.join(directory, `${filenameWithoutExtension}${suffix}.${extension}`);
40
+ }
41
+ export function addFilenamePrefix(pathname, prefix) {
42
+ const directory = getDirectory(pathname);
43
+ const filename = getFilename(pathname);
44
+ return path.join(directory, `${prefix}${filename}`);
45
+ }
46
+ export function removeFilenamePrefix(pathname, prefix) {
47
+ const directory = getDirectory(pathname);
48
+ const filename = getFilename(pathname);
49
+ if (!filename.startsWith(prefix))
50
+ return pathname;
51
+ return path.join(directory, filename.substring(prefix.length));
52
+ }
53
+ export function getFilenameWithoutExtension(filename) {
54
+ return ((filename.includes(".") && filename.split(".").slice(0, -1).join(".")) ||
55
+ filename);
56
+ }
57
+ export async function getAvailablePathname(pathname) {
58
+ for (let i = 0; i < Number.MAX_SAFE_INTEGER; i++) {
59
+ const availablePathname = i === 0 ? pathname : addFilenameSuffix(pathname, ` (${i})`);
60
+ if (!fsSync.existsSync(availablePathname))
61
+ return availablePathname;
62
+ }
63
+ return null;
64
+ }
65
+ export function getFilename(pathname) {
66
+ return pathname.split("/").slice(-1)[0];
67
+ }
68
+ export function getDirectory(pathname) {
69
+ return pathname.split("/").slice(0, -1).join("/");
70
+ }
71
+ export function normalizeFilename(filename) {
72
+ return (filename
73
+ .normalize("NFD")
74
+ .replace(/[\u0300-\u036f]/g, "")
75
+ // Avoid multiple characters
76
+ .replace(/[ ]{2,}/g, " ")
77
+ .replace(/[.]{2,}/g, ".")
78
+ .replace(/[-]{2,}/g, "-")
79
+ // Replace ' - ' to '-'
80
+ .replace(/[ ][-][ ]/g, "-")
81
+ .replace(/[-][ ]/g, "-")
82
+ .replace(/[ ][-]/g, "-")
83
+ // Replace space to '_'
84
+ .replace(/[ ]/g, "_")
85
+ // Remove all not allowed characters
86
+ .replace(/[^-.0-9_a-zA-Z[]]/g, "")
87
+ // Remove all not alphanumeric characters on start
88
+ .replace(/^[^0-9a-zA-Z]/g, ""));
89
+ }
@@ -0,0 +1,4 @@
1
+ export declare function PathArgument(previous: string): string;
2
+ export declare function NumericOption(previous: string): number;
3
+ export declare function EnumOption<E extends readonly string[], T extends E[number]>(enumerator: E): (previous: string) => T;
4
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/lib/validation.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,UAI5C;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,UAK7C;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EACzE,UAAU,EAAE,CAAC,cAEK,MAAM,KAAG,CAAC,CAQ7B"}
@@ -0,0 +1,21 @@
1
+ import { InvalidArgumentError, InvalidOptionArgumentError } from "commander";
2
+ import fs from "fs";
3
+ export function PathArgument(previous) {
4
+ if (!fs.existsSync(previous))
5
+ throw new InvalidArgumentError("No such a file or directory");
6
+ return previous;
7
+ }
8
+ export function NumericOption(previous) {
9
+ const result = parseInt(previous);
10
+ if (Number.isNaN(result))
11
+ throw new InvalidOptionArgumentError("Not a number");
12
+ return result;
13
+ }
14
+ export function EnumOption(enumerator) {
15
+ return (previous) => {
16
+ if (!enumerator.includes(previous)) {
17
+ throw new InvalidOptionArgumentError(`Expected '${enumerator.join(" | ")} ', received '${previous}'`);
18
+ }
19
+ return previous;
20
+ };
21
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/lib/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC1B,MAAM,IAAI,oBAAoB,CAAC,6BAA6B,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACtB,MAAM,IAAI,0BAA0B,CAAC,cAAc,CAAC,CAAC;IACvD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,UAAa;IAEb,OAAO,CAAC,QAAgB,EAAK,EAAE;QAC7B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,0BAA0B,CAClC,aAAa,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,QAAQ,GAAG,CAChE,CAAC;QACJ,CAAC;QACD,OAAO,QAAa,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC"}
package/bin/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
package/bin/main.js ADDED
@@ -0,0 +1,35 @@
1
+ // #!/usr/bin/env node
2
+ import { Command, CommanderError } from "commander";
3
+ // import { ZodError } from "zod";
4
+ import { FileType } from "./actions/action-compress.js";
5
+ import * as actions from "./actions/index.js";
6
+ import { Resolution } from "./lib/constants.js";
7
+ import { EnumOption, NumericOption, PathArgument } from "./lib/validation.js";
8
+ /** Setup */
9
+ const program = new Command();
10
+ program
11
+ .name("dev-toolkit")
12
+ .description("A simple CLI app to help developers in their tasks.");
13
+ program
14
+ .command("compress")
15
+ .description("Compress large files and save storage space.")
16
+ .argument("<pathname>", "Pathname", PathArgument)
17
+ .option("-V, --verbose <number>", "Level of pathname to log", NumericOption, 10)
18
+ .option("-T, --type <string>", "File type", EnumOption(FileType))
19
+ .option("-R, --resolution <string>", "Resolution", EnumOption(Resolution), "480p")
20
+ .option("-F, --force", "Ignores compressed flag")
21
+ .option("-H, --horizontal", "Force horizontal 16x9 aspect ratio")
22
+ .action(actions.compress.file);
23
+ program.parseAsync(process.argv).catch((err) => {
24
+ if (err instanceof CommanderError) {
25
+ console.log(`Error (${err.code}): ${err.message}`);
26
+ }
27
+ else if (err instanceof Error) {
28
+ if (process.env.NODE_ENV === "development") {
29
+ console.error(err);
30
+ }
31
+ else {
32
+ console.error(err.message);
33
+ }
34
+ }
35
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,sBAAsB;AAEtB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpD,kCAAkC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE9E,YAAY;AACZ,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,qDAAqD,CAAC,CAAC;AAEtE,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,8CAA8C,CAAC;KAC3D,QAAQ,CAAC,YAAY,EAAE,UAAU,EAAE,YAAY,CAAC;KAChD,MAAM,CACL,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,EAAE,CACH;KACA,MAAM,CAAC,qBAAqB,EAAE,WAAW,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;KAChE,MAAM,CACL,2BAA2B,EAC3B,YAAY,EACZ,UAAU,CAAC,UAAU,CAAC,EACtB,MAAM,CACP;KACA,MAAM,CAAC,aAAa,EAAE,yBAAyB,CAAC;KAChD,MAAM,CAAC,kBAAkB,EAAE,oCAAoC,CAAC;KAChE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAEjC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;SAAM,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QAChC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC3C,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "dev-toolkit-cli",
3
+ "version": "1.0.0",
4
+ "repository": "https://github.com/daviinacio/dev-toolkit",
5
+ "author": "Davi Inácio <aazz6850@gmail.com>",
6
+ "license": "MIT",
7
+ "main": "./bin/main.js",
8
+ "bin": {
9
+ "dtk": "./bin/main.js"
10
+ },
11
+ "type": "module",
12
+ "scripts": {
13
+ "dev": "tsc -w",
14
+ "build": "tsc",
15
+ "unlink-cli": "yarn --global unlink dev-toolkit-cli",
16
+ "link-cli": "(yarn unlink-cli || true) && chmod +x bin/main.js && yarn --global link",
17
+ "prepublish": "yarn build",
18
+ "publish": "npm publish"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^22.13.5",
22
+ "typescript": "^5.7.3"
23
+ },
24
+ "dependencies": {
25
+ "commander": "^13.1.0",
26
+ "mime": "^4.0.6",
27
+ "sharp": "^0.33.5"
28
+ }
29
+ }
@@ -0,0 +1,150 @@
1
+ import { CommanderError } from "commander";
2
+ import fs from "fs/promises";
3
+ import mime from "mime";
4
+ import path from "path";
5
+ import sharp from "sharp";
6
+
7
+ import { Resolution } from "../lib/constants.js";
8
+ import {
9
+ addFilenamePrefix,
10
+ getAvailablePathname,
11
+ getDirectory,
12
+ getFilename,
13
+ getFolderFiles,
14
+ normalizeFilename,
15
+ removeFilenamePrefix,
16
+ replaceFilenameExtension,
17
+ } from "../lib/utils/index.js";
18
+ import { check_dependencies, ffmpeg_video_compress } from "../lib/bash.js";
19
+
20
+ export const FileType = ["image", "video"] as const;
21
+ type FileType = (typeof FileType)[number];
22
+
23
+ const unsupportedFormats: { [key in FileType]: string[] } = {
24
+ image: ["image/webp", "image/gif", "image/svg+xml"],
25
+ video: [],
26
+ };
27
+
28
+ const compressedFlagPrefix = "compressed_" as const;
29
+ const compressTempPrefix = "temp." as const;
30
+
31
+ export type CompressFileArgs = {
32
+ verbose: number;
33
+ type: FileType;
34
+ resolution: Resolution;
35
+ force: boolean;
36
+ horizontal: boolean;
37
+ };
38
+
39
+ export async function file(
40
+ pathname: string,
41
+ { verbose, type, resolution, force, horizontal }: CompressFileArgs
42
+ ) {
43
+ await check_dependencies(["ffmpeg"]);
44
+
45
+ if (force) console.warn("⚠️ Ignoring already compressed files");
46
+ if (horizontal) console.warn("⚠️ Forcing horizontal aspect ratio 16x9");
47
+
48
+ let verbose_title = "";
49
+
50
+ const filePathList = await getFolderFiles(pathname, true);
51
+
52
+ for (let filePath of filePathList) {
53
+ const mimetype = mime.getType(filePath);
54
+ if (!mimetype) continue;
55
+ const fileType = mimetype.split("/")[0] as FileType;
56
+ if (
57
+ !(type ? [type] : FileType).includes(fileType as FileType) ||
58
+ (unsupportedFormats[fileType] || []).includes(mimetype) ||
59
+ (!force &&
60
+ [compressedFlagPrefix, compressTempPrefix].some((pf) =>
61
+ getFilename(filePath).startsWith(pf)
62
+ ))
63
+ )
64
+ continue;
65
+
66
+ const title = filePath
67
+ .substring(pathname.length)
68
+ .split("/")
69
+ .slice(1, 1 + verbose)
70
+ .join("/");
71
+
72
+ if (title !== verbose_title)
73
+ console.log(`Compressing ${fileType} at:`, title);
74
+
75
+ verbose_title = title;
76
+
77
+ try {
78
+ if (fileType === "image") await compressImage(filePath);
79
+ else if (fileType === "video")
80
+ await compressVideo(filePath, resolution, horizontal);
81
+ } catch (err) {
82
+ console.error(" Error compressing", `"${filePath}"`);
83
+ // console.error("Error compressing", `"${filePath}"`, err.message);
84
+ }
85
+ }
86
+
87
+ console.log("\nCompression successfully finished 🚀");
88
+ }
89
+
90
+ async function compressImage(filePath: string) {
91
+ await sharp(filePath)
92
+ .webp()
93
+ .toFile(replaceFilenameExtension(filePath, "webp"));
94
+ await fs.rm(filePath);
95
+ }
96
+
97
+ async function compressVideo(
98
+ filePath: string,
99
+ resolution: Resolution,
100
+ force?: boolean
101
+ ) {
102
+ const directory = getDirectory(filePath);
103
+ let filename = getFilename(filePath);
104
+ const normalizedFilename = normalizeFilename(filename);
105
+
106
+ if (filename !== normalizedFilename) {
107
+ const oldPathname = path.join(directory, filename);
108
+ const newPathname = await getAvailablePathname(
109
+ path.join(directory, normalizedFilename)
110
+ );
111
+
112
+ if (!newPathname) {
113
+ throw new CommanderError(
114
+ 1,
115
+ "P003",
116
+ "Could not find a new file destination"
117
+ );
118
+ }
119
+
120
+ const newFilename = getFilename(newPathname);
121
+ console.log(
122
+ " File renamed. From:",
123
+ `'${filename.trim()}'`,
124
+ "to:",
125
+ `'${newFilename.trim()}'`
126
+ );
127
+
128
+ await fs.rename(oldPathname, newPathname);
129
+ filename = newFilename;
130
+ }
131
+
132
+ const input = path.join(directory, filename);
133
+ const output = addFilenamePrefix(input, compressTempPrefix);
134
+
135
+ await ffmpeg_video_compress(input, output, resolution, force).catch(
136
+ async (err) => {
137
+ await fs.rm(output);
138
+ throw err;
139
+ }
140
+ );
141
+
142
+ await fs.rm(input);
143
+ await fs.rename(
144
+ output,
145
+ addFilenamePrefix(
146
+ removeFilenamePrefix(input, compressedFlagPrefix),
147
+ compressedFlagPrefix
148
+ )
149
+ );
150
+ }
@@ -0,0 +1 @@
1
+ export * as compress from "./action-compress.js";
@@ -0,0 +1,50 @@
1
+ import { exec } from "child_process";
2
+ import { Resolution, resolutionMapping } from "./constants.js";
3
+ import { CommanderError } from "commander";
4
+
5
+ export const execAsync = (command: string) =>
6
+ new Promise((resolve, reject) => {
7
+ exec(command, (error, stdout, stderr) => {
8
+ if (error) reject(new Error(stderr));
9
+ else resolve(stdout);
10
+ });
11
+ });
12
+
13
+ const globalDependencies = ["ffmpeg"];
14
+
15
+ async function check_dependency(dependency: string): Promise<boolean> {
16
+ return execAsync(`${dependency} -h`)
17
+ .then(() => true)
18
+ .catch(() => false);
19
+ }
20
+
21
+ export async function check_dependencies(dependencies = globalDependencies) {
22
+ const missing_dependencies = [];
23
+
24
+ for (let dep of dependencies) {
25
+ if (!(await check_dependency(dep))) missing_dependencies.push(dep);
26
+ }
27
+
28
+ if (missing_dependencies.length > 0) {
29
+ throw new CommanderError(
30
+ 1,
31
+ "missing_dependencies",
32
+ missing_dependencies.map((dep) => `'${dep}'`).join(", ")
33
+ );
34
+ }
35
+ }
36
+
37
+ export async function ffmpeg_video_compress(
38
+ input: string,
39
+ output: string,
40
+ resolution: Resolution = "480p",
41
+ forceResolution?: boolean
42
+ ) {
43
+ const { w, h } = resolutionMapping[resolution];
44
+
45
+ return execAsync(
46
+ forceResolution
47
+ ? `ffmpeg -i "${input}" -s ${w}x${h} -acodec copy -y "${output}"`
48
+ : `ffmpeg -i "${input}" -filter:v scale=-1:${h} -acodec copy -y "${output}"`
49
+ );
50
+ }
@@ -0,0 +1,47 @@
1
+ export const resolutionMapping = {
2
+ "4320p": {
3
+ w: 7680,
4
+ h: 4320,
5
+ },
6
+ "2160p": {
7
+ w: 3840,
8
+ h: 2160,
9
+ },
10
+ "1440p": {
11
+ w: 2560,
12
+ h: 1440,
13
+ },
14
+ "1080p": {
15
+ w: 1920,
16
+ h: 1080,
17
+ },
18
+ "720p": {
19
+ w: 1280,
20
+ h: 720,
21
+ },
22
+ "480p": {
23
+ w: 854,
24
+ h: 480,
25
+ },
26
+ "360p": {
27
+ w: 640,
28
+ h: 360,
29
+ },
30
+ "240p": {
31
+ w: 426,
32
+ h: 240,
33
+ },
34
+ } as const;
35
+
36
+ export const Resolution = [
37
+ "4320p",
38
+ "2160p",
39
+ "1440p",
40
+ "1080p",
41
+ "720p",
42
+ "480p",
43
+ "360p",
44
+ "240p",
45
+ ] as const;
46
+
47
+ export type Resolution = (typeof Resolution)[number];
@@ -0,0 +1,135 @@
1
+ import fs from "fs/promises";
2
+ import fsSync from "fs";
3
+ import path from "path";
4
+
5
+ type FolderContent = { folder_list: Array<string>; file_list: Array<string> };
6
+
7
+ export async function getFolderFiles(
8
+ pathname: string,
9
+ recursive = false
10
+ ): Promise<Array<string>> {
11
+ const list = await fs.readdir(pathname);
12
+
13
+ let { folder_list, file_list } = await list.reduce(async (_acc, name) => {
14
+ const acc = await _acc;
15
+ const is_directory = (
16
+ await fs.lstat(path.join(pathname, name))
17
+ ).isDirectory();
18
+
19
+ if (is_directory) acc.folder_list.push(name);
20
+ else acc.file_list.push(name);
21
+
22
+ return acc;
23
+ }, Promise.resolve({ folder_list: [], file_list: [] } as FolderContent));
24
+
25
+ file_list = file_list.map((name) => path.join(pathname, name));
26
+
27
+ if (!recursive) return file_list;
28
+
29
+ const subfolder_file_list = await Promise.all(
30
+ folder_list.map((folder_name) =>
31
+ getFolderFiles(path.join(pathname, folder_name), recursive)
32
+ )
33
+ ).then((l) => l.flatMap((l) => l));
34
+
35
+ file_list.push(...subfolder_file_list);
36
+
37
+ return file_list;
38
+ }
39
+
40
+ export async function getFolderList(pathname: string) {
41
+ return Promise.all(
42
+ (await fs.readdir(pathname)).map(async (name) => {
43
+ const is_directory = (
44
+ await fs.lstat(path.join(pathname, name))
45
+ ).isDirectory();
46
+ return { name, is_directory };
47
+ })
48
+ ).then((result) =>
49
+ result.filter((it) => it.is_directory).map((it) => it.name)
50
+ );
51
+ }
52
+
53
+ export function getFilenameExtension(filename: string) {
54
+ return (
55
+ (filename.includes(".") && filename.split(".").slice(-1)[0]) || undefined
56
+ );
57
+ }
58
+
59
+ export function replaceFilenameExtension(
60
+ filename: string,
61
+ newExtension: string
62
+ ) {
63
+ return `${getFilenameWithoutExtension(filename)}.${newExtension}`;
64
+ }
65
+
66
+ export function addFilenameSuffix(pathname: string, suffix: string) {
67
+ const directory = getDirectory(pathname);
68
+ const filename = getFilename(pathname);
69
+ const extension = getFilenameExtension(filename);
70
+ const filenameWithoutExtension = getFilenameWithoutExtension(filename);
71
+ return path.join(
72
+ directory,
73
+ `${filenameWithoutExtension}${suffix}.${extension}`
74
+ );
75
+ }
76
+
77
+ export function addFilenamePrefix(pathname: string, prefix: string) {
78
+ const directory = getDirectory(pathname);
79
+ const filename = getFilename(pathname);
80
+ return path.join(directory, `${prefix}${filename}`);
81
+ }
82
+
83
+ export function removeFilenamePrefix(pathname: string, prefix: string) {
84
+ const directory = getDirectory(pathname);
85
+ const filename = getFilename(pathname);
86
+ if (!filename.startsWith(prefix)) return pathname;
87
+ return path.join(directory, filename.substring(prefix.length));
88
+ }
89
+
90
+ export function getFilenameWithoutExtension(filename: string) {
91
+ return (
92
+ (filename.includes(".") && filename.split(".").slice(0, -1).join(".")) ||
93
+ filename
94
+ );
95
+ }
96
+
97
+ export async function getAvailablePathname(pathname: string) {
98
+ for (let i = 0; i < Number.MAX_SAFE_INTEGER; i++) {
99
+ const availablePathname =
100
+ i === 0 ? pathname : addFilenameSuffix(pathname, ` (${i})`);
101
+ if (!fsSync.existsSync(availablePathname)) return availablePathname;
102
+ }
103
+
104
+ return null;
105
+ }
106
+
107
+ export function getFilename(pathname: string) {
108
+ return pathname.split("/").slice(-1)[0];
109
+ }
110
+
111
+ export function getDirectory(pathname: string) {
112
+ return pathname.split("/").slice(0, -1).join("/");
113
+ }
114
+
115
+ export function normalizeFilename(filename: string) {
116
+ return (
117
+ filename
118
+ .normalize("NFD")
119
+ .replace(/[\u0300-\u036f]/g, "")
120
+ // Avoid multiple characters
121
+ .replace(/[ ]{2,}/g, " ")
122
+ .replace(/[.]{2,}/g, ".")
123
+ .replace(/[-]{2,}/g, "-")
124
+ // Replace ' - ' to '-'
125
+ .replace(/[ ][-][ ]/g, "-")
126
+ .replace(/[-][ ]/g, "-")
127
+ .replace(/[ ][-]/g, "-")
128
+ // Replace space to '_'
129
+ .replace(/[ ]/g, "_")
130
+ // Remove all not allowed characters
131
+ .replace(/[^-.0-9_a-zA-Z[]]/g, "")
132
+ // Remove all not alphanumeric characters on start
133
+ .replace(/^[^0-9a-zA-Z]/g, "")
134
+ );
135
+ }
@@ -0,0 +1,28 @@
1
+ import { InvalidArgumentError, InvalidOptionArgumentError } from "commander";
2
+ import fs from "fs";
3
+
4
+ export function PathArgument(previous: string) {
5
+ if (!fs.existsSync(previous))
6
+ throw new InvalidArgumentError("No such a file or directory");
7
+ return previous;
8
+ }
9
+
10
+ export function NumericOption(previous: string) {
11
+ const result = parseInt(previous);
12
+ if (Number.isNaN(result))
13
+ throw new InvalidOptionArgumentError("Not a number");
14
+ return result;
15
+ }
16
+
17
+ export function EnumOption<E extends readonly string[], T extends E[number]>(
18
+ enumerator: E
19
+ ) {
20
+ return (previous: string): T => {
21
+ if (!enumerator.includes(previous)) {
22
+ throw new InvalidOptionArgumentError(
23
+ `Expected '${enumerator.join(" | ")} ', received '${previous}'`
24
+ );
25
+ }
26
+ return previous as T;
27
+ };
28
+ }
package/src/main.ts ADDED
@@ -0,0 +1,47 @@
1
+ // #!/usr/bin/env node
2
+
3
+ import { Command, CommanderError } from "commander";
4
+ // import { ZodError } from "zod";
5
+ import { FileType } from "./actions/action-compress.js";
6
+ import * as actions from "./actions/index.js";
7
+ import { Resolution } from "./lib/constants.js";
8
+ import { EnumOption, NumericOption, PathArgument } from "./lib/validation.js";
9
+
10
+ /** Setup */
11
+ const program = new Command();
12
+ program
13
+ .name("dev-toolkit")
14
+ .description("A simple CLI app to help developers in their tasks.");
15
+
16
+ program
17
+ .command("compress")
18
+ .description("Compress large files and save storage space.")
19
+ .argument("<pathname>", "Pathname", PathArgument)
20
+ .option(
21
+ "-V, --verbose <number>",
22
+ "Level of pathname to log",
23
+ NumericOption,
24
+ 10
25
+ )
26
+ .option("-T, --type <string>", "File type", EnumOption(FileType))
27
+ .option(
28
+ "-R, --resolution <string>",
29
+ "Resolution",
30
+ EnumOption(Resolution),
31
+ "480p"
32
+ )
33
+ .option("-F, --force", "Ignores compressed flag")
34
+ .option("-H, --horizontal", "Force horizontal 16x9 aspect ratio")
35
+ .action(actions.compress.file);
36
+
37
+ program.parseAsync(process.argv).catch((err) => {
38
+ if (err instanceof CommanderError) {
39
+ console.log(`Error (${err.code}): ${err.message}`);
40
+ } else if (err instanceof Error) {
41
+ if (process.env.NODE_ENV === "development") {
42
+ console.error(err);
43
+ } else {
44
+ console.error(err.message);
45
+ }
46
+ }
47
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "outDir": "./bin",
6
+ "rootDir": "./src",
7
+ "esModuleInterop": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "resolveJsonModule": true
12
+ }
13
+ }