1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-03 17:59:37 +02:00

Run transcription after file replacement

This commit is contained in:
Chocobozzz 2025-04-17 15:15:07 +02:00
parent f8db7406cf
commit 89c0f36a53
No known key found for this signature in database
GPG key ID: 583A612D890159BE
6 changed files with 55 additions and 18 deletions

View file

@ -1,6 +1,6 @@
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'
import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core' import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core'
import { ActivatedRoute, Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router' import { ActivatedRoute, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router'
import { import {
AuthService, AuthService,
MarkdownService, MarkdownService,

View file

@ -30,8 +30,7 @@ describe('Test videos files', function () {
await servers[0].config.enableTranscoding({ hls: true, webVideo: true, resolutions: 'max' }) await servers[0].config.enableTranscoding({ hls: true, webVideo: true, resolutions: 'max' })
}) })
function runTests (objectStorage?: ObjectStorageCommand) { function runTests () {
describe('When deleting all files', function () { describe('When deleting all files', function () {
let validId1: string let validId1: string
let validId2: string let validId2: string
@ -222,7 +221,7 @@ describe('Test videos files', function () {
const objectStorage = new ObjectStorageCommand() const objectStorage = new ObjectStorageCommand()
runTests(objectStorage) runTests()
}) })
after(async function () { after(async function () {

View file

@ -205,7 +205,7 @@ describe('Test video transcription', function () {
tasks: [ tasks: [
{ {
name: 'cut' as 'cut', name: 'cut' as 'cut',
options: { start: 1 } options: { start: 10 }
} }
] ]
}) })
@ -231,7 +231,7 @@ describe('Test video transcription', function () {
tasks: [ tasks: [
{ {
name: 'cut' as 'cut', name: 'cut' as 'cut',
options: { start: 1 } options: { start: 10 }
} }
] ]
}) })
@ -242,6 +242,40 @@ describe('Test video transcription', function () {
expect(oldContent).to.equal(newContent) expect(oldContent).to.equal(newContent)
}) })
it('Should run transcription after a video replacement', async function () {
this.timeout(120000)
await servers[0].config.enableFileUpdate()
const uuid = await uploadForTranscription(servers[0])
await waitJobs(servers)
await checkAutoCaption({ servers, uuid })
const oldContent = await getCaptionContent(servers[0], uuid, 'en')
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' })
await waitJobs(servers)
const newContent = await getCaptionContent(servers[0], uuid, 'en')
expect(oldContent).to.not.equal(newContent)
})
it('Should not run transcription after video replacement if the subtitle has not been auto generated', async function () {
this.timeout(120000)
const uuid = await uploadForTranscription(servers[0], { language: 'en' })
await waitJobs(servers)
await servers[0].captions.add({ language: 'en', videoId: uuid, fixture: 'subtitle-good1.vtt' })
const oldContent = await getCaptionContent(servers[0], uuid, 'en')
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' })
await waitJobs(servers)
const newContent = await getCaptionContent(servers[0], uuid, 'en')
expect(oldContent).to.equal(newContent)
})
it('Should run transcription with HLS only and audio splitted', async function () { it('Should run transcription with HLS only and audio splitted', async function () {
this.timeout(360000) this.timeout(360000)

View file

@ -6,6 +6,7 @@ import { Hooks } from '@server/lib/plugins/hooks.js'
import { regenerateMiniaturesIfNeeded } from '@server/lib/thumbnail.js' import { regenerateMiniaturesIfNeeded } from '@server/lib/thumbnail.js'
import { setupUploadResumableRoutes } from '@server/lib/uploadx.js' import { setupUploadResumableRoutes } from '@server/lib/uploadx.js'
import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist.js' import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist.js'
import { regenerateTranscriptionTaskIfNeeded } from '@server/lib/video-captions.js'
import { buildNewFile, createVideoSource } from '@server/lib/video-file.js' import { buildNewFile, createVideoSource } from '@server/lib/video-file.js'
import { buildMoveVideoJob, buildStoryboardJobIfNeeded } from '@server/lib/video-jobs.js' import { buildMoveVideoJob, buildStoryboardJobIfNeeded } from '@server/lib/video-jobs.js'
import { VideoPathManager } from '@server/lib/video-path-manager.js' import { VideoPathManager } from '@server/lib/video-path-manager.js'
@ -198,7 +199,9 @@ async function addVideoJobsAfterUpload (video: MVideoFullLight, videoFile: MVide
}) })
} }
return JobQueue.Instance.createSequentialJobFlow(...jobs) await JobQueue.Instance.createSequentialJobFlow(...jobs)
await regenerateTranscriptionTaskIfNeeded(video)
} }
async function removeOldFiles (options: { async function removeOldFiles (options: {

View file

@ -101,6 +101,16 @@ export async function updateHLSMasterOnCaptionChange (video: MVideo, hls: MStrea
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export async function regenerateTranscriptionTaskIfNeeded (video: MVideo) {
if (video.language && CONFIG.VIDEO_TRANSCRIPTION.ENABLED) {
const caption = await VideoCaptionModel.loadByVideoIdAndLanguage(video.id, video.language)
if (caption?.automaticallyGenerated) {
await createTranscriptionTaskIfNeeded(video)
}
}
}
export async function createTranscriptionTaskIfNeeded (video: MVideoUUID & MVideoUrl) { export async function createTranscriptionTaskIfNeeded (video: MVideoUUID & MVideoUrl) {
if (CONFIG.VIDEO_TRANSCRIPTION.ENABLED !== true) return if (CONFIG.VIDEO_TRANSCRIPTION.ENABLED !== true) return

View file

@ -4,14 +4,13 @@ import { VideoStudioEditionPayload, VideoStudioTask, VideoStudioTaskPayload } fr
import { logger, loggerTagsFactory } from '@server/helpers/logger.js' import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
import { createTorrentAndSetInfoHashFromPath } from '@server/helpers/webtorrent.js' import { createTorrentAndSetInfoHashFromPath } from '@server/helpers/webtorrent.js'
import { CONFIG } from '@server/initializers/config.js' import { CONFIG } from '@server/initializers/config.js'
import { VideoCaptionModel } from '@server/models/video/video-caption.js'
import { MUser, MVideoFile, MVideoFullLight, MVideoWithAllFiles, MVideoWithFile } from '@server/types/models/index.js' import { MUser, MVideoFile, MVideoFullLight, MVideoWithAllFiles, MVideoWithFile } from '@server/types/models/index.js'
import { move, remove } from 'fs-extra/esm' import { move, remove } from 'fs-extra/esm'
import { join } from 'path' import { join } from 'path'
import { JobQueue } from './job-queue/index.js' import { JobQueue } from './job-queue/index.js'
import { VideoStudioTranscodingJobHandler } from './runners/index.js' import { VideoStudioTranscodingJobHandler } from './runners/index.js'
import { getTranscodingJobPriority } from './transcoding/transcoding-priority.js' import { getTranscodingJobPriority } from './transcoding/transcoding-priority.js'
import { createTranscriptionTaskIfNeeded } from './video-captions.js' import { regenerateTranscriptionTaskIfNeeded } from './video-captions.js'
import { buildNewFile, removeHLSPlaylist, removeWebVideoFile } from './video-file.js' import { buildNewFile, removeHLSPlaylist, removeWebVideoFile } from './video-file.js'
import { buildStoryboardJobIfNeeded } from './video-jobs.js' import { buildStoryboardJobIfNeeded } from './video-jobs.js'
import { VideoPathManager } from './video-path-manager.js' import { VideoPathManager } from './video-path-manager.js'
@ -112,7 +111,6 @@ export async function onVideoStudioEnded (options: {
await JobQueue.Instance.createSequentialJobFlow( await JobQueue.Instance.createSequentialJobFlow(
buildStoryboardJobIfNeeded({ video, federate: false }), buildStoryboardJobIfNeeded({ video, federate: false }),
{ {
type: 'federate-video' as 'federate-video', type: 'federate-video' as 'federate-video',
payload: { payload: {
@ -120,7 +118,6 @@ export async function onVideoStudioEnded (options: {
isNewVideoForFederation: false isNewVideoForFederation: false
} }
}, },
{ {
type: 'transcoding-job-builder' as 'transcoding-job-builder', type: 'transcoding-job-builder' as 'transcoding-job-builder',
payload: { payload: {
@ -132,13 +129,7 @@ export async function onVideoStudioEnded (options: {
} }
) )
if (video.language && CONFIG.VIDEO_TRANSCRIPTION.ENABLED) { await regenerateTranscriptionTaskIfNeeded(video)
const caption = await VideoCaptionModel.loadByVideoIdAndLanguage(video.id, video.language)
if (caption?.automaticallyGenerated) {
await createTranscriptionTaskIfNeeded(video)
}
}
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------