@immich/cli 2.2.79 → 2.2.98
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/.nvmrc +1 -1
- package/README.md +19 -11
- package/dist/index.js +70 -17
- package/package.json +15 -16
package/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
24.11.0
|
package/README.md
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
A command-line interface for interfacing with the self-hosted photo manager [Immich](https://immich.app/).
|
|
2
2
|
|
|
3
|
-
Please see the [Immich CLI documentation](https://immich.app/
|
|
3
|
+
Please see the [Immich CLI documentation](https://docs.immich.app/features/command-line-interface).
|
|
4
4
|
|
|
5
5
|
# For developers
|
|
6
6
|
|
|
7
7
|
Before building the CLI, you must build the immich server and the open-api client. To build the server run the following in the server folder:
|
|
8
8
|
|
|
9
|
-
$
|
|
10
|
-
$
|
|
9
|
+
$ pnpm install
|
|
10
|
+
$ pnpm run build
|
|
11
11
|
|
|
12
12
|
Then, to build the open-api client run the following in the open-api folder:
|
|
13
13
|
|
|
14
14
|
$ ./bin/generate-open-api.sh
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## Run from build
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
$ npm run build
|
|
20
|
-
$ ts-node .
|
|
18
|
+
Go to the cli folder and build it:
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
$ pnpm install
|
|
21
|
+
$ pnpm run build
|
|
22
|
+
$ node dist/index.js
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
## Run and Debug from source (VSCode)
|
|
25
|
+
|
|
26
|
+
With VScode you can run and debug the Immich CLI. Go to the launch.json file, find the Immich CLI config and change this with the command you need to debug
|
|
27
|
+
|
|
28
|
+
`"args": ["upload", "--help"],`
|
|
29
|
+
|
|
30
|
+
replace that for the command of your choice.
|
|
31
|
+
|
|
32
|
+
## Install from build
|
|
25
33
|
|
|
26
34
|
You can also build and install the CLI using
|
|
27
35
|
|
|
28
|
-
$
|
|
29
|
-
$
|
|
36
|
+
$ pnpm run build
|
|
37
|
+
$ pnpm install -g .
|
|
30
38
|
****
|
package/dist/index.js
CHANGED
|
@@ -3289,6 +3289,8 @@ var NotificationType;
|
|
|
3289
3289
|
NotificationType2["JobFailed"] = "JobFailed";
|
|
3290
3290
|
NotificationType2["BackupFailed"] = "BackupFailed";
|
|
3291
3291
|
NotificationType2["SystemMessage"] = "SystemMessage";
|
|
3292
|
+
NotificationType2["AlbumInvite"] = "AlbumInvite";
|
|
3293
|
+
NotificationType2["AlbumUpdate"] = "AlbumUpdate";
|
|
3292
3294
|
NotificationType2["Custom"] = "Custom";
|
|
3293
3295
|
})(NotificationType || (NotificationType = {}));
|
|
3294
3296
|
var UserStatus;
|
|
@@ -3327,6 +3329,13 @@ var AssetTypeEnum;
|
|
|
3327
3329
|
AssetTypeEnum2["Audio"] = "AUDIO";
|
|
3328
3330
|
AssetTypeEnum2["Other"] = "OTHER";
|
|
3329
3331
|
})(AssetTypeEnum || (AssetTypeEnum = {}));
|
|
3332
|
+
var BulkIdErrorReason;
|
|
3333
|
+
(function(BulkIdErrorReason2) {
|
|
3334
|
+
BulkIdErrorReason2["Duplicate"] = "duplicate";
|
|
3335
|
+
BulkIdErrorReason2["NoPermission"] = "no_permission";
|
|
3336
|
+
BulkIdErrorReason2["NotFound"] = "not_found";
|
|
3337
|
+
BulkIdErrorReason2["Unknown"] = "unknown";
|
|
3338
|
+
})(BulkIdErrorReason || (BulkIdErrorReason = {}));
|
|
3330
3339
|
var Error$1;
|
|
3331
3340
|
(function(Error3) {
|
|
3332
3341
|
Error3["Duplicate"] = "duplicate";
|
|
@@ -3355,6 +3364,7 @@ var Permission;
|
|
|
3355
3364
|
Permission2["AssetDownload"] = "asset.download";
|
|
3356
3365
|
Permission2["AssetUpload"] = "asset.upload";
|
|
3357
3366
|
Permission2["AssetReplace"] = "asset.replace";
|
|
3367
|
+
Permission2["AssetCopy"] = "asset.copy";
|
|
3358
3368
|
Permission2["AlbumCreate"] = "album.create";
|
|
3359
3369
|
Permission2["AlbumRead"] = "album.read";
|
|
3360
3370
|
Permission2["AlbumUpdate"] = "album.update";
|
|
@@ -3463,8 +3473,13 @@ var Permission;
|
|
|
3463
3473
|
Permission2["AdminUserRead"] = "adminUser.read";
|
|
3464
3474
|
Permission2["AdminUserUpdate"] = "adminUser.update";
|
|
3465
3475
|
Permission2["AdminUserDelete"] = "adminUser.delete";
|
|
3476
|
+
Permission2["AdminSessionRead"] = "adminSession.read";
|
|
3466
3477
|
Permission2["AdminAuthUnlinkAll"] = "adminAuth.unlinkAll";
|
|
3467
3478
|
})(Permission || (Permission = {}));
|
|
3479
|
+
var AssetMetadataKey;
|
|
3480
|
+
(function(AssetMetadataKey2) {
|
|
3481
|
+
AssetMetadataKey2["MobileApp"] = "mobile-app";
|
|
3482
|
+
})(AssetMetadataKey || (AssetMetadataKey = {}));
|
|
3468
3483
|
var AssetMediaStatus;
|
|
3469
3484
|
(function(AssetMediaStatus2) {
|
|
3470
3485
|
AssetMediaStatus2["Created"] = "created";
|
|
@@ -3520,6 +3535,7 @@ var JobName;
|
|
|
3520
3535
|
JobName2["Library"] = "library";
|
|
3521
3536
|
JobName2["Notifications"] = "notifications";
|
|
3522
3537
|
JobName2["BackupDatabase"] = "backupDatabase";
|
|
3538
|
+
JobName2["Ocr"] = "ocr";
|
|
3523
3539
|
})(JobName || (JobName = {}));
|
|
3524
3540
|
var JobCommand;
|
|
3525
3541
|
(function(JobCommand2) {
|
|
@@ -3545,6 +3561,7 @@ var SearchSuggestionType;
|
|
|
3545
3561
|
SearchSuggestionType2["City"] = "city";
|
|
3546
3562
|
SearchSuggestionType2["CameraMake"] = "camera-make";
|
|
3547
3563
|
SearchSuggestionType2["CameraModel"] = "camera-model";
|
|
3564
|
+
SearchSuggestionType2["CameraLensModel"] = "camera-lens-model";
|
|
3548
3565
|
})(SearchSuggestionType || (SearchSuggestionType = {}));
|
|
3549
3566
|
var SharedLinkType;
|
|
3550
3567
|
(function(SharedLinkType2) {
|
|
@@ -3565,6 +3582,8 @@ var SyncEntityType;
|
|
|
3565
3582
|
SyncEntityType2["AssetV1"] = "AssetV1";
|
|
3566
3583
|
SyncEntityType2["AssetDeleteV1"] = "AssetDeleteV1";
|
|
3567
3584
|
SyncEntityType2["AssetExifV1"] = "AssetExifV1";
|
|
3585
|
+
SyncEntityType2["AssetMetadataV1"] = "AssetMetadataV1";
|
|
3586
|
+
SyncEntityType2["AssetMetadataDeleteV1"] = "AssetMetadataDeleteV1";
|
|
3568
3587
|
SyncEntityType2["PartnerV1"] = "PartnerV1";
|
|
3569
3588
|
SyncEntityType2["PartnerDeleteV1"] = "PartnerDeleteV1";
|
|
3570
3589
|
SyncEntityType2["PartnerAssetV1"] = "PartnerAssetV1";
|
|
@@ -3603,6 +3622,7 @@ var SyncEntityType;
|
|
|
3603
3622
|
SyncEntityType2["UserMetadataDeleteV1"] = "UserMetadataDeleteV1";
|
|
3604
3623
|
SyncEntityType2["SyncAckV1"] = "SyncAckV1";
|
|
3605
3624
|
SyncEntityType2["SyncResetV1"] = "SyncResetV1";
|
|
3625
|
+
SyncEntityType2["SyncCompleteV1"] = "SyncCompleteV1";
|
|
3606
3626
|
})(SyncEntityType || (SyncEntityType = {}));
|
|
3607
3627
|
var SyncRequestType;
|
|
3608
3628
|
(function(SyncRequestType2) {
|
|
@@ -3613,6 +3633,7 @@ var SyncRequestType;
|
|
|
3613
3633
|
SyncRequestType2["AlbumAssetExifsV1"] = "AlbumAssetExifsV1";
|
|
3614
3634
|
SyncRequestType2["AssetsV1"] = "AssetsV1";
|
|
3615
3635
|
SyncRequestType2["AssetExifsV1"] = "AssetExifsV1";
|
|
3636
|
+
SyncRequestType2["AssetMetadataV1"] = "AssetMetadataV1";
|
|
3616
3637
|
SyncRequestType2["AuthUsersV1"] = "AuthUsersV1";
|
|
3617
3638
|
SyncRequestType2["MemoriesV1"] = "MemoriesV1";
|
|
3618
3639
|
SyncRequestType2["MemoryToAssetsV1"] = "MemoryToAssetsV1";
|
|
@@ -3703,9 +3724,12 @@ var OAuthTokenEndpointAuthMethod;
|
|
|
3703
3724
|
function isHttpError(error2) {
|
|
3704
3725
|
return error2 instanceof l;
|
|
3705
3726
|
}
|
|
3706
|
-
const init = ({ baseUrl, apiKey }) => {
|
|
3727
|
+
const init = ({ baseUrl, apiKey, headers }) => {
|
|
3707
3728
|
setBaseUrl(baseUrl);
|
|
3708
3729
|
setApiKey(apiKey);
|
|
3730
|
+
if (headers) {
|
|
3731
|
+
setHeaders(headers);
|
|
3732
|
+
}
|
|
3709
3733
|
};
|
|
3710
3734
|
const setBaseUrl = (baseUrl) => {
|
|
3711
3735
|
defaults.baseUrl = baseUrl;
|
|
@@ -3714,6 +3738,18 @@ const setApiKey = (apiKey) => {
|
|
|
3714
3738
|
defaults.headers = defaults.headers || {};
|
|
3715
3739
|
defaults.headers["x-api-key"] = apiKey;
|
|
3716
3740
|
};
|
|
3741
|
+
const setHeaders = (headers) => {
|
|
3742
|
+
defaults.headers = defaults.headers || {};
|
|
3743
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
3744
|
+
assertNoApiKey(key);
|
|
3745
|
+
defaults.headers[key] = value;
|
|
3746
|
+
}
|
|
3747
|
+
};
|
|
3748
|
+
const assertNoApiKey = (headerKey) => {
|
|
3749
|
+
if (headerKey.toLowerCase() === "x-api-key") {
|
|
3750
|
+
throw new Error("The API key header can only be set using setApiKey().");
|
|
3751
|
+
}
|
|
3752
|
+
};
|
|
3717
3753
|
let defaultOptions$1 = {};
|
|
3718
3754
|
const _options = /* @__PURE__ */ new WeakMap();
|
|
3719
3755
|
const referenceTables = {
|
|
@@ -6450,7 +6486,7 @@ function toFinite(value) {
|
|
|
6450
6486
|
return value === 0 ? value : 0;
|
|
6451
6487
|
}
|
|
6452
6488
|
value = toNumber(value);
|
|
6453
|
-
if (value === INFINITY || value === -
|
|
6489
|
+
if (value === INFINITY || value === -INFINITY) {
|
|
6454
6490
|
var sign = value < 0 ? -1 : 1;
|
|
6455
6491
|
return sign * MAX_INTEGER;
|
|
6456
6492
|
}
|
|
@@ -13374,7 +13410,7 @@ ${indent}`) + "'";
|
|
|
13374
13410
|
}
|
|
13375
13411
|
function blockString({ comment, type: type2, value }, ctx, onComment, onChompKeep) {
|
|
13376
13412
|
const { blockQuote, commentString, lineWidth } = ctx.options;
|
|
13377
|
-
if (!blockQuote || /\n[\t ]+$/.test(value)
|
|
13413
|
+
if (!blockQuote || /\n[\t ]+$/.test(value)) {
|
|
13378
13414
|
return quotedString(value, ctx);
|
|
13379
13415
|
}
|
|
13380
13416
|
const indent = ctx.indent || (ctx.forceBlockIndent || containsDocumentMarker(value) ? " " : "");
|
|
@@ -19613,10 +19649,7 @@ const uploadBatch = async (files, options2) => {
|
|
|
19613
19649
|
console.log(JSON.stringify({ newFiles, duplicates, newAssets }, void 0, 4));
|
|
19614
19650
|
}
|
|
19615
19651
|
await updateAlbums([...newAssets, ...duplicates], options2);
|
|
19616
|
-
await deleteFiles(
|
|
19617
|
-
newAssets.map(({ filepath }) => filepath),
|
|
19618
|
-
options2
|
|
19619
|
-
);
|
|
19652
|
+
await deleteFiles(newAssets, duplicates, options2);
|
|
19620
19653
|
};
|
|
19621
19654
|
const startWatch = async (paths, options2, {
|
|
19622
19655
|
batchSize = UPLOAD_WATCH_BATCH_SIZE,
|
|
@@ -19871,12 +19904,19 @@ const uploadFile = async (input, stats) => {
|
|
|
19871
19904
|
}
|
|
19872
19905
|
return response.json();
|
|
19873
19906
|
};
|
|
19874
|
-
const deleteFiles = async (
|
|
19875
|
-
|
|
19876
|
-
|
|
19907
|
+
const deleteFiles = async (uploaded, duplicates, options2) => {
|
|
19908
|
+
let fileCount = 0;
|
|
19909
|
+
if (options2.delete) {
|
|
19910
|
+
fileCount += uploaded.length;
|
|
19911
|
+
}
|
|
19912
|
+
if (options2.deleteDuplicates) {
|
|
19913
|
+
fileCount += duplicates.length;
|
|
19877
19914
|
}
|
|
19878
19915
|
if (options2.dryRun) {
|
|
19879
|
-
console.log(`Would have deleted ${
|
|
19916
|
+
console.log(`Would have deleted ${fileCount} local asset${s(fileCount)}`);
|
|
19917
|
+
return;
|
|
19918
|
+
}
|
|
19919
|
+
if (fileCount === 0) {
|
|
19880
19920
|
return;
|
|
19881
19921
|
}
|
|
19882
19922
|
console.log("Deleting assets that have been uploaded...");
|
|
@@ -19884,12 +19924,20 @@ const deleteFiles = async (files, options2) => {
|
|
|
19884
19924
|
{ format: "Deleting local assets | {bar} | {percentage}% | ETA: {eta}s | {value}/{total} assets" },
|
|
19885
19925
|
cliProgressExports.Presets.shades_classic
|
|
19886
19926
|
);
|
|
19887
|
-
deletionProgress.start(
|
|
19888
|
-
|
|
19927
|
+
deletionProgress.start(fileCount, 0);
|
|
19928
|
+
const chunkDelete = async (files) => {
|
|
19889
19929
|
for (const assetBatch of chunk(files, options2.concurrency)) {
|
|
19890
|
-
await Promise.all(assetBatch.map((input) => unlink(input)));
|
|
19930
|
+
await Promise.all(assetBatch.map((input) => unlink(input.filepath)));
|
|
19891
19931
|
deletionProgress.update(assetBatch.length);
|
|
19892
19932
|
}
|
|
19933
|
+
};
|
|
19934
|
+
try {
|
|
19935
|
+
if (options2.delete) {
|
|
19936
|
+
await chunkDelete(uploaded);
|
|
19937
|
+
}
|
|
19938
|
+
if (options2.deleteDuplicates) {
|
|
19939
|
+
await chunkDelete(duplicates);
|
|
19940
|
+
}
|
|
19893
19941
|
} finally {
|
|
19894
19942
|
deletionProgress.stop();
|
|
19895
19943
|
}
|
|
@@ -20015,8 +20063,9 @@ const serverInfo = async (options2) => {
|
|
|
20015
20063
|
console.log(` Videos: ${stats.videos}`);
|
|
20016
20064
|
console.log(` Total: ${stats.total}`);
|
|
20017
20065
|
};
|
|
20018
|
-
const version = "2.2.
|
|
20066
|
+
const version = "2.2.98";
|
|
20019
20067
|
const defaultConfigDirectory = path$1.join(os.homedir(), ".config/immich/");
|
|
20068
|
+
const defaultConcurrency = Math.max(1, os.cpus().length - 1);
|
|
20020
20069
|
const program = new Command().name("immich").version(version).description("Command line interface for Immich").addOption(
|
|
20021
20070
|
new Option("-d, --config-directory <directory>", "Configuration directory where auth.yml will be stored").env("IMMICH_CONFIG_DIR").default(defaultConfigDirectory)
|
|
20022
20071
|
).addOption(new Option("-u, --url [url]", "Immich server URL").env("IMMICH_INSTANCE_URL")).addOption(new Option("-k, --key [key]", "Immich API key").env("IMMICH_API_KEY"));
|
|
@@ -20030,10 +20079,14 @@ program.command("upload").description("Upload assets").usage("[paths...] [option
|
|
|
20030
20079
|
).addOption(
|
|
20031
20080
|
new Option("-n, --dry-run", "Don't perform any actions, just show what will be done").env("IMMICH_DRY_RUN").default(false).conflicts("skipHash")
|
|
20032
20081
|
).addOption(
|
|
20033
|
-
new Option("-c, --concurrency <number>", "Number of assets to upload at the same time").env("IMMICH_UPLOAD_CONCURRENCY").default(
|
|
20082
|
+
new Option("-c, --concurrency <number>", "Number of assets to upload at the same time").env("IMMICH_UPLOAD_CONCURRENCY").default(defaultConcurrency)
|
|
20034
20083
|
).addOption(
|
|
20035
20084
|
new Option("-j, --json-output", "Output detailed information in json format").env("IMMICH_JSON_OUTPUT").default(false)
|
|
20036
|
-
).addOption(new Option("--delete", "Delete local assets after upload").env("IMMICH_DELETE_ASSETS")).addOption(
|
|
20085
|
+
).addOption(new Option("--delete", "Delete local assets after upload").env("IMMICH_DELETE_ASSETS")).addOption(
|
|
20086
|
+
new Option("--delete-duplicates", "Delete local assets that are duplicates (already exist on server)").env(
|
|
20087
|
+
"IMMICH_DELETE_DUPLICATES"
|
|
20088
|
+
)
|
|
20089
|
+
).addOption(new Option("--no-progress", "Hide progress bars").env("IMMICH_PROGRESS_BAR").default(true)).addOption(
|
|
20037
20090
|
new Option("--watch", "Watch for changes and upload automatically").env("IMMICH_WATCH_CHANGES").default(false).implies({ progress: false })
|
|
20038
20091
|
).argument("[paths...]", "One or more paths to assets to be uploaded").action((paths, options2) => upload(paths, program.opts(), options2));
|
|
20039
20092
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immich/cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.98",
|
|
4
4
|
"description": "Command Line Interface (CLI) for Immich",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./dist/index.js",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"cli"
|
|
14
14
|
],
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@eslint/eslintrc": "^3.1.0",
|
|
17
16
|
"@eslint/js": "^9.8.0",
|
|
18
17
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
|
19
18
|
"@types/byte-size": "^8.1.0",
|
|
@@ -21,7 +20,7 @@
|
|
|
21
20
|
"@types/lodash-es": "^4.17.12",
|
|
22
21
|
"@types/micromatch": "^4.0.9",
|
|
23
22
|
"@types/mock-fs": "^4.13.1",
|
|
24
|
-
"@types/node": "^22.
|
|
23
|
+
"@types/node": "^22.18.12",
|
|
25
24
|
"@vitest/coverage-v8": "^3.0.0",
|
|
26
25
|
"byte-size": "^9.0.0",
|
|
27
26
|
"cli-progress": "^3.12.0",
|
|
@@ -42,17 +41,6 @@
|
|
|
42
41
|
"vitest-fetch-mock": "^0.4.0",
|
|
43
42
|
"yaml": "^2.3.1"
|
|
44
43
|
},
|
|
45
|
-
"scripts": {
|
|
46
|
-
"build": "vite build",
|
|
47
|
-
"lint": "eslint \"src/**/*.ts\" --max-warnings 0",
|
|
48
|
-
"lint:fix": "npm run lint -- --fix",
|
|
49
|
-
"prepack": "npm run build",
|
|
50
|
-
"test": "vitest",
|
|
51
|
-
"test:cov": "vitest --coverage",
|
|
52
|
-
"format": "prettier --check .",
|
|
53
|
-
"format:fix": "prettier --write .",
|
|
54
|
-
"check": "tsc --noEmit"
|
|
55
|
-
},
|
|
56
44
|
"repository": {
|
|
57
45
|
"type": "git",
|
|
58
46
|
"url": "git+https://github.com/immich-app/immich.git",
|
|
@@ -69,6 +57,17 @@
|
|
|
69
57
|
"micromatch": "^4.0.8"
|
|
70
58
|
},
|
|
71
59
|
"volta": {
|
|
72
|
-
"node": "
|
|
60
|
+
"node": "24.11.0"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "vite build",
|
|
64
|
+
"build:dev": "vite build --sourcemap true",
|
|
65
|
+
"lint": "eslint \"src/**/*.ts\" --max-warnings 0",
|
|
66
|
+
"lint:fix": "npm run lint -- --fix",
|
|
67
|
+
"test": "vitest",
|
|
68
|
+
"test:cov": "vitest --coverage",
|
|
69
|
+
"format": "prettier --check .",
|
|
70
|
+
"format:fix": "prettier --write .",
|
|
71
|
+
"check": "tsc --noEmit"
|
|
73
72
|
}
|
|
74
|
-
}
|
|
73
|
+
}
|