diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-03-10 14:39:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-10 14:39:40 +0100 |
commit | 8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4 (patch) | |
tree | 1f87041b2cd76222844960602cdc9f52fe206c7b /server/models/video/video-file.ts | |
parent | edb868655e52f934a71141175cf9dc6cb4753e11 (diff) | |
download | PeerTube-8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4.tar.gz PeerTube-8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4.tar.zst PeerTube-8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4.zip |
Add video file metadata to download modal, via ffprobe (#2411)
* Add video file metadata via ffprobe
* Federate video file metadata
* Add tests for file metadata generation
* Complete tests for videoFile metadata federation
* Lint migration and video-file for metadata
* Objectify metadata from getter in ffmpeg-utils
* Add metadataUrl to all videoFiles
* Simplify metadata API middleware
* Load playlist in videoFile when requesting metadata
Diffstat (limited to 'server/models/video/video-file.ts')
-rw-r--r-- | server/models/video/video-file.ts | 96 |
1 files changed, 86 insertions, 10 deletions
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index e08999385..029468004 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts | |||
@@ -10,7 +10,9 @@ import { | |||
10 | Is, | 10 | Is, |
11 | Model, | 11 | Model, |
12 | Table, | 12 | Table, |
13 | UpdatedAt | 13 | UpdatedAt, |
14 | Scopes, | ||
15 | DefaultScope | ||
14 | } from 'sequelize-typescript' | 16 | } from 'sequelize-typescript' |
15 | import { | 17 | import { |
16 | isVideoFileExtnameValid, | 18 | isVideoFileExtnameValid, |
@@ -29,6 +31,60 @@ import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '. | |||
29 | import { MStreamingPlaylistVideo, MVideo } from '@server/typings/models' | 31 | import { MStreamingPlaylistVideo, MVideo } from '@server/typings/models' |
30 | import * as memoizee from 'memoizee' | 32 | import * as memoizee from 'memoizee' |
31 | 33 | ||
34 | export enum ScopeNames { | ||
35 | WITH_VIDEO = 'WITH_VIDEO', | ||
36 | WITH_VIDEO_OR_PLAYLIST = 'WITH_VIDEO_OR_PLAYLIST', | ||
37 | WITH_METADATA = 'WITH_METADATA' | ||
38 | } | ||
39 | |||
40 | const METADATA_FIELDS = [ 'metadata', 'metadataUrl' ] | ||
41 | |||
42 | @DefaultScope(() => ({ | ||
43 | attributes: { | ||
44 | exclude: [ METADATA_FIELDS[0] ] | ||
45 | } | ||
46 | })) | ||
47 | @Scopes(() => ({ | ||
48 | [ScopeNames.WITH_VIDEO]: { | ||
49 | include: [ | ||
50 | { | ||
51 | model: VideoModel.unscoped(), | ||
52 | required: true | ||
53 | } | ||
54 | ] | ||
55 | }, | ||
56 | [ScopeNames.WITH_VIDEO_OR_PLAYLIST]: (videoIdOrUUID: string | number) => { | ||
57 | const where = (typeof videoIdOrUUID === 'number') | ||
58 | ? { id: videoIdOrUUID } | ||
59 | : { uuid: videoIdOrUUID } | ||
60 | |||
61 | return { | ||
62 | include: [ | ||
63 | { | ||
64 | model: VideoModel.unscoped(), | ||
65 | required: false, | ||
66 | where | ||
67 | }, | ||
68 | { | ||
69 | model: VideoStreamingPlaylistModel.unscoped(), | ||
70 | required: false, | ||
71 | include: [ | ||
72 | { | ||
73 | model: VideoModel.unscoped(), | ||
74 | required: true, | ||
75 | where | ||
76 | } | ||
77 | ] | ||
78 | } | ||
79 | ] | ||
80 | } | ||
81 | }, | ||
82 | [ScopeNames.WITH_METADATA]: { | ||
83 | attributes: { | ||
84 | include: METADATA_FIELDS | ||
85 | } | ||
86 | } | ||
87 | })) | ||
32 | @Table({ | 88 | @Table({ |
33 | tableName: 'videoFile', | 89 | tableName: 'videoFile', |
34 | indexes: [ | 90 | indexes: [ |
@@ -106,6 +162,14 @@ export class VideoFileModel extends Model<VideoFileModel> { | |||
106 | @Column | 162 | @Column |
107 | fps: number | 163 | fps: number |
108 | 164 | ||
165 | @AllowNull(true) | ||
166 | @Column(DataType.JSONB) | ||
167 | metadata: any | ||
168 | |||
169 | @AllowNull(true) | ||
170 | @Column | ||
171 | metadataUrl: string | ||
172 | |||
109 | @ForeignKey(() => VideoModel) | 173 | @ForeignKey(() => VideoModel) |
110 | @Column | 174 | @Column |
111 | videoId: number | 175 | videoId: number |
@@ -157,17 +221,29 @@ export class VideoFileModel extends Model<VideoFileModel> { | |||
157 | .then(results => results.length === 1) | 221 | .then(results => results.length === 1) |
158 | } | 222 | } |
159 | 223 | ||
224 | static async doesVideoExistForVideoFile (id: number, videoIdOrUUID: number | string) { | ||
225 | const videoFile = await VideoFileModel.loadWithVideoOrPlaylist(id, videoIdOrUUID) | ||
226 | return (videoFile?.Video.id === videoIdOrUUID) || | ||
227 | (videoFile?.Video.uuid === videoIdOrUUID) || | ||
228 | (videoFile?.VideoStreamingPlaylist?.Video?.id === videoIdOrUUID) || | ||
229 | (videoFile?.VideoStreamingPlaylist?.Video?.uuid === videoIdOrUUID) | ||
230 | } | ||
231 | |||
232 | static loadWithMetadata (id: number) { | ||
233 | return VideoFileModel.scope(ScopeNames.WITH_METADATA).findByPk(id) | ||
234 | } | ||
235 | |||
160 | static loadWithVideo (id: number) { | 236 | static loadWithVideo (id: number) { |
161 | const options = { | 237 | return VideoFileModel.scope(ScopeNames.WITH_VIDEO).findByPk(id) |
162 | include: [ | 238 | } |
163 | { | ||
164 | model: VideoModel.unscoped(), | ||
165 | required: true | ||
166 | } | ||
167 | ] | ||
168 | } | ||
169 | 239 | ||
170 | return VideoFileModel.findByPk(id, options) | 240 | static loadWithVideoOrPlaylist (id: number, videoIdOrUUID: number | string) { |
241 | return VideoFileModel.scope({ | ||
242 | method: [ | ||
243 | ScopeNames.WITH_VIDEO_OR_PLAYLIST, | ||
244 | videoIdOrUUID | ||
245 | ] | ||
246 | }).findByPk(id) | ||
171 | } | 247 | } |
172 | 248 | ||
173 | static listByStreamingPlaylist (streamingPlaylistId: number, transaction: Transaction) { | 249 | static listByStreamingPlaylist (streamingPlaylistId: number, transaction: Transaction) { |