diff options
author | Chocobozzz <me@florianbigard.com> | 2018-06-12 20:04:58 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-06-12 20:37:51 +0200 |
commit | 2186386cca113506791583cb07d6ccacba7af4e0 (patch) | |
tree | 3c214c0b5fbd64332624267fa6e51fd4a9cf6474 /server/models/video | |
parent | 6ccdf3a23ecec5ba2eeaf487fd1fafdc7606b4bf (diff) | |
download | PeerTube-2186386cca113506791583cb07d6ccacba7af4e0.tar.gz PeerTube-2186386cca113506791583cb07d6ccacba7af4e0.tar.zst PeerTube-2186386cca113506791583cb07d6ccacba7af4e0.zip |
Add concept of video state, and add ability to wait transcoding before
publishing a video
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/video.ts | 132 |
1 files changed, 67 insertions, 65 deletions
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 1cb1e6798..59c378efa 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -25,7 +25,7 @@ import { | |||
25 | Table, | 25 | Table, |
26 | UpdatedAt | 26 | UpdatedAt |
27 | } from 'sequelize-typescript' | 27 | } from 'sequelize-typescript' |
28 | import { VideoPrivacy, VideoResolution } from '../../../shared' | 28 | import { VideoPrivacy, VideoResolution, VideoState } from '../../../shared' |
29 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' | 29 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' |
30 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' | 30 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' |
31 | import { VideoFilter } from '../../../shared/models/videos/video-query.type' | 31 | import { VideoFilter } from '../../../shared/models/videos/video-query.type' |
@@ -47,7 +47,7 @@ import { | |||
47 | isVideoLanguageValid, | 47 | isVideoLanguageValid, |
48 | isVideoLicenceValid, | 48 | isVideoLicenceValid, |
49 | isVideoNameValid, | 49 | isVideoNameValid, |
50 | isVideoPrivacyValid, | 50 | isVideoPrivacyValid, isVideoStateValid, |
51 | isVideoSupportValid | 51 | isVideoSupportValid |
52 | } from '../../helpers/custom-validators/videos' | 52 | } from '../../helpers/custom-validators/videos' |
53 | import { generateImageFromVideoFile, getVideoFileResolution, transcode } from '../../helpers/ffmpeg-utils' | 53 | import { generateImageFromVideoFile, getVideoFileResolution, transcode } from '../../helpers/ffmpeg-utils' |
@@ -66,7 +66,7 @@ import { | |||
66 | VIDEO_EXT_MIMETYPE, | 66 | VIDEO_EXT_MIMETYPE, |
67 | VIDEO_LANGUAGES, | 67 | VIDEO_LANGUAGES, |
68 | VIDEO_LICENCES, | 68 | VIDEO_LICENCES, |
69 | VIDEO_PRIVACIES | 69 | VIDEO_PRIVACIES, VIDEO_STATES |
70 | } from '../../initializers' | 70 | } from '../../initializers' |
71 | import { | 71 | import { |
72 | getVideoCommentsActivityPubUrl, | 72 | getVideoCommentsActivityPubUrl, |
@@ -93,10 +93,7 @@ enum ScopeNames { | |||
93 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', | 93 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', |
94 | WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS', | 94 | WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS', |
95 | WITH_TAGS = 'WITH_TAGS', | 95 | WITH_TAGS = 'WITH_TAGS', |
96 | WITH_FILES = 'WITH_FILES', | 96 | WITH_FILES = 'WITH_FILES' |
97 | WITH_SHARES = 'WITH_SHARES', | ||
98 | WITH_RATES = 'WITH_RATES', | ||
99 | WITH_COMMENTS = 'WITH_COMMENTS' | ||
100 | } | 97 | } |
101 | 98 | ||
102 | @Scopes({ | 99 | @Scopes({ |
@@ -183,7 +180,20 @@ enum ScopeNames { | |||
183 | ')' | 180 | ')' |
184 | ) | 181 | ) |
185 | }, | 182 | }, |
186 | privacy: VideoPrivacy.PUBLIC | 183 | // Always list public videos |
184 | privacy: VideoPrivacy.PUBLIC, | ||
185 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding | ||
186 | [ Sequelize.Op.or ]: [ | ||
187 | { | ||
188 | state: VideoState.PUBLISHED | ||
189 | }, | ||
190 | { | ||
191 | [ Sequelize.Op.and ]: { | ||
192 | state: VideoState.TO_TRANSCODE, | ||
193 | waitTranscoding: false | ||
194 | } | ||
195 | } | ||
196 | ] | ||
187 | }, | 197 | }, |
188 | include: [ videoChannelInclude ] | 198 | include: [ videoChannelInclude ] |
189 | } | 199 | } |
@@ -272,42 +282,6 @@ enum ScopeNames { | |||
272 | required: true | 282 | required: true |
273 | } | 283 | } |
274 | ] | 284 | ] |
275 | }, | ||
276 | [ScopeNames.WITH_SHARES]: { | ||
277 | include: [ | ||
278 | { | ||
279 | ['separate' as any]: true, | ||
280 | model: () => VideoShareModel.unscoped() | ||
281 | } | ||
282 | ] | ||
283 | }, | ||
284 | [ScopeNames.WITH_RATES]: { | ||
285 | include: [ | ||
286 | { | ||
287 | ['separate' as any]: true, | ||
288 | model: () => AccountVideoRateModel, | ||
289 | include: [ | ||
290 | { | ||
291 | model: () => AccountModel.unscoped(), | ||
292 | required: true, | ||
293 | include: [ | ||
294 | { | ||
295 | attributes: [ 'url' ], | ||
296 | model: () => ActorModel.unscoped() | ||
297 | } | ||
298 | ] | ||
299 | } | ||
300 | ] | ||
301 | } | ||
302 | ] | ||
303 | }, | ||
304 | [ScopeNames.WITH_COMMENTS]: { | ||
305 | include: [ | ||
306 | { | ||
307 | ['separate' as any]: true, | ||
308 | model: () => VideoCommentModel.unscoped() | ||
309 | } | ||
310 | ] | ||
311 | } | 285 | } |
312 | }) | 286 | }) |
313 | @Table({ | 287 | @Table({ |
@@ -335,7 +309,7 @@ enum ScopeNames { | |||
335 | fields: [ 'channelId' ] | 309 | fields: [ 'channelId' ] |
336 | }, | 310 | }, |
337 | { | 311 | { |
338 | fields: [ 'id', 'privacy' ] | 312 | fields: [ 'id', 'privacy', 'state', 'waitTranscoding' ] |
339 | }, | 313 | }, |
340 | { | 314 | { |
341 | fields: [ 'url'], | 315 | fields: [ 'url'], |
@@ -435,6 +409,16 @@ export class VideoModel extends Model<VideoModel> { | |||
435 | @Column | 409 | @Column |
436 | commentsEnabled: boolean | 410 | commentsEnabled: boolean |
437 | 411 | ||
412 | @AllowNull(false) | ||
413 | @Column | ||
414 | waitTranscoding: boolean | ||
415 | |||
416 | @AllowNull(false) | ||
417 | @Default(null) | ||
418 | @Is('VideoState', value => throwIfNotValid(value, isVideoStateValid, 'state')) | ||
419 | @Column | ||
420 | state: VideoState | ||
421 | |||
438 | @CreatedAt | 422 | @CreatedAt |
439 | createdAt: Date | 423 | createdAt: Date |
440 | 424 | ||
@@ -671,7 +655,7 @@ export class VideoModel extends Model<VideoModel> { | |||
671 | }) | 655 | }) |
672 | } | 656 | } |
673 | 657 | ||
674 | static listAccountVideosForApi (accountId: number, start: number, count: number, sort: string, hideNSFW: boolean, withFiles = false) { | 658 | static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, hideNSFW: boolean, withFiles = false) { |
675 | const query: IFindOptions<VideoModel> = { | 659 | const query: IFindOptions<VideoModel> = { |
676 | offset: start, | 660 | offset: start, |
677 | limit: count, | 661 | limit: count, |
@@ -858,12 +842,13 @@ export class VideoModel extends Model<VideoModel> { | |||
858 | .findOne(options) | 842 | .findOne(options) |
859 | } | 843 | } |
860 | 844 | ||
861 | static loadByUUIDAndPopulateAccountAndServerAndTags (uuid: string) { | 845 | static loadByUUIDAndPopulateAccountAndServerAndTags (uuid: string, t?: Sequelize.Transaction) { |
862 | const options = { | 846 | const options = { |
863 | order: [ [ 'Tags', 'name', 'ASC' ] ], | 847 | order: [ [ 'Tags', 'name', 'ASC' ] ], |
864 | where: { | 848 | where: { |
865 | uuid | 849 | uuid |
866 | } | 850 | }, |
851 | transaction: t | ||
867 | } | 852 | } |
868 | 853 | ||
869 | return VideoModel | 854 | return VideoModel |
@@ -905,31 +890,23 @@ export class VideoModel extends Model<VideoModel> { | |||
905 | } | 890 | } |
906 | 891 | ||
907 | private static getCategoryLabel (id: number) { | 892 | private static getCategoryLabel (id: number) { |
908 | let categoryLabel = VIDEO_CATEGORIES[id] | 893 | return VIDEO_CATEGORIES[id] || 'Misc' |
909 | if (!categoryLabel) categoryLabel = 'Misc' | ||
910 | |||
911 | return categoryLabel | ||
912 | } | 894 | } |
913 | 895 | ||
914 | private static getLicenceLabel (id: number) { | 896 | private static getLicenceLabel (id: number) { |
915 | let licenceLabel = VIDEO_LICENCES[id] | 897 | return VIDEO_LICENCES[id] || 'Unknown' |
916 | if (!licenceLabel) licenceLabel = 'Unknown' | ||
917 | |||
918 | return licenceLabel | ||
919 | } | 898 | } |
920 | 899 | ||
921 | private static getLanguageLabel (id: string) { | 900 | private static getLanguageLabel (id: string) { |
922 | let languageLabel = VIDEO_LANGUAGES[id] | 901 | return VIDEO_LANGUAGES[id] || 'Unknown' |
923 | if (!languageLabel) languageLabel = 'Unknown' | ||
924 | |||
925 | return languageLabel | ||
926 | } | 902 | } |
927 | 903 | ||
928 | private static getPrivacyLabel (id: number) { | 904 | private static getPrivacyLabel (id: number) { |
929 | let privacyLabel = VIDEO_PRIVACIES[id] | 905 | return VIDEO_PRIVACIES[id] || 'Unknown' |
930 | if (!privacyLabel) privacyLabel = 'Unknown' | 906 | } |
931 | 907 | ||
932 | return privacyLabel | 908 | private static getStateLabel (id: number) { |
909 | return VIDEO_STATES[id] || 'Unknown' | ||
933 | } | 910 | } |
934 | 911 | ||
935 | getOriginalFile () { | 912 | getOriginalFile () { |
@@ -1026,11 +1003,16 @@ export class VideoModel extends Model<VideoModel> { | |||
1026 | return join(STATIC_PATHS.PREVIEWS, this.getPreviewName()) | 1003 | return join(STATIC_PATHS.PREVIEWS, this.getPreviewName()) |
1027 | } | 1004 | } |
1028 | 1005 | ||
1029 | toFormattedJSON (): Video { | 1006 | toFormattedJSON (options?: { |
1007 | additionalAttributes: { | ||
1008 | state: boolean, | ||
1009 | waitTranscoding: boolean | ||
1010 | } | ||
1011 | }): Video { | ||
1030 | const formattedAccount = this.VideoChannel.Account.toFormattedJSON() | 1012 | const formattedAccount = this.VideoChannel.Account.toFormattedJSON() |
1031 | const formattedVideoChannel = this.VideoChannel.toFormattedJSON() | 1013 | const formattedVideoChannel = this.VideoChannel.toFormattedJSON() |
1032 | 1014 | ||
1033 | return { | 1015 | const videoObject: Video = { |
1034 | id: this.id, | 1016 | id: this.id, |
1035 | uuid: this.uuid, | 1017 | uuid: this.uuid, |
1036 | name: this.name, | 1018 | name: this.name, |
@@ -1082,6 +1064,19 @@ export class VideoModel extends Model<VideoModel> { | |||
1082 | avatar: formattedVideoChannel.avatar | 1064 | avatar: formattedVideoChannel.avatar |
1083 | } | 1065 | } |
1084 | } | 1066 | } |
1067 | |||
1068 | if (options) { | ||
1069 | if (options.additionalAttributes.state) { | ||
1070 | videoObject.state = { | ||
1071 | id: this.state, | ||
1072 | label: VideoModel.getStateLabel(this.state) | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | if (options.additionalAttributes.waitTranscoding) videoObject.waitTranscoding = this.waitTranscoding | ||
1077 | } | ||
1078 | |||
1079 | return videoObject | ||
1085 | } | 1080 | } |
1086 | 1081 | ||
1087 | toFormattedDetailsJSON (): VideoDetails { | 1082 | toFormattedDetailsJSON (): VideoDetails { |
@@ -1094,6 +1089,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1094 | account: this.VideoChannel.Account.toFormattedJSON(), | 1089 | account: this.VideoChannel.Account.toFormattedJSON(), |
1095 | tags: map(this.Tags, 'name'), | 1090 | tags: map(this.Tags, 'name'), |
1096 | commentsEnabled: this.commentsEnabled, | 1091 | commentsEnabled: this.commentsEnabled, |
1092 | waitTranscoding: this.waitTranscoding, | ||
1093 | state: { | ||
1094 | id: this.state, | ||
1095 | label: VideoModel.getStateLabel(this.state) | ||
1096 | }, | ||
1097 | files: [] | 1097 | files: [] |
1098 | } | 1098 | } |
1099 | 1099 | ||
@@ -1207,6 +1207,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1207 | language, | 1207 | language, |
1208 | views: this.views, | 1208 | views: this.views, |
1209 | sensitive: this.nsfw, | 1209 | sensitive: this.nsfw, |
1210 | waitTranscoding: this.waitTranscoding, | ||
1211 | state: this.state, | ||
1210 | commentsEnabled: this.commentsEnabled, | 1212 | commentsEnabled: this.commentsEnabled, |
1211 | published: this.publishedAt.toISOString(), | 1213 | published: this.publishedAt.toISOString(), |
1212 | updated: this.updatedAt.toISOString(), | 1214 | updated: this.updatedAt.toISOString(), |