mirror of
https://github.com/immich-app/immich.git
synced 2026-07-28 14:47:30 -07:00
feat(cli): Add --visibility flag to immich CLI upload subcommand (#29614)
This commit is contained in:
@@ -99,6 +99,7 @@ Options:
|
||||
-H, --include-hidden Include hidden folders (default: false, env: IMMICH_INCLUDE_HIDDEN)
|
||||
-a, --album Automatically create albums based on folder name (default: false, env: IMMICH_AUTO_CREATE_ALBUM)
|
||||
-A, --album-name <name> Add all assets to specified album (env: IMMICH_ALBUM_NAME)
|
||||
--visibility <visibility> Set the visibility of uploaded assets (choices: "archive", "timeline", "hidden", "locked", env: IMMICH_VISIBILITY)
|
||||
-n, --dry-run Don't perform any actions, just show what will be done (default: false, env: IMMICH_DRY_RUN)
|
||||
-c, --concurrency <number> Number of assets to upload at the same time (default: 4, env: IMMICH_UPLOAD_CONCURRENCY)
|
||||
-j, --json-output Output detailed information in json format (default: false, env: IMMICH_JSON_OUTPUT)
|
||||
@@ -176,6 +177,12 @@ By default, hidden files are skipped. If you want to include hidden files, use t
|
||||
immich upload --include-hidden --recursive directory/
|
||||
```
|
||||
|
||||
You can set the visibility of uploaded assets to `archive`, `timeline`, `hidden`, or `locked` with the `--visibility` option:
|
||||
|
||||
```bash
|
||||
immich upload --visibility archive --recursive directory/
|
||||
```
|
||||
|
||||
You can use the `--json-output` option to get a json printed which includes
|
||||
three keys: `newFiles`, `duplicates` and `newAssets`. Due to some logging
|
||||
output you will need to strip the first three lines of output to get the json.
|
||||
|
||||
@@ -4,7 +4,14 @@ import path from 'node:path';
|
||||
import { setTimeout as sleep } from 'node:timers/promises';
|
||||
import { describe, expect, it, MockedFunction, vi } from 'vitest';
|
||||
|
||||
import { AssetRejectReason, AssetUploadAction, checkBulkUpload, defaults, getSupportedMediaTypes } from '@immich/sdk';
|
||||
import {
|
||||
AssetRejectReason,
|
||||
AssetUploadAction,
|
||||
AssetVisibility,
|
||||
checkBulkUpload,
|
||||
defaults,
|
||||
getSupportedMediaTypes,
|
||||
} from '@immich/sdk';
|
||||
import createFetchMock from 'vitest-fetch-mock';
|
||||
|
||||
import {
|
||||
@@ -102,6 +109,20 @@ describe('uploadFiles', () => {
|
||||
|
||||
await expect(uploadFiles([testFilePath], { concurrency: 1 })).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it('uploads assets with the specified visibility', async () => {
|
||||
fetchMocker.doMockIf(new RegExp(`${baseUrl}/assets$`), function () {
|
||||
return {
|
||||
status: 200,
|
||||
body: JSON.stringify({ id: 'fc5621b1-86f6-44a1-9905-403e607df9f5', status: 'created' }),
|
||||
};
|
||||
});
|
||||
|
||||
await uploadFiles([testFilePath], { concurrency: 1, visibility: AssetVisibility.Hidden });
|
||||
|
||||
const formData = fetchMocker.mock.calls[0]?.[1]?.body as FormData;
|
||||
expect(formData.get('visibility')).toBe('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkForDuplicates', () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
AssetMediaResponseDto,
|
||||
AssetMediaStatus,
|
||||
AssetUploadAction,
|
||||
AssetVisibility,
|
||||
Permission,
|
||||
addAssetsToAlbum,
|
||||
checkBulkUpload,
|
||||
@@ -39,6 +40,7 @@ export interface UploadOptionsDto {
|
||||
deleteDuplicates?: boolean;
|
||||
album?: boolean;
|
||||
albumName?: string;
|
||||
visibility?: AssetVisibility;
|
||||
includeHidden?: boolean;
|
||||
concurrency: number;
|
||||
progress?: boolean;
|
||||
@@ -306,10 +308,8 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
|
||||
return { newFiles, duplicates };
|
||||
};
|
||||
|
||||
export const uploadFiles = async (
|
||||
files: string[],
|
||||
{ dryRun, concurrency, progress }: UploadOptionsDto,
|
||||
): Promise<Asset[]> => {
|
||||
export const uploadFiles = async (files: string[], options: UploadOptionsDto): Promise<Asset[]> => {
|
||||
const { dryRun, concurrency, progress } = options;
|
||||
if (files.length === 0) {
|
||||
console.log('All assets were already uploaded, nothing to do.');
|
||||
return [];
|
||||
@@ -358,7 +358,7 @@ export const uploadFiles = async (
|
||||
throw new Error(`Stats not found for ${filepath}`);
|
||||
}
|
||||
|
||||
const response = await uploadFile(filepath, stats);
|
||||
const response = await uploadFile(filepath, stats, options);
|
||||
newAssets.push({ id: response.id, filepath });
|
||||
if (response.status === AssetMediaStatus.Duplicate) {
|
||||
duplicateCount++;
|
||||
@@ -400,7 +400,11 @@ export const uploadFiles = async (
|
||||
return newAssets;
|
||||
};
|
||||
|
||||
const uploadFile = async (input: string, stats: Stats): Promise<AssetMediaResponseDto> => {
|
||||
const uploadFile = async (
|
||||
input: string,
|
||||
stats: Stats,
|
||||
{ visibility }: UploadOptionsDto,
|
||||
): Promise<AssetMediaResponseDto> => {
|
||||
const { baseUrl, headers } = defaults;
|
||||
|
||||
const formData = new FormData();
|
||||
@@ -409,6 +413,9 @@ const uploadFile = async (input: string, stats: Stats): Promise<AssetMediaRespon
|
||||
formData.append('fileSize', String(stats.size));
|
||||
formData.append('isFavorite', 'false');
|
||||
formData.append('assetData', new UploadFile(input, stats.size));
|
||||
if (visibility) {
|
||||
formData.append('visibility', visibility);
|
||||
}
|
||||
|
||||
const sidecarPath = findSidecar(input);
|
||||
if (sidecarPath) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#! /usr/bin/env node
|
||||
import { AssetVisibility } from '@immich/sdk';
|
||||
import { Command, Option } from 'commander';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
@@ -58,6 +59,11 @@ program
|
||||
.env('IMMICH_ALBUM_NAME')
|
||||
.conflicts('album'),
|
||||
)
|
||||
.addOption(
|
||||
new Option('--visibility <visibility>', 'Set the visibility of uploaded assets')
|
||||
.choices(Object.values(AssetVisibility))
|
||||
.env('IMMICH_VISIBILITY'),
|
||||
)
|
||||
.addOption(
|
||||
new Option('-n, --dry-run', "Don't perform any actions, just show what will be done")
|
||||
.env('IMMICH_DRY_RUN')
|
||||
|
||||
Reference in New Issue
Block a user