Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/immich-app/immich into feat…
Browse files Browse the repository at this point in the history
…/nullable-dates
  • Loading branch information
etnoy committed Feb 2, 2025
2 parents 0700b45 + 2b41b5e commit 0222ef6
Show file tree
Hide file tree
Showing 85 changed files with 1,068 additions and 370 deletions.
6 changes: 3 additions & 3 deletions cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.2.46",
"version": "2.2.48",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions docker/hwaccel.transcoding.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ services:
vaapi-wsl: # use this for VAAPI if you're running Immich in WSL2
devices:
- /dev/dri:/dev/dri
- /dev/dxg:/dev/dxg
volumes:
- /usr/lib/wsl:/usr/lib/wsl
environment:
Expand Down
17 changes: 8 additions & 9 deletions docs/docs/developer/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,33 +50,32 @@ The Immich CLI is an [npm](https://www.npmjs.com/) package that lets users contr

The Immich backend is divided into several services, which are run as individual docker containers.

1. `immich-server` - Handle and respond to REST API requests
1. `immich-microservices` - Execute background jobs (thumbnail generation, metadata extraction, transcoding, etc.)
1. `immich-server` - Handle and respond to REST API requests, execute background jobs (thumbnail generation, metadata extraction, transcoding, etc.)
1. `immich-machine-learning` - Execute machine learning models
1. `postgres` - Persistent data storage
1. `redis`- Queue management for `immich-microservices`
1. `redis`- Queue management for background jobs

### Immich Server

The Immich Server is a [TypeScript](https://www.typescriptlang.org/) project written for [Node.js](https://nodejs.org/). It uses the [Nest.js](https://nestjs.com) framework, with [TypeORM](https://typeorm.io/) for database management. The server codebase also loosely follows the [Hexagonal Architecture](<https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)>). Specifically, we aim to separate technology specific implementations (`infra/`) from core business logic (`domain/`).
The Immich Server is a [TypeScript](https://www.typescriptlang.org/) project written for [Node.js](https://nodejs.org/). It uses the [Nest.js](https://nestjs.com) framework, [Express](https://expressjs.com/) server, and the query builder [Kysely](https://kysely.dev/). The server codebase also loosely follows the [Hexagonal Architecture](<https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)>). Specifically, we aim to separate technology specific implementations (`src/repositories`) from core business logic (`src/services`).

#### REST Endpoints
### API Endpoints

The server is a list of HTTP endpoints and associated handlers (controllers). Each controller usually implements the following CRUD operations:
An incoming HTTP request is mapped to a controller (`src/controllers`). Controllers are collections of HTTP endpoints. Each controller usually implements the following CRUD operations for its respective resource type:

- `POST` `/<type>` - **Create**
- `GET` `/<type>` - **Read** (all)
- `GET` `/<type>/:id` - **Read** (by id)
- `PUT` `/<type>/:id` - **Updated** (by id)
- `DELETE` `/<type>/:id` - **Delete** (by id)

#### DTOs
### Domain Transfer Objects (DTOs)

The server uses [Domain Transfer Objects](https://en.wikipedia.org/wiki/Data_transfer_object) as public interfaces for the inputs (query, params, and body) and outputs (response) for each endpoint. DTOs translate to [OpenAPI](./open-api.md) schemas and control the generated code used by each client.

### Microservices
### Background Jobs

The Immich Microservices image uses the same `Dockerfile` as the Immich Server, but with a different entrypoint. The Immich Microservices service mainly handles executing jobs, which include the following:
Immich uses a [worker](https://github.com/immich-app/immich/blob/main/server/src/utils/misc.ts#L266) to run background jobs. These jobs include:

- Thumbnail Generation
- Metadata Extraction
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/features/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ If your photos are on a network drive, automatic file watching likely won't work

#### Troubleshooting

If you encounter an `ENOSPC` error, you need to increase your file watcher limit. In sysctl, this key is called `fs.inotify.max_user_watched` and has a default value of 8192. Increase this number to a suitable value greater than the number of files you will be watching. Note that Immich has to watch all files in your import paths including any ignored files.
If you encounter an `ENOSPC` error, you need to increase your file watcher limit. In sysctl, this key is called `fs.inotify.max_user_watches` and has a default value of 8192. Increase this number to a suitable value greater than the number of files you will be watching. Note that Immich has to watch all files in your import paths including any ignored files.

```
ERROR [LibraryService] Library watcher for library c69faf55-f96d-4aa0-b83b-2d80cbc27d98 encountered error: Error: ENOSPC: System limit for number of file watchers reached, watch '/media/photo.jpg'
Expand Down
33 changes: 17 additions & 16 deletions docs/docs/features/supported-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@ For the full list, refer to the [Immich source code](https://github.com/immich-a

## Image formats

| Format | Extension(s) | Supported? | Notes |
| :-------- | :---------------------------- | :----------------: | :-------------- |
| `AVIF` | `.avif` | :white_check_mark: | |
| `BMP` | `.bmp` | :white_check_mark: | |
| `GIF` | `.gif` | :white_check_mark: | |
| `HEIC` | `.heic` | :white_check_mark: | |
| `HEIF` | `.heif` | :white_check_mark: | |
| `JPEG` | `.webp` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
| `JPEG XL` | `.jxl` | :white_check_mark: | |
| `PNG` | `.webp` | :white_check_mark: | |
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |
| `RAW` | `.raw` | :white_check_mark: | |
| `RW2` | `.rw2` | :white_check_mark: | |
| `SVG` | `.svg` | :white_check_mark: | |
| `TIFF` | `.tif` `.tiff` | :white_check_mark: | |
| `WEBP` | `.webp` | :white_check_mark: | |
| Format | Extension(s) | Supported? | Notes |
| :---------- | :---------------------------- | :----------------: | :-------------- |
| `AVIF` | `.avif` | :white_check_mark: | |
| `BMP` | `.bmp` | :white_check_mark: | |
| `GIF` | `.gif` | :white_check_mark: | |
| `HEIC` | `.heic` | :white_check_mark: | |
| `HEIF` | `.heif` | :white_check_mark: | |
| `JPEG 2000` | `.jp2` | :white_check_mark: | |
| `JPEG` | `.webp` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
| `JPEG XL` | `.jxl` | :white_check_mark: | |
| `PNG` | `.webp` | :white_check_mark: | |
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |
| `RAW` | `.raw` | :white_check_mark: | |
| `RW2` | `.rw2` | :white_check_mark: | |
| `SVG` | `.svg` | :white_check_mark: | |
| `TIFF` | `.tif` `.tiff` | :white_check_mark: | |
| `WEBP` | `.webp` | :white_check_mark: | |

## Video formats

Expand Down
4 changes: 2 additions & 2 deletions docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ const config = {
label: 'API',
},
{
to: '/blog',
href: 'https://immich.store',
position: 'right',
label: 'Blog',
label: 'Merch',
},
{
href: 'https://github.com/immich-app/immich',
Expand Down
5 changes: 5 additions & 0 deletions docs/src/components/community-projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ const projects: CommunityProjectProps[] = [
description: 'Downloads a configurable number of random photos based on people or album ID.',
url: 'https://github.com/jon6fingrs/immich-dl',
},
{
title: 'Immich Upload Optimizer',
description: 'Automatically optimize files uploaded to Immich in order to save storage space',
url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer',
},
];

function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {
Expand Down
7 changes: 7 additions & 0 deletions docs/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ function HomepageHeader() {
>
Demo
</Link>

<Link
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary/10 dark:bg-gray-300 rounded-xl hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
to="https://demo.immich.app/"
>
Buy Merch
</Link>
</div>

<div className="my-12 flex gap-1 font-medium place-items-center place-content-center text-immich-primary dark:text-immich-dark-primary">
Expand Down
8 changes: 8 additions & 0 deletions docs/static/archived-versions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
[
{
"label": "v1.125.7",
"url": "https://v1.125.7.archive.immich.app"
},
{
"label": "v1.125.6",
"url": "https://v1.125.6.archive.immich.app"
},
{
"label": "v1.125.5",
"url": "https://v1.125.5.archive.immich.app"
Expand Down
8 changes: 4 additions & 4 deletions e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "1.125.5",
"version": "1.125.7",
"description": "",
"main": "index.js",
"type": "module",
Expand Down
14 changes: 14 additions & 0 deletions e2e/src/api/specs/asset.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,20 @@ describe('/asset', () => {
expect(status).toEqual(200);
});

it('should set the negative rating', async () => {
const { status, body } = await request(app)
.put(`/assets/${user1Assets[0].id}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ rating: -1 });
expect(body).toMatchObject({
id: user1Assets[0].id,
exifInfo: expect.objectContaining({
rating: -1,
}),
});
expect(status).toEqual(200);
});

it('should reject invalid rating', async () => {
for (const test of [{ rating: 7 }, { rating: 3.5 }, { rating: null }]) {
const { status, body } = await request(app)
Expand Down
19 changes: 19 additions & 0 deletions e2e/src/api/specs/user-admin.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,5 +356,24 @@ describe('/admin/users', () => {
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});

it('should restore a user', async () => {
const user = await utils.userSetup(admin.accessToken, createUserDto.create('restore'));

await deleteUserAdmin({ id: user.userId, userAdminDeleteDto: {} }, { headers: asBearerAuth(admin.accessToken) });

const { status, body } = await request(app)
.post(`/admin/users/${user.userId}/restore`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual(
expect.objectContaining({
id: user.userId,
email: user.userEmail,
status: 'active',
deletedAt: null,
}),
);
});
});
});
Loading

0 comments on commit 0222ef6

Please sign in to comment.