mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-05 02:39:33 +02:00
modularize abstract video list header and implement video hotness recommendation variant
This commit is contained in:
parent
7a4994873c
commit
5bcbcbe338
34 changed files with 396 additions and 63 deletions
|
@ -32,6 +32,8 @@ export type BuildVideosQueryOptions = {
|
|||
videoPlaylistId?: number
|
||||
|
||||
trendingDays?: number
|
||||
hot?: boolean
|
||||
|
||||
user?: MUserAccountId
|
||||
historyOfUser?: MUserId
|
||||
|
||||
|
@ -239,14 +241,46 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions)
|
|||
}
|
||||
}
|
||||
|
||||
// We don't exclude results in this if so if we do a count we don't need to add this complex clauses
|
||||
// We don't exclude results in this so if we do a count we don't need to add this complex clause
|
||||
if (options.trendingDays && options.isCount !== true) {
|
||||
const viewsGteDate = new Date(new Date().getTime() - (24 * 3600 * 1000) * options.trendingDays)
|
||||
|
||||
joins.push('LEFT JOIN "videoView" ON "video"."id" = "videoView"."videoId" AND "videoView"."startDate" >= :viewsGteDate')
|
||||
replacements.viewsGteDate = viewsGteDate
|
||||
|
||||
attributes.push('COALESCE(SUM("videoView"."views"), 0) AS "videoViewsSum"')
|
||||
attributes.push('COALESCE(SUM("videoView"."views"), 0) AS "score"')
|
||||
|
||||
group = 'GROUP BY "video"."id"'
|
||||
} else if (options.hot && options.isCount !== true) {
|
||||
/**
|
||||
* "Hotness" is a measure based on absolute view/comment/like/dislike numbers,
|
||||
* with fixed weights only applied to their log values.
|
||||
*
|
||||
* This algorithm gives little chance for an old video to have a good score,
|
||||
* for which recent spikes in interactions could be a sign of "hotness" and
|
||||
* justify a better score. However there are multiple ways to achieve that
|
||||
* goal, which is left for later. Yes, this is a TODO :)
|
||||
*
|
||||
* note: weights and base score are in number of half-days.
|
||||
* see https://github.com/reddit-archive/reddit/blob/master/r2/r2/lib/db/_sorts.pyx#L47-L58
|
||||
*/
|
||||
const weights = {
|
||||
like: 3,
|
||||
dislike: 3,
|
||||
view: 1 / 12,
|
||||
comment: 6
|
||||
}
|
||||
|
||||
joins.push('LEFT JOIN "videoComment" ON "video"."id" = "videoComment"."videoId"')
|
||||
|
||||
attributes.push(
|
||||
`LOG(GREATEST(1, "video"."likes" - 1)) * ${weights.like} ` + // likes (+)
|
||||
`- LOG(GREATEST(1, "video"."dislikes" - 1)) * ${weights.dislike} ` + // dislikes (-)
|
||||
`+ LOG("video"."views" + 1) * ${weights.view} ` + // views (+)
|
||||
`+ LOG(GREATEST(1, COUNT(DISTINCT "videoComment"."id") - 1)) * ${weights.comment} ` + // comments (+)
|
||||
'+ (SELECT EXTRACT(epoch FROM "video"."publishedAt") / 47000) ' + // base score (in number of half-days)
|
||||
'AS "score"'
|
||||
)
|
||||
|
||||
group = 'GROUP BY "video"."id"'
|
||||
}
|
||||
|
@ -372,8 +406,8 @@ function buildOrder (value: string) {
|
|||
|
||||
if (field.toLowerCase() === 'random') return 'ORDER BY RANDOM()'
|
||||
|
||||
if (field.toLowerCase() === 'trending') { // Sort by aggregation
|
||||
return `ORDER BY "videoViewsSum" ${direction}, "video"."views" ${direction}`
|
||||
if ([ 'trending', 'hot' ].includes(field.toLowerCase())) { // Sort by aggregation
|
||||
return `ORDER BY "score" ${direction}, "video"."views" ${direction}`
|
||||
}
|
||||
|
||||
let firstSort: string
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue