mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca877a004f | |||
| b4f719653f | |||
| f370b4bac6 | |||
| d788169bf3 | |||
| eea820fa2f |
@@ -175,7 +175,10 @@ jobs:
|
|||||||
|
|
||||||
Download: ${{ env.APK_URL }}
|
Download: ${{ env.APK_URL }}
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>QR code</summary>
|
||||||
<img src="https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=${{ env.APK_URL }}" alt="QR code" />
|
<img src="https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=${{ env.APK_URL }}" alt="QR code" />
|
||||||
|
</details>
|
||||||
|
|
||||||
Installs as a separate app (applicationId `app.alextran.immich.pr${{ github.event.pull_request.number }}`), so it coexists with the Play Store version and any other PR builds.
|
Installs as a separate app (applicationId `app.alextran.immich.pr${{ github.event.pull_request.number }}`), so it coexists with the Play Store version and any other PR builds.
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ The default configuration looks like this:
|
|||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
"accel": "disabled",
|
"accel": "disabled",
|
||||||
"accelDecode": false,
|
"accelDecode": true,
|
||||||
"acceptedAudioCodecs": ["aac", "mp3", "opus"],
|
"acceptedAudioCodecs": ["aac", "mp3", "opus"],
|
||||||
"acceptedContainers": ["mov", "ogg", "webm"],
|
"acceptedContainers": ["mov", "ogg", "webm"],
|
||||||
"acceptedVideoCodecs": ["h264"],
|
"acceptedVideoCodecs": ["h264"],
|
||||||
|
|||||||
-3
@@ -25,7 +25,6 @@ class AudioCodec {
|
|||||||
|
|
||||||
static const mp3 = AudioCodec._(r'mp3');
|
static const mp3 = AudioCodec._(r'mp3');
|
||||||
static const aac = AudioCodec._(r'aac');
|
static const aac = AudioCodec._(r'aac');
|
||||||
static const libopus = AudioCodec._(r'libopus');
|
|
||||||
static const opus = AudioCodec._(r'opus');
|
static const opus = AudioCodec._(r'opus');
|
||||||
static const pcmS16le = AudioCodec._(r'pcm_s16le');
|
static const pcmS16le = AudioCodec._(r'pcm_s16le');
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ class AudioCodec {
|
|||||||
static const values = <AudioCodec>[
|
static const values = <AudioCodec>[
|
||||||
mp3,
|
mp3,
|
||||||
aac,
|
aac,
|
||||||
libopus,
|
|
||||||
opus,
|
opus,
|
||||||
pcmS16le,
|
pcmS16le,
|
||||||
];
|
];
|
||||||
@@ -76,7 +74,6 @@ class AudioCodecTypeTransformer {
|
|||||||
switch (data) {
|
switch (data) {
|
||||||
case r'mp3': return AudioCodec.mp3;
|
case r'mp3': return AudioCodec.mp3;
|
||||||
case r'aac': return AudioCodec.aac;
|
case r'aac': return AudioCodec.aac;
|
||||||
case r'libopus': return AudioCodec.libopus;
|
|
||||||
case r'opus': return AudioCodec.opus;
|
case r'opus': return AudioCodec.opus;
|
||||||
case r'pcm_s16le': return AudioCodec.pcmS16le;
|
case r'pcm_s16le': return AudioCodec.pcmS16le;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ dependencies:
|
|||||||
path: ^1.9.1
|
path: ^1.9.1
|
||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
path_provider_foundation: ^2.6.0
|
path_provider_foundation: ^2.6.0
|
||||||
permission_handler: ^11.4.0
|
permission_handler: ^12.0.0
|
||||||
photo_manager: ^3.9.0
|
photo_manager: ^3.9.0
|
||||||
pinput: ^5.0.2
|
pinput: ^5.0.2
|
||||||
punycode: ^1.0.0
|
punycode: ^1.0.0
|
||||||
|
|||||||
@@ -16929,7 +16929,6 @@
|
|||||||
"enum": [
|
"enum": [
|
||||||
"mp3",
|
"mp3",
|
||||||
"aac",
|
"aac",
|
||||||
"libopus",
|
|
||||||
"opus",
|
"opus",
|
||||||
"pcm_s16le"
|
"pcm_s16le"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -7241,7 +7241,6 @@ export enum TranscodeHWAccel {
|
|||||||
export enum AudioCodec {
|
export enum AudioCodec {
|
||||||
Mp3 = "mp3",
|
Mp3 = "mp3",
|
||||||
Aac = "aac",
|
Aac = "aac",
|
||||||
Libopus = "libopus",
|
|
||||||
Opus = "opus",
|
Opus = "opus",
|
||||||
PcmS16Le = "pcm_s16le"
|
PcmS16Le = "pcm_s16le"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+6
-18
@@ -480,11 +480,11 @@ importers:
|
|||||||
specifier: ^9.0.2
|
specifier: ^9.0.2
|
||||||
version: 9.0.3
|
version: 9.0.3
|
||||||
kysely:
|
kysely:
|
||||||
specifier: 0.29.0
|
specifier: 0.28.16
|
||||||
version: 0.29.0
|
version: 0.28.16
|
||||||
kysely-postgres-js:
|
kysely-postgres-js:
|
||||||
specifier: ^3.0.0
|
specifier: ^3.0.0
|
||||||
version: 3.0.0(kysely@0.29.0)(postgres@3.4.9)
|
version: 3.0.0(kysely@0.28.16)(postgres@3.4.9)
|
||||||
lodash:
|
lodash:
|
||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 4.18.1
|
version: 4.18.1
|
||||||
@@ -505,7 +505,7 @@ importers:
|
|||||||
version: 6.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
version: 6.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
nestjs-kysely:
|
nestjs-kysely:
|
||||||
specifier: 3.1.2
|
specifier: 3.1.2
|
||||||
version: 3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.29.0)(reflect-metadata@0.2.2)
|
version: 3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.28.16)(reflect-metadata@0.2.2)
|
||||||
nestjs-otel:
|
nestjs-otel:
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)
|
version: 8.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)
|
||||||
@@ -8727,10 +8727,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww==}
|
resolution: {integrity: sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww==}
|
||||||
engines: {node: '>=20.0.0'}
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
kysely@0.29.0:
|
|
||||||
resolution: {integrity: sha512-LrQfPUeTW7MXbMvT62moEMnpMTuj9TO3lqjCeLKjM975PJ4Alrl/43f2tlDX7xOsNptKgH4LSNGwIbXwEkLg4g==}
|
|
||||||
engines: {node: '>=22.0.0'}
|
|
||||||
|
|
||||||
langium@3.3.1:
|
langium@3.3.1:
|
||||||
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
|
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
@@ -21740,16 +21736,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postgres: 3.4.9
|
postgres: 3.4.9
|
||||||
|
|
||||||
kysely-postgres-js@3.0.0(kysely@0.29.0)(postgres@3.4.9):
|
|
||||||
dependencies:
|
|
||||||
kysely: 0.29.0
|
|
||||||
optionalDependencies:
|
|
||||||
postgres: 3.4.9
|
|
||||||
|
|
||||||
kysely@0.28.16: {}
|
kysely@0.28.16: {}
|
||||||
|
|
||||||
kysely@0.29.0: {}
|
|
||||||
|
|
||||||
langium@3.3.1:
|
langium@3.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
chevrotain: 11.0.3
|
chevrotain: 11.0.3
|
||||||
@@ -22821,11 +22809,11 @@ snapshots:
|
|||||||
reflect-metadata: 0.2.2
|
reflect-metadata: 0.2.2
|
||||||
rxjs: 7.8.2
|
rxjs: 7.8.2
|
||||||
|
|
||||||
nestjs-kysely@3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.29.0)(reflect-metadata@0.2.2):
|
nestjs-kysely@3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.28.16)(reflect-metadata@0.2.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nestjs/common': 11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
'@nestjs/common': 11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
'@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(@nestjs/websockets@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
'@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.19)(@nestjs/websockets@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
kysely: 0.29.0
|
kysely: 0.28.16
|
||||||
reflect-metadata: 0.2.2
|
reflect-metadata: 0.2.2
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -84,7 +84,7 @@
|
|||||||
"jose": "^6.0.0",
|
"jose": "^6.0.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"kysely": "0.29.0",
|
"kysely": "0.28.16",
|
||||||
"kysely-postgres-js": "^3.0.0",
|
"kysely-postgres-js": "^3.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.4.2",
|
"luxon": "^3.4.2",
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ export const defaults = Object.freeze<SystemConfig>({
|
|||||||
transcode: TranscodePolicy.Required,
|
transcode: TranscodePolicy.Required,
|
||||||
tonemap: ToneMapping.Hable,
|
tonemap: ToneMapping.Hable,
|
||||||
accel: TranscodeHardwareAcceleration.Disabled,
|
accel: TranscodeHardwareAcceleration.Disabled,
|
||||||
accelDecode: false,
|
accelDecode: true,
|
||||||
},
|
},
|
||||||
job: {
|
job: {
|
||||||
[QueueName.BackgroundTask]: { concurrency: 5 },
|
[QueueName.BackgroundTask]: { concurrency: 5 },
|
||||||
|
|||||||
@@ -199,7 +199,6 @@ export const endpointTags: Record<ApiTag, string> = {
|
|||||||
export const AUDIO_ENCODER: Record<AudioCodec, string> = {
|
export const AUDIO_ENCODER: Record<AudioCodec, string> = {
|
||||||
[AudioCodec.Aac]: 'aac',
|
[AudioCodec.Aac]: 'aac',
|
||||||
[AudioCodec.Mp3]: 'mp3',
|
[AudioCodec.Mp3]: 'mp3',
|
||||||
[AudioCodec.Libopus]: 'libopus',
|
|
||||||
[AudioCodec.Opus]: 'libopus',
|
[AudioCodec.Opus]: 'libopus',
|
||||||
[AudioCodec.PcmS16le]: 'pcm_s16le',
|
[AudioCodec.PcmS16le]: 'pcm_s16le',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
OcrConfigSchema,
|
OcrConfigSchema,
|
||||||
} from 'src/dtos/model-config.dto';
|
} from 'src/dtos/model-config.dto';
|
||||||
import {
|
import {
|
||||||
AudioCodec,
|
|
||||||
AudioCodecSchema,
|
AudioCodecSchema,
|
||||||
ColorspaceSchema,
|
ColorspaceSchema,
|
||||||
CQModeSchema,
|
CQModeSchema,
|
||||||
@@ -65,10 +64,7 @@ const SystemConfigFFmpegSchema = z
|
|||||||
targetVideoCodec: VideoCodecSchema,
|
targetVideoCodec: VideoCodecSchema,
|
||||||
acceptedVideoCodecs: z.array(VideoCodecSchema).describe('Accepted video codecs'),
|
acceptedVideoCodecs: z.array(VideoCodecSchema).describe('Accepted video codecs'),
|
||||||
targetAudioCodec: AudioCodecSchema,
|
targetAudioCodec: AudioCodecSchema,
|
||||||
acceptedAudioCodecs: z
|
acceptedAudioCodecs: z.array(AudioCodecSchema).describe('Accepted audio codecs'),
|
||||||
.array(AudioCodecSchema)
|
|
||||||
.transform((value): AudioCodec[] => value.map((v) => (v === AudioCodec.Libopus ? AudioCodec.Opus : v)))
|
|
||||||
.describe('Accepted audio codecs'),
|
|
||||||
acceptedContainers: z.array(VideoContainerSchema).describe('Accepted containers'),
|
acceptedContainers: z.array(VideoContainerSchema).describe('Accepted containers'),
|
||||||
targetResolution: z.string().describe('Target resolution'),
|
targetResolution: z.string().describe('Target resolution'),
|
||||||
maxBitrate: z.string().describe('Max bitrate'),
|
maxBitrate: z.string().describe('Max bitrate'),
|
||||||
|
|||||||
@@ -454,8 +454,6 @@ export enum VideoSegmentCodec {
|
|||||||
export enum AudioCodec {
|
export enum AudioCodec {
|
||||||
Mp3 = 'mp3',
|
Mp3 = 'mp3',
|
||||||
Aac = 'aac',
|
Aac = 'aac',
|
||||||
/** @deprecated Use `Opus` instead */
|
|
||||||
Libopus = 'libopus',
|
|
||||||
Opus = 'opus',
|
Opus = 'opus',
|
||||||
PcmS16le = 'pcm_s16le',
|
PcmS16le = 'pcm_s16le',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -765,7 +765,6 @@ export class AssetRepository {
|
|||||||
getTimeBucket(timeBucket: string, options: TimeBucketOptions, auth: AuthDto) {
|
getTimeBucket(timeBucket: string, options: TimeBucketOptions, auth: AuthDto) {
|
||||||
const order = options.order ?? 'desc';
|
const order = options.order ?? 'desc';
|
||||||
const query = this.db
|
const query = this.db
|
||||||
.$pickTables<'asset' | 'asset_exif' | 'album_asset' | 'stack'>()
|
|
||||||
.with('cte', (qb) =>
|
.with('cte', (qb) =>
|
||||||
qb
|
qb
|
||||||
.selectFrom('asset')
|
.selectFrom('asset')
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { schemaDiff, schemaFromCode, schemaFromDatabase } from '@immich/sql-tools';
|
import { schemaDiff, schemaFromCode, schemaFromDatabase } from '@immich/sql-tools';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import AsyncLock from 'async-lock';
|
import AsyncLock from 'async-lock';
|
||||||
import { Kysely, sql } from 'kysely';
|
import { FileMigrationProvider, Kysely, Migrator, sql } from 'kysely';
|
||||||
import { FileMigrationProvider, Migrator } from 'kysely/migration';
|
|
||||||
import { InjectKysely } from 'nestjs-kysely';
|
import { InjectKysely } from 'nestjs-kysely';
|
||||||
import { readdir } from 'node:fs/promises';
|
import { readdir } from 'node:fs/promises';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class NotificationTable {
|
|||||||
type!: Generated<NotificationType>;
|
type!: Generated<NotificationType>;
|
||||||
|
|
||||||
@Column({ type: 'jsonb', nullable: true })
|
@Column({ type: 'jsonb', nullable: true })
|
||||||
data!: unknown | null;
|
data!: any | null;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
title!: string;
|
title!: string;
|
||||||
|
|||||||
@@ -2698,9 +2698,11 @@ describe(MediaService.name, () => {
|
|||||||
expect(mocks.media.transcode).not.toHaveBeenCalled();
|
expect(mocks.media.transcode).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set options for nvenc', async () => {
|
it('should set options for nvenc sw decode', async () => {
|
||||||
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
||||||
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Nvenc } });
|
mocks.systemMetadata.get.mockResolvedValue({
|
||||||
|
ffmpeg: { accel: TranscodeHardwareAcceleration.Nvenc, accelDecode: false },
|
||||||
|
});
|
||||||
await sut.handleVideoConversion({ id: 'video-id' });
|
await sut.handleVideoConversion({ id: 'video-id' });
|
||||||
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
@@ -2758,7 +2760,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining(['-init_hw_device', 'cuda=cuda:0', '-filter_hw_device', 'cuda']),
|
inputOptions: expect.any(Array),
|
||||||
outputOptions: expect.arrayContaining([expect.stringContaining('-multipass')]),
|
outputOptions: expect.arrayContaining([expect.stringContaining('-multipass')]),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -2775,7 +2777,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining(['-init_hw_device', 'cuda=cuda:0', '-filter_hw_device', 'cuda']),
|
inputOptions: expect.any(Array),
|
||||||
outputOptions: expect.arrayContaining(['-cq:v', '23', '-maxrate', '10000k', '-bufsize', '6897k']),
|
outputOptions: expect.arrayContaining(['-cq:v', '23', '-maxrate', '10000k', '-bufsize', '6897k']),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -2792,7 +2794,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining(['-init_hw_device', 'cuda=cuda:0', '-filter_hw_device', 'cuda']),
|
inputOptions: expect.any(Array),
|
||||||
outputOptions: expect.not.stringContaining('-maxrate'),
|
outputOptions: expect.not.stringContaining('-maxrate'),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -2809,7 +2811,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining(['-init_hw_device', 'cuda=cuda:0', '-filter_hw_device', 'cuda']),
|
inputOptions: expect.any(Array),
|
||||||
outputOptions: expect.not.arrayContaining([expect.stringContaining('-preset')]),
|
outputOptions: expect.not.arrayContaining([expect.stringContaining('-preset')]),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -2824,7 +2826,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining(['-init_hw_device', 'cuda=cuda:0', '-filter_hw_device', 'cuda']),
|
inputOptions: expect.any(Array),
|
||||||
outputOptions: expect.not.arrayContaining([expect.stringContaining('-multipass')]),
|
outputOptions: expect.not.arrayContaining([expect.stringContaining('-multipass')]),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -2894,10 +2896,10 @@ describe(MediaService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set options for qsv', async () => {
|
it('should set options for qsv with sw decode', async () => {
|
||||||
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
||||||
mocks.systemMetadata.get.mockResolvedValue({
|
mocks.systemMetadata.get.mockResolvedValue({
|
||||||
ffmpeg: { accel: TranscodeHardwareAcceleration.Qsv, maxBitrate: '10000k' },
|
ffmpeg: { accel: TranscodeHardwareAcceleration.Qsv, maxBitrate: '10000k', accelDecode: false },
|
||||||
});
|
});
|
||||||
await sut.handleVideoConversion({ id: 'video-id' });
|
await sut.handleVideoConversion({ id: 'video-id' });
|
||||||
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
||||||
@@ -2947,13 +2949,14 @@ describe(MediaService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set options for qsv with custom dri node', async () => {
|
it('should set options for qsv with custom dri node with sw decode', async () => {
|
||||||
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
||||||
mocks.systemMetadata.get.mockResolvedValue({
|
mocks.systemMetadata.get.mockResolvedValue({
|
||||||
ffmpeg: {
|
ffmpeg: {
|
||||||
accel: TranscodeHardwareAcceleration.Qsv,
|
accel: TranscodeHardwareAcceleration.Qsv,
|
||||||
maxBitrate: '10000k',
|
maxBitrate: '10000k',
|
||||||
preferredHwDevice: '/dev/dri/renderD128',
|
preferredHwDevice: '/dev/dri/renderD128',
|
||||||
|
accelDecode: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await sut.handleVideoConversion({ id: 'video-id' });
|
await sut.handleVideoConversion({ id: 'video-id' });
|
||||||
@@ -2983,12 +2986,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.any(Array),
|
||||||
'-init_hw_device',
|
|
||||||
'qsv=hw,child_device=/dev/dri/renderD128',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'hw',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.not.arrayContaining([expect.stringContaining('-preset')]),
|
outputOptions: expect.not.arrayContaining([expect.stringContaining('-preset')]),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -3005,12 +3003,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.any(Array),
|
||||||
'-init_hw_device',
|
|
||||||
'qsv=hw,child_device=/dev/dri/renderD128',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'hw',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.arrayContaining(['-low_power', '1']),
|
outputOptions: expect.arrayContaining(['-low_power', '1']),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -3036,12 +3029,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.arrayContaining(['-qsv_device', '/dev/dri/renderD129']),
|
||||||
'-init_hw_device',
|
|
||||||
'qsv=hw,child_device=/dev/dri/renderD129',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'hw',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.arrayContaining(['-c:v', 'h264_qsv']),
|
outputOptions: expect.arrayContaining(['-c:v', 'h264_qsv']),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -3158,9 +3146,11 @@ describe(MediaService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set options for vaapi', async () => {
|
it('should set options for sw decode vaapi', async () => {
|
||||||
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
||||||
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Vaapi } });
|
mocks.systemMetadata.get.mockResolvedValue({
|
||||||
|
ffmpeg: { accel: TranscodeHardwareAcceleration.Vaapi, accelDecode: false },
|
||||||
|
});
|
||||||
await sut.handleVideoConversion({ id: 'video-id' });
|
await sut.handleVideoConversion({ id: 'video-id' });
|
||||||
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
@@ -3211,12 +3201,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.any(Array),
|
||||||
'-init_hw_device',
|
|
||||||
'vaapi=accel:/dev/dri/renderD128',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'accel',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.arrayContaining([
|
outputOptions: expect.arrayContaining([
|
||||||
'-c:v',
|
'-c:v',
|
||||||
'h264_vaapi',
|
'h264_vaapi',
|
||||||
@@ -3242,12 +3227,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.any(Array),
|
||||||
'-init_hw_device',
|
|
||||||
'vaapi=accel:/dev/dri/renderD128',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'accel',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.arrayContaining([
|
outputOptions: expect.arrayContaining([
|
||||||
'-c:v',
|
'-c:v',
|
||||||
'h264_vaapi',
|
'h264_vaapi',
|
||||||
@@ -3275,12 +3255,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.any(Array),
|
||||||
'-init_hw_device',
|
|
||||||
'vaapi=accel:/dev/dri/renderD128',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'accel',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.not.arrayContaining([expect.stringContaining('-compression_level')]),
|
outputOptions: expect.not.arrayContaining([expect.stringContaining('-compression_level')]),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -3296,12 +3271,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.arrayContaining(['-hwaccel_device', '/dev/dri/renderD129']),
|
||||||
'-init_hw_device',
|
|
||||||
'vaapi=accel:/dev/dri/renderD129',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'accel',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.arrayContaining(['-c:v', 'h264_vaapi']),
|
outputOptions: expect.arrayContaining(['-c:v', 'h264_vaapi']),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -3319,12 +3289,7 @@ describe(MediaService.name, () => {
|
|||||||
'/original/path.ext',
|
'/original/path.ext',
|
||||||
expect.any(String),
|
expect.any(String),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining([
|
inputOptions: expect.arrayContaining(['-hwaccel_device', '/dev/dri/renderD128']),
|
||||||
'-init_hw_device',
|
|
||||||
'vaapi=accel:/dev/dri/renderD128',
|
|
||||||
'-filter_hw_device',
|
|
||||||
'accel',
|
|
||||||
]),
|
|
||||||
outputOptions: expect.arrayContaining(['-c:v', 'h264_vaapi']),
|
outputOptions: expect.arrayContaining(['-c:v', 'h264_vaapi']),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
@@ -3481,7 +3446,9 @@ describe(MediaService.name, () => {
|
|||||||
|
|
||||||
it('should fallback to sw transcoding if hw transcoding fails and hw decoding is disabled', async () => {
|
it('should fallback to sw transcoding if hw transcoding fails and hw decoding is disabled', async () => {
|
||||||
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
mocks.assetJob.getForVideoConversion.mockResolvedValue({ ...asset, ...probeStub.matroskaContainer });
|
||||||
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Vaapi } });
|
mocks.systemMetadata.get.mockResolvedValue({
|
||||||
|
ffmpeg: { accel: TranscodeHardwareAcceleration.Vaapi, accelDecode: false },
|
||||||
|
});
|
||||||
mocks.media.transcode.mockRejectedValueOnce(new Error('error'));
|
mocks.media.transcode.mockRejectedValueOnce(new Error('error'));
|
||||||
await sut.handleVideoConversion({ id: 'video-id' });
|
await sut.handleVideoConversion({ id: 'video-id' });
|
||||||
expect(mocks.media.transcode).toHaveBeenCalledTimes(2);
|
expect(mocks.media.transcode).toHaveBeenCalledTimes(2);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const updatedConfig = Object.freeze<SystemConfig>({
|
|||||||
preferredHwDevice: 'auto',
|
preferredHwDevice: 'auto',
|
||||||
transcode: TranscodePolicy.Required,
|
transcode: TranscodePolicy.Required,
|
||||||
accel: TranscodeHardwareAcceleration.Disabled,
|
accel: TranscodeHardwareAcceleration.Disabled,
|
||||||
accelDecode: false,
|
accelDecode: true,
|
||||||
tonemap: ToneMapping.Hable,
|
tonemap: ToneMapping.Hable,
|
||||||
},
|
},
|
||||||
logging: {
|
logging: {
|
||||||
|
|||||||
@@ -373,7 +373,6 @@ export function searchAssetBuilder(kysely: Kysely<DB>, options: AssetSearchBuild
|
|||||||
const visibility = options.visibility == null ? AssetVisibility.Timeline : options.visibility;
|
const visibility = options.visibility == null ? AssetVisibility.Timeline : options.visibility;
|
||||||
|
|
||||||
return kysely
|
return kysely
|
||||||
.$pickTables<'asset' | 'tag_asset' | 'asset_exif' | 'asset_file' | 'album_asset' | 'ocr_search' | 'smart_search'>()
|
|
||||||
.withPlugin(joinDeduplicationPlugin)
|
.withPlugin(joinDeduplicationPlugin)
|
||||||
.selectFrom('asset')
|
.selectFrom('asset')
|
||||||
.where('asset.visibility', '=', visibility)
|
.where('asset.visibility', '=', visibility)
|
||||||
|
|||||||
Reference in New Issue
Block a user