aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/download.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/download.ts')
-rw-r--r--server/controllers/download.ts213
1 files changed, 0 insertions, 213 deletions
diff --git a/server/controllers/download.ts b/server/controllers/download.ts
deleted file mode 100644
index 4b94e34bd..000000000
--- a/server/controllers/download.ts
+++ /dev/null
@@ -1,213 +0,0 @@
1import cors from 'cors'
2import express from 'express'
3import { logger } from '@server/helpers/logger'
4import { VideoTorrentsSimpleFileCache } from '@server/lib/files-cache'
5import { generateHLSFilePresignedUrl, generateWebVideoPresignedUrl } from '@server/lib/object-storage'
6import { Hooks } from '@server/lib/plugins/hooks'
7import { VideoPathManager } from '@server/lib/video-path-manager'
8import { MStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoFullLight } from '@server/types/models'
9import { forceNumber } from '@shared/core-utils'
10import { HttpStatusCode, VideoStorage, VideoStreamingPlaylistType } from '@shared/models'
11import { STATIC_DOWNLOAD_PATHS } from '../initializers/constants'
12import { asyncMiddleware, optionalAuthenticate, videosDownloadValidator } from '../middlewares'
13
14const downloadRouter = express.Router()
15
16downloadRouter.use(cors())
17
18downloadRouter.use(
19 STATIC_DOWNLOAD_PATHS.TORRENTS + ':filename',
20 asyncMiddleware(downloadTorrent)
21)
22
23downloadRouter.use(
24 STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension',
25 optionalAuthenticate,
26 asyncMiddleware(videosDownloadValidator),
27 asyncMiddleware(downloadVideoFile)
28)
29
30downloadRouter.use(
31 STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension',
32 optionalAuthenticate,
33 asyncMiddleware(videosDownloadValidator),
34 asyncMiddleware(downloadHLSVideoFile)
35)
36
37// ---------------------------------------------------------------------------
38
39export {
40 downloadRouter
41}
42
43// ---------------------------------------------------------------------------
44
45async function downloadTorrent (req: express.Request, res: express.Response) {
46 const result = await VideoTorrentsSimpleFileCache.Instance.getFilePath(req.params.filename)
47 if (!result) {
48 return res.fail({
49 status: HttpStatusCode.NOT_FOUND_404,
50 message: 'Torrent file not found'
51 })
52 }
53
54 const allowParameters = {
55 req,
56 res,
57 torrentPath: result.path,
58 downloadName: result.downloadName
59 }
60
61 const allowedResult = await Hooks.wrapFun(
62 isTorrentDownloadAllowed,
63 allowParameters,
64 'filter:api.download.torrent.allowed.result'
65 )
66
67 if (!checkAllowResult(res, allowParameters, allowedResult)) return
68
69 return res.download(result.path, result.downloadName)
70}
71
72async function downloadVideoFile (req: express.Request, res: express.Response) {
73 const video = res.locals.videoAll
74
75 const videoFile = getVideoFile(req, video.VideoFiles)
76 if (!videoFile) {
77 return res.fail({
78 status: HttpStatusCode.NOT_FOUND_404,
79 message: 'Video file not found'
80 })
81 }
82
83 const allowParameters = {
84 req,
85 res,
86 video,
87 videoFile
88 }
89
90 const allowedResult = await Hooks.wrapFun(
91 isVideoDownloadAllowed,
92 allowParameters,
93 'filter:api.download.video.allowed.result'
94 )
95
96 if (!checkAllowResult(res, allowParameters, allowedResult)) return
97
98 // Express uses basename on filename parameter
99 const videoName = video.name.replace(/[/\\]/g, '_')
100 const downloadFilename = `${videoName}-${videoFile.resolution}p${videoFile.extname}`
101
102 if (videoFile.storage === VideoStorage.OBJECT_STORAGE) {
103 return redirectToObjectStorage({ req, res, video, file: videoFile, downloadFilename })
104 }
105
106 await VideoPathManager.Instance.makeAvailableVideoFile(videoFile.withVideoOrPlaylist(video), path => {
107 return res.download(path, downloadFilename)
108 })
109}
110
111async function downloadHLSVideoFile (req: express.Request, res: express.Response) {
112 const video = res.locals.videoAll
113 const streamingPlaylist = getHLSPlaylist(video)
114 if (!streamingPlaylist) return res.status(HttpStatusCode.NOT_FOUND_404).end
115
116 const videoFile = getVideoFile(req, streamingPlaylist.VideoFiles)
117 if (!videoFile) {
118 return res.fail({
119 status: HttpStatusCode.NOT_FOUND_404,
120 message: 'Video file not found'
121 })
122 }
123
124 const allowParameters = {
125 req,
126 res,
127 video,
128 streamingPlaylist,
129 videoFile
130 }
131
132 const allowedResult = await Hooks.wrapFun(
133 isVideoDownloadAllowed,
134 allowParameters,
135 'filter:api.download.video.allowed.result'
136 )
137
138 if (!checkAllowResult(res, allowParameters, allowedResult)) return
139
140 const downloadFilename = `${video.name}-${videoFile.resolution}p-${streamingPlaylist.getStringType()}${videoFile.extname}`
141
142 if (videoFile.storage === VideoStorage.OBJECT_STORAGE) {
143 return redirectToObjectStorage({ req, res, video, streamingPlaylist, file: videoFile, downloadFilename })
144 }
145
146 await VideoPathManager.Instance.makeAvailableVideoFile(videoFile.withVideoOrPlaylist(streamingPlaylist), path => {
147 return res.download(path, downloadFilename)
148 })
149}
150
151function getVideoFile (req: express.Request, files: MVideoFile[]) {
152 const resolution = forceNumber(req.params.resolution)
153 return files.find(f => f.resolution === resolution)
154}
155
156function getHLSPlaylist (video: MVideoFullLight) {
157 const playlist = video.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
158 if (!playlist) return undefined
159
160 return Object.assign(playlist, { Video: video })
161}
162
163type AllowedResult = {
164 allowed: boolean
165 errorMessage?: string
166}
167
168function isTorrentDownloadAllowed (_object: {
169 torrentPath: string
170}): AllowedResult {
171 return { allowed: true }
172}
173
174function isVideoDownloadAllowed (_object: {
175 video: MVideo
176 videoFile: MVideoFile
177 streamingPlaylist?: MStreamingPlaylist
178}): AllowedResult {
179 return { allowed: true }
180}
181
182function checkAllowResult (res: express.Response, allowParameters: any, result?: AllowedResult) {
183 if (!result || result.allowed !== true) {
184 logger.info('Download is not allowed.', { result, allowParameters })
185
186 res.fail({
187 status: HttpStatusCode.FORBIDDEN_403,
188 message: result?.errorMessage || 'Refused download'
189 })
190 return false
191 }
192
193 return true
194}
195
196async function redirectToObjectStorage (options: {
197 req: express.Request
198 res: express.Response
199 video: MVideo
200 file: MVideoFile
201 streamingPlaylist?: MStreamingPlaylistVideo
202 downloadFilename: string
203}) {
204 const { res, video, streamingPlaylist, file, downloadFilename } = options
205
206 const url = streamingPlaylist
207 ? await generateHLSFilePresignedUrl({ streamingPlaylist, file, downloadFilename })
208 : await generateWebVideoPresignedUrl({ file, downloadFilename })
209
210 logger.debug('Generating pre-signed URL %s for video %s', url, video.uuid)
211
212 return res.redirect(url)
213}