1 import { VideoModel } from '@server/models/video/video'
2 import { MScheduleVideoUpdate } from '@server/types/models'
3 import { VideoPrivacy, VideoState } from '@shared/models'
4 import { logger } from '../../helpers/logger'
5 import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
6 import { sequelizeTypescript } from '../../initializers/database'
7 import { ScheduleVideoUpdateModel } from '../../models/video/schedule-video-update'
8 import { Notifier } from '../notifier'
9 import { addVideoJobsAfterUpdate } from '../video'
10 import { VideoPathManager } from '../video-path-manager'
11 import { setVideoPrivacy } from '../video-privacy'
12 import { AbstractScheduler } from './abstract-scheduler'
14 export class UpdateVideosScheduler extends AbstractScheduler {
16 private static instance: AbstractScheduler
18 protected schedulerIntervalMs = SCHEDULER_INTERVALS_MS.UPDATE_VIDEOS
20 private constructor () {
24 protected async internalExecute () {
25 return this.updateVideos()
28 private async updateVideos () {
29 if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined
31 const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate()
33 for (const schedule of schedules) {
34 const videoOnly = await VideoModel.load(schedule.videoId)
35 const mutexReleaser = await VideoPathManager.Instance.lockFiles(videoOnly.uuid)
38 const { video, published } = await this.updateAVideo(schedule)
40 if (published) Notifier.Instance.notifyOnVideoPublishedAfterScheduledUpdate(video)
42 logger.error('Cannot update video', { err })
49 private async updateAVideo (schedule: MScheduleVideoUpdate) {
50 let oldPrivacy: VideoPrivacy
51 let isNewVideo: boolean
54 const video = await sequelizeTypescript.transaction(async t => {
55 const video = await VideoModel.loadFull(schedule.videoId, t)
56 if (video.state === VideoState.TO_TRANSCODE) return
58 logger.info('Executing scheduled video update on %s.', video.uuid)
60 if (schedule.privacy) {
61 isNewVideo = video.isNewVideo(schedule.privacy)
62 oldPrivacy = video.privacy
64 setVideoPrivacy(video, schedule.privacy)
65 await video.save({ transaction: t })
67 if (oldPrivacy === VideoPrivacy.PRIVATE) {
72 await schedule.destroy({ transaction: t })
77 await addVideoJobsAfterUpdate({ video, oldPrivacy, isNewVideo, nameChanged: false })
79 return { video, published }
82 static get Instance () {
83 return this.instance || (this.instance = new this())