]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/api/search/search-videos.ts
Don't store remote rates of remote videos
[github/Chocobozzz/PeerTube.git] / server / controllers / api / search / search-videos.ts
CommitLineData
41fb13c3 1import express from 'express'
37a44fc9 2import { sanitizeUrl } from '@server/helpers/core-utils'
d6886027 3import { pickSearchVideoQuery } from '@server/helpers/query'
dedcd583 4import { doJSONRequest, findLatestRedirection } from '@server/helpers/requests'
37a44fc9
C
5import { CONFIG } from '@server/initializers/config'
6import { WEBSERVER } from '@server/initializers/constants'
7import { getOrCreateAPVideo } from '@server/lib/activitypub/videos'
8import { Hooks } from '@server/lib/plugins/hooks'
9import { buildMutedForSearchIndex, isSearchIndexSearch, isURISearch } from '@server/lib/search'
2760b454
C
10import { getServerActor } from '@server/models/application/application'
11import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils'
4c7e60bc 12import { HttpStatusCode, ResultList, Video } from '@shared/models'
d6886027 13import { VideosSearchQueryAfterSanitize } from '../../../../shared/models/search'
37a44fc9
C
14import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../../helpers/express-utils'
15import { logger } from '../../../helpers/logger'
16import { getFormattedObjects } from '../../../helpers/utils'
17import {
18 asyncMiddleware,
19 commonVideosFiltersValidator,
20 openapiOperationDoc,
21 optionalAuthenticate,
22 paginationValidator,
23 setDefaultPagination,
24 setDefaultSearchSort,
25 videosSearchSortValidator,
26 videosSearchValidator
27} from '../../../middlewares'
28import { VideoModel } from '../../../models/video/video'
29import { MVideoAccountLightBlacklistAllFiles } from '../../../types/models'
400043b1 30import { searchLocalUrl } from './shared'
37a44fc9
C
31
32const searchVideosRouter = express.Router()
33
34searchVideosRouter.get('/videos',
35 openapiOperationDoc({ operationId: 'searchVideos' }),
36 paginationValidator,
37 setDefaultPagination,
38 videosSearchSortValidator,
39 setDefaultSearchSort,
40 optionalAuthenticate,
41 commonVideosFiltersValidator,
42 videosSearchValidator,
43 asyncMiddleware(searchVideos)
44)
45
46// ---------------------------------------------------------------------------
47
48export { searchVideosRouter }
49
50// ---------------------------------------------------------------------------
51
52function searchVideos (req: express.Request, res: express.Response) {
d6886027 53 const query = pickSearchVideoQuery(req.query)
37a44fc9
C
54 const search = query.search
55
56 if (isURISearch(search)) {
57 return searchVideoURI(search, res)
58 }
59
60 if (isSearchIndexSearch(query)) {
61 return searchVideosIndex(query, res)
62 }
63
64 return searchVideosDB(query, res)
65}
66
d6886027 67async function searchVideosIndex (query: VideosSearchQueryAfterSanitize, res: express.Response) {
37a44fc9
C
68 const result = await buildMutedForSearchIndex(res)
69
d6886027 70 let body = { ...query, ...result }
37a44fc9
C
71
72 // Use the default instance NSFW policy if not specified
73 if (!body.nsfw) {
74 const nsfwPolicy = res.locals.oauth
75 ? res.locals.oauth.token.User.nsfwPolicy
76 : CONFIG.INSTANCE.DEFAULT_NSFW_POLICY
77
78 body.nsfw = nsfwPolicy === 'do_not_list'
79 ? 'false'
80 : 'both'
81 }
82
83 body = await Hooks.wrapObject(body, 'filter:api.search.videos.index.list.params')
84
85 const url = sanitizeUrl(CONFIG.SEARCH.SEARCH_INDEX.URL) + '/api/v1/search/videos'
86
87 try {
88 logger.debug('Doing videos search index request on %s.', url, { body })
89
90 const { body: searchIndexResult } = await doJSONRequest<ResultList<Video>>(url, { method: 'POST', json: body })
91 const jsonResult = await Hooks.wrapObject(searchIndexResult, 'filter:api.search.videos.index.list.result')
92
93 return res.json(jsonResult)
94 } catch (err) {
95 logger.warn('Cannot use search index to make video search.', { err })
96
97 return res.fail({
98 status: HttpStatusCode.INTERNAL_SERVER_ERROR_500,
99 message: 'Cannot use search index to make video search'
100 })
101 }
102}
103
d6886027 104async function searchVideosDB (query: VideosSearchQueryAfterSanitize, res: express.Response) {
2760b454
C
105 const serverActor = await getServerActor()
106
d6886027
C
107 const apiOptions = await Hooks.wrapObject({
108 ...query,
109
2760b454
C
110 displayOnlyForFollower: {
111 actorId: serverActor.id,
112 orLocalVideos: true
113 },
d6886027
C
114
115 nsfw: buildNSFWFilter(res, query.nsfw),
116 user: res.locals.oauth
117 ? res.locals.oauth.token.User
118 : undefined
119 }, 'filter:api.search.videos.local.list.params')
37a44fc9
C
120
121 const resultList = await Hooks.wrapPromiseFun(
122 VideoModel.searchAndPopulateAccountAndServer,
123 apiOptions,
124 'filter:api.search.videos.local.list.result'
125 )
126
2760b454 127 return res.json(getFormattedObjects(resultList.data, resultList.total, guessAdditionalAttributesFromQuery(query)))
37a44fc9
C
128}
129
130async function searchVideoURI (url: string, res: express.Response) {
131 let video: MVideoAccountLightBlacklistAllFiles
132
133 // Check if we can fetch a remote video with the URL
134 if (isUserAbleToSearchRemoteURI(res)) {
135 try {
136 const syncParam = {
57e4e1c1 137 rates: false,
37a44fc9
C
138 shares: false,
139 comments: false,
140 thumbnail: true,
141 refreshVideo: false
142 }
143
dedcd583
C
144 const result = await getOrCreateAPVideo({
145 videoObject: await findLatestRedirection(url, { activityPub: true }),
146 syncParam
147 })
37a44fc9
C
148 video = result ? result.video : undefined
149 } catch (err) {
150 logger.info('Cannot search remote video %s.', url, { err })
151 }
152 } else {
400043b1 153 video = await searchLocalUrl(sanitizeLocalUrl(url), url => VideoModel.loadByUrlAndPopulateAccount(url))
37a44fc9
C
154 }
155
156 return res.json({
157 total: video ? 1 : 0,
158 data: video ? [ video.toFormattedJSON() ] : []
159 })
160}
161
162function sanitizeLocalUrl (url: string) {
163 if (!url) return ''
164
165 // Handle alternative video URLs
166 return url.replace(new RegExp('^' + WEBSERVER.URL + '/w/'), WEBSERVER.URL + '/videos/watch/')
167}