aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/runners/job-handlers/vod-hls-transcoding-job-handler.ts
blob: cc94bcbda072da9583541911e85a7a030a210bfb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { move } from 'fs-extra'
import { dirname, join } from 'path'
import { logger } from '@server/helpers/logger'
import { renameVideoFileInPlaylist } from '@server/lib/hls'
import { getHlsResolutionPlaylistFilename } from '@server/lib/paths'
import { onTranscodingEnded } from '@server/lib/transcoding/ended-transcoding'
import { onHLSVideoFileTranscoding } from '@server/lib/transcoding/hls-transcoding'
import { buildNewFile, removeAllWebTorrentFiles } from '@server/lib/video-file'
import { VideoJobInfoModel } from '@server/models/video/video-job-info'
import { MVideo } from '@server/types/models'
import { MRunnerJob } from '@server/types/models/runners'
import { pick } from '@shared/core-utils'
import { buildUUID } from '@shared/extra-utils'
import {
  RunnerJobUpdatePayload,
  RunnerJobVODHLSTranscodingPayload,
  RunnerJobVODHLSTranscodingPrivatePayload,
  VODHLSTranscodingSuccess
} from '@shared/models'
import { generateRunnerTranscodingVideoInputFileUrl } from '../runner-urls'
import { AbstractVODTranscodingJobHandler } from './abstract-vod-transcoding-job-handler'
import { loadTranscodingRunnerVideo } from './shared'

type CreateOptions = {
  video: MVideo
  isNewVideo: boolean
  deleteWebVideoFiles: boolean
  resolution: number
  fps: number
  priority: number
  dependsOnRunnerJob?: MRunnerJob
}

// eslint-disable-next-line max-len
export class VODHLSTranscodingJobHandler extends AbstractVODTranscodingJobHandler<CreateOptions, RunnerJobUpdatePayload, VODHLSTranscodingSuccess> {

  async create (options: CreateOptions) {
    const { video, resolution, fps, dependsOnRunnerJob, priority } = options

    const jobUUID = buildUUID()

    const payload: RunnerJobVODHLSTranscodingPayload = {
      input: {
        videoFileUrl: generateRunnerTranscodingVideoInputFileUrl(jobUUID, video.uuid)
      },
      output: {
        resolution,
        fps
      }
    }

    const privatePayload: RunnerJobVODHLSTranscodingPrivatePayload = {
      ...pick(options, [ 'isNewVideo', 'deleteWebVideoFiles' ]),

      videoUUID: video.uuid
    }

    const job = await this.createRunnerJob({
      type: 'vod-hls-transcoding',
      jobUUID,
      payload,
      privatePayload,
      priority,
      dependsOnRunnerJob
    })

    await VideoJobInfoModel.increaseOrCreate(video.uuid, 'pendingTranscode')

    return job
  }

  // ---------------------------------------------------------------------------

  protected async specificComplete (options: {
    runnerJob: MRunnerJob
    resultPayload: VODHLSTranscodingSuccess
  }) {
    const { runnerJob, resultPayload } = options
    const privatePayload = runnerJob.privatePayload as RunnerJobVODHLSTranscodingPrivatePayload

    const video = await loadTranscodingRunnerVideo(runnerJob, this.lTags)
    if (!video) return

    const videoFilePath = resultPayload.videoFile as string
    const resolutionPlaylistFilePath = resultPayload.resolutionPlaylistFile as string

    const videoFile = await buildNewFile({ path: videoFilePath, mode: 'hls' })
    const newVideoFilePath = join(dirname(videoFilePath), videoFile.filename)
    await move(videoFilePath, newVideoFilePath)

    const resolutionPlaylistFilename = getHlsResolutionPlaylistFilename(videoFile.filename)
    const newResolutionPlaylistFilePath = join(dirname(resolutionPlaylistFilePath), resolutionPlaylistFilename)
    await move(resolutionPlaylistFilePath, newResolutionPlaylistFilePath)

    await renameVideoFileInPlaylist(newResolutionPlaylistFilePath, videoFile.filename)

    await onHLSVideoFileTranscoding({
      video,
      videoFile,
      m3u8OutputPath: newResolutionPlaylistFilePath,
      videoOutputPath: newVideoFilePath
    })

    await onTranscodingEnded({ isNewVideo: privatePayload.isNewVideo, moveVideoToNextState: true, video })

    if (privatePayload.deleteWebVideoFiles === true) {
      logger.info('Removing web video files of %s now we have a HLS version of it.', video.uuid, this.lTags(video.uuid))

      await removeAllWebTorrentFiles(video)
    }

    logger.info('Runner VOD HLS job %s for %s ended.', runnerJob.uuid, video.uuid, this.lTags(runnerJob.uuid, video.uuid))
  }
}