From 90a8bd305de4153ec21137a73ff482dcc2e3e19b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 16 Feb 2021 16:25:53 +0100 Subject: Dissociate video file names and video uuid --- server/controllers/api/videos/index.ts | 7 ++- server/controllers/download.ts | 78 ++++++++++++++++++++++++++++++ server/controllers/index.ts | 1 + server/controllers/lazy-static.ts | 23 +++++++-- server/controllers/static.ts | 88 ++-------------------------------- 5 files changed, 105 insertions(+), 92 deletions(-) create mode 100644 server/controllers/download.ts (limited to 'server/controllers') diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 9504c40a4..dcd6194ae 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -7,7 +7,7 @@ import { changeVideoChannelShare } from '@server/lib/activitypub/share' import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' import { LiveManager } from '@server/lib/live-manager' import { addOptimizeOrMergeAudioJob, buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' -import { getVideoFilePath } from '@server/lib/video-paths' +import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' import { getServerActor } from '@server/models/application/application' import { MVideoFullLight } from '@server/types/models' import { VideoCreate, VideoState, VideoUpdate } from '../../../../shared' @@ -189,6 +189,7 @@ async function addVideo (req: express.Request, res: express.Response) { videoData.duration = videoPhysicalFile['duration'] // duration was added by a previous middleware const video = new VideoModel(videoData) as MVideoFullLight + video.VideoChannel = res.locals.videoChannel video.url = getLocalVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object const videoFile = new VideoFileModel({ @@ -205,6 +206,8 @@ async function addVideo (req: express.Request, res: express.Response) { videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path)).videoFileResolution } + videoFile.filename = generateVideoFilename(video, false, videoFile.resolution, videoFile.extname) + // Move physical file const destination = getVideoFilePath(video, videoFile) await move(videoPhysicalFile.path, destination) @@ -219,7 +222,7 @@ async function addVideo (req: express.Request, res: express.Response) { }) // Create the torrent file - await createTorrentAndSetInfoHash(video, videoFile) + await createTorrentAndSetInfoHash(video, video, videoFile) const { videoCreated } = await sequelizeTypescript.transaction(async t => { const sequelizeOptions = { transaction: t } diff --git a/server/controllers/download.ts b/server/controllers/download.ts new file mode 100644 index 000000000..27caa1518 --- /dev/null +++ b/server/controllers/download.ts @@ -0,0 +1,78 @@ +import * as cors from 'cors' +import * as express from 'express' +import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache' +import { getVideoFilePath } from '@server/lib/video-paths' +import { MVideoFile, MVideoFullLight } from '@server/types/models' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' +import { VideoStreamingPlaylistType } from '@shared/models' +import { STATIC_DOWNLOAD_PATHS } from '../initializers/constants' +import { asyncMiddleware, videosDownloadValidator } from '../middlewares' + +const downloadRouter = express.Router() + +downloadRouter.use(cors()) + +downloadRouter.use( + STATIC_DOWNLOAD_PATHS.TORRENTS + ':filename', + downloadTorrent +) + +downloadRouter.use( + STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', + asyncMiddleware(videosDownloadValidator), + downloadVideoFile +) + +downloadRouter.use( + STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', + asyncMiddleware(videosDownloadValidator), + downloadHLSVideoFile +) + +// --------------------------------------------------------------------------- + +export { + downloadRouter +} + +// --------------------------------------------------------------------------- + +async function downloadTorrent (req: express.Request, res: express.Response) { + const result = await VideosTorrentCache.Instance.getFilePath(req.params.filename) + if (!result) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) + + return res.download(result.path, result.downloadName) +} + +function downloadVideoFile (req: express.Request, res: express.Response) { + const video = res.locals.videoAll + + const videoFile = getVideoFile(req, video.VideoFiles) + if (!videoFile) return res.status(HttpStatusCode.NOT_FOUND_404).end() + + return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) +} + +function downloadHLSVideoFile (req: express.Request, res: express.Response) { + const video = res.locals.videoAll + const playlist = getHLSPlaylist(video) + if (!playlist) return res.status(HttpStatusCode.NOT_FOUND_404).end + + const videoFile = getVideoFile(req, playlist.VideoFiles) + if (!videoFile) return res.status(HttpStatusCode.NOT_FOUND_404).end() + + const filename = `${video.name}-${videoFile.resolution}p-${playlist.getStringType()}${videoFile.extname}` + return res.download(getVideoFilePath(playlist, videoFile), filename) +} + +function getVideoFile (req: express.Request, files: MVideoFile[]) { + const resolution = parseInt(req.params.resolution, 10) + return files.find(f => f.resolution === resolution) +} + +function getHLSPlaylist (video: MVideoFullLight) { + const playlist = video.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) + if (!playlist) return undefined + + return Object.assign(playlist, { Video: video }) +} diff --git a/server/controllers/index.ts b/server/controllers/index.ts index 5a199ae9c..fa27ecec2 100644 --- a/server/controllers/index.ts +++ b/server/controllers/index.ts @@ -1,6 +1,7 @@ export * from './activitypub' export * from './api' export * from './client' +export * from './download' export * from './feeds' export * from './services' export * from './static' diff --git a/server/controllers/lazy-static.ts b/server/controllers/lazy-static.ts index 656dea223..c2f5c7b56 100644 --- a/server/controllers/lazy-static.ts +++ b/server/controllers/lazy-static.ts @@ -1,12 +1,13 @@ import * as cors from 'cors' import * as express from 'express' +import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache' +import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' +import { logger } from '../helpers/logger' import { LAZY_STATIC_PATHS, STATIC_MAX_AGE } from '../initializers/constants' +import { avatarPathUnsafeCache, pushAvatarProcessInQueue } from '../lib/avatar' import { VideosCaptionCache, VideosPreviewCache } from '../lib/files-cache' import { asyncMiddleware } from '../middlewares' import { AvatarModel } from '../models/avatar/avatar' -import { logger } from '../helpers/logger' -import { avatarPathUnsafeCache, pushAvatarProcessInQueue } from '../lib/avatar' -import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' const lazyStaticRouter = express.Router() @@ -27,6 +28,11 @@ lazyStaticRouter.use( asyncMiddleware(getVideoCaption) ) +lazyStaticRouter.use( + LAZY_STATIC_PATHS.TORRENTS + ':filename', + asyncMiddleware(getTorrent) +) + // --------------------------------------------------------------------------- export { @@ -67,19 +73,26 @@ async function getAvatar (req: express.Request, res: express.Response) { const path = avatar.getPath() avatarPathUnsafeCache.set(filename, path) - return res.sendFile(path, { maxAge: STATIC_MAX_AGE.SERVER }) + return res.sendFile(path, { maxAge: STATIC_MAX_AGE.LAZY_SERVER }) } async function getPreview (req: express.Request, res: express.Response) { const result = await VideosPreviewCache.Instance.getFilePath(req.params.filename) if (!result) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) - return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE.SERVER }) + return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE.LAZY_SERVER }) } async function getVideoCaption (req: express.Request, res: express.Response) { const result = await VideosCaptionCache.Instance.getFilePath(req.params.filename) if (!result) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) + return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE.LAZY_SERVER }) +} + +async function getTorrent (req: express.Request, res: express.Response) { + const result = await VideosTorrentCache.Instance.getFilePath(req.params.filename) + if (!result) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) + return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE.SERVER }) } diff --git a/server/controllers/static.ts b/server/controllers/static.ts index 2064857eb..7cc7f2c62 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts @@ -3,10 +3,7 @@ import * as express from 'express' import { join } from 'path' import { getRegisteredPlugins, getRegisteredThemes } from '@server/controllers/api/config' import { serveIndexHTML } from '@server/lib/client-html' -import { getTorrentFilePath, getVideoFilePath } from '@server/lib/video-paths' -import { MVideoFile, MVideoFullLight } from '@server/types/models' import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' -import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type' import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo' import { root } from '../helpers/core-utils' import { CONFIG, isEmailEnabled } from '../initializers/config' @@ -16,14 +13,13 @@ import { HLS_STREAMING_PLAYLIST_DIRECTORY, PEERTUBE_VERSION, ROUTE_CACHE_LIFETIME, - STATIC_DOWNLOAD_PATHS, STATIC_MAX_AGE, STATIC_PATHS, WEBSERVER } from '../initializers/constants' import { getThemeOrDefault } from '../lib/plugins/theme-utils' import { getEnabledResolutions } from '../lib/video-transcoding' -import { asyncMiddleware, videosDownloadValidator } from '../middlewares' +import { asyncMiddleware } from '../middlewares' import { cacheRoute } from '../middlewares/cache' import { UserModel } from '../models/account/user' import { VideoModel } from '../models/video/video' @@ -37,47 +33,23 @@ staticRouter.use(cors()) Cors is very important to let other servers access torrent and video files */ +// FIXME: deprecated in 3.2, use lazy-statics instead const torrentsPhysicalPath = CONFIG.STORAGE.TORRENTS_DIR staticRouter.use( STATIC_PATHS.TORRENTS, - cors(), express.static(torrentsPhysicalPath, { maxAge: 0 }) // Don't cache because we could regenerate the torrent file ) -staticRouter.use( - STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', - asyncMiddleware(videosDownloadValidator), - downloadTorrent -) -staticRouter.use( - STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', - asyncMiddleware(videosDownloadValidator), - downloadHLSVideoFileTorrent -) -// Videos path for webseeding +// Videos path for webseed staticRouter.use( STATIC_PATHS.WEBSEED, - cors(), express.static(CONFIG.STORAGE.VIDEOS_DIR, { fallthrough: false }) // 404 because we don't have this video ) staticRouter.use( STATIC_PATHS.REDUNDANCY, - cors(), express.static(CONFIG.STORAGE.REDUNDANCY_DIR, { fallthrough: false }) // 404 because we don't have this video ) -staticRouter.use( - STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', - asyncMiddleware(videosDownloadValidator), - downloadVideoFile -) - -staticRouter.use( - STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', - asyncMiddleware(videosDownloadValidator), - downloadHLSVideoFile -) - // HLS staticRouter.use( STATIC_PATHS.STREAMING_PLAYLISTS.HLS, @@ -327,60 +299,6 @@ async function generateNodeinfo (req: express.Request, res: express.Response) { return res.send(json).end() } -function downloadTorrent (req: express.Request, res: express.Response) { - const video = res.locals.videoAll - - const videoFile = getVideoFile(req, video.VideoFiles) - if (!videoFile) return res.status(HttpStatusCode.NOT_FOUND_404).end() - - return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) -} - -function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { - const video = res.locals.videoAll - - const playlist = getHLSPlaylist(video) - if (!playlist) return res.status(HttpStatusCode.NOT_FOUND_404).end - - const videoFile = getVideoFile(req, playlist.VideoFiles) - if (!videoFile) return res.status(HttpStatusCode.NOT_FOUND_404).end() - - return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) -} - -function downloadVideoFile (req: express.Request, res: express.Response) { - const video = res.locals.videoAll - - const videoFile = getVideoFile(req, video.VideoFiles) - if (!videoFile) return res.status(HttpStatusCode.NOT_FOUND_404).end() - - return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) -} - -function downloadHLSVideoFile (req: express.Request, res: express.Response) { - const video = res.locals.videoAll - const playlist = getHLSPlaylist(video) - if (!playlist) return res.status(HttpStatusCode.NOT_FOUND_404).end - - const videoFile = getVideoFile(req, playlist.VideoFiles) - if (!videoFile) return res.status(HttpStatusCode.NOT_FOUND_404).end() - - const filename = `${video.name}-${videoFile.resolution}p-${playlist.getStringType()}${videoFile.extname}` - return res.download(getVideoFilePath(playlist, videoFile), filename) -} - -function getVideoFile (req: express.Request, files: MVideoFile[]) { - const resolution = parseInt(req.params.resolution, 10) - return files.find(f => f.resolution === resolution) -} - -function getHLSPlaylist (video: MVideoFullLight) { - const playlist = video.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) - if (!playlist) return undefined - - return Object.assign(playlist, { Video: video }) -} - function getCup (req: express.Request, res: express.Response, next: express.NextFunction) { res.status(HttpStatusCode.I_AM_A_TEAPOT_418) res.setHeader('Accept-Additions', 'Non-Dairy;1,Sugar;1') -- cgit v1.2.3