diff options
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/sql/videos-id-list-query-builder.ts | 45 | ||||
-rw-r--r-- | server/models/video/video.ts | 44 |
2 files changed, 68 insertions, 21 deletions
diff --git a/server/models/video/sql/videos-id-list-query-builder.ts b/server/models/video/sql/videos-id-list-query-builder.ts index 5064afafe..4a882e790 100644 --- a/server/models/video/sql/videos-id-list-query-builder.ts +++ b/server/models/video/sql/videos-id-list-query-builder.ts | |||
@@ -44,6 +44,8 @@ export type BuildVideosListQueryOptions = { | |||
44 | uuids?: string[] | 44 | uuids?: string[] |
45 | 45 | ||
46 | hasFiles?: boolean | 46 | hasFiles?: boolean |
47 | hasHLSFiles?: boolean | ||
48 | hasWebtorrentFiles?: boolean | ||
47 | 49 | ||
48 | accountId?: number | 50 | accountId?: number |
49 | videoChannelId?: number | 51 | videoChannelId?: number |
@@ -169,6 +171,14 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery { | |||
169 | this.whereFileExists() | 171 | this.whereFileExists() |
170 | } | 172 | } |
171 | 173 | ||
174 | if (exists(options.hasWebtorrentFiles)) { | ||
175 | this.whereWebTorrentFileExists(options.hasWebtorrentFiles) | ||
176 | } | ||
177 | |||
178 | if (exists(options.hasHLSFiles)) { | ||
179 | this.whereHLSFileExists(options.hasHLSFiles) | ||
180 | } | ||
181 | |||
172 | if (options.tagsOneOf) { | 182 | if (options.tagsOneOf) { |
173 | this.whereTagsOneOf(options.tagsOneOf) | 183 | this.whereTagsOneOf(options.tagsOneOf) |
174 | } | 184 | } |
@@ -371,16 +381,31 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery { | |||
371 | } | 381 | } |
372 | 382 | ||
373 | private whereFileExists () { | 383 | private whereFileExists () { |
374 | this.and.push( | 384 | this.and.push(`(${this.buildWebTorrentFileExistsQuery(true)} OR ${this.buildHLSFileExistsQuery(true)})`) |
375 | '(' + | 385 | } |
376 | ' EXISTS (SELECT 1 FROM "videoFile" WHERE "videoFile"."videoId" = "video"."id") ' + | 386 | |
377 | ' OR EXISTS (' + | 387 | private whereWebTorrentFileExists (exists: boolean) { |
378 | ' SELECT 1 FROM "videoStreamingPlaylist" ' + | 388 | this.and.push(this.buildWebTorrentFileExistsQuery(exists)) |
379 | ' INNER JOIN "videoFile" ON "videoFile"."videoStreamingPlaylistId" = "videoStreamingPlaylist"."id" ' + | 389 | } |
380 | ' WHERE "videoStreamingPlaylist"."videoId" = "video"."id"' + | 390 | |
381 | ' )' + | 391 | private whereHLSFileExists (exists: boolean) { |
382 | ')' | 392 | this.and.push(this.buildHLSFileExistsQuery(exists)) |
383 | ) | 393 | } |
394 | |||
395 | private buildWebTorrentFileExistsQuery (exists: boolean) { | ||
396 | const prefix = exists ? '' : 'NOT ' | ||
397 | |||
398 | return prefix + 'EXISTS (SELECT 1 FROM "videoFile" WHERE "videoFile"."videoId" = "video"."id")' | ||
399 | } | ||
400 | |||
401 | private buildHLSFileExistsQuery (exists: boolean) { | ||
402 | const prefix = exists ? '' : 'NOT ' | ||
403 | |||
404 | return prefix + 'EXISTS (' + | ||
405 | ' SELECT 1 FROM "videoStreamingPlaylist" ' + | ||
406 | ' INNER JOIN "videoFile" ON "videoFile"."videoStreamingPlaylistId" = "videoStreamingPlaylist"."id" ' + | ||
407 | ' WHERE "videoStreamingPlaylist"."videoId" = "video"."id"' + | ||
408 | ')' | ||
384 | } | 409 | } |
385 | 410 | ||
386 | private whereTagsOneOf (tagsOneOf: string[]) { | 411 | private whereTagsOneOf (tagsOneOf: string[]) { |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index f9618c102..aef4fd20a 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1030,6 +1030,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1030 | include?: VideoInclude | 1030 | include?: VideoInclude |
1031 | 1031 | ||
1032 | hasFiles?: boolean // default false | 1032 | hasFiles?: boolean // default false |
1033 | hasWebtorrentFiles?: boolean | ||
1034 | hasHLSFiles?: boolean | ||
1033 | 1035 | ||
1034 | categoryOneOf?: number[] | 1036 | categoryOneOf?: number[] |
1035 | licenceOneOf?: number[] | 1037 | licenceOneOf?: number[] |
@@ -1053,9 +1055,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1053 | 1055 | ||
1054 | search?: string | 1056 | search?: string |
1055 | }) { | 1057 | }) { |
1056 | if (VideoModel.isPrivateInclude(options.include) && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { | 1058 | VideoModel.throwIfPrivateIncludeWithoutUser(options.include, options.user) |
1057 | throw new Error('Try to filter all-local but no user has not the see all videos right') | ||
1058 | } | ||
1059 | 1059 | ||
1060 | const trendingDays = options.sort.endsWith('trending') | 1060 | const trendingDays = options.sort.endsWith('trending') |
1061 | ? CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS | 1061 | ? CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS |
@@ -1088,6 +1088,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1088 | 'videoPlaylistId', | 1088 | 'videoPlaylistId', |
1089 | 'user', | 1089 | 'user', |
1090 | 'historyOfUser', | 1090 | 'historyOfUser', |
1091 | 'hasHLSFiles', | ||
1092 | 'hasWebtorrentFiles', | ||
1091 | 'search' | 1093 | 'search' |
1092 | ]), | 1094 | ]), |
1093 | 1095 | ||
@@ -1103,27 +1105,39 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1103 | start: number | 1105 | start: number |
1104 | count: number | 1106 | count: number |
1105 | sort: string | 1107 | sort: string |
1106 | search?: string | 1108 | |
1107 | host?: string | ||
1108 | startDate?: string // ISO 8601 | ||
1109 | endDate?: string // ISO 8601 | ||
1110 | originallyPublishedStartDate?: string | ||
1111 | originallyPublishedEndDate?: string | ||
1112 | nsfw?: boolean | 1109 | nsfw?: boolean |
1113 | isLive?: boolean | 1110 | isLive?: boolean |
1114 | isLocal?: boolean | 1111 | isLocal?: boolean |
1115 | include?: VideoInclude | 1112 | include?: VideoInclude |
1113 | |||
1116 | categoryOneOf?: number[] | 1114 | categoryOneOf?: number[] |
1117 | licenceOneOf?: number[] | 1115 | licenceOneOf?: number[] |
1118 | languageOneOf?: string[] | 1116 | languageOneOf?: string[] |
1119 | tagsOneOf?: string[] | 1117 | tagsOneOf?: string[] |
1120 | tagsAllOf?: string[] | 1118 | tagsAllOf?: string[] |
1119 | |||
1120 | displayOnlyForFollower: DisplayOnlyForFollowerOptions | null | ||
1121 | |||
1122 | user?: MUserAccountId | ||
1123 | |||
1124 | hasWebtorrentFiles?: boolean | ||
1125 | hasHLSFiles?: boolean | ||
1126 | |||
1127 | search?: string | ||
1128 | |||
1129 | host?: string | ||
1130 | startDate?: string // ISO 8601 | ||
1131 | endDate?: string // ISO 8601 | ||
1132 | originallyPublishedStartDate?: string | ||
1133 | originallyPublishedEndDate?: string | ||
1134 | |||
1121 | durationMin?: number // seconds | 1135 | durationMin?: number // seconds |
1122 | durationMax?: number // seconds | 1136 | durationMax?: number // seconds |
1123 | user?: MUserAccountId | ||
1124 | uuids?: string[] | 1137 | uuids?: string[] |
1125 | displayOnlyForFollower: DisplayOnlyForFollowerOptions | null | ||
1126 | }) { | 1138 | }) { |
1139 | VideoModel.throwIfPrivateIncludeWithoutUser(options.include, options.user) | ||
1140 | |||
1127 | const serverActor = await getServerActor() | 1141 | const serverActor = await getServerActor() |
1128 | 1142 | ||
1129 | const queryOptions = { | 1143 | const queryOptions = { |
@@ -1148,6 +1162,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1148 | 'originallyPublishedEndDate', | 1162 | 'originallyPublishedEndDate', |
1149 | 'durationMin', | 1163 | 'durationMin', |
1150 | 'durationMax', | 1164 | 'durationMax', |
1165 | 'hasHLSFiles', | ||
1166 | 'hasWebtorrentFiles', | ||
1151 | 'uuids', | 1167 | 'uuids', |
1152 | 'search', | 1168 | 'search', |
1153 | 'displayOnlyForFollower' | 1169 | 'displayOnlyForFollower' |
@@ -1489,6 +1505,12 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1489 | } | 1505 | } |
1490 | } | 1506 | } |
1491 | 1507 | ||
1508 | private static throwIfPrivateIncludeWithoutUser (include: VideoInclude, user: MUserAccountId) { | ||
1509 | if (VideoModel.isPrivateInclude(include) && !user?.hasRight(UserRight.SEE_ALL_VIDEOS)) { | ||
1510 | throw new Error('Try to filter all-local but no user has not the see all videos right') | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1492 | private static isPrivateInclude (include: VideoInclude) { | 1514 | private static isPrivateInclude (include: VideoInclude) { |
1493 | return include & VideoInclude.BLACKLISTED || | 1515 | return include & VideoInclude.BLACKLISTED || |
1494 | include & VideoInclude.BLOCKED_OWNER || | 1516 | include & VideoInclude.BLOCKED_OWNER || |