2021-08-17 08:26:20 +02:00
|
|
|
import { remove } from 'fs-extra'
|
|
|
|
import { extname, join } from 'path'
|
|
|
|
import { extractVideo } from '@server/helpers/video'
|
|
|
|
import { CONFIG } from '@server/initializers/config'
|
2021-11-18 14:35:08 +01:00
|
|
|
import {
|
|
|
|
MStreamingPlaylistVideo,
|
|
|
|
MVideo,
|
|
|
|
MVideoFile,
|
|
|
|
MVideoFileStreamingPlaylistVideo,
|
|
|
|
MVideoFileVideo,
|
|
|
|
MVideoUUID
|
|
|
|
} from '@server/types/models'
|
2021-12-29 14:44:58 +01:00
|
|
|
import { buildUUID } from '@shared/extra-utils'
|
2021-08-17 08:26:20 +02:00
|
|
|
import { VideoStorage } from '@shared/models'
|
|
|
|
import { makeHLSFileAvailable, makeWebTorrentFileAvailable } from './object-storage'
|
|
|
|
import { getHLSDirectory, getHLSRedundancyDirectory, getHlsResolutionPlaylistFilename } from './paths'
|
|
|
|
|
|
|
|
type MakeAvailableCB <T> = (path: string) => Promise<T> | T
|
|
|
|
|
|
|
|
class VideoPathManager {
|
|
|
|
|
|
|
|
private static instance: VideoPathManager
|
|
|
|
|
|
|
|
private constructor () {}
|
|
|
|
|
|
|
|
getFSHLSOutputPath (video: MVideoUUID, filename?: string) {
|
|
|
|
const base = getHLSDirectory(video)
|
|
|
|
if (!filename) return base
|
|
|
|
|
|
|
|
return join(base, filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
getFSRedundancyVideoFilePath (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) {
|
|
|
|
if (videoFile.isHLS()) {
|
|
|
|
const video = extractVideo(videoOrPlaylist)
|
|
|
|
|
|
|
|
return join(getHLSRedundancyDirectory(video), videoFile.filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
return join(CONFIG.STORAGE.REDUNDANCY_DIR, videoFile.filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
getFSVideoFileOutputPath (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) {
|
|
|
|
if (videoFile.isHLS()) {
|
|
|
|
const video = extractVideo(videoOrPlaylist)
|
|
|
|
|
|
|
|
return join(getHLSDirectory(video), videoFile.filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
return join(CONFIG.STORAGE.VIDEOS_DIR, videoFile.filename)
|
|
|
|
}
|
|
|
|
|
2021-11-18 14:35:08 +01:00
|
|
|
async makeAvailableVideoFile <T> (videoFile: MVideoFileVideo | MVideoFileStreamingPlaylistVideo, cb: MakeAvailableCB<T>) {
|
2021-08-17 08:26:20 +02:00
|
|
|
if (videoFile.storage === VideoStorage.FILE_SYSTEM) {
|
|
|
|
return this.makeAvailableFactory(
|
2021-11-18 14:35:08 +01:00
|
|
|
() => this.getFSVideoFileOutputPath(videoFile.getVideoOrStreamingPlaylist(), videoFile),
|
2021-08-17 08:26:20 +02:00
|
|
|
false,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const destination = this.buildTMPDestination(videoFile.filename)
|
|
|
|
|
|
|
|
if (videoFile.isHLS()) {
|
2021-11-18 14:35:08 +01:00
|
|
|
const playlist = (videoFile as MVideoFileStreamingPlaylistVideo).VideoStreamingPlaylist
|
2021-08-17 08:26:20 +02:00
|
|
|
|
|
|
|
return this.makeAvailableFactory(
|
2021-11-18 14:35:08 +01:00
|
|
|
() => makeHLSFileAvailable(playlist, videoFile.filename, destination),
|
2021-08-17 08:26:20 +02:00
|
|
|
true,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.makeAvailableFactory(
|
|
|
|
() => makeWebTorrentFileAvailable(videoFile.filename, destination),
|
|
|
|
true,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-18 14:35:08 +01:00
|
|
|
async makeAvailableResolutionPlaylistFile <T> (videoFile: MVideoFileStreamingPlaylistVideo, cb: MakeAvailableCB<T>) {
|
2021-08-17 08:26:20 +02:00
|
|
|
const filename = getHlsResolutionPlaylistFilename(videoFile.filename)
|
|
|
|
|
|
|
|
if (videoFile.storage === VideoStorage.FILE_SYSTEM) {
|
|
|
|
return this.makeAvailableFactory(
|
2021-11-18 14:35:08 +01:00
|
|
|
() => join(getHLSDirectory(videoFile.getVideo()), filename),
|
2021-08-17 08:26:20 +02:00
|
|
|
false,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-18 14:35:08 +01:00
|
|
|
const playlist = videoFile.VideoStreamingPlaylist
|
2021-08-17 08:26:20 +02:00
|
|
|
return this.makeAvailableFactory(
|
2021-11-18 14:35:08 +01:00
|
|
|
() => makeHLSFileAvailable(playlist, filename, this.buildTMPDestination(filename)),
|
2021-08-17 08:26:20 +02:00
|
|
|
true,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
async makeAvailablePlaylistFile <T> (playlist: MStreamingPlaylistVideo, filename: string, cb: MakeAvailableCB<T>) {
|
|
|
|
if (playlist.storage === VideoStorage.FILE_SYSTEM) {
|
|
|
|
return this.makeAvailableFactory(
|
|
|
|
() => join(getHLSDirectory(playlist.Video), filename),
|
|
|
|
false,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.makeAvailableFactory(
|
2021-11-18 14:35:08 +01:00
|
|
|
() => makeHLSFileAvailable(playlist, filename, this.buildTMPDestination(filename)),
|
2021-08-17 08:26:20 +02:00
|
|
|
true,
|
|
|
|
cb
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
private async makeAvailableFactory <T> (method: () => Promise<string> | string, clean: boolean, cb: MakeAvailableCB<T>) {
|
|
|
|
let result: T
|
|
|
|
|
|
|
|
const destination = await method()
|
|
|
|
|
|
|
|
try {
|
|
|
|
result = await cb(destination)
|
|
|
|
} catch (err) {
|
|
|
|
if (destination && clean) await remove(destination)
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clean) await remove(destination)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
private buildTMPDestination (filename: string) {
|
|
|
|
return join(CONFIG.STORAGE.TMP_DIR, buildUUID() + extname(filename))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static get Instance () {
|
|
|
|
return this.instance || (this.instance = new this())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
export {
|
|
|
|
VideoPathManager
|
|
|
|
}
|