]>
Commit | Line | Data |
---|---|---|
09209296 C |
1 | import { VideoModel } from '../models/video/video' |
2 | import { basename, dirname, join } from 'path' | |
3 | import { HLS_PLAYLIST_DIRECTORY, CONFIG } from '../initializers' | |
4 | import { outputJSON, pathExists, readdir, readFile, remove, writeFile, move } from 'fs-extra' | |
5 | import { getVideoFileSize } from '../helpers/ffmpeg-utils' | |
6 | import { sha256 } from '../helpers/core-utils' | |
7 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' | |
8 | import HLSDownloader from 'hlsdownloader' | |
9 | import { logger } from '../helpers/logger' | |
10 | import { parse } from 'url' | |
11 | ||
12 | async function updateMasterHLSPlaylist (video: VideoModel) { | |
13 | const directory = join(HLS_PLAYLIST_DIRECTORY, video.uuid) | |
14 | const masterPlaylists: string[] = [ '#EXTM3U', '#EXT-X-VERSION:3' ] | |
15 | const masterPlaylistPath = join(directory, VideoStreamingPlaylistModel.getMasterHlsPlaylistFilename()) | |
16 | ||
17 | for (const file of video.VideoFiles) { | |
18 | // If we did not generated a playlist for this resolution, skip | |
19 | const filePlaylistPath = join(directory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(file.resolution)) | |
20 | if (await pathExists(filePlaylistPath) === false) continue | |
21 | ||
22 | const videoFilePath = video.getVideoFilePath(file) | |
23 | ||
24 | const size = await getVideoFileSize(videoFilePath) | |
25 | ||
26 | const bandwidth = 'BANDWIDTH=' + video.getBandwidthBits(file) | |
27 | const resolution = `RESOLUTION=${size.width}x${size.height}` | |
28 | ||
29 | let line = `#EXT-X-STREAM-INF:${bandwidth},${resolution}` | |
30 | if (file.fps) line += ',FRAME-RATE=' + file.fps | |
31 | ||
32 | masterPlaylists.push(line) | |
33 | masterPlaylists.push(VideoStreamingPlaylistModel.getHlsPlaylistFilename(file.resolution)) | |
34 | } | |
35 | ||
36 | await writeFile(masterPlaylistPath, masterPlaylists.join('\n') + '\n') | |
37 | } | |
38 | ||
39 | async function updateSha256Segments (video: VideoModel) { | |
40 | const directory = join(HLS_PLAYLIST_DIRECTORY, video.uuid) | |
41 | const files = await readdir(directory) | |
42 | const json: { [filename: string]: string} = {} | |
43 | ||
44 | for (const file of files) { | |
45 | if (file.endsWith('.ts') === false) continue | |
46 | ||
47 | const buffer = await readFile(join(directory, file)) | |
48 | const filename = basename(file) | |
49 | ||
50 | json[filename] = sha256(buffer) | |
51 | } | |
52 | ||
53 | const outputPath = join(directory, VideoStreamingPlaylistModel.getHlsSha256SegmentsFilename()) | |
54 | await outputJSON(outputPath, json) | |
55 | } | |
56 | ||
57 | function downloadPlaylistSegments (playlistUrl: string, destinationDir: string, timeout: number) { | |
58 | let timer | |
59 | ||
60 | logger.info('Importing HLS playlist %s', playlistUrl) | |
61 | ||
62 | const params = { | |
63 | playlistURL: playlistUrl, | |
64 | destination: CONFIG.STORAGE.TMP_DIR | |
65 | } | |
66 | const downloader = new HLSDownloader(params) | |
67 | ||
68 | const hlsDestinationDir = join(CONFIG.STORAGE.TMP_DIR, dirname(parse(playlistUrl).pathname)) | |
69 | ||
70 | return new Promise<string>(async (res, rej) => { | |
71 | downloader.startDownload(err => { | |
72 | clearTimeout(timer) | |
73 | ||
74 | if (err) { | |
75 | deleteTmpDirectory(hlsDestinationDir) | |
76 | ||
77 | return rej(err) | |
78 | } | |
79 | ||
80 | move(hlsDestinationDir, destinationDir, { overwrite: true }) | |
81 | .then(() => res()) | |
82 | .catch(err => { | |
83 | deleteTmpDirectory(hlsDestinationDir) | |
84 | ||
85 | return rej(err) | |
86 | }) | |
87 | }) | |
88 | ||
89 | timer = setTimeout(() => { | |
90 | deleteTmpDirectory(hlsDestinationDir) | |
91 | ||
92 | return rej(new Error('HLS download timeout.')) | |
93 | }, timeout) | |
94 | ||
95 | function deleteTmpDirectory (directory: string) { | |
96 | remove(directory) | |
97 | .catch(err => logger.error('Cannot delete path on HLS download error.', { err })) | |
98 | } | |
99 | }) | |
100 | } | |
101 | ||
102 | // --------------------------------------------------------------------------- | |
103 | ||
104 | export { | |
105 | updateMasterHLSPlaylist, | |
106 | updateSha256Segments, | |
107 | downloadPlaylistSegments | |
108 | } | |
109 | ||
110 | // --------------------------------------------------------------------------- |