diff options
author | Chocobozzz <me@florianbigard.com> | 2018-09-14 09:57:21 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-09-14 09:57:21 +0200 |
commit | b36f41ca09e92ecb30d367d91d1089a23d10d585 (patch) | |
tree | 34b7c90e17f73f37d069a2f08d60dc36fa08372f /server/models/redundancy | |
parent | 6f0c46be8c9f4690d5e5cb758c4df6164b006f83 (diff) | |
download | PeerTube-b36f41ca09e92ecb30d367d91d1089a23d10d585.tar.gz PeerTube-b36f41ca09e92ecb30d367d91d1089a23d10d585.tar.zst PeerTube-b36f41ca09e92ecb30d367d91d1089a23d10d585.zip |
Add trending videos strategy
Diffstat (limited to 'server/models/redundancy')
-rw-r--r-- | server/models/redundancy/video-redundancy.ts | 115 |
1 files changed, 76 insertions, 39 deletions
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index 48ec77206..b13ade0f4 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts | |||
@@ -14,11 +14,10 @@ import { | |||
14 | UpdatedAt | 14 | UpdatedAt |
15 | } from 'sequelize-typescript' | 15 | } from 'sequelize-typescript' |
16 | import { ActorModel } from '../activitypub/actor' | 16 | import { ActorModel } from '../activitypub/actor' |
17 | import { throwIfNotValid } from '../utils' | 17 | import { getVideoSort, throwIfNotValid } from '../utils' |
18 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 18 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
19 | import { CONSTRAINTS_FIELDS, VIDEO_EXT_MIMETYPE } from '../../initializers' | 19 | import { CONFIG, CONSTRAINTS_FIELDS, VIDEO_EXT_MIMETYPE } from '../../initializers' |
20 | import { VideoFileModel } from '../video/video-file' | 20 | import { VideoFileModel } from '../video/video-file' |
21 | import { isDateValid } from '../../helpers/custom-validators/misc' | ||
22 | import { getServerActor } from '../../helpers/utils' | 21 | import { getServerActor } from '../../helpers/utils' |
23 | import { VideoModel } from '../video/video' | 22 | import { VideoModel } from '../video/video' |
24 | import { VideoRedundancyStrategy } from '../../../shared/models/redundancy' | 23 | import { VideoRedundancyStrategy } from '../../../shared/models/redundancy' |
@@ -145,50 +144,51 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
145 | return VideoRedundancyModel.findOne(query) | 144 | return VideoRedundancyModel.findOne(query) |
146 | } | 145 | } |
147 | 146 | ||
147 | static getVideoSample (rows: { id: number }[]) { | ||
148 | const ids = rows.map(r => r.id) | ||
149 | const id = sample(ids) | ||
150 | |||
151 | return VideoModel.loadWithFile(id, undefined, !isTestInstance()) | ||
152 | } | ||
153 | |||
148 | static async findMostViewToDuplicate (randomizedFactor: number) { | 154 | static async findMostViewToDuplicate (randomizedFactor: number) { |
149 | // On VideoModel! | 155 | // On VideoModel! |
150 | const query = { | 156 | const query = { |
157 | attributes: [ 'id', 'views' ], | ||
151 | logging: !isTestInstance(), | 158 | logging: !isTestInstance(), |
152 | limit: randomizedFactor, | 159 | limit: randomizedFactor, |
153 | order: [ [ 'views', 'DESC' ] ], | 160 | order: getVideoSort('-views'), |
154 | include: [ | 161 | include: [ |
155 | { | 162 | await VideoRedundancyModel.buildVideoFileForDuplication(), |
156 | model: VideoFileModel.unscoped(), | 163 | VideoRedundancyModel.buildServerRedundancyInclude() |
157 | required: true, | 164 | ] |
158 | where: { | 165 | } |
159 | id: { | 166 | |
160 | [ Sequelize.Op.notIn ]: await VideoRedundancyModel.buildExcludeIn() | 167 | const rows = await VideoModel.unscoped().findAll(query) |
161 | } | 168 | |
162 | } | 169 | return VideoRedundancyModel.getVideoSample(rows as { id: number }[]) |
163 | }, | 170 | } |
164 | { | 171 | |
165 | attributes: [], | 172 | static async findTrendingToDuplicate (randomizedFactor: number) { |
166 | model: VideoChannelModel.unscoped(), | 173 | // On VideoModel! |
167 | required: true, | 174 | const query = { |
168 | include: [ | 175 | attributes: [ 'id', 'views' ], |
169 | { | 176 | subQuery: false, |
170 | attributes: [], | 177 | logging: !isTestInstance(), |
171 | model: ActorModel.unscoped(), | 178 | group: 'VideoModel.id', |
172 | required: true, | 179 | limit: randomizedFactor, |
173 | include: [ | 180 | order: getVideoSort('-trending'), |
174 | { | 181 | include: [ |
175 | attributes: [], | 182 | await VideoRedundancyModel.buildVideoFileForDuplication(), |
176 | model: ServerModel.unscoped(), | 183 | VideoRedundancyModel.buildServerRedundancyInclude(), |
177 | required: true, | 184 | |
178 | where: { | 185 | VideoModel.buildTrendingQuery(CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS) |
179 | redundancyAllowed: true | ||
180 | } | ||
181 | } | ||
182 | ] | ||
183 | } | ||
184 | ] | ||
185 | } | ||
186 | ] | 186 | ] |
187 | } | 187 | } |
188 | 188 | ||
189 | const rows = await VideoModel.unscoped().findAll(query) | 189 | const rows = await VideoModel.unscoped().findAll(query) |
190 | 190 | ||
191 | return sample(rows) | 191 | return VideoRedundancyModel.getVideoSample(rows as { id: number }[]) |
192 | } | 192 | } |
193 | 193 | ||
194 | static async getVideoFiles (strategy: VideoRedundancyStrategy) { | 194 | static async getVideoFiles (strategy: VideoRedundancyStrategy) { |
@@ -211,7 +211,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
211 | logging: !isTestInstance(), | 211 | logging: !isTestInstance(), |
212 | where: { | 212 | where: { |
213 | expiresOn: { | 213 | expiresOn: { |
214 | [Sequelize.Op.lt]: new Date() | 214 | [ Sequelize.Op.lt ]: new Date() |
215 | } | 215 | } |
216 | } | 216 | } |
217 | } | 217 | } |
@@ -237,13 +237,50 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
237 | } | 237 | } |
238 | } | 238 | } |
239 | 239 | ||
240 | private static async buildExcludeIn () { | 240 | // Don't include video files we already duplicated |
241 | private static async buildVideoFileForDuplication () { | ||
241 | const actor = await getServerActor() | 242 | const actor = await getServerActor() |
242 | 243 | ||
243 | return Sequelize.literal( | 244 | const notIn = Sequelize.literal( |
244 | '(' + | 245 | '(' + |
245 | `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "expiresOn" >= NOW()` + | 246 | `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "expiresOn" >= NOW()` + |
246 | ')' | 247 | ')' |
247 | ) | 248 | ) |
249 | |||
250 | return { | ||
251 | attributes: [], | ||
252 | model: VideoFileModel.unscoped(), | ||
253 | required: true, | ||
254 | where: { | ||
255 | id: { | ||
256 | [ Sequelize.Op.notIn ]: notIn | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | private static buildServerRedundancyInclude () { | ||
263 | return { | ||
264 | attributes: [], | ||
265 | model: VideoChannelModel.unscoped(), | ||
266 | required: true, | ||
267 | include: [ | ||
268 | { | ||
269 | attributes: [], | ||
270 | model: ActorModel.unscoped(), | ||
271 | required: true, | ||
272 | include: [ | ||
273 | { | ||
274 | attributes: [], | ||
275 | model: ServerModel.unscoped(), | ||
276 | required: true, | ||
277 | where: { | ||
278 | redundancyAllowed: true | ||
279 | } | ||
280 | } | ||
281 | ] | ||
282 | } | ||
283 | ] | ||
284 | } | ||
248 | } | 285 | } |
249 | } | 286 | } |