diff options
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/video-interface.ts | 3 | ||||
-rw-r--r-- | server/models/video/video.ts | 78 |
2 files changed, 64 insertions, 17 deletions
diff --git a/server/models/video/video-interface.ts b/server/models/video/video-interface.ts index 587652f45..cfe65f9aa 100644 --- a/server/models/video/video-interface.ts +++ b/server/models/video/video-interface.ts | |||
@@ -49,6 +49,7 @@ export namespace VideoMethods { | |||
49 | export type ListOwnedByAuthor = (author: string) => Promise<VideoInstance[]> | 49 | export type ListOwnedByAuthor = (author: string) => Promise<VideoInstance[]> |
50 | 50 | ||
51 | export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<VideoInstance> > | 51 | export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<VideoInstance> > |
52 | export type ListUserVideosForApi = (userId: number, start: number, count: number, sort: string) => Promise< ResultList<VideoInstance> > | ||
52 | export type SearchAndPopulateAuthorAndPodAndTags = ( | 53 | export type SearchAndPopulateAuthorAndPodAndTags = ( |
53 | value: string, | 54 | value: string, |
54 | field: string, | 55 | field: string, |
@@ -75,6 +76,7 @@ export interface VideoClass { | |||
75 | generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData | 76 | generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData |
76 | list: VideoMethods.List | 77 | list: VideoMethods.List |
77 | listForApi: VideoMethods.ListForApi | 78 | listForApi: VideoMethods.ListForApi |
79 | listUserVideosForApi: VideoMethods.ListUserVideosForApi | ||
78 | listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags | 80 | listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags |
79 | listOwnedByAuthor: VideoMethods.ListOwnedByAuthor | 81 | listOwnedByAuthor: VideoMethods.ListOwnedByAuthor |
80 | load: VideoMethods.Load | 82 | load: VideoMethods.Load |
@@ -97,6 +99,7 @@ export interface VideoAttributes { | |||
97 | nsfw: boolean | 99 | nsfw: boolean |
98 | description: string | 100 | description: string |
99 | duration: number | 101 | duration: number |
102 | privacy: number | ||
100 | views?: number | 103 | views?: number |
101 | likes?: number | 104 | likes?: number |
102 | dislikes?: number | 105 | dislikes?: number |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 1877c506a..2c1bd6b6e 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -18,6 +18,7 @@ import { | |||
18 | isVideoNSFWValid, | 18 | isVideoNSFWValid, |
19 | isVideoDescriptionValid, | 19 | isVideoDescriptionValid, |
20 | isVideoDurationValid, | 20 | isVideoDurationValid, |
21 | isVideoPrivacyValid, | ||
21 | readFileBufferPromise, | 22 | readFileBufferPromise, |
22 | unlinkPromise, | 23 | unlinkPromise, |
23 | renamePromise, | 24 | renamePromise, |
@@ -38,10 +39,11 @@ import { | |||
38 | THUMBNAILS_SIZE, | 39 | THUMBNAILS_SIZE, |
39 | PREVIEWS_SIZE, | 40 | PREVIEWS_SIZE, |
40 | CONSTRAINTS_FIELDS, | 41 | CONSTRAINTS_FIELDS, |
41 | API_VERSION | 42 | API_VERSION, |
43 | VIDEO_PRIVACIES | ||
42 | } from '../../initializers' | 44 | } from '../../initializers' |
43 | import { removeVideoToFriends } from '../../lib' | 45 | import { removeVideoToFriends } from '../../lib' |
44 | import { VideoResolution } from '../../../shared' | 46 | import { VideoResolution, VideoPrivacy } from '../../../shared' |
45 | import { VideoFileInstance, VideoFileModel } from './video-file-interface' | 47 | import { VideoFileInstance, VideoFileModel } from './video-file-interface' |
46 | 48 | ||
47 | import { addMethodsToModel, getSort } from '../utils' | 49 | import { addMethodsToModel, getSort } from '../utils' |
@@ -79,6 +81,7 @@ let getTruncatedDescription: VideoMethods.GetTruncatedDescription | |||
79 | let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData | 81 | let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData |
80 | let list: VideoMethods.List | 82 | let list: VideoMethods.List |
81 | let listForApi: VideoMethods.ListForApi | 83 | let listForApi: VideoMethods.ListForApi |
84 | let listUserVideosForApi: VideoMethods.ListUserVideosForApi | ||
82 | let loadByHostAndUUID: VideoMethods.LoadByHostAndUUID | 85 | let loadByHostAndUUID: VideoMethods.LoadByHostAndUUID |
83 | let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags | 86 | let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags |
84 | let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor | 87 | let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor |
@@ -146,6 +149,16 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
146 | } | 149 | } |
147 | } | 150 | } |
148 | }, | 151 | }, |
152 | privacy: { | ||
153 | type: DataTypes.INTEGER, | ||
154 | allowNull: false, | ||
155 | validate: { | ||
156 | privacyValid: value => { | ||
157 | const res = isVideoPrivacyValid(value) | ||
158 | if (res === false) throw new Error('Video privacy is not valid.') | ||
159 | } | ||
160 | } | ||
161 | }, | ||
149 | nsfw: { | 162 | nsfw: { |
150 | type: DataTypes.BOOLEAN, | 163 | type: DataTypes.BOOLEAN, |
151 | allowNull: false, | 164 | allowNull: false, |
@@ -245,6 +258,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
245 | generateThumbnailFromData, | 258 | generateThumbnailFromData, |
246 | list, | 259 | list, |
247 | listForApi, | 260 | listForApi, |
261 | listUserVideosForApi, | ||
248 | listOwnedAndPopulateAuthorAndTags, | 262 | listOwnedAndPopulateAuthorAndTags, |
249 | listOwnedByAuthor, | 263 | listOwnedByAuthor, |
250 | load, | 264 | load, |
@@ -501,7 +515,13 @@ toFormattedJSON = function (this: VideoInstance) { | |||
501 | toFormattedDetailsJSON = function (this: VideoInstance) { | 515 | toFormattedDetailsJSON = function (this: VideoInstance) { |
502 | const formattedJson = this.toFormattedJSON() | 516 | const formattedJson = this.toFormattedJSON() |
503 | 517 | ||
518 | // Maybe our pod is not up to date and there are new privacy settings since our version | ||
519 | let privacyLabel = VIDEO_PRIVACIES[this.privacy] | ||
520 | if (!privacyLabel) privacyLabel = 'Unknown' | ||
521 | |||
504 | const detailsJson = { | 522 | const detailsJson = { |
523 | privacyLabel, | ||
524 | privacy: this.privacy, | ||
505 | descriptionPath: this.getDescriptionPath(), | 525 | descriptionPath: this.getDescriptionPath(), |
506 | channel: this.VideoChannel.toFormattedJSON(), | 526 | channel: this.VideoChannel.toFormattedJSON(), |
507 | files: [] | 527 | files: [] |
@@ -555,6 +575,7 @@ toAddRemoteJSON = function (this: VideoInstance) { | |||
555 | views: this.views, | 575 | views: this.views, |
556 | likes: this.likes, | 576 | likes: this.likes, |
557 | dislikes: this.dislikes, | 577 | dislikes: this.dislikes, |
578 | privacy: this.privacy, | ||
558 | files: [] | 579 | files: [] |
559 | } | 580 | } |
560 | 581 | ||
@@ -587,6 +608,7 @@ toUpdateRemoteJSON = function (this: VideoInstance) { | |||
587 | views: this.views, | 608 | views: this.views, |
588 | likes: this.likes, | 609 | likes: this.likes, |
589 | dislikes: this.dislikes, | 610 | dislikes: this.dislikes, |
611 | privacy: this.privacy, | ||
590 | files: [] | 612 | files: [] |
591 | } | 613 | } |
592 | 614 | ||
@@ -746,8 +768,39 @@ list = function () { | |||
746 | return Video.findAll(query) | 768 | return Video.findAll(query) |
747 | } | 769 | } |
748 | 770 | ||
771 | listUserVideosForApi = function (userId: number, start: number, count: number, sort: string) { | ||
772 | const query = { | ||
773 | distinct: true, | ||
774 | offset: start, | ||
775 | limit: count, | ||
776 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ], | ||
777 | include: [ | ||
778 | { | ||
779 | model: Video['sequelize'].models.VideoChannel, | ||
780 | required: true, | ||
781 | include: [ | ||
782 | { | ||
783 | model: Video['sequelize'].models.Author, | ||
784 | where: { | ||
785 | userId | ||
786 | }, | ||
787 | required: true | ||
788 | } | ||
789 | ] | ||
790 | }, | ||
791 | Video['sequelize'].models.Tag | ||
792 | ] | ||
793 | } | ||
794 | |||
795 | return Video.findAndCountAll(query).then(({ rows, count }) => { | ||
796 | return { | ||
797 | data: rows, | ||
798 | total: count | ||
799 | } | ||
800 | }) | ||
801 | } | ||
802 | |||
749 | listForApi = function (start: number, count: number, sort: string) { | 803 | listForApi = function (start: number, count: number, sort: string) { |
750 | // Exclude blacklisted videos from the list | ||
751 | const query = { | 804 | const query = { |
752 | distinct: true, | 805 | distinct: true, |
753 | offset: start, | 806 | offset: start, |
@@ -768,8 +821,7 @@ listForApi = function (start: number, count: number, sort: string) { | |||
768 | } | 821 | } |
769 | ] | 822 | ] |
770 | }, | 823 | }, |
771 | Video['sequelize'].models.Tag, | 824 | Video['sequelize'].models.Tag |
772 | Video['sequelize'].models.VideoFile | ||
773 | ], | 825 | ], |
774 | where: createBaseVideosWhere() | 826 | where: createBaseVideosWhere() |
775 | } | 827 | } |
@@ -969,10 +1021,6 @@ searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, s | |||
969 | model: Video['sequelize'].models.Tag | 1021 | model: Video['sequelize'].models.Tag |
970 | } | 1022 | } |
971 | 1023 | ||
972 | const videoFileInclude: Sequelize.IncludeOptions = { | ||
973 | model: Video['sequelize'].models.VideoFile | ||
974 | } | ||
975 | |||
976 | const query: Sequelize.FindOptions<VideoAttributes> = { | 1024 | const query: Sequelize.FindOptions<VideoAttributes> = { |
977 | distinct: true, | 1025 | distinct: true, |
978 | where: createBaseVideosWhere(), | 1026 | where: createBaseVideosWhere(), |
@@ -981,12 +1029,7 @@ searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, s | |||
981 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ] | 1029 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ] |
982 | } | 1030 | } |
983 | 1031 | ||
984 | // Make an exact search with the magnet | 1032 | if (field === 'tags') { |
985 | if (field === 'magnetUri') { | ||
986 | videoFileInclude.where = { | ||
987 | infoHash: magnetUtil.decode(value).infoHash | ||
988 | } | ||
989 | } else if (field === 'tags') { | ||
990 | const escapedValue = Video['sequelize'].escape('%' + value + '%') | 1033 | const escapedValue = Video['sequelize'].escape('%' + value + '%') |
991 | query.where['id'][Sequelize.Op.in] = Video['sequelize'].literal( | 1034 | query.where['id'][Sequelize.Op.in] = Video['sequelize'].literal( |
992 | `(SELECT "VideoTags"."videoId" | 1035 | `(SELECT "VideoTags"."videoId" |
@@ -1016,7 +1059,7 @@ searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, s | |||
1016 | } | 1059 | } |
1017 | 1060 | ||
1018 | query.include = [ | 1061 | query.include = [ |
1019 | videoChannelInclude, tagInclude, videoFileInclude | 1062 | videoChannelInclude, tagInclude |
1020 | ] | 1063 | ] |
1021 | 1064 | ||
1022 | return Video.findAndCountAll(query).then(({ rows, count }) => { | 1065 | return Video.findAndCountAll(query).then(({ rows, count }) => { |
@@ -1035,7 +1078,8 @@ function createBaseVideosWhere () { | |||
1035 | [Sequelize.Op.notIn]: Video['sequelize'].literal( | 1078 | [Sequelize.Op.notIn]: Video['sequelize'].literal( |
1036 | '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")' | 1079 | '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")' |
1037 | ) | 1080 | ) |
1038 | } | 1081 | }, |
1082 | privacy: VideoPrivacy.PUBLIC | ||
1039 | } | 1083 | } |
1040 | } | 1084 | } |
1041 | 1085 | ||