Compare commits

...

6 Commits

Author SHA1 Message Date
Daniel Dietzler bcb905a673 fix: integrity checks dto validation 2026-07-06 10:44:35 +02:00
Daniel Dietzler 6da890ee37 fix: web search timeline visibility (#29518) 2026-07-03 17:41:25 +02:00
Lukas Schaefer e7ba8d3632 fix: live transcoding when viewing from a link share (#29471) 2026-07-03 11:34:37 -04:00
Lukas Schaefer 5645149e09 fix: downmix audio to stereo to fix broken channel layout (#29485)
* fix: downmix audio to stereo to fix broken channel layout

Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>

* add todo

Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>

---------

Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
2026-07-03 10:55:12 -04:00
Alex 5a104f9dbe chore: update docs with v3 tags (#29312) 2026-07-03 12:27:18 +02:00
bo0tzz 13d17b3a11 fix: re-add gCastEnabled negation (#29499) 2026-07-03 11:05:22 +02:00
8 changed files with 29 additions and 9 deletions
@@ -28,8 +28,8 @@ class SystemConfigIntegrityChecksumJob {
/// Percentage limit of the integrity checksum job
///
/// Minimum value: 0
/// Maximum value: 9007199254740991
int percentageLimit;
/// Maximum value: 1
num percentageLimit;
/// How long the integrity checksum job may run for
///
@@ -75,7 +75,7 @@ class SystemConfigIntegrityChecksumJob {
return SystemConfigIntegrityChecksumJob(
cronExpression: mapValueOfType<String>(json, r'cronExpression')!,
enabled: mapValueOfType<bool>(json, r'enabled')!,
percentageLimit: mapValueOfType<int>(json, r'percentageLimit')!,
percentageLimit: num.parse('${json[r'percentageLimit']}'),
timeLimit: mapValueOfType<int>(json, r'timeLimit')!,
);
}
+2 -2
View File
@@ -25890,9 +25890,9 @@
},
"percentageLimit": {
"description": "Percentage limit of the integrity checksum job",
"maximum": 9007199254740991,
"maximum": 1,
"minimum": 0,
"type": "integer"
"type": "number"
},
"timeLimit": {
"description": "How long the integrity checksum job may run for",
+1 -1
View File
@@ -73,7 +73,7 @@ const SystemConfigIntegrityJobSchema = z
const SystemConfigIntegrityChecksumJobSchema = SystemConfigIntegrityJobSchema.extend({
timeLimit: z.int().nonnegative().describe('How long the integrity checksum job may run for'),
percentageLimit: z.int().nonnegative().describe('Percentage limit of the integrity checksum job'),
percentageLimit: z.number().nonnegative().max(1).describe('Percentage limit of the integrity checksum job'),
})
.describe('Integrity checksum job config')
.meta({ id: 'SystemConfigIntegrityChecksumJob' });
@@ -381,6 +381,8 @@ describe(TranscodingService.name, () => {
'50',
'-keyint_min',
'50',
'-ac',
'2',
'-copyts',
'-r',
'50130000/2012441',
+5
View File
@@ -200,6 +200,11 @@ export class BaseConfig implements VideoCodecSWConfig {
const options = ['-c:v', videoCodec, '-c:a', audioCodec, '-map', `0:${videoStream.index}`, '-map_metadata', '-1'];
if (audioStream) {
options.push('-map', `0:${audioStream.index}`);
// If there are more than 2 channels sometimes the channel config is broken when re-encoded
// TODO: Store the number of channels in the db and then set it during the transcoding: -channel_layout 5.1
if ([TranscodeTarget.All, TranscodeTarget.Audio].includes(target)) {
options.push('-ac', '2');
}
}
if (this.getBFrames() > -1) {
options.push('-bf', `${this.getBFrames()}`);
@@ -5,6 +5,7 @@
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
import { castManager } from '$lib/managers/cast-manager.svelte';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { mediaCapabilitiesManager } from '$lib/managers/media-capabilities-manager.svelte';
import { autoPlayVideo, lang, loopVideo as loopVideoPreference } from '$lib/stores/preferences.store';
import { getAssetHlsSessionUrl, getAssetHlsUrl, getAssetMediaUrl, getAssetPlaybackUrl } from '$lib/utils';
@@ -150,6 +151,15 @@
},
},
useMediaCapabilities: false,
xhrSetup: (xhr: XMLHttpRequest, url: string) => {
const authenticatedUrl = new URL(url, globalThis.location.origin);
for (const [key, value] of Object.entries(authManager.params)) {
if (value) {
authenticatedUrl.searchParams.set(key, value as string);
}
}
xhr.open('GET', authenticatedUrl.toString());
},
};
const releaseSession = () => {
@@ -25,7 +25,7 @@ export class GCastDestination implements ICastDestination {
private currentUrl: string | null = null;
async initialize(): Promise<boolean> {
if (!authManager.authenticated || authManager.preferences.cast.gCastEnabled) {
if (!authManager.authenticated || !authManager.preferences.cast.gCastEnabled) {
this.isAvailable = false;
return false;
}
@@ -34,6 +34,7 @@
import {
type AlbumResponseDto,
type AssetResponseDto,
AssetVisibility,
getPerson,
getTagById,
type MetadataSearchDto,
@@ -141,8 +142,10 @@
try {
const { albums, assets } =
('query' in searchDto || 'queryAssetId' in searchDto) && smartSearchEnabled
? await searchSmart({ smartSearchDto: { ...searchDto, language: $lang } })
: await searchAssets({ metadataSearchDto: searchDto });
? await searchSmart({
smartSearchDto: { visibility: AssetVisibility.Timeline, ...searchDto, language: $lang },
})
: await searchAssets({ metadataSearchDto: { visibility: AssetVisibility.Timeline, ...searchDto } });
searchResultAlbums.push(...albums.items);
searchResultAssets.push(...assets.items);