]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/video-file.ts
Force live stream termination
[github/Chocobozzz/PeerTube.git] / server / lib / video-file.ts
1 import { FfprobeData } from 'fluent-ffmpeg'
2 import { logger } from '@server/helpers/logger'
3 import { VideoFileModel } from '@server/models/video/video-file'
4 import { MVideoWithAllFiles } from '@server/types/models'
5 import { getLowercaseExtension } from '@shared/core-utils'
6 import { getFileSize } from '@shared/extra-utils'
7 import { ffprobePromise, getVideoStreamDimensionsInfo, getVideoStreamFPS, isAudioFile } from '@shared/ffmpeg'
8 import { VideoFileMetadata, VideoResolution } from '@shared/models'
9 import { lTags } from './object-storage/shared'
10 import { generateHLSVideoFilename, generateWebTorrentVideoFilename } from './paths'
11
12 async function buildNewFile (options: {
13 path: string
14 mode: 'web-video' | 'hls'
15 }) {
16 const { path, mode } = options
17
18 const probe = await ffprobePromise(path)
19 const size = await getFileSize(path)
20
21 const videoFile = new VideoFileModel({
22 extname: getLowercaseExtension(path),
23 size,
24 metadata: await buildFileMetadata(path, probe)
25 })
26
27 if (await isAudioFile(path, probe)) {
28 videoFile.resolution = VideoResolution.H_NOVIDEO
29 } else {
30 videoFile.fps = await getVideoStreamFPS(path, probe)
31 videoFile.resolution = (await getVideoStreamDimensionsInfo(path, probe)).resolution
32 }
33
34 videoFile.filename = mode === 'web-video'
35 ? generateWebTorrentVideoFilename(videoFile.resolution, videoFile.extname)
36 : generateHLSVideoFilename(videoFile.resolution)
37
38 return videoFile
39 }
40
41 // ---------------------------------------------------------------------------
42
43 async function removeHLSPlaylist (video: MVideoWithAllFiles) {
44 const hls = video.getHLSPlaylist()
45 if (!hls) return
46
47 await video.removeStreamingPlaylistFiles(hls)
48 await hls.destroy()
49
50 video.VideoStreamingPlaylists = video.VideoStreamingPlaylists.filter(p => p.id !== hls.id)
51 }
52
53 async function removeHLSFile (video: MVideoWithAllFiles, fileToDeleteId: number) {
54 logger.info('Deleting HLS file %d of %s.', fileToDeleteId, video.url, lTags(video.uuid))
55
56 const hls = video.getHLSPlaylist()
57 const files = hls.VideoFiles
58
59 if (files.length === 1) {
60 await removeHLSPlaylist(video)
61 return undefined
62 }
63
64 const toDelete = files.find(f => f.id === fileToDeleteId)
65 await video.removeStreamingPlaylistVideoFile(video.getHLSPlaylist(), toDelete)
66 await toDelete.destroy()
67
68 hls.VideoFiles = hls.VideoFiles.filter(f => f.id !== toDelete.id)
69
70 return hls
71 }
72
73 // ---------------------------------------------------------------------------
74
75 async function removeAllWebTorrentFiles (video: MVideoWithAllFiles) {
76 for (const file of video.VideoFiles) {
77 await video.removeWebTorrentFile(file)
78 await file.destroy()
79 }
80
81 video.VideoFiles = []
82
83 return video
84 }
85
86 async function removeWebTorrentFile (video: MVideoWithAllFiles, fileToDeleteId: number) {
87 const files = video.VideoFiles
88
89 if (files.length === 1) {
90 return removeAllWebTorrentFiles(video)
91 }
92
93 const toDelete = files.find(f => f.id === fileToDeleteId)
94 await video.removeWebTorrentFile(toDelete)
95 await toDelete.destroy()
96
97 video.VideoFiles = files.filter(f => f.id !== toDelete.id)
98
99 return video
100 }
101
102 // ---------------------------------------------------------------------------
103
104 async function buildFileMetadata (path: string, existingProbe?: FfprobeData) {
105 const metadata = existingProbe || await ffprobePromise(path)
106
107 return new VideoFileMetadata(metadata)
108 }
109
110 // ---------------------------------------------------------------------------
111
112 export {
113 buildNewFile,
114
115 removeHLSPlaylist,
116 removeHLSFile,
117 removeAllWebTorrentFiles,
118 removeWebTorrentFile,
119
120 buildFileMetadata
121 }