aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/schedulers/update-videos-scheduler.ts
blob: e38685c04aa6bde6661feb501764c8fbb9e6e3ed (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
import { VideoModel } from '@server/models/video/video'
import { MScheduleVideoUpdate } from '@server/types/models'
import { VideoPrivacy, VideoState } from '@shared/models'
import { logger } from '../../helpers/logger'
import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
import { sequelizeTypescript } from '../../initializers/database'
import { ScheduleVideoUpdateModel } from '../../models/video/schedule-video-update'
import { Notifier } from '../notifier'
import { addVideoJobsAfterUpdate } from '../video'
import { VideoPathManager } from '../video-path-manager'
import { setVideoPrivacy } from '../video-privacy'
import { AbstractScheduler } from './abstract-scheduler'

export class UpdateVideosScheduler extends AbstractScheduler {

  private static instance: AbstractScheduler

  protected schedulerIntervalMs = SCHEDULER_INTERVALS_MS.UPDATE_VIDEOS

  private constructor () {
    super()
  }

  protected async internalExecute () {
    return this.updateVideos()
  }

  private async updateVideos () {
    if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined

    const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate()

    for (const schedule of schedules) {
      const videoOnly = await VideoModel.load(schedule.videoId)
      const mutexReleaser = await VideoPathManager.Instance.lockFiles(videoOnly.uuid)

      try {
        const { video, published } = await this.updateAVideo(schedule)

        if (published) Notifier.Instance.notifyOnVideoPublishedAfterScheduledUpdate(video)
      } catch (err) {
        logger.error('Cannot update video', { err })
      }

      mutexReleaser()
    }
  }

  private async updateAVideo (schedule: MScheduleVideoUpdate) {
    let oldPrivacy: VideoPrivacy
    let isNewVideo: boolean
    let published = false

    const video = await sequelizeTypescript.transaction(async t => {
      const video = await VideoModel.loadFull(schedule.videoId, t)
      if (video.state === VideoState.TO_TRANSCODE) return null

      logger.info('Executing scheduled video update on %s.', video.uuid)

      if (schedule.privacy) {
        isNewVideo = video.isNewVideo(schedule.privacy)
        oldPrivacy = video.privacy

        setVideoPrivacy(video, schedule.privacy)
        await video.save({ transaction: t })

        if (oldPrivacy === VideoPrivacy.PRIVATE) {
          published = true
        }
      }

      await schedule.destroy({ transaction: t })

      return video
    })

    if (!video) {
      return { video, published: false }
    }

    await addVideoJobsAfterUpdate({ video, oldPrivacy, isNewVideo, nameChanged: false })

    return { video, published }
  }

  static get Instance () {
    return this.instance || (this.instance = new this())
  }
}