diff options
Diffstat (limited to 'server/models/video/video.ts')
-rw-r--r-- | server/models/video/video.ts | 86 |
1 files changed, 29 insertions, 57 deletions
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index b5c46c86c..26be34329 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -34,12 +34,12 @@ import { VideoPathManager } from '@server/lib/video-path-manager' | |||
34 | import { getServerActor } from '@server/models/application/application' | 34 | import { getServerActor } from '@server/models/application/application' |
35 | import { ModelCache } from '@server/models/model-cache' | 35 | import { ModelCache } from '@server/models/model-cache' |
36 | import { AttributesOnly, buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils' | 36 | import { AttributesOnly, buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils' |
37 | import { VideoInclude } from '@shared/models' | ||
37 | import { VideoFile } from '@shared/models/videos/video-file.model' | 38 | import { VideoFile } from '@shared/models/videos/video-file.model' |
38 | import { ResultList, UserRight, VideoPrivacy, VideoState } from '../../../shared' | 39 | import { ResultList, UserRight, VideoPrivacy, VideoState } from '../../../shared' |
39 | import { VideoObject } from '../../../shared/models/activitypub/objects' | 40 | import { VideoObject } from '../../../shared/models/activitypub/objects' |
40 | import { Video, VideoDetails, VideoRateType, VideoStorage } from '../../../shared/models/videos' | 41 | import { Video, VideoDetails, VideoRateType, VideoStorage } from '../../../shared/models/videos' |
41 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 42 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
42 | import { VideoFilter } from '../../../shared/models/videos/video-query.type' | ||
43 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 43 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
44 | import { peertubeTruncate } from '../../helpers/core-utils' | 44 | import { peertubeTruncate } from '../../helpers/core-utils' |
45 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 45 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
@@ -106,7 +106,7 @@ import { | |||
106 | } from './formatter/video-format-utils' | 106 | } from './formatter/video-format-utils' |
107 | import { ScheduleVideoUpdateModel } from './schedule-video-update' | 107 | import { ScheduleVideoUpdateModel } from './schedule-video-update' |
108 | import { VideosModelGetQueryBuilder } from './sql/video-model-get-query-builder' | 108 | import { VideosModelGetQueryBuilder } from './sql/video-model-get-query-builder' |
109 | import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './sql/videos-id-list-query-builder' | 109 | import { BuildVideosListQueryOptions, DisplayOnlyForFollowerOptions, VideosIdListQueryBuilder } from './sql/videos-id-list-query-builder' |
110 | import { VideosModelListQueryBuilder } from './sql/videos-model-list-query-builder' | 110 | import { VideosModelListQueryBuilder } from './sql/videos-model-list-query-builder' |
111 | import { TagModel } from './tag' | 111 | import { TagModel } from './tag' |
112 | import { ThumbnailModel } from './thumbnail' | 112 | import { ThumbnailModel } from './thumbnail' |
@@ -145,35 +145,6 @@ export type ForAPIOptions = { | |||
145 | withAccountBlockerIds?: number[] | 145 | withAccountBlockerIds?: number[] |
146 | } | 146 | } |
147 | 147 | ||
148 | export type AvailableForListIDsOptions = { | ||
149 | serverAccountId: number | ||
150 | followerActorId: number | ||
151 | includeLocalVideos: boolean | ||
152 | |||
153 | attributesType?: 'none' | 'id' | 'all' | ||
154 | |||
155 | filter?: VideoFilter | ||
156 | categoryOneOf?: number[] | ||
157 | nsfw?: boolean | ||
158 | licenceOneOf?: number[] | ||
159 | languageOneOf?: string[] | ||
160 | tagsOneOf?: string[] | ||
161 | tagsAllOf?: string[] | ||
162 | |||
163 | withFiles?: boolean | ||
164 | |||
165 | accountId?: number | ||
166 | videoChannelId?: number | ||
167 | |||
168 | videoPlaylistId?: number | ||
169 | |||
170 | trendingDays?: number | ||
171 | user?: MUserAccountId | ||
172 | historyOfUser?: MUserId | ||
173 | |||
174 | baseWhere?: WhereOptions[] | ||
175 | } | ||
176 | |||
177 | @Scopes(() => ({ | 148 | @Scopes(() => ({ |
178 | [ScopeNames.WITH_IMMUTABLE_ATTRIBUTES]: { | 149 | [ScopeNames.WITH_IMMUTABLE_ATTRIBUTES]: { |
179 | attributes: [ 'id', 'url', 'uuid', 'remote' ] | 150 | attributes: [ 'id', 'url', 'uuid', 'remote' ] |
@@ -1054,10 +1025,10 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1054 | sort: string | 1025 | sort: string |
1055 | 1026 | ||
1056 | nsfw: boolean | 1027 | nsfw: boolean |
1057 | filter?: VideoFilter | ||
1058 | isLive?: boolean | 1028 | isLive?: boolean |
1029 | isLocal?: boolean | ||
1030 | include?: VideoInclude | ||
1059 | 1031 | ||
1060 | includeLocalVideos: boolean | ||
1061 | withFiles: boolean | 1032 | withFiles: boolean |
1062 | 1033 | ||
1063 | categoryOneOf?: number[] | 1034 | categoryOneOf?: number[] |
@@ -1069,7 +1040,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1069 | accountId?: number | 1040 | accountId?: number |
1070 | videoChannelId?: number | 1041 | videoChannelId?: number |
1071 | 1042 | ||
1072 | followerActorId?: number | 1043 | displayOnlyForFollower: DisplayOnlyForFollowerOptions | null |
1073 | 1044 | ||
1074 | videoPlaylistId?: number | 1045 | videoPlaylistId?: number |
1075 | 1046 | ||
@@ -1082,7 +1053,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1082 | 1053 | ||
1083 | search?: string | 1054 | search?: string |
1084 | }) { | 1055 | }) { |
1085 | if ((options.filter === 'all-local' || options.filter === 'all') && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { | 1056 | if (options.include && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { |
1086 | throw new Error('Try to filter all-local but no user has not the see all videos right') | 1057 | throw new Error('Try to filter all-local but no user has not the see all videos right') |
1087 | } | 1058 | } |
1088 | 1059 | ||
@@ -1096,11 +1067,6 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1096 | 1067 | ||
1097 | const serverActor = await getServerActor() | 1068 | const serverActor = await getServerActor() |
1098 | 1069 | ||
1099 | // followerActorId === null has a meaning, so just check undefined | ||
1100 | const followerActorId = options.followerActorId !== undefined | ||
1101 | ? options.followerActorId | ||
1102 | : serverActor.id | ||
1103 | |||
1104 | const queryOptions = { | 1070 | const queryOptions = { |
1105 | ...pick(options, [ | 1071 | ...pick(options, [ |
1106 | 'start', | 1072 | 'start', |
@@ -1113,19 +1079,19 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1113 | 'languageOneOf', | 1079 | 'languageOneOf', |
1114 | 'tagsOneOf', | 1080 | 'tagsOneOf', |
1115 | 'tagsAllOf', | 1081 | 'tagsAllOf', |
1116 | 'filter', | 1082 | 'isLocal', |
1083 | 'include', | ||
1084 | 'displayOnlyForFollower', | ||
1117 | 'withFiles', | 1085 | 'withFiles', |
1118 | 'accountId', | 1086 | 'accountId', |
1119 | 'videoChannelId', | 1087 | 'videoChannelId', |
1120 | 'videoPlaylistId', | 1088 | 'videoPlaylistId', |
1121 | 'includeLocalVideos', | ||
1122 | 'user', | 1089 | 'user', |
1123 | 'historyOfUser', | 1090 | 'historyOfUser', |
1124 | 'search' | 1091 | 'search' |
1125 | ]), | 1092 | ]), |
1126 | 1093 | ||
1127 | followerActorId, | 1094 | serverAccountIdForBlock: serverActor.Account.id, |
1128 | serverAccountId: serverActor.Account.id, | ||
1129 | trendingDays, | 1095 | trendingDays, |
1130 | trendingAlgorithm | 1096 | trendingAlgorithm |
1131 | } | 1097 | } |
@@ -1137,7 +1103,6 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1137 | start: number | 1103 | start: number |
1138 | count: number | 1104 | count: number |
1139 | sort: string | 1105 | sort: string |
1140 | includeLocalVideos: boolean | ||
1141 | search?: string | 1106 | search?: string |
1142 | host?: string | 1107 | host?: string |
1143 | startDate?: string // ISO 8601 | 1108 | startDate?: string // ISO 8601 |
@@ -1146,6 +1111,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1146 | originallyPublishedEndDate?: string | 1111 | originallyPublishedEndDate?: string |
1147 | nsfw?: boolean | 1112 | nsfw?: boolean |
1148 | isLive?: boolean | 1113 | isLive?: boolean |
1114 | isLocal?: boolean | ||
1115 | include?: VideoInclude | ||
1149 | categoryOneOf?: number[] | 1116 | categoryOneOf?: number[] |
1150 | licenceOneOf?: number[] | 1117 | licenceOneOf?: number[] |
1151 | languageOneOf?: string[] | 1118 | languageOneOf?: string[] |
@@ -1154,14 +1121,14 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1154 | durationMin?: number // seconds | 1121 | durationMin?: number // seconds |
1155 | durationMax?: number // seconds | 1122 | durationMax?: number // seconds |
1156 | user?: MUserAccountId | 1123 | user?: MUserAccountId |
1157 | filter?: VideoFilter | ||
1158 | uuids?: string[] | 1124 | uuids?: string[] |
1125 | displayOnlyForFollower: DisplayOnlyForFollowerOptions | null | ||
1159 | }) { | 1126 | }) { |
1160 | const serverActor = await getServerActor() | 1127 | const serverActor = await getServerActor() |
1161 | 1128 | ||
1162 | const queryOptions = { | 1129 | const queryOptions = { |
1163 | ...pick(options, [ | 1130 | ...pick(options, [ |
1164 | 'includeLocalVideos', | 1131 | 'include', |
1165 | 'nsfw', | 1132 | 'nsfw', |
1166 | 'isLive', | 1133 | 'isLive', |
1167 | 'categoryOneOf', | 1134 | 'categoryOneOf', |
@@ -1170,7 +1137,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1170 | 'tagsOneOf', | 1137 | 'tagsOneOf', |
1171 | 'tagsAllOf', | 1138 | 'tagsAllOf', |
1172 | 'user', | 1139 | 'user', |
1173 | 'filter', | 1140 | 'isLocal', |
1174 | 'host', | 1141 | 'host', |
1175 | 'start', | 1142 | 'start', |
1176 | 'count', | 1143 | 'count', |
@@ -1182,11 +1149,10 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1182 | 'durationMin', | 1149 | 'durationMin', |
1183 | 'durationMax', | 1150 | 'durationMax', |
1184 | 'uuids', | 1151 | 'uuids', |
1185 | 'search' | 1152 | 'search', |
1153 | 'displayOnlyForFollower' | ||
1186 | ]), | 1154 | ]), |
1187 | 1155 | serverAccountIdForBlock: serverActor.Account.id | |
1188 | followerActorId: serverActor.id, | ||
1189 | serverAccountId: serverActor.Account.id | ||
1190 | } | 1156 | } |
1191 | 1157 | ||
1192 | return VideoModel.getAvailableForApi(queryOptions) | 1158 | return VideoModel.getAvailableForApi(queryOptions) |
@@ -1369,12 +1335,17 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1369 | // Sequelize could return null... | 1335 | // Sequelize could return null... |
1370 | if (!totalLocalVideoViews) totalLocalVideoViews = 0 | 1336 | if (!totalLocalVideoViews) totalLocalVideoViews = 0 |
1371 | 1337 | ||
1338 | const serverActor = await getServerActor() | ||
1339 | |||
1372 | const { total: totalVideos } = await VideoModel.listForApi({ | 1340 | const { total: totalVideos } = await VideoModel.listForApi({ |
1373 | start: 0, | 1341 | start: 0, |
1374 | count: 0, | 1342 | count: 0, |
1375 | sort: '-publishedAt', | 1343 | sort: '-publishedAt', |
1376 | nsfw: buildNSFWFilter(), | 1344 | nsfw: buildNSFWFilter(), |
1377 | includeLocalVideos: true, | 1345 | displayOnlyForFollower: { |
1346 | actorId: serverActor.id, | ||
1347 | orLocalVideos: true | ||
1348 | }, | ||
1378 | withFiles: false | 1349 | withFiles: false |
1379 | }) | 1350 | }) |
1380 | 1351 | ||
@@ -1455,7 +1426,6 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1455 | // threshold corresponds to how many video the field should have to be returned | 1426 | // threshold corresponds to how many video the field should have to be returned |
1456 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { | 1427 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { |
1457 | const serverActor = await getServerActor() | 1428 | const serverActor = await getServerActor() |
1458 | const followerActorId = serverActor.id | ||
1459 | 1429 | ||
1460 | const queryOptions: BuildVideosListQueryOptions = { | 1430 | const queryOptions: BuildVideosListQueryOptions = { |
1461 | attributes: [ `"${field}"` ], | 1431 | attributes: [ `"${field}"` ], |
@@ -1464,9 +1434,11 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1464 | start: 0, | 1434 | start: 0, |
1465 | sort: 'random', | 1435 | sort: 'random', |
1466 | count, | 1436 | count, |
1467 | serverAccountId: serverActor.Account.id, | 1437 | serverAccountIdForBlock: serverActor.Account.id, |
1468 | followerActorId, | 1438 | displayOnlyForFollower: { |
1469 | includeLocalVideos: true | 1439 | actorId: serverActor.id, |
1440 | orLocalVideos: true | ||
1441 | } | ||
1470 | } | 1442 | } |
1471 | 1443 | ||
1472 | const queryBuilder = new VideosIdListQueryBuilder(VideoModel.sequelize) | 1444 | const queryBuilder = new VideosIdListQueryBuilder(VideoModel.sequelize) |