fix: SSE bez nazwanych zdarzen (postep stal na 0); usun tryb testowy; opcja napisow (osadz/.srt)
All checks were successful
deploy / deploy (push) Successful in 28s

- jobs.controller: usun pole type z MessageEvent — onmessage w EventSource
  reaguje tylko na domyslne 'message', przez co front nie dostawal zdarzen
- usun trial (health, compose, deploy.yml, UI, zmienne Gitea)
- napisy: wybor osadzania w wideo lub osobnego pliku .srt (--convert-subs srt)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 11:22:12 +02:00
parent a16bb14298
commit 94278f119d
11 changed files with 46 additions and 48 deletions

View File

@@ -8,11 +8,6 @@ export class HealthController {
ok: true,
service: 'vsd-api',
version: process.env.APP_VERSION || '6.5.6',
trial: {
enabled: process.env.TRIAL_ENABLED === '1',
expires: process.env.TRIAL_EXPIRES || null,
daysLeft: process.env.TRIAL_DAYS_LEFT ? Number(process.env.TRIAL_DAYS_LEFT) : null,
},
};
}
}

View File

@@ -28,4 +28,9 @@ export class CreateJobDto {
@IsOptional()
@IsBoolean()
subtitles?: boolean;
// 'embed' = osadź napisy w pliku wideo; 'file' = zapisz jako osobny plik .srt
@IsOptional()
@IsIn(['embed', 'file'])
subsMode?: 'embed' | 'file';
}

View File

@@ -30,8 +30,10 @@ export class JobsController {
@Sse(':id/events')
events(@Param('id') id: string): Observable<MessageEvent> {
// Bez pola `type` — inaczej Nest emituje nazwane zdarzenia (event: <kind>),
// a przeglądarkowy EventSource.onmessage reaguje tylko na domyślne „message”.
return this.jobs.events(id).pipe(
map((ev) => ({ data: JSON.stringify(ev), type: ev.kind }) as MessageEvent),
map((ev) => ({ data: JSON.stringify(ev) }) as MessageEvent),
);
}

View File

@@ -67,7 +67,14 @@ export class JobsService {
private async run(job: Job, dto: CreateJobDto) {
const outTemplate = path.join(job.workDir, '%(playlist_index&{} - |)s%(title)s.%(ext)s');
const args = buildArgs(dto.mode, dto.url, dto.format, !!dto.subtitles, outTemplate);
const args = buildArgs(
dto.mode,
dto.url,
dto.format,
!!dto.subtitles,
dto.subsMode || 'embed',
outTemplate,
);
this.emit(job, { kind: 'status', status: 'running' });
this.emit(job, { kind: 'log', line: `$ yt-dlp ${args.join(' ')}` });

View File

@@ -12,6 +12,7 @@ export function buildArgs(
url: string,
format: string | undefined,
subtitles: boolean,
subsMode: 'embed' | 'file',
outTemplate: string,
): string[] {
const base = [
@@ -25,8 +26,11 @@ export function buildArgs(
];
// Napisy: tylko realne (bez automatycznie generowanych przez YouTube).
// embed -> wtopione w plik wideo; file -> osobny plik .srt obok wideo (do ZIP).
const subs = subtitles
? ['--write-subs', '--no-write-auto-subs', '--sub-langs', 'all', '--embed-subs']
? subsMode === 'file'
? ['--write-subs', '--no-write-auto-subs', '--sub-langs', 'all', '--convert-subs', 'srt']
: ['--write-subs', '--no-write-auto-subs', '--sub-langs', 'all', '--embed-subs']
: [];
switch (mode) {