@macrulez/mediatoolz 0.0.0-stage → 0.1.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.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -2
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +243 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/image-batch/backup.d.ts +22 -0
  7. package/dist/commands/image-batch/backup.js +55 -0
  8. package/dist/commands/image-batch/backup.js.map +1 -0
  9. package/dist/commands/image-batch/cache.d.ts +15 -0
  10. package/dist/commands/image-batch/cache.js +38 -0
  11. package/dist/commands/image-batch/cache.js.map +1 -0
  12. package/dist/commands/image-batch/cli.d.ts +15 -0
  13. package/dist/commands/image-batch/cli.js +323 -0
  14. package/dist/commands/image-batch/cli.js.map +1 -0
  15. package/dist/commands/image-batch/codecs.d.ts +38 -0
  16. package/dist/commands/image-batch/codecs.js +366 -0
  17. package/dist/commands/image-batch/codecs.js.map +1 -0
  18. package/dist/commands/image-batch/config.d.ts +121 -0
  19. package/dist/commands/image-batch/config.js +690 -0
  20. package/dist/commands/image-batch/config.js.map +1 -0
  21. package/dist/commands/image-batch/errors.d.ts +5 -0
  22. package/dist/commands/image-batch/errors.js +8 -0
  23. package/dist/commands/image-batch/errors.js.map +1 -0
  24. package/dist/commands/image-batch/geometry.d.ts +26 -0
  25. package/dist/commands/image-batch/geometry.js +90 -0
  26. package/dist/commands/image-batch/geometry.js.map +1 -0
  27. package/dist/commands/image-batch/inputs.d.ts +22 -0
  28. package/dist/commands/image-batch/inputs.js +87 -0
  29. package/dist/commands/image-batch/inputs.js.map +1 -0
  30. package/dist/commands/image-batch/manage-cli.d.ts +2 -0
  31. package/dist/commands/image-batch/manage-cli.js +276 -0
  32. package/dist/commands/image-batch/manage-cli.js.map +1 -0
  33. package/dist/commands/image-batch/manage.d.ts +51 -0
  34. package/dist/commands/image-batch/manage.js +1041 -0
  35. package/dist/commands/image-batch/manage.js.map +1 -0
  36. package/dist/commands/image-batch/overwrite.d.ts +14 -0
  37. package/dist/commands/image-batch/overwrite.js +31 -0
  38. package/dist/commands/image-batch/overwrite.js.map +1 -0
  39. package/dist/commands/image-batch/plan.d.ts +86 -0
  40. package/dist/commands/image-batch/plan.js +396 -0
  41. package/dist/commands/image-batch/plan.js.map +1 -0
  42. package/dist/commands/image-batch/process.d.ts +8 -0
  43. package/dist/commands/image-batch/process.js +97 -0
  44. package/dist/commands/image-batch/process.js.map +1 -0
  45. package/dist/commands/image-batch/report.d.ts +6 -0
  46. package/dist/commands/image-batch/report.js +251 -0
  47. package/dist/commands/image-batch/report.js.map +1 -0
  48. package/dist/commands/image-batch/restore.d.ts +29 -0
  49. package/dist/commands/image-batch/restore.js +125 -0
  50. package/dist/commands/image-batch/restore.js.map +1 -0
  51. package/dist/commands/image-batch/run.d.ts +127 -0
  52. package/dist/commands/image-batch/run.js +656 -0
  53. package/dist/commands/image-batch/run.js.map +1 -0
  54. package/dist/commands/image-batch/sharpen-ask.d.ts +6 -0
  55. package/dist/commands/image-batch/sharpen-ask.js +53 -0
  56. package/dist/commands/image-batch/sharpen-ask.js.map +1 -0
  57. package/dist/commands/image-batch/sharpen-manage.d.ts +26 -0
  58. package/dist/commands/image-batch/sharpen-manage.js +238 -0
  59. package/dist/commands/image-batch/sharpen-manage.js.map +1 -0
  60. package/dist/commands/image-batch/sharpen-presets.d.ts +24 -0
  61. package/dist/commands/image-batch/sharpen-presets.js +145 -0
  62. package/dist/commands/image-batch/sharpen-presets.js.map +1 -0
  63. package/dist/commands/image-batch/sharpen.d.ts +46 -0
  64. package/dist/commands/image-batch/sharpen.js +159 -0
  65. package/dist/commands/image-batch/sharpen.js.map +1 -0
  66. package/dist/commands/image-batch/template.d.ts +45 -0
  67. package/dist/commands/image-batch/template.js +142 -0
  68. package/dist/commands/image-batch/template.js.map +1 -0
  69. package/dist/commands/image-hash/cache.d.ts +14 -0
  70. package/dist/commands/image-hash/cache.js +40 -0
  71. package/dist/commands/image-hash/cache.js.map +1 -0
  72. package/dist/commands/image-hash/core.d.ts +61 -0
  73. package/dist/commands/image-hash/core.js +302 -0
  74. package/dist/commands/image-hash/core.js.map +1 -0
  75. package/dist/commands/image-hash/hash.d.ts +21 -0
  76. package/dist/commands/image-hash/hash.js +104 -0
  77. package/dist/commands/image-hash/hash.js.map +1 -0
  78. package/dist/commands/image-hash/report.d.ts +3 -0
  79. package/dist/commands/image-hash/report.js +96 -0
  80. package/dist/commands/image-hash/report.js.map +1 -0
  81. package/dist/commands/image-hash/run.d.ts +61 -0
  82. package/dist/commands/image-hash/run.js +317 -0
  83. package/dist/commands/image-hash/run.js.map +1 -0
  84. package/dist/commands/image-hash/sharp-loader.d.ts +64 -0
  85. package/dist/commands/image-hash/sharp-loader.js +81 -0
  86. package/dist/commands/image-hash/sharp-loader.js.map +1 -0
  87. package/dist/commands/ui/cli.d.ts +2 -0
  88. package/dist/commands/ui/cli.js +78 -0
  89. package/dist/commands/ui/cli.js.map +1 -0
  90. package/dist/commands/ui/fs-routes.d.ts +7 -0
  91. package/dist/commands/ui/fs-routes.js +135 -0
  92. package/dist/commands/ui/fs-routes.js.map +1 -0
  93. package/dist/commands/ui/http.d.ts +41 -0
  94. package/dist/commands/ui/http.js +81 -0
  95. package/dist/commands/ui/http.js.map +1 -0
  96. package/dist/commands/ui/jobs.d.ts +15 -0
  97. package/dist/commands/ui/jobs.js +73 -0
  98. package/dist/commands/ui/jobs.js.map +1 -0
  99. package/dist/commands/ui/modules/image-batch-backups.d.ts +2 -0
  100. package/dist/commands/ui/modules/image-batch-backups.js +116 -0
  101. package/dist/commands/ui/modules/image-batch-backups.js.map +1 -0
  102. package/dist/commands/ui/modules/image-batch-manage.d.ts +2 -0
  103. package/dist/commands/ui/modules/image-batch-manage.js +245 -0
  104. package/dist/commands/ui/modules/image-batch-manage.js.map +1 -0
  105. package/dist/commands/ui/modules/image-batch.d.ts +2 -0
  106. package/dist/commands/ui/modules/image-batch.js +225 -0
  107. package/dist/commands/ui/modules/image-batch.js.map +1 -0
  108. package/dist/commands/ui/modules/image-hash.d.ts +2 -0
  109. package/dist/commands/ui/modules/image-hash.js +158 -0
  110. package/dist/commands/ui/modules/image-hash.js.map +1 -0
  111. package/dist/commands/ui/modules/index.d.ts +2 -0
  112. package/dist/commands/ui/modules/index.js +4 -0
  113. package/dist/commands/ui/modules/index.js.map +1 -0
  114. package/dist/commands/ui/open-browser.d.ts +1 -0
  115. package/dist/commands/ui/open-browser.js +18 -0
  116. package/dist/commands/ui/open-browser.js.map +1 -0
  117. package/dist/commands/ui/scan.d.ts +20 -0
  118. package/dist/commands/ui/scan.js +57 -0
  119. package/dist/commands/ui/scan.js.map +1 -0
  120. package/dist/commands/ui/server.d.ts +18 -0
  121. package/dist/commands/ui/server.js +196 -0
  122. package/dist/commands/ui/server.js.map +1 -0
  123. package/dist/format/bytes.d.ts +2 -0
  124. package/dist/format/bytes.js +17 -0
  125. package/dist/format/bytes.js.map +1 -0
  126. package/dist/format/colors.d.ts +12 -0
  127. package/dist/format/colors.js +15 -0
  128. package/dist/format/colors.js.map +1 -0
  129. package/dist/format/diff-render.d.ts +2 -0
  130. package/dist/format/diff-render.js +35 -0
  131. package/dist/format/diff-render.js.map +1 -0
  132. package/dist/format/file-list.d.ts +6 -0
  133. package/dist/format/file-list.js +15 -0
  134. package/dist/format/file-list.js.map +1 -0
  135. package/dist/format/findings-list.d.ts +7 -0
  136. package/dist/format/findings-list.js +14 -0
  137. package/dist/format/findings-list.js.map +1 -0
  138. package/dist/format/style.d.ts +20 -0
  139. package/dist/format/style.js +36 -0
  140. package/dist/format/style.js.map +1 -0
  141. package/dist/format/table.d.ts +8 -0
  142. package/dist/format/table.js +44 -0
  143. package/dist/format/table.js.map +1 -0
  144. package/dist/format/vibes.d.ts +13 -0
  145. package/dist/format/vibes.js +82 -0
  146. package/dist/format/vibes.js.map +1 -0
  147. package/dist/index.d.ts +9 -0
  148. package/dist/index.js +6 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/ui/assets/ImageBatchPage-D3f4z6YA.js +4 -0
  151. package/dist/ui/assets/ImageBatchPage-DwaunraE.css +1 -0
  152. package/dist/ui/assets/ImageHashPage-D0xZlLGw.css +1 -0
  153. package/dist/ui/assets/ImageHashPage-DjIlDPu-.js +1 -0
  154. package/dist/ui/assets/SourcePicker-D8aZjDwP.css +1 -0
  155. package/dist/ui/assets/SourcePicker-Db0dG6zc.js +1 -0
  156. package/dist/ui/assets/index-D1s-23_t.css +1 -0
  157. package/dist/ui/assets/index-yiehSw5D.js +3 -0
  158. package/dist/ui/index.html +17 -0
  159. package/dist/utils/closest.d.ts +2 -0
  160. package/dist/utils/closest.js +35 -0
  161. package/dist/utils/closest.js.map +1 -0
  162. package/dist/utils/glob.d.ts +4 -0
  163. package/dist/utils/glob.js +86 -0
  164. package/dist/utils/glob.js.map +1 -0
  165. package/dist/utils/split-list.d.ts +1 -0
  166. package/dist/utils/split-list.js +4 -0
  167. package/dist/utils/split-list.js.map +1 -0
  168. package/dist/utils/tty.d.ts +60 -0
  169. package/dist/utils/tty.js +390 -0
  170. package/dist/utils/tty.js.map +1 -0
  171. package/dist/utils/walk.d.ts +21 -0
  172. package/dist/utils/walk.js +116 -0
  173. package/dist/utils/walk.js.map +1 -0
  174. package/package.json +82 -4
