1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-05 10:49:28 +02:00

Fix sort with a video search

This commit is contained in:
Chocobozzz 2025-04-17 11:40:35 +02:00
parent 8f72e470f4
commit d31993b714
No known key found for this signature in database
GPG key ID: 583A612D890159BE
4 changed files with 38 additions and 20 deletions

View file

@ -1,3 +1,5 @@
// dprint-ignore-file
export type VideoSortField = export type VideoSortField =
'name' | '-name' | 'name' | '-name' |
'duration' | '-duration' | 'duration' | '-duration' |
@ -6,8 +8,14 @@ export type VideoSortField =
'createdAt' | '-createdAt' | 'createdAt' | '-createdAt' |
'views' | '-views' | 'views' | '-views' |
'likes' | '-likes' | 'likes' | '-likes' |
'comments' | '-comments' |
'match' | '-match' |
'localVideoFilesSize' | '-localVideoFilesSize' |
// trending sorts // trending sorts
'trending' | '-trending' | 'trending' | '-trending' |
'hot' | '-hot' | 'hot' | '-hot' |
'best' | '-best' |
'best' | '-best' 'best' | '-best'

View file

@ -76,28 +76,22 @@ describe('Test videos API validator', function () {
}) })
describe('When searching a video', function () { describe('When searching a video', function () {
it('Should fail with nothing', async function () { const path = '/api/v1/search/videos'
await makeGetRequest({
url: server.url,
path: join(path, 'search'),
expectedStatus: HttpStatusCode.BAD_REQUEST_400
})
})
it('Should fail with a bad start pagination', async function () { it('Should fail with a bad start pagination', async function () {
await checkBadStartPagination(server.url, join(path, 'search', 'test')) await checkBadStartPagination(server.url, path, undefined, { search: 'test' })
}) })
it('Should fail with a bad count pagination', async function () { it('Should fail with a bad count pagination', async function () {
await checkBadCountPagination(server.url, join(path, 'search', 'test')) await checkBadCountPagination(server.url, path, undefined, { search: 'test' })
}) })
it('Should fail with an incorrect sort', async function () { it('Should fail with an incorrect sort', async function () {
await checkBadSortPagination(server.url, join(path, 'search', 'test')) await checkBadSortPagination(server.url, path, undefined, { search: 'test' })
}) })
it('Should success with the correct parameters', async function () { it('Should success with the correct parameters', async function () {
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 }) await makeGetRequest({ url: server.url, path, query: { search: 'test' }, expectedStatus: HttpStatusCode.OK_200 })
}) })
}) })

View file

@ -550,6 +550,22 @@ describe('Test videos filter', function () {
}) })
}) })
describe('Check sorts', function () {
it('Should correctly sort with a search', async function () {
for (
const sort of [
'-match',
'hot',
'trending',
'best',
'localVideoFilesSize'
]
) {
await servers[0].videos.listAllForAdmin({ sort, search: 'toto' })
}
})
})
after(async function () { after(async function () {
await cleanupTests(servers) await cleanupTests(servers)
}) })

View file

@ -1,11 +1,11 @@
import { Sequelize, Transaction } from 'sequelize'
import validator from 'validator'
import { forceNumber } from '@peertube/peertube-core-utils' import { forceNumber } from '@peertube/peertube-core-utils'
import { VideoInclude, VideoIncludeType, VideoPrivacy, VideoPrivacyType, VideoState } from '@peertube/peertube-models' import { VideoInclude, VideoIncludeType, VideoPrivacy, VideoPrivacyType, VideoState } from '@peertube/peertube-models'
import { exists } from '@server/helpers/custom-validators/misc.js' import { exists } from '@server/helpers/custom-validators/misc.js'
import { WEBSERVER } from '@server/initializers/constants.js' import { WEBSERVER } from '@server/initializers/constants.js'
import { buildSortDirectionAndField } from '@server/models/shared/index.js' import { buildSortDirectionAndField } from '@server/models/shared/index.js'
import { MUserAccountId, MUserId } from '@server/types/models/index.js' import { MUserAccountId, MUserId } from '@server/types/models/index.js'
import { Sequelize, Transaction } from 'sequelize'
import validator from 'validator'
import { AbstractRunQuery } from '../../../shared/abstract-run-query.js' import { AbstractRunQuery } from '../../../shared/abstract-run-query.js'
import { createSafeIn, parseRowCountResult } from '../../../shared/index.js' import { createSafeIn, parseRowCountResult } from '../../../shared/index.js'
@ -615,7 +615,11 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
base += ')' base += ')'
this.and.push(base) this.and.push(base)
this.attributes.push(`COALESCE("trigramSearch"."similarity", 0) as similarity`)
let attribute = `COALESCE("trigramSearch"."similarity", 0)`
if (this.group) attribute = `AVG(${attribute})`
this.attributes.push(`${attribute} as similarity`)
} }
private whereNotBlacklisted () { private whereNotBlacklisted () {
@ -699,12 +703,10 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
history: -2 * 50 history: -2 * 50
} }
this.joins.push('LEFT JOIN "videoComment" ON "video"."id" = "videoComment"."videoId"')
let attribute = `LOG(GREATEST(1, "video"."likes" - 1)) * ${weights.like} ` + // likes (+) let attribute = `LOG(GREATEST(1, "video"."likes" - 1)) * ${weights.like} ` + // likes (+)
`+ LOG(GREATEST(1, "video"."dislikes" - 1)) * ${weights.dislike} ` + // dislikes (-) `+ LOG(GREATEST(1, "video"."dislikes" - 1)) * ${weights.dislike} ` + // dislikes (-)
`+ LOG("video"."views" + 1) * ${weights.view} ` + // views (+) `+ LOG("video"."views" + 1) * ${weights.view} ` + // views (+)
`+ LOG(GREATEST(1, COUNT(DISTINCT "videoComment"."id"))) * ${weights.comment} ` + // comments (+) `+ LOG(GREATEST(1, "video"."comments")) * ${weights.comment} ` + // comments (+)
'+ (SELECT (EXTRACT(epoch FROM "video"."publishedAt") - 1446156582) / 47000) ' // base score (in number of half-days) '+ (SELECT (EXTRACT(epoch FROM "video"."publishedAt") - 1446156582) / 47000) ' // base score (in number of half-days)
if (trendingAlgorithm === 'best' && user) { if (trendingAlgorithm === 'best' && user) {
@ -713,13 +715,11 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
) )
this.replacements.bestUser = user.id this.replacements.bestUser = user.id
attribute += `+ POWER(COUNT(DISTINCT "userVideoHistory"."id"), 2.0) * ${weights.history} ` attribute += `+ POWER(CASE WHEN "userVideoHistory"."id" IS NULL THEN 0 ELSE 1 END, 2.0) * ${weights.history} `
} }
attribute += 'AS "score"' attribute += 'AS "score"'
this.attributes.push(attribute) this.attributes.push(attribute)
this.group = 'GROUP BY "video"."id"'
} }
private setSort (sort: string) { private setSort (sort: string) {