diff options
Diffstat (limited to 'server/lib')
-rw-r--r-- | server/lib/activitypub/videos.ts | 54 | ||||
-rw-r--r-- | server/lib/files-cache/abstract-video-static-file-cache.ts | 2 | ||||
-rw-r--r-- | server/lib/files-cache/videos-torrent-cache.ts | 54 | ||||
-rw-r--r-- | server/lib/hls.ts | 4 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-file-import.ts | 14 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-import.ts | 8 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-live-ending.ts | 2 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-transcoding.ts | 2 | ||||
-rw-r--r-- | server/lib/live-manager.ts | 6 | ||||
-rw-r--r-- | server/lib/schedulers/videos-redundancy-scheduler.ts | 12 | ||||
-rw-r--r-- | server/lib/video-paths.ts | 75 | ||||
-rw-r--r-- | server/lib/video-transcoding.ts | 33 |
12 files changed, 194 insertions, 72 deletions
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 66981f43f..a5f6537eb 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { maxBy, minBy } from 'lodash' | 2 | import { maxBy, minBy } from 'lodash' |
3 | import * as magnetUtil from 'magnet-uri' | 3 | import * as magnetUtil from 'magnet-uri' |
4 | import { join } from 'path' | 4 | import { basename, join } from 'path' |
5 | import * as request from 'request' | 5 | import * as request from 'request' |
6 | import * as sequelize from 'sequelize' | 6 | import * as sequelize from 'sequelize' |
7 | import { VideoLiveModel } from '@server/models/video/video-live' | 7 | import { VideoLiveModel } from '@server/models/video/video-live' |
@@ -30,11 +30,11 @@ import { doRequest } from '../../helpers/requests' | |||
30 | import { fetchVideoByUrl, getExtFromMimetype, VideoFetchByUrlType } from '../../helpers/video' | 30 | import { fetchVideoByUrl, getExtFromMimetype, VideoFetchByUrlType } from '../../helpers/video' |
31 | import { | 31 | import { |
32 | ACTIVITY_PUB, | 32 | ACTIVITY_PUB, |
33 | LAZY_STATIC_PATHS, | ||
33 | MIMETYPES, | 34 | MIMETYPES, |
34 | P2P_MEDIA_LOADER_PEER_VERSION, | 35 | P2P_MEDIA_LOADER_PEER_VERSION, |
35 | PREVIEWS_SIZE, | 36 | PREVIEWS_SIZE, |
36 | REMOTE_SCHEME, | 37 | REMOTE_SCHEME, |
37 | STATIC_PATHS, | ||
38 | THUMBNAILS_SIZE | 38 | THUMBNAILS_SIZE |
39 | } from '../../initializers/constants' | 39 | } from '../../initializers/constants' |
40 | import { sequelizeTypescript } from '../../initializers/database' | 40 | import { sequelizeTypescript } from '../../initializers/database' |
@@ -51,6 +51,8 @@ import { | |||
51 | MChannelDefault, | 51 | MChannelDefault, |
52 | MChannelId, | 52 | MChannelId, |
53 | MStreamingPlaylist, | 53 | MStreamingPlaylist, |
54 | MStreamingPlaylistFilesVideo, | ||
55 | MStreamingPlaylistVideo, | ||
54 | MVideo, | 56 | MVideo, |
55 | MVideoAccountLight, | 57 | MVideoAccountLight, |
56 | MVideoAccountLightBlacklistAllFiles, | 58 | MVideoAccountLightBlacklistAllFiles, |
@@ -61,7 +63,8 @@ import { | |||
61 | MVideoFullLight, | 63 | MVideoFullLight, |
62 | MVideoId, | 64 | MVideoId, |
63 | MVideoImmutable, | 65 | MVideoImmutable, |
64 | MVideoThumbnail | 66 | MVideoThumbnail, |
67 | MVideoWithHost | ||
65 | } from '../../types/models' | 68 | } from '../../types/models' |
66 | import { MThumbnail } from '../../types/models/video/thumbnail' | 69 | import { MThumbnail } from '../../types/models/video/thumbnail' |
67 | import { FilteredModelAttributes } from '../../types/sequelize' | 70 | import { FilteredModelAttributes } from '../../types/sequelize' |
@@ -72,6 +75,7 @@ import { PeerTubeSocket } from '../peertube-socket' | |||
72 | import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail' | 75 | import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail' |
73 | import { setVideoTags } from '../video' | 76 | import { setVideoTags } from '../video' |
74 | import { autoBlacklistVideoIfNeeded } from '../video-blacklist' | 77 | import { autoBlacklistVideoIfNeeded } from '../video-blacklist' |
78 | import { generateTorrentFileName } from '../video-paths' | ||
75 | import { getOrCreateActorAndServerAndModel } from './actor' | 79 | import { getOrCreateActorAndServerAndModel } from './actor' |
76 | import { crawlCollectionPage } from './crawl' | 80 | import { crawlCollectionPage } from './crawl' |
77 | import { sendCreateVideo, sendUpdateVideo } from './send' | 81 | import { sendCreateVideo, sendUpdateVideo } from './send' |
@@ -405,7 +409,8 @@ async function updateVideoFromAP (options: { | |||
405 | 409 | ||
406 | for (const playlistAttributes of streamingPlaylistAttributes) { | 410 | for (const playlistAttributes of streamingPlaylistAttributes) { |
407 | const streamingPlaylistModel = await VideoStreamingPlaylistModel.upsert(playlistAttributes, { returning: true, transaction: t }) | 411 | const streamingPlaylistModel = await VideoStreamingPlaylistModel.upsert(playlistAttributes, { returning: true, transaction: t }) |
408 | .then(([ streamingPlaylist ]) => streamingPlaylist) | 412 | .then(([ streamingPlaylist ]) => streamingPlaylist as MStreamingPlaylistFilesVideo) |
413 | streamingPlaylistModel.Video = videoUpdated | ||
409 | 414 | ||
410 | const newVideoFiles: MVideoFile[] = videoFileActivityUrlToDBAttributes(streamingPlaylistModel, playlistAttributes.tagAPObject) | 415 | const newVideoFiles: MVideoFile[] = videoFileActivityUrlToDBAttributes(streamingPlaylistModel, playlistAttributes.tagAPObject) |
411 | .map(a => new VideoFileModel(a)) | 416 | .map(a => new VideoFileModel(a)) |
@@ -637,13 +642,14 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi | |||
637 | videoCreated.VideoStreamingPlaylists = [] | 642 | videoCreated.VideoStreamingPlaylists = [] |
638 | 643 | ||
639 | for (const playlistAttributes of streamingPlaylistsAttributes) { | 644 | for (const playlistAttributes of streamingPlaylistsAttributes) { |
640 | const playlistModel = await VideoStreamingPlaylistModel.create(playlistAttributes, { transaction: t }) | 645 | const playlist = await VideoStreamingPlaylistModel.create(playlistAttributes, { transaction: t }) as MStreamingPlaylistFilesVideo |
646 | playlist.Video = videoCreated | ||
641 | 647 | ||
642 | const playlistFiles = videoFileActivityUrlToDBAttributes(playlistModel, playlistAttributes.tagAPObject) | 648 | const playlistFiles = videoFileActivityUrlToDBAttributes(playlist, playlistAttributes.tagAPObject) |
643 | const videoFilePromises = playlistFiles.map(f => VideoFileModel.create(f, { transaction: t })) | 649 | const videoFilePromises = playlistFiles.map(f => VideoFileModel.create(f, { transaction: t })) |
644 | playlistModel.VideoFiles = await Promise.all(videoFilePromises) | 650 | playlist.VideoFiles = await Promise.all(videoFilePromises) |
645 | 651 | ||
646 | videoCreated.VideoStreamingPlaylists.push(playlistModel) | 652 | videoCreated.VideoStreamingPlaylists.push(playlist) |
647 | } | 653 | } |
648 | 654 | ||
649 | // Process tags | 655 | // Process tags |
@@ -766,7 +772,7 @@ function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObjec | |||
766 | } | 772 | } |
767 | 773 | ||
768 | function videoFileActivityUrlToDBAttributes ( | 774 | function videoFileActivityUrlToDBAttributes ( |
769 | videoOrPlaylist: MVideo | MStreamingPlaylist, | 775 | videoOrPlaylist: MVideo | MStreamingPlaylistVideo, |
770 | urls: (ActivityTagObject | ActivityUrlObject)[] | 776 | urls: (ActivityTagObject | ActivityUrlObject)[] |
771 | ) { | 777 | ) { |
772 | const fileUrls = urls.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[] | 778 | const fileUrls = urls.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[] |
@@ -786,6 +792,10 @@ function videoFileActivityUrlToDBAttributes ( | |||
786 | throw new Error('Cannot parse magnet URI ' + magnet.href) | 792 | throw new Error('Cannot parse magnet URI ' + magnet.href) |
787 | } | 793 | } |
788 | 794 | ||
795 | const torrentUrl = Array.isArray(parsed.xs) | ||
796 | ? parsed.xs[0] | ||
797 | : parsed.xs | ||
798 | |||
789 | // Fetch associated metadata url, if any | 799 | // Fetch associated metadata url, if any |
790 | const metadata = urls.filter(isAPVideoFileMetadataObject) | 800 | const metadata = urls.filter(isAPVideoFileMetadataObject) |
791 | .find(u => { | 801 | .find(u => { |
@@ -794,18 +804,30 @@ function videoFileActivityUrlToDBAttributes ( | |||
794 | u.rel.includes(fileUrl.mediaType) | 804 | u.rel.includes(fileUrl.mediaType) |
795 | }) | 805 | }) |
796 | 806 | ||
797 | const mediaType = fileUrl.mediaType | 807 | const extname = getExtFromMimetype(MIMETYPES.VIDEO.MIMETYPE_EXT, fileUrl.mediaType) |
808 | const resolution = fileUrl.height | ||
809 | const videoId = (videoOrPlaylist as MStreamingPlaylist).playlistUrl ? null : videoOrPlaylist.id | ||
810 | const videoStreamingPlaylistId = (videoOrPlaylist as MStreamingPlaylist).playlistUrl ? videoOrPlaylist.id : null | ||
811 | |||
798 | const attribute = { | 812 | const attribute = { |
799 | extname: getExtFromMimetype(MIMETYPES.VIDEO.MIMETYPE_EXT, mediaType), | 813 | extname, |
800 | infoHash: parsed.infoHash, | 814 | infoHash: parsed.infoHash, |
801 | resolution: fileUrl.height, | 815 | resolution, |
802 | size: fileUrl.size, | 816 | size: fileUrl.size, |
803 | fps: fileUrl.fps || -1, | 817 | fps: fileUrl.fps || -1, |
804 | metadataUrl: metadata?.href, | 818 | metadataUrl: metadata?.href, |
805 | 819 | ||
820 | // Use the name of the remote file because we don't proxify video file requests | ||
821 | filename: basename(fileUrl.href), | ||
822 | fileUrl: fileUrl.href, | ||
823 | |||
824 | torrentUrl, | ||
825 | // Use our own torrent name since we proxify torrent requests | ||
826 | torrentFilename: generateTorrentFileName(videoOrPlaylist, resolution), | ||
827 | |||
806 | // This is a video file owned by a video or by a streaming playlist | 828 | // This is a video file owned by a video or by a streaming playlist |
807 | videoId: (videoOrPlaylist as MStreamingPlaylist).playlistUrl ? null : videoOrPlaylist.id, | 829 | videoId, |
808 | videoStreamingPlaylistId: (videoOrPlaylist as MStreamingPlaylist).playlistUrl ? videoOrPlaylist.id : null | 830 | videoStreamingPlaylistId |
809 | } | 831 | } |
810 | 832 | ||
811 | attributes.push(attribute) | 833 | attributes.push(attribute) |
@@ -862,8 +884,8 @@ function getPreviewFromIcons (videoObject: VideoObject) { | |||
862 | return maxBy(validIcons, 'width') | 884 | return maxBy(validIcons, 'width') |
863 | } | 885 | } |
864 | 886 | ||
865 | function getPreviewUrl (previewIcon: ActivityIconObject, video: MVideoAccountLight) { | 887 | function getPreviewUrl (previewIcon: ActivityIconObject, video: MVideoWithHost) { |
866 | return previewIcon | 888 | return previewIcon |
867 | ? previewIcon.url | 889 | ? previewIcon.url |
868 | : buildRemoteVideoBaseUrl(video, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | 890 | : buildRemoteVideoBaseUrl(video, join(LAZY_STATIC_PATHS.PREVIEWS, video.generatePreviewName())) |
869 | } | 891 | } |
diff --git a/server/lib/files-cache/abstract-video-static-file-cache.ts b/server/lib/files-cache/abstract-video-static-file-cache.ts index c06355446..af66689a0 100644 --- a/server/lib/files-cache/abstract-video-static-file-cache.ts +++ b/server/lib/files-cache/abstract-video-static-file-cache.ts | |||
@@ -2,7 +2,7 @@ import { remove } from 'fs-extra' | |||
2 | import { logger } from '../../helpers/logger' | 2 | import { logger } from '../../helpers/logger' |
3 | import * as memoizee from 'memoizee' | 3 | import * as memoizee from 'memoizee' |
4 | 4 | ||
5 | type GetFilePathResult = { isOwned: boolean, path: string } | undefined | 5 | type GetFilePathResult = { isOwned: boolean, path: string, downloadName?: string } | undefined |
6 | 6 | ||
7 | export abstract class AbstractVideoStaticFileCache <T> { | 7 | export abstract class AbstractVideoStaticFileCache <T> { |
8 | 8 | ||
diff --git a/server/lib/files-cache/videos-torrent-cache.ts b/server/lib/files-cache/videos-torrent-cache.ts new file mode 100644 index 000000000..ca0e1770d --- /dev/null +++ b/server/lib/files-cache/videos-torrent-cache.ts | |||
@@ -0,0 +1,54 @@ | |||
1 | import { join } from 'path' | ||
2 | import { doRequestAndSaveToFile } from '@server/helpers/requests' | ||
3 | import { VideoFileModel } from '@server/models/video/video-file' | ||
4 | import { CONFIG } from '../../initializers/config' | ||
5 | import { FILES_CACHE } from '../../initializers/constants' | ||
6 | import { VideoModel } from '../../models/video/video' | ||
7 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' | ||
8 | |||
9 | class VideosTorrentCache extends AbstractVideoStaticFileCache <string> { | ||
10 | |||
11 | private static instance: VideosTorrentCache | ||
12 | |||
13 | private constructor () { | ||
14 | super() | ||
15 | } | ||
16 | |||
17 | static get Instance () { | ||
18 | return this.instance || (this.instance = new this()) | ||
19 | } | ||
20 | |||
21 | async getFilePathImpl (filename: string) { | ||
22 | const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(filename) | ||
23 | if (!file) return undefined | ||
24 | |||
25 | if (file.getVideo().isOwned()) return { isOwned: true, path: join(CONFIG.STORAGE.TORRENTS_DIR, file.torrentFilename) } | ||
26 | |||
27 | return this.loadRemoteFile(filename) | ||
28 | } | ||
29 | |||
30 | // Key is the torrent filename | ||
31 | protected async loadRemoteFile (key: string) { | ||
32 | const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(key) | ||
33 | if (!file) return undefined | ||
34 | |||
35 | if (file.getVideo().isOwned()) throw new Error('Cannot load remote file of owned video.') | ||
36 | |||
37 | // Used to fetch the path | ||
38 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(file.getVideo().id) | ||
39 | if (!video) return undefined | ||
40 | |||
41 | const remoteUrl = file.getRemoteTorrentUrl(video) | ||
42 | const destPath = join(FILES_CACHE.TORRENTS.DIRECTORY, file.torrentFilename) | ||
43 | |||
44 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) | ||
45 | |||
46 | const downloadName = `${video.name}-${file.resolution}p.torrent` | ||
47 | |||
48 | return { isOwned: false, path: destPath, downloadName } | ||
49 | } | ||
50 | } | ||
51 | |||
52 | export { | ||
53 | VideosTorrentCache | ||
54 | } | ||
diff --git a/server/lib/hls.ts b/server/lib/hls.ts index ef489097a..04187668c 100644 --- a/server/lib/hls.ts +++ b/server/lib/hls.ts | |||
@@ -12,7 +12,7 @@ import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION } from | |||
12 | import { sequelizeTypescript } from '../initializers/database' | 12 | import { sequelizeTypescript } from '../initializers/database' |
13 | import { VideoFileModel } from '../models/video/video-file' | 13 | import { VideoFileModel } from '../models/video/video-file' |
14 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' | 14 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' |
15 | import { getVideoFilename, getVideoFilePath } from './video-paths' | 15 | import { getVideoFilePath } from './video-paths' |
16 | 16 | ||
17 | async function updateStreamingPlaylistsInfohashesIfNeeded () { | 17 | async function updateStreamingPlaylistsInfohashesIfNeeded () { |
18 | const playlistsToUpdate = await VideoStreamingPlaylistModel.listByIncorrectPeerVersion() | 18 | const playlistsToUpdate = await VideoStreamingPlaylistModel.listByIncorrectPeerVersion() |
@@ -93,7 +93,7 @@ async function updateSha256VODSegments (video: MVideoWithFile) { | |||
93 | } | 93 | } |
94 | await close(fd) | 94 | await close(fd) |
95 | 95 | ||
96 | const videoFilename = getVideoFilename(hlsPlaylist, file) | 96 | const videoFilename = file.filename |
97 | json[videoFilename] = rangeHashes | 97 | json[videoFilename] = rangeHashes |
98 | } | 98 | } |
99 | 99 | ||
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index cd95aa075..86c9b5c29 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts | |||
@@ -2,9 +2,9 @@ import * as Bull from 'bull' | |||
2 | import { copy, stat } from 'fs-extra' | 2 | import { copy, stat } from 'fs-extra' |
3 | import { extname } from 'path' | 3 | import { extname } from 'path' |
4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | 4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' |
5 | import { getVideoFilePath } from '@server/lib/video-paths' | 5 | import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' |
6 | import { UserModel } from '@server/models/account/user' | 6 | import { UserModel } from '@server/models/account/user' |
7 | import { MVideoFile, MVideoWithFile } from '@server/types/models' | 7 | import { MVideoFile, MVideoFullLight } from '@server/types/models' |
8 | import { VideoFileImportPayload } from '@shared/models' | 8 | import { VideoFileImportPayload } from '@shared/models' |
9 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' | 9 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' |
10 | import { logger } from '../../../helpers/logger' | 10 | import { logger } from '../../../helpers/logger' |
@@ -50,14 +50,16 @@ export { | |||
50 | 50 | ||
51 | // --------------------------------------------------------------------------- | 51 | // --------------------------------------------------------------------------- |
52 | 52 | ||
53 | async function updateVideoFile (video: MVideoWithFile, inputFilePath: string) { | 53 | async function updateVideoFile (video: MVideoFullLight, inputFilePath: string) { |
54 | const { videoFileResolution } = await getVideoFileResolution(inputFilePath) | 54 | const { videoFileResolution } = await getVideoFileResolution(inputFilePath) |
55 | const { size } = await stat(inputFilePath) | 55 | const { size } = await stat(inputFilePath) |
56 | const fps = await getVideoFileFPS(inputFilePath) | 56 | const fps = await getVideoFileFPS(inputFilePath) |
57 | 57 | ||
58 | const fileExt = extname(inputFilePath) | ||
58 | let updatedVideoFile = new VideoFileModel({ | 59 | let updatedVideoFile = new VideoFileModel({ |
59 | resolution: videoFileResolution, | 60 | resolution: videoFileResolution, |
60 | extname: extname(inputFilePath), | 61 | extname: fileExt, |
62 | filename: generateVideoFilename(video, false, videoFileResolution, fileExt), | ||
61 | size, | 63 | size, |
62 | fps, | 64 | fps, |
63 | videoId: video.id | 65 | videoId: video.id |
@@ -68,7 +70,7 @@ async function updateVideoFile (video: MVideoWithFile, inputFilePath: string) { | |||
68 | if (currentVideoFile) { | 70 | if (currentVideoFile) { |
69 | // Remove old file and old torrent | 71 | // Remove old file and old torrent |
70 | await video.removeFile(currentVideoFile) | 72 | await video.removeFile(currentVideoFile) |
71 | await video.removeTorrent(currentVideoFile) | 73 | await currentVideoFile.removeTorrent() |
72 | // Remove the old video file from the array | 74 | // Remove the old video file from the array |
73 | video.VideoFiles = video.VideoFiles.filter(f => f !== currentVideoFile) | 75 | video.VideoFiles = video.VideoFiles.filter(f => f !== currentVideoFile) |
74 | 76 | ||
@@ -83,7 +85,7 @@ async function updateVideoFile (video: MVideoWithFile, inputFilePath: string) { | |||
83 | const outputPath = getVideoFilePath(video, updatedVideoFile) | 85 | const outputPath = getVideoFilePath(video, updatedVideoFile) |
84 | await copy(inputFilePath, outputPath) | 86 | await copy(inputFilePath, outputPath) |
85 | 87 | ||
86 | await createTorrentAndSetInfoHash(video, updatedVideoFile) | 88 | await createTorrentAndSetInfoHash(video, video, updatedVideoFile) |
87 | 89 | ||
88 | await updatedVideoFile.save() | 90 | await updatedVideoFile.save() |
89 | 91 | ||
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 0d00c1b9d..8fa024105 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -6,7 +6,7 @@ import { isPostImportVideoAccepted } from '@server/lib/moderation' | |||
6 | import { Hooks } from '@server/lib/plugins/hooks' | 6 | import { Hooks } from '@server/lib/plugins/hooks' |
7 | import { isAbleToUploadVideo } from '@server/lib/user' | 7 | import { isAbleToUploadVideo } from '@server/lib/user' |
8 | import { addOptimizeOrMergeAudioJob } from '@server/lib/video' | 8 | import { addOptimizeOrMergeAudioJob } from '@server/lib/video' |
9 | import { getVideoFilePath } from '@server/lib/video-paths' | 9 | import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' |
10 | import { ThumbnailModel } from '@server/models/video/thumbnail' | 10 | import { ThumbnailModel } from '@server/models/video/thumbnail' |
11 | import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/types/models/video/video-import' | 11 | import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/types/models/video/video-import' |
12 | import { | 12 | import { |
@@ -116,10 +116,12 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
116 | const duration = await getDurationFromVideoFile(tempVideoPath) | 116 | const duration = await getDurationFromVideoFile(tempVideoPath) |
117 | 117 | ||
118 | // Prepare video file object for creation in database | 118 | // Prepare video file object for creation in database |
119 | const fileExt = extname(tempVideoPath) | ||
119 | const videoFileData = { | 120 | const videoFileData = { |
120 | extname: extname(tempVideoPath), | 121 | extname: fileExt, |
121 | resolution: videoFileResolution, | 122 | resolution: videoFileResolution, |
122 | size: stats.size, | 123 | size: stats.size, |
124 | filename: generateVideoFilename(videoImport.Video, false, videoFileResolution, fileExt), | ||
123 | fps, | 125 | fps, |
124 | videoId: videoImport.videoId | 126 | videoId: videoImport.videoId |
125 | } | 127 | } |
@@ -183,7 +185,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
183 | } | 185 | } |
184 | 186 | ||
185 | // Create torrent | 187 | // Create torrent |
186 | await createTorrentAndSetInfoHash(videoImportWithFiles.Video, videoFile) | 188 | await createTorrentAndSetInfoHash(videoImportWithFiles.Video, videoImportWithFiles.Video, videoFile) |
187 | 189 | ||
188 | const videoFileSave = videoFile.toJSON() | 190 | const videoFileSave = videoFile.toJSON() |
189 | 191 | ||
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts index 6d50635bb..d57202ca5 100644 --- a/server/lib/job-queue/handlers/video-live-ending.ts +++ b/server/lib/job-queue/handlers/video-live-ending.ts | |||
@@ -85,7 +85,7 @@ async function saveLive (video: MVideo, live: MVideoLive) { | |||
85 | await video.save() | 85 | await video.save() |
86 | 86 | ||
87 | // Remove old HLS playlist video files | 87 | // Remove old HLS playlist video files |
88 | const videoWithFiles = await VideoModel.loadWithFiles(video.id) | 88 | const videoWithFiles = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.id) |
89 | 89 | ||
90 | const hlsPlaylist = videoWithFiles.getHLSPlaylist() | 90 | const hlsPlaylist = videoWithFiles.getHLSPlaylist() |
91 | await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id) | 91 | await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id) |
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index e248b645e..8573d4d12 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -128,7 +128,7 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, user: MUser, pay | |||
128 | // Remove webtorrent files if not enabled | 128 | // Remove webtorrent files if not enabled |
129 | for (const file of video.VideoFiles) { | 129 | for (const file of video.VideoFiles) { |
130 | await video.removeFile(file) | 130 | await video.removeFile(file) |
131 | await video.removeTorrent(file) | 131 | await file.removeTorrent() |
132 | await file.destroy() | 132 | await file.destroy() |
133 | } | 133 | } |
134 | 134 | ||
diff --git a/server/lib/live-manager.ts b/server/lib/live-manager.ts index 9f17b8820..b549c189f 100644 --- a/server/lib/live-manager.ts +++ b/server/lib/live-manager.ts | |||
@@ -16,7 +16,7 @@ import { VideoModel } from '@server/models/video/video' | |||
16 | import { VideoFileModel } from '@server/models/video/video-file' | 16 | import { VideoFileModel } from '@server/models/video/video-file' |
17 | import { VideoLiveModel } from '@server/models/video/video-live' | 17 | import { VideoLiveModel } from '@server/models/video/video-live' |
18 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' | 18 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' |
19 | import { MStreamingPlaylist, MUserId, MVideoLive, MVideoLiveVideo } from '@server/types/models' | 19 | import { MStreamingPlaylist, MStreamingPlaylistVideo, MUserId, MVideoLive, MVideoLiveVideo } from '@server/types/models' |
20 | import { VideoState, VideoStreamingPlaylistType } from '@shared/models' | 20 | import { VideoState, VideoStreamingPlaylistType } from '@shared/models' |
21 | import { federateVideoIfNeeded } from './activitypub/videos' | 21 | import { federateVideoIfNeeded } from './activitypub/videos' |
22 | import { buildSha256Segment } from './hls' | 22 | import { buildSha256Segment } from './hls' |
@@ -277,7 +277,7 @@ class LiveManager { | |||
277 | return this.runMuxing({ | 277 | return this.runMuxing({ |
278 | sessionId, | 278 | sessionId, |
279 | videoLive, | 279 | videoLive, |
280 | playlist: videoStreamingPlaylist, | 280 | playlist: Object.assign(videoStreamingPlaylist, { Video: video }), |
281 | rtmpUrl, | 281 | rtmpUrl, |
282 | fps, | 282 | fps, |
283 | allResolutions | 283 | allResolutions |
@@ -287,7 +287,7 @@ class LiveManager { | |||
287 | private async runMuxing (options: { | 287 | private async runMuxing (options: { |
288 | sessionId: string | 288 | sessionId: string |
289 | videoLive: MVideoLiveVideo | 289 | videoLive: MVideoLiveVideo |
290 | playlist: MStreamingPlaylist | 290 | playlist: MStreamingPlaylistVideo |
291 | rtmpUrl: string | 291 | rtmpUrl: string |
292 | fps: number | 292 | fps: number |
293 | allResolutions: number[] | 293 | allResolutions: number[] |
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index 93e76626c..60008e695 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts | |||
@@ -18,14 +18,14 @@ import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' | |||
18 | import { logger } from '../../helpers/logger' | 18 | import { logger } from '../../helpers/logger' |
19 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' | 19 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' |
20 | import { CONFIG } from '../../initializers/config' | 20 | import { CONFIG } from '../../initializers/config' |
21 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants' | 21 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT } from '../../initializers/constants' |
22 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 22 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
23 | import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send' | 23 | import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send' |
24 | import { getLocalVideoCacheFileActivityPubUrl, getLocalVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url' | 24 | import { getLocalVideoCacheFileActivityPubUrl, getLocalVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url' |
25 | import { getOrCreateVideoAndAccountAndChannel } from '../activitypub/videos' | 25 | import { getOrCreateVideoAndAccountAndChannel } from '../activitypub/videos' |
26 | import { downloadPlaylistSegments } from '../hls' | 26 | import { downloadPlaylistSegments } from '../hls' |
27 | import { removeVideoRedundancy } from '../redundancy' | 27 | import { removeVideoRedundancy } from '../redundancy' |
28 | import { getVideoFilename } from '../video-paths' | 28 | import { generateHLSRedundancyUrl, generateWebTorrentRedundancyUrl } from '../video-paths' |
29 | import { AbstractScheduler } from './abstract-scheduler' | 29 | import { AbstractScheduler } from './abstract-scheduler' |
30 | 30 | ||
31 | type CandidateToDuplicate = { | 31 | type CandidateToDuplicate = { |
@@ -222,17 +222,17 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
222 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy) | 222 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy) |
223 | 223 | ||
224 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() | 224 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() |
225 | const magnetUri = generateMagnetUri(video, file, baseUrlHttp, baseUrlWs) | 225 | const magnetUri = generateMagnetUri(video, video, file, baseUrlHttp, baseUrlWs) |
226 | 226 | ||
227 | const tmpPath = await downloadWebTorrentVideo({ magnetUri }, VIDEO_IMPORT_TIMEOUT) | 227 | const tmpPath = await downloadWebTorrentVideo({ magnetUri }, VIDEO_IMPORT_TIMEOUT) |
228 | 228 | ||
229 | const destPath = join(CONFIG.STORAGE.REDUNDANCY_DIR, getVideoFilename(video, file)) | 229 | const destPath = join(CONFIG.STORAGE.REDUNDANCY_DIR, file.filename) |
230 | await move(tmpPath, destPath, { overwrite: true }) | 230 | await move(tmpPath, destPath, { overwrite: true }) |
231 | 231 | ||
232 | const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ | 232 | const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ |
233 | expiresOn, | 233 | expiresOn, |
234 | url: getLocalVideoCacheFileActivityPubUrl(file), | 234 | url: getLocalVideoCacheFileActivityPubUrl(file), |
235 | fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), | 235 | fileUrl: generateWebTorrentRedundancyUrl(file), |
236 | strategy, | 236 | strategy, |
237 | videoFileId: file.id, | 237 | videoFileId: file.id, |
238 | actorId: serverActor.id | 238 | actorId: serverActor.id |
@@ -271,7 +271,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
271 | const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ | 271 | const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ |
272 | expiresOn, | 272 | expiresOn, |
273 | url: getLocalVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), | 273 | url: getLocalVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), |
274 | fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), | 274 | fileUrl: generateHLSRedundancyUrl(video, playlistArg), |
275 | strategy, | 275 | strategy, |
276 | videoStreamingPlaylistId: playlist.id, | 276 | videoStreamingPlaylistId: playlist.id, |
277 | actorId: serverActor.id | 277 | actorId: serverActor.id |
diff --git a/server/lib/video-paths.ts b/server/lib/video-paths.ts index 53fc8e81d..0385e89cc 100644 --- a/server/lib/video-paths.ts +++ b/server/lib/video-paths.ts | |||
@@ -1,19 +1,23 @@ | |||
1 | import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoUUID } from '@server/types/models' | ||
2 | import { join } from 'path' | 1 | import { join } from 'path' |
3 | import { CONFIG } from '@server/initializers/config' | ||
4 | import { HLS_REDUNDANCY_DIRECTORY, HLS_STREAMING_PLAYLIST_DIRECTORY } from '@server/initializers/constants' | ||
5 | import { extractVideo } from '@server/helpers/video' | 2 | import { extractVideo } from '@server/helpers/video' |
3 | import { CONFIG } from '@server/initializers/config' | ||
4 | import { HLS_REDUNDANCY_DIRECTORY, HLS_STREAMING_PLAYLIST_DIRECTORY, STATIC_PATHS, WEBSERVER } from '@server/initializers/constants' | ||
5 | import { isStreamingPlaylist, MStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoUUID } from '@server/types/models' | ||
6 | 6 | ||
7 | // ################## Video file name ################## | 7 | // ################## Video file name ################## |
8 | 8 | ||
9 | function getVideoFilename (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { | 9 | function generateVideoFilename (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, isHls: boolean, resolution: number, extname: string) { |
10 | const video = extractVideo(videoOrPlaylist) | 10 | const video = extractVideo(videoOrPlaylist) |
11 | 11 | ||
12 | if (videoFile.isHLS()) { | 12 | // FIXME: use a generated uuid instead, that will break compatibility with PeerTube < 3.2 |
13 | return generateVideoStreamingPlaylistName(video.uuid, videoFile.resolution) | 13 | // const uuid = uuidv4() |
14 | const uuid = video.uuid | ||
15 | |||
16 | if (isHls) { | ||
17 | return generateVideoStreamingPlaylistName(uuid, resolution) | ||
14 | } | 18 | } |
15 | 19 | ||
16 | return generateWebTorrentVideoName(video.uuid, videoFile.resolution, videoFile.extname) | 20 | return generateWebTorrentVideoName(uuid, resolution, extname) |
17 | } | 21 | } |
18 | 22 | ||
19 | function generateVideoStreamingPlaylistName (uuid: string, resolution: number) { | 23 | function generateVideoStreamingPlaylistName (uuid: string, resolution: number) { |
@@ -28,36 +32,64 @@ function getVideoFilePath (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, vi | |||
28 | if (videoFile.isHLS()) { | 32 | if (videoFile.isHLS()) { |
29 | const video = extractVideo(videoOrPlaylist) | 33 | const video = extractVideo(videoOrPlaylist) |
30 | 34 | ||
31 | return join(getHLSDirectory(video), getVideoFilename(videoOrPlaylist, videoFile)) | 35 | return join(getHLSDirectory(video), videoFile.filename) |
32 | } | 36 | } |
33 | 37 | ||
34 | const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR | 38 | const baseDir = isRedundancy |
35 | return join(baseDir, getVideoFilename(videoOrPlaylist, videoFile)) | 39 | ? CONFIG.STORAGE.REDUNDANCY_DIR |
40 | : CONFIG.STORAGE.VIDEOS_DIR | ||
41 | |||
42 | return join(baseDir, videoFile.filename) | ||
43 | } | ||
44 | |||
45 | // ################## Redundancy ################## | ||
46 | |||
47 | function generateHLSRedundancyUrl (video: MVideo, playlist: MStreamingPlaylist) { | ||
48 | // Base URL used by our HLS player | ||
49 | return WEBSERVER.URL + STATIC_PATHS.REDUNDANCY + playlist.getStringType() + '/' + video.uuid | ||
50 | } | ||
51 | |||
52 | function generateWebTorrentRedundancyUrl (file: MVideoFile) { | ||
53 | return WEBSERVER.URL + STATIC_PATHS.REDUNDANCY + file.filename | ||
36 | } | 54 | } |
37 | 55 | ||
38 | // ################## Streaming playlist ################## | 56 | // ################## Streaming playlist ################## |
39 | 57 | ||
40 | function getHLSDirectory (video: MVideoUUID, isRedundancy = false) { | 58 | function getHLSDirectory (video: MVideoUUID, isRedundancy = false) { |
41 | const baseDir = isRedundancy ? HLS_REDUNDANCY_DIRECTORY : HLS_STREAMING_PLAYLIST_DIRECTORY | 59 | const baseDir = isRedundancy |
60 | ? HLS_REDUNDANCY_DIRECTORY | ||
61 | : HLS_STREAMING_PLAYLIST_DIRECTORY | ||
42 | 62 | ||
43 | return join(baseDir, video.uuid) | 63 | return join(baseDir, video.uuid) |
44 | } | 64 | } |
45 | 65 | ||
46 | // ################## Torrents ################## | 66 | // ################## Torrents ################## |
47 | 67 | ||
48 | function getTorrentFileName (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { | 68 | function generateTorrentFileName (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, resolution: number) { |
49 | const video = extractVideo(videoOrPlaylist) | 69 | const video = extractVideo(videoOrPlaylist) |
50 | const extension = '.torrent' | 70 | const extension = '.torrent' |
51 | 71 | ||
72 | // FIXME: use a generated uuid instead, that will break compatibility with PeerTube < 3.2 | ||
73 | // const uuid = uuidv4() | ||
74 | const uuid = video.uuid | ||
75 | |||
52 | if (isStreamingPlaylist(videoOrPlaylist)) { | 76 | if (isStreamingPlaylist(videoOrPlaylist)) { |
53 | return `${video.uuid}-${videoFile.resolution}-${videoOrPlaylist.getStringType()}${extension}` | 77 | return `${uuid}-${resolution}-${videoOrPlaylist.getStringType()}${extension}` |
54 | } | 78 | } |
55 | 79 | ||
56 | return video.uuid + '-' + videoFile.resolution + extension | 80 | return uuid + '-' + resolution + extension |
81 | } | ||
82 | |||
83 | function getTorrentFilePath (videoFile: MVideoFile) { | ||
84 | return join(CONFIG.STORAGE.TORRENTS_DIR, videoFile.torrentFilename) | ||
57 | } | 85 | } |
58 | 86 | ||
59 | function getTorrentFilePath (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { | 87 | // ################## Meta data ################## |
60 | return join(CONFIG.STORAGE.TORRENTS_DIR, getTorrentFileName(videoOrPlaylist, videoFile)) | 88 | |
89 | function getLocalVideoFileMetadataUrl (video: MVideoUUID, videoFile: MVideoFile) { | ||
90 | const path = '/api/v1/videos/' | ||
91 | |||
92 | return WEBSERVER.URL + path + video.uuid + '/metadata/' + videoFile.id | ||
61 | } | 93 | } |
62 | 94 | ||
63 | // --------------------------------------------------------------------------- | 95 | // --------------------------------------------------------------------------- |
@@ -65,11 +97,16 @@ function getTorrentFilePath (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, | |||
65 | export { | 97 | export { |
66 | generateVideoStreamingPlaylistName, | 98 | generateVideoStreamingPlaylistName, |
67 | generateWebTorrentVideoName, | 99 | generateWebTorrentVideoName, |
68 | getVideoFilename, | 100 | generateVideoFilename, |
69 | getVideoFilePath, | 101 | getVideoFilePath, |
70 | 102 | ||
71 | getTorrentFileName, | 103 | generateTorrentFileName, |
72 | getTorrentFilePath, | 104 | getTorrentFilePath, |
73 | 105 | ||
74 | getHLSDirectory | 106 | getHLSDirectory, |
107 | |||
108 | getLocalVideoFileMetadataUrl, | ||
109 | |||
110 | generateWebTorrentRedundancyUrl, | ||
111 | generateHLSRedundancyUrl | ||
75 | } | 112 | } |
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index a58c9dd20..b366e2e44 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts | |||
@@ -2,7 +2,7 @@ import { Job } from 'bull' | |||
2 | import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' | 2 | import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' |
3 | import { basename, extname as extnameUtil, join } from 'path' | 3 | import { basename, extname as extnameUtil, join } from 'path' |
4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | 4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' |
5 | import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoWithAllFiles, MVideoWithFile } from '@server/types/models' | 5 | import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoFullLight } from '@server/types/models' |
6 | import { VideoResolution } from '../../shared/models/videos' | 6 | import { VideoResolution } from '../../shared/models/videos' |
7 | import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' | 7 | import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' |
8 | import { transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils' | 8 | import { transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils' |
@@ -13,7 +13,7 @@ import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSER | |||
13 | import { VideoFileModel } from '../models/video/video-file' | 13 | import { VideoFileModel } from '../models/video/video-file' |
14 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' | 14 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' |
15 | import { updateMasterHLSPlaylist, updateSha256VODSegments } from './hls' | 15 | import { updateMasterHLSPlaylist, updateSha256VODSegments } from './hls' |
16 | import { generateVideoStreamingPlaylistName, getVideoFilename, getVideoFilePath } from './video-paths' | 16 | import { generateVideoFilename, generateVideoStreamingPlaylistName, getVideoFilePath } from './video-paths' |
17 | import { VideoTranscodingProfilesManager } from './video-transcoding-profiles' | 17 | import { VideoTranscodingProfilesManager } from './video-transcoding-profiles' |
18 | 18 | ||
19 | /** | 19 | /** |
@@ -24,7 +24,7 @@ import { VideoTranscodingProfilesManager } from './video-transcoding-profiles' | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | // Optimize the original video file and replace it. The resolution is not changed. | 26 | // Optimize the original video file and replace it. The resolution is not changed. |
27 | async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFile: MVideoFile, job?: Job) { | 27 | async function optimizeOriginalVideofile (video: MVideoFullLight, inputVideoFile: MVideoFile, job?: Job) { |
28 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | 28 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR |
29 | const newExtname = '.mp4' | 29 | const newExtname = '.mp4' |
30 | 30 | ||
@@ -55,8 +55,9 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFile: | |||
55 | try { | 55 | try { |
56 | await remove(videoInputPath) | 56 | await remove(videoInputPath) |
57 | 57 | ||
58 | // Important to do this before getVideoFilename() to take in account the new file extension | 58 | // Important to do this before getVideoFilename() to take in account the new filename |
59 | inputVideoFile.extname = newExtname | 59 | inputVideoFile.extname = newExtname |
60 | inputVideoFile.filename = generateVideoFilename(video, false, inputVideoFile.resolution, newExtname) | ||
60 | 61 | ||
61 | const videoOutputPath = getVideoFilePath(video, inputVideoFile) | 62 | const videoOutputPath = getVideoFilePath(video, inputVideoFile) |
62 | 63 | ||
@@ -72,7 +73,7 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFile: | |||
72 | } | 73 | } |
73 | 74 | ||
74 | // Transcode the original video file to a lower resolution. | 75 | // Transcode the original video file to a lower resolution. |
75 | async function transcodeNewWebTorrentResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean, job: Job) { | 76 | async function transcodeNewWebTorrentResolution (video: MVideoFullLight, resolution: VideoResolution, isPortrait: boolean, job: Job) { |
76 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | 77 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR |
77 | const extname = '.mp4' | 78 | const extname = '.mp4' |
78 | 79 | ||
@@ -82,11 +83,13 @@ async function transcodeNewWebTorrentResolution (video: MVideoWithFile, resoluti | |||
82 | const newVideoFile = new VideoFileModel({ | 83 | const newVideoFile = new VideoFileModel({ |
83 | resolution, | 84 | resolution, |
84 | extname, | 85 | extname, |
86 | filename: generateVideoFilename(video, false, resolution, extname), | ||
85 | size: 0, | 87 | size: 0, |
86 | videoId: video.id | 88 | videoId: video.id |
87 | }) | 89 | }) |
90 | |||
88 | const videoOutputPath = getVideoFilePath(video, newVideoFile) | 91 | const videoOutputPath = getVideoFilePath(video, newVideoFile) |
89 | const videoTranscodedPath = join(transcodeDirectory, getVideoFilename(video, newVideoFile)) | 92 | const videoTranscodedPath = join(transcodeDirectory, newVideoFile.filename) |
90 | 93 | ||
91 | const transcodeOptions = resolution === VideoResolution.H_NOVIDEO | 94 | const transcodeOptions = resolution === VideoResolution.H_NOVIDEO |
92 | ? { | 95 | ? { |
@@ -122,7 +125,7 @@ async function transcodeNewWebTorrentResolution (video: MVideoWithFile, resoluti | |||
122 | } | 125 | } |
123 | 126 | ||
124 | // Merge an image with an audio file to create a video | 127 | // Merge an image with an audio file to create a video |
125 | async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: VideoResolution, job: Job) { | 128 | async function mergeAudioVideofile (video: MVideoFullLight, resolution: VideoResolution, job: Job) { |
126 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | 129 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR |
127 | const newExtname = '.mp4' | 130 | const newExtname = '.mp4' |
128 | 131 | ||
@@ -175,7 +178,7 @@ async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: Video | |||
175 | 178 | ||
176 | // Concat TS segments from a live video to a fragmented mp4 HLS playlist | 179 | // Concat TS segments from a live video to a fragmented mp4 HLS playlist |
177 | async function generateHlsPlaylistResolutionFromTS (options: { | 180 | async function generateHlsPlaylistResolutionFromTS (options: { |
178 | video: MVideoWithFile | 181 | video: MVideoFullLight |
179 | concatenatedTsFilePath: string | 182 | concatenatedTsFilePath: string |
180 | resolution: VideoResolution | 183 | resolution: VideoResolution |
181 | isPortraitMode: boolean | 184 | isPortraitMode: boolean |
@@ -193,7 +196,7 @@ async function generateHlsPlaylistResolutionFromTS (options: { | |||
193 | 196 | ||
194 | // Generate an HLS playlist from an input file, and update the master playlist | 197 | // Generate an HLS playlist from an input file, and update the master playlist |
195 | function generateHlsPlaylistResolution (options: { | 198 | function generateHlsPlaylistResolution (options: { |
196 | video: MVideoWithFile | 199 | video: MVideoFullLight |
197 | videoInputPath: string | 200 | videoInputPath: string |
198 | resolution: VideoResolution | 201 | resolution: VideoResolution |
199 | copyCodecs: boolean | 202 | copyCodecs: boolean |
@@ -235,7 +238,7 @@ export { | |||
235 | // --------------------------------------------------------------------------- | 238 | // --------------------------------------------------------------------------- |
236 | 239 | ||
237 | async function onWebTorrentVideoFileTranscoding ( | 240 | async function onWebTorrentVideoFileTranscoding ( |
238 | video: MVideoWithFile, | 241 | video: MVideoFullLight, |
239 | videoFile: MVideoFile, | 242 | videoFile: MVideoFile, |
240 | transcodingPath: string, | 243 | transcodingPath: string, |
241 | outputPath: string | 244 | outputPath: string |
@@ -250,7 +253,7 @@ async function onWebTorrentVideoFileTranscoding ( | |||
250 | videoFile.fps = fps | 253 | videoFile.fps = fps |
251 | videoFile.metadata = metadata | 254 | videoFile.metadata = metadata |
252 | 255 | ||
253 | await createTorrentAndSetInfoHash(video, videoFile) | 256 | await createTorrentAndSetInfoHash(video, video, videoFile) |
254 | 257 | ||
255 | await VideoFileModel.customUpsert(videoFile, 'video', undefined) | 258 | await VideoFileModel.customUpsert(videoFile, 'video', undefined) |
256 | video.VideoFiles = await video.$get('VideoFiles') | 259 | video.VideoFiles = await video.$get('VideoFiles') |
@@ -260,7 +263,7 @@ async function onWebTorrentVideoFileTranscoding ( | |||
260 | 263 | ||
261 | async function generateHlsPlaylistCommon (options: { | 264 | async function generateHlsPlaylistCommon (options: { |
262 | type: 'hls' | 'hls-from-ts' | 265 | type: 'hls' | 'hls-from-ts' |
263 | video: MVideoWithFile | 266 | video: MVideoFullLight |
264 | inputPath: string | 267 | inputPath: string |
265 | resolution: VideoResolution | 268 | resolution: VideoResolution |
266 | copyCodecs?: boolean | 269 | copyCodecs?: boolean |
@@ -318,10 +321,12 @@ async function generateHlsPlaylistCommon (options: { | |||
318 | videoStreamingPlaylist.Video = video | 321 | videoStreamingPlaylist.Video = video |
319 | 322 | ||
320 | // Build the new playlist file | 323 | // Build the new playlist file |
324 | const extname = extnameUtil(videoFilename) | ||
321 | const newVideoFile = new VideoFileModel({ | 325 | const newVideoFile = new VideoFileModel({ |
322 | resolution, | 326 | resolution, |
323 | extname: extnameUtil(videoFilename), | 327 | extname, |
324 | size: 0, | 328 | size: 0, |
329 | filename: generateVideoFilename(video, true, resolution, extname), | ||
325 | fps: -1, | 330 | fps: -1, |
326 | videoStreamingPlaylistId: videoStreamingPlaylist.id | 331 | videoStreamingPlaylistId: videoStreamingPlaylist.id |
327 | }) | 332 | }) |
@@ -344,7 +349,7 @@ async function generateHlsPlaylistCommon (options: { | |||
344 | newVideoFile.fps = await getVideoFileFPS(videoFilePath) | 349 | newVideoFile.fps = await getVideoFileFPS(videoFilePath) |
345 | newVideoFile.metadata = await getMetadataFromFile(videoFilePath) | 350 | newVideoFile.metadata = await getMetadataFromFile(videoFilePath) |
346 | 351 | ||
347 | await createTorrentAndSetInfoHash(videoStreamingPlaylist, newVideoFile) | 352 | await createTorrentAndSetInfoHash(videoStreamingPlaylist, video, newVideoFile) |
348 | 353 | ||
349 | await VideoFileModel.customUpsert(newVideoFile, 'streaming-playlist', undefined) | 354 | await VideoFileModel.customUpsert(newVideoFile, 'streaming-playlist', undefined) |
350 | videoStreamingPlaylist.VideoFiles = await videoStreamingPlaylist.$get('VideoFiles') | 355 | videoStreamingPlaylist.VideoFiles = await videoStreamingPlaylist.$get('VideoFiles') |