]>
Commit | Line | Data |
---|---|---|
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 | import { VideoPathManager } from './video-path-manager' | |
12 | ||
13 | async function buildNewFile (options: { | |
14 | path: string | |
15 | mode: 'web-video' | 'hls' | |
16 | }) { | |
17 | const { path, mode } = options | |
18 | ||
19 | const probe = await ffprobePromise(path) | |
20 | const size = await getFileSize(path) | |
21 | ||
22 | const videoFile = new VideoFileModel({ | |
23 | extname: getLowercaseExtension(path), | |
24 | size, | |
25 | metadata: await buildFileMetadata(path, probe) | |
26 | }) | |
27 | ||
28 | if (await isAudioFile(path, probe)) { | |
29 | videoFile.resolution = VideoResolution.H_NOVIDEO | |
30 | } else { | |
31 | videoFile.fps = await getVideoStreamFPS(path, probe) | |
32 | videoFile.resolution = (await getVideoStreamDimensionsInfo(path, probe)).resolution | |
33 | } | |
34 | ||
35 | videoFile.filename = mode === 'web-video' | |
36 | ? generateWebTorrentVideoFilename(videoFile.resolution, videoFile.extname) | |
37 | : generateHLSVideoFilename(videoFile.resolution) | |
38 | ||
39 | return videoFile | |
40 | } | |
41 | ||
42 | // --------------------------------------------------------------------------- | |
43 | ||
44 | async function removeHLSPlaylist (video: MVideoWithAllFiles) { | |
45 | const hls = video.getHLSPlaylist() | |
46 | if (!hls) return | |
47 | ||
48 | const videoFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid) | |
49 | ||
50 | try { | |
51 | await video.removeStreamingPlaylistFiles(hls) | |
52 | await hls.destroy() | |
53 | ||
54 | video.VideoStreamingPlaylists = video.VideoStreamingPlaylists.filter(p => p.id !== hls.id) | |
55 | } finally { | |
56 | videoFileMutexReleaser() | |
57 | } | |
58 | } | |
59 | ||
60 | async function removeHLSFile (video: MVideoWithAllFiles, fileToDeleteId: number) { | |
61 | logger.info('Deleting HLS file %d of %s.', fileToDeleteId, video.url, lTags(video.uuid)) | |
62 | ||
63 | const hls = video.getHLSPlaylist() | |
64 | const files = hls.VideoFiles | |
65 | ||
66 | if (files.length === 1) { | |
67 | await removeHLSPlaylist(video) | |
68 | return undefined | |
69 | } | |
70 | ||
71 | const videoFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid) | |
72 | ||
73 | try { | |
74 | const toDelete = files.find(f => f.id === fileToDeleteId) | |
75 | await video.removeStreamingPlaylistVideoFile(video.getHLSPlaylist(), toDelete) | |
76 | await toDelete.destroy() | |
77 | ||
78 | hls.VideoFiles = hls.VideoFiles.filter(f => f.id !== toDelete.id) | |
79 | } finally { | |
80 | videoFileMutexReleaser() | |
81 | } | |
82 | ||
83 | return hls | |
84 | } | |
85 | ||
86 | // --------------------------------------------------------------------------- | |
87 | ||
88 | async function removeAllWebTorrentFiles (video: MVideoWithAllFiles) { | |
89 | const videoFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid) | |
90 | ||
91 | try { | |
92 | for (const file of video.VideoFiles) { | |
93 | await video.removeWebTorrentFile(file) | |
94 | await file.destroy() | |
95 | } | |
96 | ||
97 | video.VideoFiles = [] | |
98 | } finally { | |
99 | videoFileMutexReleaser() | |
100 | } | |
101 | ||
102 | return video | |
103 | } | |
104 | ||
105 | async function removeWebTorrentFile (video: MVideoWithAllFiles, fileToDeleteId: number) { | |
106 | const files = video.VideoFiles | |
107 | ||
108 | if (files.length === 1) { | |
109 | return removeAllWebTorrentFiles(video) | |
110 | } | |
111 | ||
112 | const videoFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid) | |
113 | try { | |
114 | const toDelete = files.find(f => f.id === fileToDeleteId) | |
115 | await video.removeWebTorrentFile(toDelete) | |
116 | await toDelete.destroy() | |
117 | ||
118 | video.VideoFiles = files.filter(f => f.id !== toDelete.id) | |
119 | } finally { | |
120 | videoFileMutexReleaser() | |
121 | } | |
122 | ||
123 | return video | |
124 | } | |
125 | ||
126 | // --------------------------------------------------------------------------- | |
127 | ||
128 | async function buildFileMetadata (path: string, existingProbe?: FfprobeData) { | |
129 | const metadata = existingProbe || await ffprobePromise(path) | |
130 | ||
131 | return new VideoFileMetadata(metadata) | |
132 | } | |
133 | ||
134 | // --------------------------------------------------------------------------- | |
135 | ||
136 | export { | |
137 | buildNewFile, | |
138 | ||
139 | removeHLSPlaylist, | |
140 | removeHLSFile, | |
141 | removeAllWebTorrentFiles, | |
142 | removeWebTorrentFile, | |
143 | ||
144 | buildFileMetadata | |
145 | } |