merge: integrate dev branch, resolve package.json and lockfile conflicts

Co-authored-by: ajnart <49837342+ajnart@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]andajnart committed 2026-03-13 09:20:05 +00:00
1 parent 1e438ec3c3
commit 6cbf72462a
117 files changed
+4495 -1648

No files matched your search

@@ -19,6 +19,7 @@ import { GitlabIntegration } from "../gitlab/gitlab-integration";
import { GlancesIntegration } from "../glances/glances-integration";
import { HomeAssistantIntegration } from "../homeassistant/homeassistant-integration";
import { ICalIntegration } from "../ical/ical-integration";
import { ImmichIntegration } from "../immich/immich-integration";
import { JellyfinIntegration } from "../jellyfin/jellyfin-integration";
import { JellyseerrIntegration } from "../jellyseerr/jellyseerr-integration";
import { LinuxServerIOIntegration } from "../linuxserverio/linuxserverio-integration";
@@ -39,6 +40,7 @@ import { PlexIntegration } from "../plex/plex-integration";
import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration";
import { ProxmoxIntegration } from "../proxmox/proxmox-integration";
import { QuayIntegration } from "../quay/quay-integration";
import { SeerrIntegration } from "../seerr/seerr-integration";
import { TrueNasIntegration } from "../truenas/truenas-integration";
import { UnifiControllerIntegration } from "../unifi-controller/unifi-controller-integration";
import { UnraidIntegration } from "../unraid/unraid-integration";
@@ -82,6 +84,7 @@ export const integrationCreators = {
slskd: SlskdIntegration,
aria2: Aria2Integration,
jellyseerr: JellyseerrIntegration,
seerr: SeerrIntegration,
overseerr: OverseerrIntegration,
prowlarr: ProwlarrIntegration,
openmediavault: OpenMediaVaultIntegration,
@@ -109,6 +112,7 @@ export const integrationCreators = {
unraid: UnraidIntegration,
coolify: CoolifyIntegration,
glances: GlancesIntegration,
immich: ImmichIntegration,
} satisfies Record<IntegrationKind, IntegrationInstance | [(input: IntegrationInput) => Promise<Integration>]>;
type IntegrationInstanceOfKind<TKind extends keyof typeof integrationCreators> = {
@@ -0,0 +1,111 @@
import { getAlbumInfo, getAllAlbums, getMyUser, getServerStatistics, init, searchUsers } from "@immich/sdk";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { ImageProxy } from "@homarr/image-proxy";
import type { IntegrationInput, IntegrationTestingInput } from "../base/integration";
import { Integration } from "../base/integration";
import type { TestingResult } from "../base/test-connection/test-connection-service";
export interface ImmichServerStats {
userCount: number;
photoCount: number;
videoCount: number;
totalLibraryUsageInBytes: number;
}
export interface ImmichAlbum {
id: string;
albumName: string;
assets: ImmichAsset[];
}
export interface ImmichAsset {
id: string;
deviceAssetId: string;
originalPath: string;
thumbhash: string | null;
fileModifiedAt: string;
fileCreatedAt: string;
updatedAt: string;
type: "IMAGE" | "VIDEO" | "AUDIO" | "OTHER";
publicLink: string;
}
const logger = createLogger({ module: "immich-integration" });
export class ImmichIntegration extends Integration {
constructor(integration: IntegrationInput) {
super(integration);
}
public async getServerStatsAsync(): Promise<ImmichServerStats> {
this.initClient();
const [statistics, users] = await Promise.all([getServerStatistics(), searchUsers()]);
return {
photoCount: statistics.photos,
userCount: users.length,
totalLibraryUsageInBytes: statistics.usage,
videoCount: statistics.videos,
};
}
public async getAlbumAsync(albumId: string): Promise<ImmichAlbum> {
this.initClient();
const album = await getAlbumInfo({ id: albumId });
const imageProxy = new ImageProxy();
return {
albumName: album.albumName,
assets: await Promise.all(
album.assets.map(async (asset) => {
const publicLink = await imageProxy.createImageAsync(
this.url(`/api/assets/${asset.id}/original`).toString(),
{
"x-api-key": this.getSecretValue("apiKey"),
},
);
return {
id: asset.id,
type: asset.type,
deviceAssetId: asset.deviceAssetId,
thumbhash: asset.thumbhash,
fileCreatedAt: asset.fileCreatedAt,
fileModifiedAt: asset.fileModifiedAt,
originalPath: asset.originalPath,
updatedAt: asset.updatedAt,
publicLink,
};
}),
),
id: album.id,
};
}
public async getAlbumsAsync(): Promise<
{
id: string;
albumName: string;
assetCount: number;
}[]
> {
this.initClient();
const albums = await getAllAlbums({});
return albums.map((album) => ({ id: album.id, albumName: album.albumName, assetCount: album.assetCount }));
}
protected async testingAsync(_: IntegrationTestingInput): Promise<TestingResult> {
this.initClient();
const user = await getMyUser();
logger.debug(`Logged in as ${user.name} (${user.id})`);
return { success: true };
}
/**
* Sets the credentials and prepares the client for calls.
* Must be called before any other functions.
* @private
*/
private initClient() {
init({ baseUrl: this.url("/api").toString(), apiKey: this.getSecretValue("apiKey") });
}
}
+3
View File
@@ -19,6 +19,7 @@ export { NTFYIntegration } from "./ntfy/ntfy-integration";
export { OpenMediaVaultIntegration } from "./openmediavault/openmediavault-integration";
export { GlancesIntegration } from "./glances/glances-integration";
export { OverseerrIntegration } from "./overseerr/overseerr-integration";
export { SeerrIntegration } from "./seerr/seerr-integration";
export { PiHoleIntegrationV5 } from "./pi-hole/v5/pi-hole-integration-v5";
export { PiHoleIntegrationV6 } from "./pi-hole/v6/pi-hole-integration-v6";
export { PlexIntegration } from "./plex/plex-integration";
@@ -28,6 +29,7 @@ export { UnraidIntegration } from "./unraid/unraid-integration";
export { OPNsenseIntegration } from "./opnsense/opnsense-integration";
export { ICalIntegration } from "./ical/ical-integration";
export { CoolifyIntegration } from "./coolify/coolify-integration";
export { ImmichIntegration } from "./immich/immich-integration";
// Types
export type { IntegrationInput } from "./base/integration";
@@ -53,6 +55,7 @@ export type {
} from "./interfaces/media-transcoding/media-transcoding-types";
export type { ReleasesRepository, ReleaseResponse } from "./interfaces/releases-providers/releases-providers-types";
export type { Notification } from "./interfaces/notifications/notification-types";
export type { ImmichServerStats, ImmichAlbum, ImmichAsset } from "./immich/immich-integration";
// Schemas
export { downloadClientItemSchema } from "./interfaces/downloads/download-client-items";
@@ -0,0 +1,4 @@
import { OverseerrIntegration } from "../overseerr/overseerr-integration";
// Seerr is a fork of Overseerr, the API is compatible and no additional logic is required.
export class SeerrIntegration extends OverseerrIntegration {}