From f162d32da098aa55f6de2367142faa166edb7c08 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jun 2023 15:59:51 +0200 Subject: Support lazy download thumbnails --- .../abstract-video-static-file-cache.ts | 30 ------ .../lib/files-cache/avatar-permanent-file-cache.ts | 27 +++++ server/lib/files-cache/index.ts | 9 +- .../shared/abstract-permanent-file-cache.ts | 119 +++++++++++++++++++++ .../shared/abstract-simple-file-cache.ts | 30 ++++++ server/lib/files-cache/shared/index.ts | 2 + .../video-captions-simple-file-cache.ts | 61 +++++++++++ .../video-previews-simple-file-cache.ts | 58 ++++++++++ .../video-storyboards-simple-file-cache.ts | 53 +++++++++ .../video-torrents-simple-file-cache.ts | 70 ++++++++++++ server/lib/files-cache/videos-caption-cache.ts | 59 ---------- server/lib/files-cache/videos-preview-cache.ts | 58 ---------- server/lib/files-cache/videos-storyboard-cache.ts | 53 --------- server/lib/files-cache/videos-torrent-cache.ts | 70 ------------ 14 files changed, 425 insertions(+), 274 deletions(-) delete mode 100644 server/lib/files-cache/abstract-video-static-file-cache.ts create mode 100644 server/lib/files-cache/avatar-permanent-file-cache.ts create mode 100644 server/lib/files-cache/shared/abstract-permanent-file-cache.ts create mode 100644 server/lib/files-cache/shared/abstract-simple-file-cache.ts create mode 100644 server/lib/files-cache/shared/index.ts create mode 100644 server/lib/files-cache/video-captions-simple-file-cache.ts create mode 100644 server/lib/files-cache/video-previews-simple-file-cache.ts create mode 100644 server/lib/files-cache/video-storyboards-simple-file-cache.ts create mode 100644 server/lib/files-cache/video-torrents-simple-file-cache.ts delete mode 100644 server/lib/files-cache/videos-caption-cache.ts delete mode 100644 server/lib/files-cache/videos-preview-cache.ts delete mode 100644 server/lib/files-cache/videos-storyboard-cache.ts delete mode 100644 server/lib/files-cache/videos-torrent-cache.ts (limited to 'server/lib/files-cache') diff --git a/server/lib/files-cache/abstract-video-static-file-cache.ts b/server/lib/files-cache/abstract-video-static-file-cache.ts deleted file mode 100644 index a7ac88525..000000000 --- a/server/lib/files-cache/abstract-video-static-file-cache.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { remove } from 'fs-extra' -import { logger } from '../../helpers/logger' -import memoizee from 'memoizee' - -type GetFilePathResult = { isOwned: boolean, path: string, downloadName?: string } | undefined - -export abstract class AbstractVideoStaticFileCache { - - getFilePath: (params: T) => Promise - - abstract getFilePathImpl (params: T): Promise - - // Load and save the remote file, then return the local path from filesystem - protected abstract loadRemoteFile (key: string): Promise - - init (max: number, maxAge: number) { - this.getFilePath = memoizee(this.getFilePathImpl, { - maxAge, - max, - promise: true, - dispose: (result?: GetFilePathResult) => { - if (result && result.isOwned !== true) { - remove(result.path) - .then(() => logger.debug('%s removed from %s', result.path, this.constructor.name)) - .catch(err => logger.error('Cannot remove %s from cache %s.', result.path, this.constructor.name, { err })) - } - } - }) - } -} diff --git a/server/lib/files-cache/avatar-permanent-file-cache.ts b/server/lib/files-cache/avatar-permanent-file-cache.ts new file mode 100644 index 000000000..89228c5a5 --- /dev/null +++ b/server/lib/files-cache/avatar-permanent-file-cache.ts @@ -0,0 +1,27 @@ +import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants' +import { ActorImageModel } from '@server/models/actor/actor-image' +import { MActorImage } from '@server/types/models' +import { AbstractPermanentFileCache } from './shared' +import { CONFIG } from '@server/initializers/config' + +export class AvatarPermanentFileCache extends AbstractPermanentFileCache { + + constructor () { + super(CONFIG.STORAGE.ACTOR_IMAGES) + } + + protected loadModel (filename: string) { + return ActorImageModel.loadByName(filename) + } + + protected getImageSize (image: MActorImage): { width: number, height: number } { + if (image.width && image.height) { + return { + height: image.height, + width: image.width + } + } + + return ACTOR_IMAGES_SIZE[image.type][0] + } +} diff --git a/server/lib/files-cache/index.ts b/server/lib/files-cache/index.ts index 59cec7215..cc11d5385 100644 --- a/server/lib/files-cache/index.ts +++ b/server/lib/files-cache/index.ts @@ -1,4 +1,5 @@ -export * from './videos-caption-cache' -export * from './videos-preview-cache' -export * from './videos-storyboard-cache' -export * from './videos-torrent-cache' +export * from './avatar-permanent-file-cache' +export * from './video-captions-simple-file-cache' +export * from './video-previews-simple-file-cache' +export * from './video-storyboards-simple-file-cache' +export * from './video-torrents-simple-file-cache' diff --git a/server/lib/files-cache/shared/abstract-permanent-file-cache.ts b/server/lib/files-cache/shared/abstract-permanent-file-cache.ts new file mode 100644 index 000000000..22596c3eb --- /dev/null +++ b/server/lib/files-cache/shared/abstract-permanent-file-cache.ts @@ -0,0 +1,119 @@ +import express from 'express' +import { LRUCache } from 'lru-cache' +import { logger } from '@server/helpers/logger' +import { LRU_CACHE, STATIC_MAX_AGE } from '@server/initializers/constants' +import { downloadImageFromWorker } from '@server/lib/worker/parent-process' +import { HttpStatusCode } from '@shared/models' +import { Model } from 'sequelize' + +type ImageModel = { + fileUrl: string + filename: string + onDisk: boolean + + isOwned (): boolean + getPath (): string + + save (): Promise +} + +export abstract class AbstractPermanentFileCache { + // Unsafe because it can return paths that do not exist anymore + private readonly filenameToPathUnsafeCache = new LRUCache({ + max: LRU_CACHE.FILENAME_TO_PATH_PERMANENT_FILE_CACHE.MAX_SIZE + }) + + protected abstract getImageSize (image: M): { width: number, height: number } + protected abstract loadModel (filename: string): Promise + + constructor (private readonly directory: string) { + + } + + async lazyServe (options: { + filename: string + res: express.Response + next: express.NextFunction + }) { + const { filename, res, next } = options + + if (this.filenameToPathUnsafeCache.has(filename)) { + return res.sendFile(this.filenameToPathUnsafeCache.get(filename), { maxAge: STATIC_MAX_AGE.SERVER }) + } + + const image = await this.loadModel(filename) + if (!image) return res.status(HttpStatusCode.NOT_FOUND_404).end() + + if (image.onDisk === false) { + if (!image.fileUrl) return res.status(HttpStatusCode.NOT_FOUND_404).end() + + try { + await this.downloadRemoteFile(image) + } catch (err) { + logger.warn('Cannot process remote image %s.', image.fileUrl, { err }) + + return res.status(HttpStatusCode.NOT_FOUND_404).end() + } + } + + const path = image.getPath() + this.filenameToPathUnsafeCache.set(filename, path) + + return res.sendFile(path, { maxAge: STATIC_MAX_AGE.LAZY_SERVER }, (err: any) => { + if (!err) return + + this.onServeError({ err, image, next, filename }) + }) + } + + private async downloadRemoteFile (image: M) { + logger.info('Download remote image %s lazily.', image.fileUrl) + + await this.downloadImage({ + filename: image.filename, + fileUrl: image.fileUrl, + size: this.getImageSize(image) + }) + + image.onDisk = true + image.save() + .catch(err => logger.error('Cannot save new image disk state.', { err })) + } + + private onServeError (options: { + err: any + image: M + filename: string + next: express.NextFunction + }) { + const { err, image, filename, next } = options + + // It seems this actor image is not on the disk anymore + if (err.status === HttpStatusCode.NOT_FOUND_404 && !image.isOwned()) { + logger.error('Cannot lazy serve image %s.', filename, { err }) + + this.filenameToPathUnsafeCache.delete(filename) + + image.onDisk = false + image.save() + .catch(err => logger.error('Cannot save new image disk state.', { err })) + } + + return next(err) + } + + private downloadImage (options: { + fileUrl: string + filename: string + size: { width: number, height: number } + }) { + const downloaderOptions = { + url: options.fileUrl, + destDir: this.directory, + destName: options.filename, + size: options.size + } + + return downloadImageFromWorker(downloaderOptions) + } +} diff --git a/server/lib/files-cache/shared/abstract-simple-file-cache.ts b/server/lib/files-cache/shared/abstract-simple-file-cache.ts new file mode 100644 index 000000000..6fab322cd --- /dev/null +++ b/server/lib/files-cache/shared/abstract-simple-file-cache.ts @@ -0,0 +1,30 @@ +import { remove } from 'fs-extra' +import { logger } from '../../../helpers/logger' +import memoizee from 'memoizee' + +type GetFilePathResult = { isOwned: boolean, path: string, downloadName?: string } | undefined + +export abstract class AbstractSimpleFileCache { + + getFilePath: (params: T) => Promise + + abstract getFilePathImpl (params: T): Promise + + // Load and save the remote file, then return the local path from filesystem + protected abstract loadRemoteFile (key: string): Promise + + init (max: number, maxAge: number) { + this.getFilePath = memoizee(this.getFilePathImpl, { + maxAge, + max, + promise: true, + dispose: (result?: GetFilePathResult) => { + if (result && result.isOwned !== true) { + remove(result.path) + .then(() => logger.debug('%s removed from %s', result.path, this.constructor.name)) + .catch(err => logger.error('Cannot remove %s from cache %s.', result.path, this.constructor.name, { err })) + } + } + }) + } +} diff --git a/server/lib/files-cache/shared/index.ts b/server/lib/files-cache/shared/index.ts new file mode 100644 index 000000000..61c4aacc7 --- /dev/null +++ b/server/lib/files-cache/shared/index.ts @@ -0,0 +1,2 @@ +export * from './abstract-permanent-file-cache' +export * from './abstract-simple-file-cache' diff --git a/server/lib/files-cache/video-captions-simple-file-cache.ts b/server/lib/files-cache/video-captions-simple-file-cache.ts new file mode 100644 index 000000000..cbeeff732 --- /dev/null +++ b/server/lib/files-cache/video-captions-simple-file-cache.ts @@ -0,0 +1,61 @@ +import { join } from 'path' +import { logger } from '@server/helpers/logger' +import { doRequestAndSaveToFile } from '@server/helpers/requests' +import { CONFIG } from '../../initializers/config' +import { FILES_CACHE } from '../../initializers/constants' +import { VideoModel } from '../../models/video/video' +import { VideoCaptionModel } from '../../models/video/video-caption' +import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache' + +class VideoCaptionsSimpleFileCache extends AbstractSimpleFileCache { + + private static instance: VideoCaptionsSimpleFileCache + + private constructor () { + super() + } + + static get Instance () { + return this.instance || (this.instance = new this()) + } + + async getFilePathImpl (filename: string) { + const videoCaption = await VideoCaptionModel.loadWithVideoByFilename(filename) + if (!videoCaption) return undefined + + if (videoCaption.isOwned()) { + return { isOwned: true, path: join(CONFIG.STORAGE.CAPTIONS_DIR, videoCaption.filename) } + } + + return this.loadRemoteFile(filename) + } + + // Key is the caption filename + protected async loadRemoteFile (key: string) { + const videoCaption = await VideoCaptionModel.loadWithVideoByFilename(key) + if (!videoCaption) return undefined + + if (videoCaption.isOwned()) throw new Error('Cannot load remote caption of owned video.') + + // Used to fetch the path + const video = await VideoModel.loadFull(videoCaption.videoId) + if (!video) return undefined + + const remoteUrl = videoCaption.getFileUrl(video) + const destPath = join(FILES_CACHE.VIDEO_CAPTIONS.DIRECTORY, videoCaption.filename) + + try { + await doRequestAndSaveToFile(remoteUrl, destPath) + + return { isOwned: false, path: destPath } + } catch (err) { + logger.info('Cannot fetch remote caption file %s.', remoteUrl, { err }) + + return undefined + } + } +} + +export { + VideoCaptionsSimpleFileCache +} diff --git a/server/lib/files-cache/video-previews-simple-file-cache.ts b/server/lib/files-cache/video-previews-simple-file-cache.ts new file mode 100644 index 000000000..a05e80e16 --- /dev/null +++ b/server/lib/files-cache/video-previews-simple-file-cache.ts @@ -0,0 +1,58 @@ +import { join } from 'path' +import { FILES_CACHE } from '../../initializers/constants' +import { VideoModel } from '../../models/video/video' +import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache' +import { doRequestAndSaveToFile } from '@server/helpers/requests' +import { ThumbnailModel } from '@server/models/video/thumbnail' +import { ThumbnailType } from '@shared/models' +import { logger } from '@server/helpers/logger' + +class VideoPreviewsSimpleFileCache extends AbstractSimpleFileCache { + + private static instance: VideoPreviewsSimpleFileCache + + private constructor () { + super() + } + + static get Instance () { + return this.instance || (this.instance = new this()) + } + + async getFilePathImpl (filename: string) { + const thumbnail = await ThumbnailModel.loadWithVideoByFilename(filename, ThumbnailType.PREVIEW) + if (!thumbnail) return undefined + + if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() } + + return this.loadRemoteFile(thumbnail.Video.uuid) + } + + // Key is the video UUID + protected async loadRemoteFile (key: string) { + const video = await VideoModel.loadFull(key) + if (!video) return undefined + + if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.') + + const preview = video.getPreview() + const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, preview.filename) + const remoteUrl = preview.getOriginFileUrl(video) + + try { + await doRequestAndSaveToFile(remoteUrl, destPath) + + logger.debug('Fetched remote preview %s to %s.', remoteUrl, destPath) + + return { isOwned: false, path: destPath } + } catch (err) { + logger.info('Cannot fetch remote preview file %s.', remoteUrl, { err }) + + return undefined + } + } +} + +export { + VideoPreviewsSimpleFileCache +} diff --git a/server/lib/files-cache/video-storyboards-simple-file-cache.ts b/server/lib/files-cache/video-storyboards-simple-file-cache.ts new file mode 100644 index 000000000..4cd96e70c --- /dev/null +++ b/server/lib/files-cache/video-storyboards-simple-file-cache.ts @@ -0,0 +1,53 @@ +import { join } from 'path' +import { logger } from '@server/helpers/logger' +import { doRequestAndSaveToFile } from '@server/helpers/requests' +import { StoryboardModel } from '@server/models/video/storyboard' +import { FILES_CACHE } from '../../initializers/constants' +import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache' + +class VideoStoryboardsSimpleFileCache extends AbstractSimpleFileCache { + + private static instance: VideoStoryboardsSimpleFileCache + + private constructor () { + super() + } + + static get Instance () { + return this.instance || (this.instance = new this()) + } + + async getFilePathImpl (filename: string) { + const storyboard = await StoryboardModel.loadWithVideoByFilename(filename) + if (!storyboard) return undefined + + if (storyboard.Video.isOwned()) return { isOwned: true, path: storyboard.getPath() } + + return this.loadRemoteFile(storyboard.filename) + } + + // Key is the storyboard filename + protected async loadRemoteFile (key: string) { + const storyboard = await StoryboardModel.loadWithVideoByFilename(key) + if (!storyboard) return undefined + + const destPath = join(FILES_CACHE.STORYBOARDS.DIRECTORY, storyboard.filename) + const remoteUrl = storyboard.getOriginFileUrl(storyboard.Video) + + try { + await doRequestAndSaveToFile(remoteUrl, destPath) + + logger.debug('Fetched remote storyboard %s to %s.', remoteUrl, destPath) + + return { isOwned: false, path: destPath } + } catch (err) { + logger.info('Cannot fetch remote storyboard file %s.', remoteUrl, { err }) + + return undefined + } + } +} + +export { + VideoStoryboardsSimpleFileCache +} diff --git a/server/lib/files-cache/video-torrents-simple-file-cache.ts b/server/lib/files-cache/video-torrents-simple-file-cache.ts new file mode 100644 index 000000000..8bcd0b9bf --- /dev/null +++ b/server/lib/files-cache/video-torrents-simple-file-cache.ts @@ -0,0 +1,70 @@ +import { join } from 'path' +import { logger } from '@server/helpers/logger' +import { doRequestAndSaveToFile } from '@server/helpers/requests' +import { VideoFileModel } from '@server/models/video/video-file' +import { MVideo, MVideoFile } from '@server/types/models' +import { CONFIG } from '../../initializers/config' +import { FILES_CACHE } from '../../initializers/constants' +import { VideoModel } from '../../models/video/video' +import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache' + +class VideoTorrentsSimpleFileCache extends AbstractSimpleFileCache { + + private static instance: VideoTorrentsSimpleFileCache + + private constructor () { + super() + } + + static get Instance () { + return this.instance || (this.instance = new this()) + } + + async getFilePathImpl (filename: string) { + const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(filename) + if (!file) return undefined + + if (file.getVideo().isOwned()) { + const downloadName = this.buildDownloadName(file.getVideo(), file) + + return { isOwned: true, path: join(CONFIG.STORAGE.TORRENTS_DIR, file.torrentFilename), downloadName } + } + + return this.loadRemoteFile(filename) + } + + // Key is the torrent filename + protected async loadRemoteFile (key: string) { + const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(key) + if (!file) return undefined + + if (file.getVideo().isOwned()) throw new Error('Cannot load remote file of owned video.') + + // Used to fetch the path + const video = await VideoModel.loadFull(file.getVideo().id) + if (!video) return undefined + + const remoteUrl = file.getRemoteTorrentUrl(video) + const destPath = join(FILES_CACHE.TORRENTS.DIRECTORY, file.torrentFilename) + + try { + await doRequestAndSaveToFile(remoteUrl, destPath) + + const downloadName = this.buildDownloadName(video, file) + + return { isOwned: false, path: destPath, downloadName } + } catch (err) { + logger.info('Cannot fetch remote torrent file %s.', remoteUrl, { err }) + + return undefined + } + } + + private buildDownloadName (video: MVideo, file: MVideoFile) { + return `${video.name}-${file.resolution}p.torrent` + } +} + +export { + VideoTorrentsSimpleFileCache +} diff --git a/server/lib/files-cache/videos-caption-cache.ts b/server/lib/files-cache/videos-caption-cache.ts deleted file mode 100644 index d21acf4ef..000000000 --- a/server/lib/files-cache/videos-caption-cache.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { join } from 'path' -import { logger } from '@server/helpers/logger' -import { doRequestAndSaveToFile } from '@server/helpers/requests' -import { CONFIG } from '../../initializers/config' -import { FILES_CACHE } from '../../initializers/constants' -import { VideoModel } from '../../models/video/video' -import { VideoCaptionModel } from '../../models/video/video-caption' -import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' - -class VideosCaptionCache extends AbstractVideoStaticFileCache { - - private static instance: VideosCaptionCache - - private constructor () { - super() - } - - static get Instance () { - return this.instance || (this.instance = new this()) - } - - async getFilePathImpl (filename: string) { - const videoCaption = await VideoCaptionModel.loadWithVideoByFilename(filename) - if (!videoCaption) return undefined - - if (videoCaption.isOwned()) return { isOwned: true, path: join(CONFIG.STORAGE.CAPTIONS_DIR, videoCaption.filename) } - - return this.loadRemoteFile(filename) - } - - // Key is the caption filename - protected async loadRemoteFile (key: string) { - const videoCaption = await VideoCaptionModel.loadWithVideoByFilename(key) - if (!videoCaption) return undefined - - if (videoCaption.isOwned()) throw new Error('Cannot load remote caption of owned video.') - - // Used to fetch the path - const video = await VideoModel.loadFull(videoCaption.videoId) - if (!video) return undefined - - const remoteUrl = videoCaption.getFileUrl(video) - const destPath = join(FILES_CACHE.VIDEO_CAPTIONS.DIRECTORY, videoCaption.filename) - - try { - await doRequestAndSaveToFile(remoteUrl, destPath) - - return { isOwned: false, path: destPath } - } catch (err) { - logger.info('Cannot fetch remote caption file %s.', remoteUrl, { err }) - - return undefined - } - } -} - -export { - VideosCaptionCache -} diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts deleted file mode 100644 index d19c3f4f4..000000000 --- a/server/lib/files-cache/videos-preview-cache.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { join } from 'path' -import { FILES_CACHE } from '../../initializers/constants' -import { VideoModel } from '../../models/video/video' -import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' -import { doRequestAndSaveToFile } from '@server/helpers/requests' -import { ThumbnailModel } from '@server/models/video/thumbnail' -import { ThumbnailType } from '@shared/models' -import { logger } from '@server/helpers/logger' - -class VideosPreviewCache extends AbstractVideoStaticFileCache { - - private static instance: VideosPreviewCache - - private constructor () { - super() - } - - static get Instance () { - return this.instance || (this.instance = new this()) - } - - async getFilePathImpl (filename: string) { - const thumbnail = await ThumbnailModel.loadWithVideoByFilename(filename, ThumbnailType.PREVIEW) - if (!thumbnail) return undefined - - if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() } - - return this.loadRemoteFile(thumbnail.Video.uuid) - } - - // Key is the video UUID - protected async loadRemoteFile (key: string) { - const video = await VideoModel.loadFull(key) - if (!video) return undefined - - if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.') - - const preview = video.getPreview() - const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, preview.filename) - const remoteUrl = preview.getOriginFileUrl(video) - - try { - await doRequestAndSaveToFile(remoteUrl, destPath) - - logger.debug('Fetched remote preview %s to %s.', remoteUrl, destPath) - - return { isOwned: false, path: destPath } - } catch (err) { - logger.info('Cannot fetch remote preview file %s.', remoteUrl, { err }) - - return undefined - } - } -} - -export { - VideosPreviewCache -} diff --git a/server/lib/files-cache/videos-storyboard-cache.ts b/server/lib/files-cache/videos-storyboard-cache.ts deleted file mode 100644 index b0a55104f..000000000 --- a/server/lib/files-cache/videos-storyboard-cache.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { join } from 'path' -import { logger } from '@server/helpers/logger' -import { doRequestAndSaveToFile } from '@server/helpers/requests' -import { StoryboardModel } from '@server/models/video/storyboard' -import { FILES_CACHE } from '../../initializers/constants' -import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' - -class VideosStoryboardCache extends AbstractVideoStaticFileCache { - - private static instance: VideosStoryboardCache - - private constructor () { - super() - } - - static get Instance () { - return this.instance || (this.instance = new this()) - } - - async getFilePathImpl (filename: string) { - const storyboard = await StoryboardModel.loadWithVideoByFilename(filename) - if (!storyboard) return undefined - - if (storyboard.Video.isOwned()) return { isOwned: true, path: storyboard.getPath() } - - return this.loadRemoteFile(storyboard.filename) - } - - // Key is the storyboard filename - protected async loadRemoteFile (key: string) { - const storyboard = await StoryboardModel.loadWithVideoByFilename(key) - if (!storyboard) return undefined - - const destPath = join(FILES_CACHE.STORYBOARDS.DIRECTORY, storyboard.filename) - const remoteUrl = storyboard.getOriginFileUrl(storyboard.Video) - - try { - await doRequestAndSaveToFile(remoteUrl, destPath) - - logger.debug('Fetched remote storyboard %s to %s.', remoteUrl, destPath) - - return { isOwned: false, path: destPath } - } catch (err) { - logger.info('Cannot fetch remote storyboard file %s.', remoteUrl, { err }) - - return undefined - } - } -} - -export { - VideosStoryboardCache -} diff --git a/server/lib/files-cache/videos-torrent-cache.ts b/server/lib/files-cache/videos-torrent-cache.ts deleted file mode 100644 index a6bf98dd4..000000000 --- a/server/lib/files-cache/videos-torrent-cache.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { join } from 'path' -import { logger } from '@server/helpers/logger' -import { doRequestAndSaveToFile } from '@server/helpers/requests' -import { VideoFileModel } from '@server/models/video/video-file' -import { MVideo, MVideoFile } from '@server/types/models' -import { CONFIG } from '../../initializers/config' -import { FILES_CACHE } from '../../initializers/constants' -import { VideoModel } from '../../models/video/video' -import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' - -class VideosTorrentCache extends AbstractVideoStaticFileCache { - - private static instance: VideosTorrentCache - - private constructor () { - super() - } - - static get Instance () { - return this.instance || (this.instance = new this()) - } - - async getFilePathImpl (filename: string) { - const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(filename) - if (!file) return undefined - - if (file.getVideo().isOwned()) { - const downloadName = this.buildDownloadName(file.getVideo(), file) - - return { isOwned: true, path: join(CONFIG.STORAGE.TORRENTS_DIR, file.torrentFilename), downloadName } - } - - return this.loadRemoteFile(filename) - } - - // Key is the torrent filename - protected async loadRemoteFile (key: string) { - const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(key) - if (!file) return undefined - - if (file.getVideo().isOwned()) throw new Error('Cannot load remote file of owned video.') - - // Used to fetch the path - const video = await VideoModel.loadFull(file.getVideo().id) - if (!video) return undefined - - const remoteUrl = file.getRemoteTorrentUrl(video) - const destPath = join(FILES_CACHE.TORRENTS.DIRECTORY, file.torrentFilename) - - try { - await doRequestAndSaveToFile(remoteUrl, destPath) - - const downloadName = this.buildDownloadName(video, file) - - return { isOwned: false, path: destPath, downloadName } - } catch (err) { - logger.info('Cannot fetch remote torrent file %s.', remoteUrl, { err }) - - return undefined - } - } - - private buildDownloadName (video: MVideo, file: MVideoFile) { - return `${video.name}-${file.resolution}p.torrent` - } -} - -export { - VideosTorrentCache -} -- cgit v1.2.3