@@ -0,0 +1,46 @@
1
+ import type { Command } from 'commander';
2
+ export declare const SHARPEN_TARGETS: readonly ["screen", "matte", "glossy"];
3
+ export declare const SHARPEN_AMOUNTS: readonly ["low", "standard", "high"];
4
+ export declare const SHARPEN_FINE_KEYS: readonly ["radius", "flat", "jagged", "threshold"];
5
+ export type SharpenTarget = (typeof SHARPEN_TARGETS)[number];
6
+ export type SharpenAmount = (typeof SHARPEN_AMOUNTS)[number];
7
+ export type SharpenFineKey = (typeof SHARPEN_FINE_KEYS)[number];
8
+ export interface SharpenFields {
9
+ for?: SharpenTarget;
10
+ amount?: SharpenAmount;
11
+ radius?: number;
12
+ flat?: number;
13
+ jagged?: number;
14
+ threshold?: number;
15
+ }
16
+ export interface SharpenLayer extends SharpenFields {
17
+ preset?: string;
18
+ }
19
+ export interface SharpenSpec extends SharpenFields {
20
+ for: SharpenTarget;
21
+ amount: SharpenAmount;
22
+ }
23
+ export interface SharpenParams {
24
+ sigma: number;
25
+ m1: number;
26
+ m2: number;
27
+ x1?: number;
28
+ }
29
+ export declare const SHARPEN_RANGES: Record<SharpenFineKey, readonly [number, number]>;
30
+ export declare function completeSharpen(fields: SharpenFields): SharpenSpec;
31
+ export declare function sharpenParams(spec: SharpenSpec): SharpenParams;
32
+ export declare function describeSharpen(fields: SharpenLayer): string;
33
+ export declare function parseSharpenFields(object: Record<string, unknown>, at: string, allowPreset: boolean): SharpenLayer;
34
+ export declare function parseSharpenLayer(value: unknown, at: string): SharpenLayer;
35
+ export declare function expandSharpen(layer: SharpenLayer, presets: Record<string, SharpenFields> | undefined, at: string): SharpenFields;
36
+ export interface SharpenFlagOptions {
37
+ sharpen?: string;
38
+ sharpenFor?: string;
39
+ sharpenAmount?: string;
40
+ sharpenRadius?: string;
41
+ sharpenFlat?: string;
42
+ sharpenJagged?: string;
43
+ sharpenThreshold?: string;
44
+ }
45
+ export declare function parseSharpenFlags(options: SharpenFlagOptions): SharpenLayer | undefined;
46
+ export declare function addSharpenFlags(command: Command, withPreset?: boolean): Command;
@@ -0,0 +1,159 @@
1
+ import { ImageBatchUsageError } from './errors.js';
2
+ export const SHARPEN_TARGETS = ['screen', 'matte', 'glossy'];
3
+ export const SHARPEN_AMOUNTS = ['low', 'standard', 'high'];
4
+ export const SHARPEN_FINE_KEYS = ['radius', 'flat', 'jagged', 'threshold'];
5
+ export const SHARPEN_RANGES = {
6
+ radius: [0.000001, 10],
7
+ flat: [0, 1_000_000],
8
+ jagged: [0, 1_000_000],
9
+ threshold: [0, 1_000_000],
10
+ };
11
+ const RADIUS = { screen: 0.6, matte: 1, glossy: 1.4 };
12
+ const STRENGTH = {
13
+ low: { m1: 0.5, m2: 1.5 },
14
+ standard: { m1: 1, m2: 3 },
15
+ high: { m1: 1.8, m2: 5 },
16
+ };
17
+ const LAYER_KEYS = ['preset', 'for', 'amount', ...SHARPEN_FINE_KEYS];
18
+ const FIELD_KEYS = LAYER_KEYS.filter((key) => key !== 'preset');
19
+ export function completeSharpen(fields) {
20
+ return { ...fields, for: fields.for ?? 'screen', amount: fields.amount ?? 'standard' };
21
+ }
22
+ export function sharpenParams(spec) {
23
+ const strength = STRENGTH[spec.amount];
24
+ return {
25
+ sigma: spec.radius ?? RADIUS[spec.for],
26
+ m1: spec.flat ?? strength.m1,
27
+ m2: spec.jagged ?? strength.m2,
28
+ ...(spec.threshold !== undefined ? { x1: spec.threshold } : {}),
29
+ };
30
+ }
31
+ export function describeSharpen(fields) {
32
+ const parts = [];
33
+ if (fields.preset !== undefined)
34
+ parts.push(fields.preset);
35
+ if (fields.for !== undefined)
36
+ parts.push(`for ${fields.for}`);
37
+ if (fields.amount !== undefined)
38
+ parts.push(fields.amount);
39
+ for (const key of SHARPEN_FINE_KEYS) {
40
+ if (fields[key] !== undefined)
41
+ parts.push(`${key} ${fields[key]}`);
42
+ }
43
+ return parts.join(', ');
44
+ }
45
+ function rangeText(key) {
46
+ const [min, max] = SHARPEN_RANGES[key];
47
+ return `${min} to ${max}`;
48
+ }
49
+ function checkFine(key, value, where) {
50
+ const [min, max] = SHARPEN_RANGES[key];
51
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < min || value > max) {
52
+ throw new ImageBatchUsageError(`${where}: expected a number from ${rangeText(key)}`);
53
+ }
54
+ return value;
55
+ }
56
+ export function parseSharpenFields(object, at, allowPreset) {
57
+ const allowed = allowPreset ? LAYER_KEYS : FIELD_KEYS;
58
+ for (const key of Object.keys(object)) {
59
+ if (!allowed.includes(key)) {
60
+ throw new ImageBatchUsageError(`${at}: unknown key "${key}" — expected ${allowed.join(', ')}`);
61
+ }
62
+ }
63
+ const layer = {};
64
+ if (object.preset !== undefined) {
65
+ if (typeof object.preset !== 'string' || object.preset === '') {
66
+ throw new ImageBatchUsageError(`${at}.preset: expected the name of a sharpen preset`);
67
+ }
68
+ layer.preset = object.preset;
69
+ }
70
+ if (object.for !== undefined) {
71
+ if (!SHARPEN_TARGETS.includes(object.for)) {
72
+ throw new ImageBatchUsageError(`${at}.for: expected one of ${SHARPEN_TARGETS.join(', ')}`);
73
+ }
74
+ layer.for = object.for;
75
+ }
76
+ if (object.amount !== undefined) {
77
+ if (!SHARPEN_AMOUNTS.includes(object.amount)) {
78
+ throw new ImageBatchUsageError(`${at}.amount: expected one of ${SHARPEN_AMOUNTS.join(', ')}`);
79
+ }
80
+ layer.amount = object.amount;
81
+ }
82
+ for (const key of SHARPEN_FINE_KEYS) {
83
+ if (object[key] !== undefined)
84
+ layer[key] = checkFine(key, object[key], `${at}.${key}`);
85
+ }
86
+ if (Object.keys(layer).length === 0) {
87
+ throw new ImageBatchUsageError(`${at}: expected at least one of ${allowed.join(', ')}`);
88
+ }
89
+ return layer;
90
+ }
91
+ export function parseSharpenLayer(value, at) {
92
+ if (typeof value === 'string') {
93
+ return parseSharpenFields({ preset: value }, at, true);
94
+ }
95
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
96
+ throw new ImageBatchUsageError(`${at}: expected a preset name or an object with ${LAYER_KEYS.join(', ')}`);
97
+ }
98
+ return parseSharpenFields(value, at, true);
99
+ }
100
+ export function expandSharpen(layer, presets, at) {
101
+ const { preset, ...own } = layer;
102
+ if (preset === undefined)
103
+ return own;
104
+ const base = presets?.[preset];
105
+ if (!base) {
106
+ throw new ImageBatchUsageError(`${at}: the sharpen preset "${preset}" is not loaded — see \`mediatoolz image-batch sharpen list\``);
107
+ }
108
+ return { ...base, ...own };
109
+ }
110
+ const FLAG_FINE = [
111
+ ['radius', 'sharpenRadius'],
112
+ ['flat', 'sharpenFlat'],
113
+ ['jagged', 'sharpenJagged'],
114
+ ['threshold', 'sharpenThreshold'],
115
+ ];
116
+ export function parseSharpenFlags(options) {
117
+ const raw = {};
118
+ if (options.sharpen !== undefined)
119
+ raw.preset = options.sharpen;
120
+ if (options.sharpenFor !== undefined)
121
+ raw.for = options.sharpenFor;
122
+ if (options.sharpenAmount !== undefined)
123
+ raw.amount = options.sharpenAmount;
124
+ for (const [key, flag] of FLAG_FINE) {
125
+ const text = options[flag];
126
+ if (text === undefined)
127
+ continue;
128
+ const number = Number(text);
129
+ if (text.trim() === '' || !Number.isFinite(number)) {
130
+ throw new ImageBatchUsageError(`--sharpen-${key} must be a number from ${rangeText(key)}`);
131
+ }
132
+ raw[key] = number;
133
+ }
134
+ if (Object.keys(raw).length === 0)
135
+ return undefined;
136
+ try {
137
+ return parseSharpenFields(raw, 'sharpen', true);
138
+ }
139
+ catch (error) {
140
+ const message = error instanceof Error ? error.message : String(error);
141
+ throw new ImageBatchUsageError(message
142
+ .replace(/^sharpen\.for/, '--sharpen-for')
143
+ .replace(/^sharpen\.amount/, '--sharpen-amount')
144
+ .replace(/^sharpen\.(radius|flat|jagged|threshold)/, '--sharpen-$1'));
145
+ }
146
+ }
147
+ export function addSharpenFlags(command, withPreset = true) {
148
+ if (withPreset) {
149
+ command.option('--sharpen <preset>', 'sharpen with a saved preset (see the sharpen command)');
150
+ }
151
+ return command
152
+ .option('--sharpen-for <target>', 'sharpen the result for: screen, matte or glossy')
153
+ .option('--sharpen-amount <amount>', 'sharpening amount: low, standard or high')
154
+ .option('--sharpen-radius <sigma>', 'sharpening radius (sigma), 0.000001 to 10')
155
+ .option('--sharpen-flat <n>', 'sharpening strength on flat areas, 0 to 1000000')
156
+ .option('--sharpen-jagged <n>', 'sharpening strength on sharp edges, 0 to 1000000')
157
+ .option('--sharpen-threshold <n>', 'edge threshold that separates flat from jagged, 0 to 1000000');
158
+ }
159
+ //# sourceMappingURL=sharpen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharpen.js","sourceRoot":"","sources":["../../../src/commands/image-batch/sharpen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export declare const TEMPLATE_VARIABLES: readonly ["name", "ext", "format", "dir", "width", "height", "size", "long", "short", "mp", "percent", "scale", "index", "hash", "date", "orig"];
2
+ export type TemplateVariable = (typeof TEMPLATE_VARIABLES)[number];
3
+ export type TemplateToken = {
4
+ type: 'text';
5
+ text: string;
6
+ } | {
7
+ type: 'var';
8
+ name: TemplateVariable;
9
+ param?: number;
10
+ };
11
+ export interface TemplateValues {
12
+ name: string;
13
+ ext: string;
14
+ format: string;
15
+ dir: string;
16
+ width: number;
17
+ height: number;
18
+ size: string;
19
+ long: number;
20
+ short: number;
21
+ mp: string;
22
+ percent: string;
23
+ scale: string;
24
+ index: number;
25
+ hash: string;
26
+ date: string;
27
+ orig: string;
28
+ }
29
+ export interface DefaultTemplateShape {
30
+ widths?: boolean;
31
+ heights?: boolean;
32
+ size?: boolean;
33
+ longEdge?: boolean;
34
+ shortEdge?: boolean;
35
+ megapixels?: boolean;
36
+ percent?: boolean;
37
+ scale?: boolean;
38
+ }
39
+ export declare function defaultTemplate(shape: DefaultTemplateShape): string;
40
+ export declare function parseTemplate(text: string, where: string): TemplateToken[];
41
+ export declare function templateUses(tokens: TemplateToken[], name: TemplateVariable): boolean;
42
+ export declare function templateUsesAny(tokens: TemplateToken[], names: TemplateVariable[]): boolean;
43
+ export declare function normalizeRelativePath(path: string, where: string): string;
44
+ export declare function expandTemplate(tokens: TemplateToken[], values: TemplateValues, where: string): string;
45
+ export declare function formatDate(date: Date): string;
@@ -0,0 +1,142 @@
1
+ import { didYouMean } from '../../utils/closest.js';
2
+ import { ImageBatchUsageError } from './errors.js';
3
+ export const TEMPLATE_VARIABLES = [
4
+ 'name',
5
+ 'ext',
6
+ 'format',
7
+ 'dir',
8
+ 'width',
9
+ 'height',
10
+ 'size',
11
+ 'long',
12
+ 'short',
13
+ 'mp',
14
+ 'percent',
15
+ 'scale',
16
+ 'index',
17
+ 'hash',
18
+ 'date',
19
+ 'orig',
20
+ ];
21
+ const PARAMETERIZED = ['index', 'hash'];
22
+ const DEFAULT_HASH_LENGTH = 8;
23
+ const MAX_HASH_LENGTH = 40;
24
+ const MAX_INDEX_PADDING = 12;
25
+ const FORBIDDEN_SEGMENT_CHARS = /[<>:"|?*]/;
26
+ export function defaultTemplate(shape) {
27
+ if (shape.widths)
28
+ return '{dir}/{name}-{width}w.{format}';
29
+ if (shape.heights)
30
+ return '{dir}/{name}-{height}h.{format}';
31
+ if (shape.size)
32
+ return '{dir}/{name}-{size}.{format}';
33
+ if (shape.longEdge)
34
+ return '{dir}/{name}-{long}l.{format}';
35
+ if (shape.shortEdge)
36
+ return '{dir}/{name}-{short}s.{format}';
37
+ if (shape.megapixels)
38
+ return '{dir}/{name}-{mp}mp.{format}';
39
+ if (shape.percent)
40
+ return '{dir}/{name}-{percent}pct.{format}';
41
+ if (shape.scale)
42
+ return '{dir}/{name}@{scale}x.{format}';
43
+ return '{dir}/{name}.{format}';
44
+ }
45
+ export function parseTemplate(text, where) {
46
+ if (text.trim() === '') {
47
+ throw new ImageBatchUsageError(`${where}: the name template is empty`);
48
+ }
49
+ if (/^([\\/]|[A-Za-z]:)/.test(text)) {
50
+ throw new ImageBatchUsageError(`${where}: the name template "${text}" is an absolute path — templates are always relative to the output folder`);
51
+ }
52
+ const tokens = [];
53
+ const pattern = /\{([a-zA-Z]+)(?::(\d+))?\}/g;
54
+ let last = 0;
55
+ let match;
56
+ while ((match = pattern.exec(text)) !== null) {
57
+ if (match.index > last)
58
+ tokens.push({ type: 'text', text: text.slice(last, match.index) });
59
+ const name = match[1];
60
+ if (!TEMPLATE_VARIABLES.includes(name)) {
61
+ throw new ImageBatchUsageError(`${where}: unknown variable {${name}} in "${text}".${didYouMean(name, TEMPLATE_VARIABLES)} Available: ${TEMPLATE_VARIABLES.map((v) => `{${v}}`).join(' ')}`);
62
+ }
63
+ const variable = name;
64
+ if (match[2] !== undefined) {
65
+ if (!PARAMETERIZED.includes(variable)) {
66
+ throw new ImageBatchUsageError(`${where}: {${variable}} takes no parameter (only ${PARAMETERIZED.map((v) => `{${v}:N}`).join(' and ')} do)`);
67
+ }
68
+ const param = Number(match[2]);
69
+ const limit = variable === 'hash' ? MAX_HASH_LENGTH : MAX_INDEX_PADDING;
70
+ if (param < 1 || param > limit) {
71
+ throw new ImageBatchUsageError(`${where}: {${variable}:${param}} must be 1–${limit}`);
72
+ }
73
+ tokens.push({ type: 'var', name: variable, param });
74
+ }
75
+ else {
76
+ tokens.push({ type: 'var', name: variable });
77
+ }
78
+ last = match.index + match[0].length;
79
+ }
80
+ if (last < text.length)
81
+ tokens.push({ type: 'text', text: text.slice(last) });
82
+ const literal = tokens
83
+ .filter((t) => t.type === 'text')
84
+ .map((t) => t.text)
85
+ .join('');
86
+ if (/[{}]/.test(literal)) {
87
+ throw new ImageBatchUsageError(`${where}: unbalanced "{" or "}" in the name template "${text}" — write variables as {name}`);
88
+ }
89
+ const shape = tokens.map((t) => (t.type === 'text' ? t.text : 'x')).join('');
90
+ if (shape.split(/[\\/]/).includes('..')) {
91
+ throw new ImageBatchUsageError(`${where}: the name template "${text}" must not contain ".." — results stay inside the output folder`);
92
+ }
93
+ return tokens;
94
+ }
95
+ export function templateUses(tokens, name) {
96
+ return tokens.some((token) => token.type === 'var' && token.name === name);
97
+ }
98
+ export function templateUsesAny(tokens, names) {
99
+ return names.some((name) => templateUses(tokens, name));
100
+ }
101
+ export function normalizeRelativePath(path, where) {
102
+ const segments = [];
103
+ for (const segment of path.split(/[\\/]/)) {
104
+ if (segment === '' || segment === '.')
105
+ continue;
106
+ if (segment === '..') {
107
+ throw new ImageBatchUsageError(`${where}: "${path}" escapes the output folder`);
108
+ }
109
+ if (FORBIDDEN_SEGMENT_CHARS.test(segment) || [...segment].some((ch) => ch.charCodeAt(0) < 32)) {
110
+ throw new ImageBatchUsageError(`${where}: "${segment}" contains a character that is not allowed in a file name`);
111
+ }
112
+ segments.push(segment);
113
+ }
114
+ if (segments.length === 0) {
115
+ throw new ImageBatchUsageError(`${where}: the name template produced an empty path`);
116
+ }
117
+ return segments.join('/');
118
+ }
119
+ export function expandTemplate(tokens, values, where) {
120
+ const pieces = tokens.map((token) => {
121
+ if (token.type === 'text')
122
+ return token.text;
123
+ switch (token.name) {
124
+ case 'index':
125
+ return String(values.index).padStart(token.param ?? 1, '0');
126
+ case 'hash':
127
+ return values.hash.slice(0, token.param ?? DEFAULT_HASH_LENGTH);
128
+ case 'width':
129
+ return String(values.width);
130
+ case 'height':
131
+ return String(values.height);
132
+ default:
133
+ return String(values[token.name]);
134
+ }
135
+ });
136
+ return normalizeRelativePath(pieces.join(''), where);
137
+ }
138
+ export function formatDate(date) {
139
+ const pad = (n) => String(n).padStart(2, '0');
140
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
141
+ }
142
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/commands/image-batch/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type HashType } from './core.js';
2
+ import type { ComputedHashes } from './hash.js';
3
+ export interface CacheRecord extends ComputedHashes {
4
+ sig: string;
5
+ params: string;
6
+ }
7
+ export interface CacheFile {
8
+ version: 1;
9
+ files: Record<string, CacheRecord>;
10
+ }
11
+ export declare function emptyCache(): CacheFile;
12
+ export declare function loadCache(path: string): CacheFile;
13
+ export declare function saveCache(path: string, cache: CacheFile): void;
14
+ export declare function cacheHit(record: CacheRecord | undefined, sig: string, params: string, types: HashType[]): ComputedHashes | null;
@@ -0,0 +1,40 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ import { ALL_TYPES } from './core.js';
4
+ export function emptyCache() {
5
+ return { version: 1, files: {} };
6
+ }
7
+ export function loadCache(path) {
8
+ if (!existsSync(path))
9
+ return emptyCache();
10
+ try {
11
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
12
+ if (parsed.version !== 1 || typeof parsed.files !== 'object' || parsed.files === null) {
13
+ return emptyCache();
14
+ }
15
+ return parsed;
16
+ }
17
+ catch {
18
+ return emptyCache();
19
+ }
20
+ }
21
+ export function saveCache(path, cache) {
22
+ mkdirSync(dirname(path), { recursive: true });
23
+ writeFileSync(path, `${JSON.stringify(cache)}\n`);
24
+ }
25
+ export function cacheHit(record, sig, params, types) {
26
+ if (!record || record.sig !== sig || record.params !== params)
27
+ return null;
28
+ for (const type of types) {
29
+ if (record[type] === undefined)
30
+ return null;
31
+ }
32
+ const hit = { width: record.width, height: record.height };
33
+ for (const type of ALL_TYPES) {
34
+ const value = record[type];
35
+ if (value !== undefined)
36
+ hit[type] = value;
37
+ }
38
+ return hit;
39
+ }
40
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/commands/image-hash/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAiB,MAAM,WAAW,CAAA;AAapD,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,EAAE,CAAA;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAc,CAAA;QAClE,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACtF,OAAO,UAAU,EAAE,CAAA;QACrB,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,UAAU,EAAE,CAAA;IACrB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAgB;IACtD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,MAA+B,EAC/B,GAAW,EACX,MAAc,EACd,KAAiB;IAEjB,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,IAAI,CAAA;IAC7C,CAAC;IACD,MAAM,GAAG,GAAmB,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;IAC1E,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,IAAI,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IAC5C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,61 @@
1
+ export type HashType = 'hazehash' | 'blurhash' | 'thumbhash' | 'color' | 'preview';
2
+ export declare const ALL_TYPES: HashType[];
3
+ export declare const OUTPUT_FORMATS: readonly ["json", "plain", "csv", "ts", "js"];
4
+ export type OutputFormat = (typeof OUTPUT_FORMATS)[number];
5
+ export declare const DEFAULT_IMAGE_EXTENSIONS: string[];
6
+ export declare const DEFAULT_EXPORT_NAME = "imageHashes";
7
+ export declare const DEFAULT_BLURHASH_COMPONENTS: {
8
+ x: number;
9
+ y: number;
10
+ };
11
+ export declare const DEFAULT_HAZEHASH_BUDGET = 28;
12
+ export declare const MIN_HAZEHASH_BUDGET = 7;
13
+ export declare const MAX_HAZEHASH_BUDGET = 48;
14
+ export declare const DEFAULT_SAMPLE_SIZE = 100;
15
+ export declare const MAX_SAMPLE_SIZE = 100;
16
+ export declare const DEFAULT_CACHE_FILE = ".mediatoolz-image-hash-cache.json";
17
+ export type Components = {
18
+ x: number;
19
+ y: number;
20
+ } | 'auto';
21
+ export declare class ImageHashUsageError extends Error {
22
+ }
23
+ export interface HashEntry {
24
+ file: string;
25
+ width: number;
26
+ height: number;
27
+ hazehash?: string;
28
+ blurhash?: string;
29
+ thumbhash?: string;
30
+ color?: string;
31
+ preview?: string;
32
+ }
33
+ export interface OutputUnit {
34
+ token: string;
35
+ content: string;
36
+ }
37
+ export declare function parseTypes(value: string): HashType[];
38
+ export declare function orderTypes(types: Iterable<HashType>): HashType[];
39
+ export declare function parseFormat(value: string): OutputFormat;
40
+ export declare function parseComponents(value: string): Components;
41
+ export declare function resolveComponents(components: Components, width: number, height: number): {
42
+ x: number;
43
+ y: number;
44
+ };
45
+ export declare function componentsLabel(components: Components): string;
46
+ export declare function parseBudget(value: string): number;
47
+ export declare function parseSampleSize(value: string): number;
48
+ export declare function parseMaxPixels(value: string): number;
49
+ export declare function parseExtensions(value: string): string[];
50
+ export declare function withUpperCaseVariants(extensions: string[]): string[];
51
+ export declare function validateExportName(name: string): string;
52
+ export declare function isUrl(value: string): boolean;
53
+ export declare function splitPathArguments(args: string[], exists?: (path: string) => boolean): string[];
54
+ export declare function parseFileList(text: string): string[];
55
+ export declare function defaultOutExtension(format: OutputFormat): string;
56
+ export declare function normalizeOutExtension(value: string | undefined, format: OutputFormat): string;
57
+ export declare function validateSuffix(suffix: string | undefined, types: HashType[], format: OutputFormat): string;
58
+ export declare function formatAggregate(entries: HashEntry[], types: HashType[], format: OutputFormat, exportName: string): string;
59
+ export declare function formatPerFile(entry: HashEntry, types: HashType[], format: OutputFormat): OutputUnit[];
60
+ export declare function outputFileName(imagePath: string, suffix: string, token: string, extension: string): string;
61
+ export declare function parseAggregate(content: string, format: OutputFormat): HashEntry[];