@kitschpatrol/aphex 0.1.3 → 0.1.5
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/dist/aphex-swift +0 -0
- package/dist/index.d.ts +14 -14
- package/dist/index.js +23 -17
- package/package.json +101 -100
- package/readme.md +46 -7
package/dist/aphex-swift
CHANGED
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -8,11 +8,11 @@ import { OmitDeep, PartialDeep, Simplify } from "type-fest";
|
|
|
8
8
|
*
|
|
9
9
|
* @throws {Error} If the session is already active or fails to start
|
|
10
10
|
*/
|
|
11
|
-
declare function interactiveSessionStart(): Promise<void>;
|
|
11
|
+
export declare function interactiveSessionStart(): Promise<void>;
|
|
12
12
|
/**
|
|
13
13
|
* Stop the interactive session if one is active.
|
|
14
14
|
*/
|
|
15
|
-
declare function interactiveSessionStop(): Promise<void>;
|
|
15
|
+
export declare function interactiveSessionStop(): Promise<void>;
|
|
16
16
|
/**
|
|
17
17
|
* TypeScript type definition for ResourceInfo from the Swift implementation
|
|
18
18
|
*/
|
|
@@ -63,7 +63,7 @@ declare function aphexPhotoInfo(identifiers: string | string[], caseSensitive?:
|
|
|
63
63
|
declare function aphexAlbumInfo(identifiers: string | string[], caseSensitive?: boolean): Promise<AlbumInfo[]>;
|
|
64
64
|
//#endregion
|
|
65
65
|
//#region src/utilities/image/mime.d.ts
|
|
66
|
-
declare const IMAGE_MIME_TYPES: readonly ["arw", "avif", "bmp", "cr2", "cr3", "crw", "tga", "dng", "gif", "heic", "heif", "jpeg", "nef", "pef", "png", "psd", "svg+xml", "tiff", "webp"];
|
|
66
|
+
export declare const IMAGE_MIME_TYPES: readonly ["arw", "avif", "bmp", "cr2", "cr3", "crw", "tga", "dng", "gif", "heic", "heif", "jpeg", "nef", "pef", "png", "psd", "svg+xml", "tiff", "webp"];
|
|
67
67
|
type ImageMimeType = (typeof IMAGE_MIME_TYPES)[number];
|
|
68
68
|
//#endregion
|
|
69
69
|
//#region src/pipeline/engines/applescript-gui.d.ts
|
|
@@ -327,7 +327,7 @@ type ProcessImageResult = {
|
|
|
327
327
|
*
|
|
328
328
|
* Run in parallel through a worker for album processing
|
|
329
329
|
*/
|
|
330
|
-
declare function processImage(sourceImagePath: string, destinationDirectory: string, options: ProcessImageOptions): Promise<ProcessImageResult>;
|
|
330
|
+
export declare function processImage(sourceImagePath: string, destinationDirectory: string, options: ProcessImageOptions): Promise<ProcessImageResult>;
|
|
331
331
|
//#endregion
|
|
332
332
|
//#region src/pipeline/image-sync.d.ts
|
|
333
333
|
type DiffStrategy = 'exif-tags' | 'export-options' | 'file-name' | 'force-update' | 'metadata-options' | 'photo-info' | 'process-options';
|
|
@@ -354,7 +354,7 @@ type SyncResult = {
|
|
|
354
354
|
* This should be called when you're done using exiftool to prevent hanging
|
|
355
355
|
* processes. It's safe to call multiple times.
|
|
356
356
|
*/
|
|
357
|
-
declare function endExiftool(): Promise<void>;
|
|
357
|
+
export declare function endExiftool(): Promise<void>;
|
|
358
358
|
//#endregion
|
|
359
359
|
//#region src/utilities/log.d.ts
|
|
360
360
|
/**
|
|
@@ -364,22 +364,22 @@ declare function endExiftool(): Promise<void>;
|
|
|
364
364
|
* @param logger - Accepts either a LogLayer instance or a Console- or
|
|
365
365
|
* Stream-like log target
|
|
366
366
|
*/
|
|
367
|
-
declare function setLogger(logger?: ILogBasic | ILogLayer<unknown>): void;
|
|
367
|
+
export declare function setLogger(logger?: ILogBasic | ILogLayer<unknown>): void;
|
|
368
368
|
//#endregion
|
|
369
369
|
//#region src/index.d.ts
|
|
370
370
|
/**
|
|
371
371
|
* Helper for deep merging ExportOptions object against library defaults.
|
|
372
372
|
* Exported for unplugin-aphex.
|
|
373
373
|
*/
|
|
374
|
-
declare function mergeDefaultExportOptions(options: PartialDeep<ExportOptions> | undefined): ExportOptions;
|
|
375
|
-
type ExportOptions = {
|
|
374
|
+
export declare function mergeDefaultExportOptions(options: PartialDeep<ExportOptions> | undefined): ExportOptions;
|
|
375
|
+
export type ExportOptions = {
|
|
376
376
|
exportOptions: ExportApplePhotoOptions;
|
|
377
377
|
metadataOptions: 'disabled' | ManageMetadataOptions;
|
|
378
378
|
processOptions: 'disabled' | ProcessImageOptions;
|
|
379
379
|
syncOptions: 'disabled' | SyncOptions;
|
|
380
380
|
};
|
|
381
|
-
declare const defaultSyncOptions: SyncOptions;
|
|
382
|
-
declare const defaultExportOptions: ExportOptions;
|
|
381
|
+
export declare const defaultSyncOptions: SyncOptions;
|
|
382
|
+
export declare const defaultExportOptions: ExportOptions;
|
|
383
383
|
/** Some fields omitted for relevance... */
|
|
384
384
|
type ExportResults = {
|
|
385
385
|
exportResult: Simplify<Omit<ExportApplePhotoResult, 'exportOptions' | 'path' | 'photoInfo'>> | undefined;
|
|
@@ -387,7 +387,7 @@ type ExportResults = {
|
|
|
387
387
|
processResult: Simplify<OmitDeep<ProcessImageResult, 'input.path' | 'output.path' | 'path'>> | undefined;
|
|
388
388
|
syncResult: Simplify<Omit<SyncResult['plan'][number], 'photoInfo'>> | undefined;
|
|
389
389
|
};
|
|
390
|
-
type ExportResult = {
|
|
390
|
+
export type ExportResult = {
|
|
391
391
|
options: ExportOptions;
|
|
392
392
|
path: string;
|
|
393
393
|
photoInfo: PhotoInfo;
|
|
@@ -396,10 +396,10 @@ type ExportResult = {
|
|
|
396
396
|
/**
|
|
397
397
|
* Export a single photo
|
|
398
398
|
*/
|
|
399
|
-
declare function exportPhoto(identifier: PhotoInfo | string, destinationDirectory: string, options?: PartialDeep<ExportOptions>): Promise<ExportResult>;
|
|
399
|
+
export declare function exportPhoto(identifier: PhotoInfo | string, destinationDirectory: string, options?: PartialDeep<ExportOptions>): Promise<ExportResult>;
|
|
400
400
|
/**
|
|
401
401
|
* Export photos
|
|
402
402
|
*/
|
|
403
|
-
declare function exportPhotos(identifiers: Array<AlbumInfo | PhotoInfo | string>, destinationDirectory: string, options?: PartialDeep<ExportOptions>): Promise<ExportResult[]>;
|
|
403
|
+
export declare function exportPhotos(identifiers: Array<AlbumInfo | PhotoInfo | string>, destinationDirectory: string, options?: PartialDeep<ExportOptions>): Promise<ExportResult[]>;
|
|
404
404
|
//#endregion
|
|
405
|
-
export {
|
|
405
|
+
export { type ImageMimeType, aphexAlbumInfo as getAlbumInfo, aphexPhotoInfo as getPhotoInfo };
|
package/dist/index.js
CHANGED
|
@@ -75,7 +75,9 @@ function scheduleProcessCleanup() {
|
|
|
75
75
|
process.on("beforeExit", () => {
|
|
76
76
|
if (cleanupScheduled) return;
|
|
77
77
|
cleanupScheduled = true;
|
|
78
|
-
endExiftool()
|
|
78
|
+
endExiftool().catch((error) => {
|
|
79
|
+
log.warn(`Failed to end exiftool processes: ${String(error)}`);
|
|
80
|
+
});
|
|
79
81
|
});
|
|
80
82
|
process.on("exit", () => {
|
|
81
83
|
if (exiftoolInstance.pids.length > 0) log.debug(`Exiftool processes still running at exit: ${exiftoolInstance.pids.join(", ")}`);
|
|
@@ -83,14 +85,22 @@ function scheduleProcessCleanup() {
|
|
|
83
85
|
process.on("SIGINT", () => {
|
|
84
86
|
(async () => {
|
|
85
87
|
log.debug("Received SIGINT, cleaning up exiftool...");
|
|
86
|
-
|
|
88
|
+
try {
|
|
89
|
+
await endExiftool();
|
|
90
|
+
} catch (error) {
|
|
91
|
+
log.warn(`Failed to end exiftool processes: ${String(error)}`);
|
|
92
|
+
}
|
|
87
93
|
process.exit(130);
|
|
88
94
|
})();
|
|
89
95
|
});
|
|
90
96
|
process.on("SIGTERM", () => {
|
|
91
97
|
(async () => {
|
|
92
98
|
log.debug("Received SIGTERM, cleaning up exiftool...");
|
|
93
|
-
|
|
99
|
+
try {
|
|
100
|
+
await endExiftool();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
log.warn(`Failed to end exiftool processes: ${String(error)}`);
|
|
103
|
+
}
|
|
94
104
|
process.exit(143);
|
|
95
105
|
})();
|
|
96
106
|
});
|
|
@@ -172,10 +182,9 @@ async function sipsTempCleanup() {
|
|
|
172
182
|
"--mime",
|
|
173
183
|
filePath
|
|
174
184
|
]);
|
|
175
|
-
if (stdout.startsWith("image/"))
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
185
|
+
if (!stdout.startsWith("image/")) continue;
|
|
186
|
+
await fse.rm(filePath, { force: true });
|
|
187
|
+
cleanCount += 1;
|
|
179
188
|
}
|
|
180
189
|
return cleanCount;
|
|
181
190
|
}
|
|
@@ -340,10 +349,7 @@ async function executeInteractiveCommand(command) {
|
|
|
340
349
|
* Arguments with spaces or special characters are quoted.
|
|
341
350
|
*/
|
|
342
351
|
function escapeCommand(args) {
|
|
343
|
-
return args.map((arg) => {
|
|
344
|
-
if (SHELL_SPECIAL_CHARS_REGEX.test(arg)) return `'${arg.replaceAll("'", String.raw`'\''`)}'`;
|
|
345
|
-
return arg;
|
|
346
|
-
}).join(" ");
|
|
352
|
+
return args.map((arg) => SHELL_SPECIAL_CHARS_REGEX.test(arg) ? `'${arg.replaceAll("'", String.raw`'\''`)}'` : arg).join(" ");
|
|
347
353
|
}
|
|
348
354
|
/**
|
|
349
355
|
* Runtime type guard for ResourceInfo
|
|
@@ -816,14 +822,14 @@ function parseUserComment(userComment) {
|
|
|
816
822
|
* Set the tags on an image
|
|
817
823
|
*/
|
|
818
824
|
async function setTags(imagePath, imageTags) {
|
|
819
|
-
const { aphexMetadata, creator, credit, description, label, preservedFileName } = imageTags;
|
|
825
|
+
const { aphexMetadata, creator = "", credit = "", description = "", label = "", preservedFileName = "" } = imageTags;
|
|
820
826
|
const userComment = aphexMetadata ? JSON.stringify(aphexMetadata) : void 0;
|
|
821
827
|
const tags = {
|
|
822
|
-
..."creator" in imageTags && { "XMP:Creator": creator
|
|
823
|
-
..."description" in imageTags && { "XMP:Description": description
|
|
824
|
-
..."credit" in imageTags && { "XMP:Credit": credit
|
|
825
|
-
..."label" in imageTags && { "XMP:Label": label
|
|
826
|
-
..."preservedFileName" in imageTags && { "XMP:PreservedFileName": preservedFileName
|
|
828
|
+
..."creator" in imageTags && { "XMP:Creator": creator },
|
|
829
|
+
..."description" in imageTags && { "XMP:Description": description },
|
|
830
|
+
..."credit" in imageTags && { "XMP:Credit": credit },
|
|
831
|
+
..."label" in imageTags && { "XMP:Label": label },
|
|
832
|
+
..."preservedFileName" in imageTags && { "XMP:PreservedFileName": preservedFileName },
|
|
827
833
|
..."aphexMetadata" in imageTags && { "XMP:UserComment": userComment ?? "" }
|
|
828
834
|
};
|
|
829
835
|
await getExiftool().write(imagePath, tags, { writeArgs: ["-overwrite_original_in_place"] });
|
package/package.json
CHANGED
|
@@ -1,101 +1,102 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
2
|
+
"name": "@kitschpatrol/aphex",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Apple Photos Export. TypeScript library and CLI tool to export and process images and albums from your macOS Photos.app library.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"apple",
|
|
7
|
+
"apple-photos",
|
|
8
|
+
"photokit",
|
|
9
|
+
"photos",
|
|
10
|
+
"npm-package"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/kitschpatrol/aphex",
|
|
13
|
+
"bugs": "https://github.com/kitschpatrol/aphex/issues",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/kitschpatrol/aphex.git"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": {
|
|
20
|
+
"name": "Eric Mika",
|
|
21
|
+
"email": "eric@ericmika.com",
|
|
22
|
+
"url": "https://ericmika.com"
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"type": "module",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"bin": {
|
|
36
|
+
"aphex": "./dist/aphex-swift"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist/*"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@sindresorhus/is": "^8.1.0",
|
|
43
|
+
"defu": "^6.1.7",
|
|
44
|
+
"execa": "^10.1.0",
|
|
45
|
+
"exiftool-vendored": "^39.0.0",
|
|
46
|
+
"fast-equals": "^6.1.0",
|
|
47
|
+
"fs-extra": "^11.4.1",
|
|
48
|
+
"github-slugger": "^2.0.0",
|
|
49
|
+
"image-size": "^2.0.4",
|
|
50
|
+
"importx": "^0.5.2",
|
|
51
|
+
"lognow": "^0.8.5",
|
|
52
|
+
"mrmime": "^2.0.1",
|
|
53
|
+
"piscina": "^5.3.2",
|
|
54
|
+
"type-fest": "^5.10.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@arethetypeswrong/core": "^0.18.5",
|
|
58
|
+
"@clack/prompts": "^1.8.1",
|
|
59
|
+
"@kitschpatrol/shared-config": "^8.12.1",
|
|
60
|
+
"@types/fs-extra": "^11.0.4",
|
|
61
|
+
"@types/node": "~24.13.6",
|
|
62
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
63
|
+
"brewpub": "^0.5.0",
|
|
64
|
+
"bumpp": "^12.3.0",
|
|
65
|
+
"globby": "^16.2.4",
|
|
66
|
+
"markdown-table": "^3.0.4",
|
|
67
|
+
"mdat-plugin-cli-help": "^3.4.1",
|
|
68
|
+
"open": "^11.0.4",
|
|
69
|
+
"pretty-bytes": "^7.2.0",
|
|
70
|
+
"pretty-ms": "^9.3.1",
|
|
71
|
+
"publint": "^0.3.25",
|
|
72
|
+
"skills": "^1.7.0",
|
|
73
|
+
"tsdown": "^0.23.0",
|
|
74
|
+
"tsx": "^4.23.15",
|
|
75
|
+
"typescript": "~6.0.3",
|
|
76
|
+
"vitest": "^5.0.3"
|
|
77
|
+
},
|
|
78
|
+
"engines": {
|
|
79
|
+
"node": "^24.16.0 || >=26.3.0"
|
|
80
|
+
},
|
|
81
|
+
"os": [
|
|
82
|
+
"darwin"
|
|
83
|
+
],
|
|
84
|
+
"cpu": [
|
|
85
|
+
"arm64"
|
|
86
|
+
],
|
|
87
|
+
"publishConfig": {
|
|
88
|
+
"access": "public"
|
|
89
|
+
},
|
|
90
|
+
"scripts": {
|
|
91
|
+
"build": "pnpm run --sequential /^build:/",
|
|
92
|
+
"build:1-lib": "tsdown",
|
|
93
|
+
"build:2-native": "cd native/aphex-swift && ./build.sh",
|
|
94
|
+
"build:3-publint": "publint",
|
|
95
|
+
"clean-deep": "git rm -f pnpm-lock.yaml && git clean -fdX -e !.claude/",
|
|
96
|
+
"fix": "ksc fix && mdat ./native/aphex-swift/readme.md",
|
|
97
|
+
"lint": "ksc lint",
|
|
98
|
+
"release": "bumpp --commit 'Release: %s' && pnpm build && pnpm publish --otp $(op item get npm --otp) && brewpub --tap kitschpatrol/tap",
|
|
99
|
+
"test": "vitest run",
|
|
100
|
+
"test:coverage": "vitest run --coverage"
|
|
101
|
+
}
|
|
102
|
+
}
|
package/readme.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
[](https://www.npmjs.com/package/@kitschpatrol/aphex)
|
|
12
12
|
[](https://opensource.org/license/mit)
|
|
13
|
+
[](https://github.com/kitschpatrol/homebrew-tap/blob/HEAD/Formula/aphex.rb)
|
|
13
14
|
|
|
14
15
|
<!-- /badges -->
|
|
15
16
|
|
|
@@ -37,7 +38,7 @@ It makes it simple to export high-quality versions of specific photos or albums
|
|
|
37
38
|
|
|
38
39
|
I created this library for integration in static website content management asset pipelines, and to attempt to work around some issues related to [exporting high-quality versions of edited images](https://github.com/RhetTbull/osxphotos/discussions/1522) from the Photos.app library. (See the [unplugin-aphex](https://github.com/kitschpatrol/unplugin-aphex) project for an additional layer of integration with various build tools, and the [vscode-aphex-preview](https://github.com/kitschpatrol/vscode-aphex-preview) plugin for hover previews of Aphex links in VS Code.)
|
|
39
40
|
|
|
40
|
-
This repository also embeds the `aphex-swift` CLI project, which provides a minimal and performant wrapper around parts of Apple's PhotoKit framework. It's not intended for direct use
|
|
41
|
+
This repository also embeds the `aphex-swift` CLI project, which provides a minimal and performant wrapper around parts of Apple's PhotoKit framework. It's not really intended for direct use beyond querying the Photos library and simple exports. It provides just enough functionality to support the parts of the methods provided by the `aphex` TypeScript library that can only be implemented natively.
|
|
41
42
|
|
|
42
43
|
<!-- /* spell-checker:disable */ -->
|
|
43
44
|
|
|
@@ -47,12 +48,35 @@ The name "Aphex" is a concatenation of **A**pple **PH**otos **EX**port.
|
|
|
47
48
|
|
|
48
49
|
## Getting started
|
|
49
50
|
|
|
51
|
+
<!-- dependencies -->
|
|
52
|
+
|
|
50
53
|
### Dependencies
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
- [Node.js](https://nodejs.org/) 24.16.0 or newer (specifically `^24.16.0 || >=26.3.0`)
|
|
56
|
+
- Supported operating systems: macOS
|
|
57
|
+
|
|
58
|
+
<!-- /dependencies -->
|
|
59
|
+
|
|
60
|
+
Requires an Apple Silicon (`arm64`) Mac with Photos.app installed. No Intel (`x86_64`) build of the bundled native binary is provided.
|
|
61
|
+
|
|
62
|
+
### Installation
|
|
63
|
+
|
|
64
|
+
Pick the option that matches how you plan to use it.
|
|
65
|
+
|
|
66
|
+
#### Library installation
|
|
67
|
+
|
|
68
|
+
Add it to your project to import the TypeScript API. This also puts the `aphex` CLI on your project's path:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
npm install @kitschpatrol/aphex
|
|
72
|
+
```
|
|
53
73
|
|
|
54
74
|
Full image processing functionality also requires a number of command-line tools available via [Homebrew](https://brew.sh):
|
|
55
75
|
|
|
76
|
+
```sh
|
|
77
|
+
brew install libavif mozjpeg imagemagick webp dssim ffmpeg guetzli oxipng
|
|
78
|
+
```
|
|
79
|
+
|
|
56
80
|
| Tool | Used for |
|
|
57
81
|
| ------------- | ------------------------------------------------------------------------- |
|
|
58
82
|
| `libavif` | AVIF encoding |
|
|
@@ -64,13 +88,28 @@ Full image processing functionality also requires a number of command-line tools
|
|
|
64
88
|
| `ffmpeg` | Media probing used by some conversion paths |
|
|
65
89
|
| `dssim` | Perceptual similarity metrics (only needed if `logSimilarity` is enabled) |
|
|
66
90
|
|
|
67
|
-
If you skip image processing (`processOptions: 'disabled'`) you can omit
|
|
91
|
+
If you skip image processing (`processOptions: 'disabled'`) you can omit these.
|
|
68
92
|
|
|
69
|
-
|
|
93
|
+
#### CLI installation
|
|
94
|
+
|
|
95
|
+
Note that the Aphex CLI does _not_ expose all the functionality from the TypeScript library. It's a native bridge focused on querying your library for images and metadata, and also certain fast-path export strategies.
|
|
96
|
+
|
|
97
|
+
Run it once without installing:
|
|
70
98
|
|
|
71
99
|
```sh
|
|
72
|
-
|
|
73
|
-
|
|
100
|
+
npx @kitschpatrol/aphex
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or install it globally with Homebrew:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
brew install kitschpatrol/tap/aphex
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or install it globally with npm:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
npm install --global @kitschpatrol/aphex
|
|
74
113
|
```
|
|
75
114
|
|
|
76
115
|
### Permissions
|
|
@@ -192,7 +231,7 @@ setLogger(console)
|
|
|
192
231
|
|
|
193
232
|
##### Exporting a photo by filename
|
|
194
233
|
|
|
195
|
-
Let's assume you have an album named "Trip" in your Photos.app library containing a photo with the filename "
|
|
234
|
+
Let's assume you have an album named "Trip" in your Photos.app library containing a photo with the filename "IMG_1922.jpeg":
|
|
196
235
|
|
|
197
236
|
```ts
|
|
198
237
|
const result = await exportPhoto('Trip/IMG_1922.jpeg', '~/Desktop')
|