X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Fschedulers%2Fvideos-redundancy-scheduler.ts;h=6e61cbe7d79bc283c24db626492c16255c816291;hb=cf59a2a0c367683ba35758419499bf6087c192ec;hp=d326148d0779de8d411c716ec93d340f75341a95;hpb=282e61e6c11f79e919c543871783fe1a00298d18;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index d326148d0..6e61cbe7d 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts @@ -1,9 +1,9 @@ import { AbstractScheduler } from './abstract-scheduler' import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants' import { logger } from '../../helpers/logger' -import { VideosRedundancy } from '../../../shared/models/redundancy' +import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' -import { downloadWebTorrentVideo } from '../../helpers/webtorrent' +import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' import { join } from 'path' import { move } from 'fs-extra' import { getServerActor } from '../../helpers/utils' @@ -14,7 +14,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../activitypub' import { downloadPlaylistSegments } from '../hls' import { CONFIG } from '../../initializers/config' import { - MStreamingPlaylist, + MStreamingPlaylist, MStreamingPlaylistFiles, MStreamingPlaylistVideo, MVideoAccountLight, MVideoFile, @@ -24,12 +24,14 @@ import { MVideoRedundancyVideo, MVideoWithAllFiles } from '@server/typings/models' +import { getVideoFilename } from '../video-paths' +import { VideoModel } from '@server/models/video/video' type CandidateToDuplicate = { - redundancy: VideosRedundancy, + redundancy: VideosRedundancyStrategy, video: MVideoWithAllFiles, files: MVideoFile[], - streamingPlaylists: MStreamingPlaylist[] + streamingPlaylists: MStreamingPlaylistFiles[] } function isMVideoRedundancyFileVideo ( @@ -40,7 +42,7 @@ function isMVideoRedundancyFileVideo ( export class VideosRedundancyScheduler extends AbstractScheduler { - private static instance: AbstractScheduler + private static instance: VideosRedundancyScheduler protected schedulerIntervalMs = CONFIG.REDUNDANCY.VIDEOS.CHECK_INTERVAL @@ -48,6 +50,22 @@ export class VideosRedundancyScheduler extends AbstractScheduler { super() } + async createManualRedundancy (videoId: number) { + const videoToDuplicate = await VideoModel.loadWithFiles(videoId) + + if (!videoToDuplicate) { + logger.warn('Video to manually duplicate %d does not exist anymore.', videoId) + return + } + + return this.createVideoRedundancies({ + video: videoToDuplicate, + redundancy: null, + files: videoToDuplicate.VideoFiles, + streamingPlaylists: videoToDuplicate.VideoStreamingPlaylists + }) + } + protected async internalExecute () { for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy) @@ -93,7 +111,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { for (const redundancyModel of expired) { try { const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) - const candidate = { + const candidate: CandidateToDuplicate = { redundancy: redundancyConfig, video: null, files: [], @@ -139,7 +157,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { } } - private findVideoToDuplicate (cache: VideosRedundancy) { + private findVideoToDuplicate (cache: VideosRedundancyStrategy) { if (cache.strategy === 'most-views') { return VideoRedundancyModel.findMostViewToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR) } @@ -186,27 +204,35 @@ export class VideosRedundancyScheduler extends AbstractScheduler { } } - private async createVideoFileRedundancy (redundancy: VideosRedundancy, video: MVideoAccountLight, fileArg: MVideoFile) { + private async createVideoFileRedundancy (redundancy: VideosRedundancyStrategy | null, video: MVideoAccountLight, fileArg: MVideoFile) { + let strategy = 'manual' + let expiresOn: Date = null + + if (redundancy) { + strategy = redundancy.strategy + expiresOn = this.buildNewExpiration(redundancy.minLifetime) + } + const file = fileArg as MVideoFileVideo file.Video = video const serverActor = await getServerActor() - logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, redundancy.strategy) + logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy) const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() - const magnetUri = video.generateMagnetUri(file, baseUrlHttp, baseUrlWs) + const magnetUri = generateMagnetUri(video, file, baseUrlHttp, baseUrlWs) const tmpPath = await downloadWebTorrentVideo({ magnetUri }, VIDEO_IMPORT_TIMEOUT) - const destPath = join(CONFIG.STORAGE.REDUNDANCY_DIR, video.getVideoFilename(file)) + const destPath = join(CONFIG.STORAGE.REDUNDANCY_DIR, getVideoFilename(video, file)) await move(tmpPath, destPath, { overwrite: true }) const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ - expiresOn: this.buildNewExpiration(redundancy.minLifetime), + expiresOn, url: getVideoCacheFileActivityPubUrl(file), fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), - strategy: redundancy.strategy, + strategy, videoFileId: file.id, actorId: serverActor.id }) @@ -219,25 +245,33 @@ export class VideosRedundancyScheduler extends AbstractScheduler { } private async createStreamingPlaylistRedundancy ( - redundancy: VideosRedundancy, + redundancy: VideosRedundancyStrategy, video: MVideoAccountLight, playlistArg: MStreamingPlaylist ) { + let strategy = 'manual' + let expiresOn: Date = null + + if (redundancy) { + strategy = redundancy.strategy + expiresOn = this.buildNewExpiration(redundancy.minLifetime) + } + const playlist = playlistArg as MStreamingPlaylistVideo playlist.Video = video const serverActor = await getServerActor() - logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, redundancy.strategy) + logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy) const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) await downloadPlaylistSegments(playlist.playlistUrl, destDirectory, VIDEO_IMPORT_TIMEOUT) const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ - expiresOn: this.buildNewExpiration(redundancy.minLifetime), + expiresOn, url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), - strategy: redundancy.strategy, + strategy, videoStreamingPlaylistId: playlist.id, actorId: serverActor.id }) @@ -261,7 +295,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { } private async purgeCacheIfNeeded (candidateToDuplicate: CandidateToDuplicate) { - while (this.isTooHeavy(candidateToDuplicate)) { + while (await this.isTooHeavy(candidateToDuplicate)) { const redundancy = candidateToDuplicate.redundancy const toDelete = await VideoRedundancyModel.loadOldestLocalExpired(redundancy.strategy, redundancy.minLifetime) if (!toDelete) return @@ -289,12 +323,15 @@ export class VideosRedundancyScheduler extends AbstractScheduler { return `${object.VideoStreamingPlaylist.playlistUrl}` } - private getTotalFileSizes (files: MVideoFile[], playlists: MStreamingPlaylist[]) { + private getTotalFileSizes (files: MVideoFile[], playlists: MStreamingPlaylistFiles[]) { const fileReducer = (previous: number, current: MVideoFile) => previous + current.size - const totalSize = files.reduce(fileReducer, 0) + let allFiles = files + for (const p of playlists) { + allFiles = allFiles.concat(p.VideoFiles) + } - return totalSize + (totalSize * playlists.length) + return allFiles.reduce(fileReducer, 0) } private async loadAndRefreshVideo (videoUrl: string) {