153 lines
4.6 KiB
TypeScript
153 lines
4.6 KiB
TypeScript
import { createHash } from 'crypto'
|
|
import { logger } from '../../helpers/logger'
|
|
import { client } from '../../helpers/meilisearch'
|
|
import { CONFIG } from '../../initializers/constants'
|
|
import { DBChannel, APIVideoChannel, IndexableChannel } from '../../types/channel.model'
|
|
import { ChannelsSearchQuery } from '../../types/search-query/channel-search.model'
|
|
import { buildInValuesArray, buildSort, extractSearchQueryResult } from './meilisearch-queries'
|
|
import {
|
|
formatActorImageForAPI,
|
|
formatActorImageForDB,
|
|
formatActorImagesForAPI,
|
|
formatActorImagesForDB
|
|
} from './shared/meilisearch-avatar'
|
|
|
|
export async function queryChannels (search: ChannelsSearchQuery) {
|
|
const filter: string[] = [ 'videosCount != 0' ]
|
|
|
|
if (search.host) filter.push(`host = '${search.host}'`)
|
|
|
|
if (search.blockedAccounts && search.blockedAccounts.length !== 0) {
|
|
filter.push(`ownerAccount.handle NOT IN ${buildInValuesArray(search.blockedAccounts)}`)
|
|
}
|
|
|
|
if (search.handles && search.handles.length !== 0) {
|
|
filter.push(`handle IN ${buildInValuesArray(search.handles)}`)
|
|
}
|
|
|
|
if (search.blockedHosts && search.blockedHosts.length !== 0) {
|
|
filter.push(`host NOT IN ${buildInValuesArray(search.blockedHosts)}`)
|
|
}
|
|
|
|
logger.debug({ filter }, 'Will query Meilisearch for channels.')
|
|
|
|
const result = await client.index(CONFIG.MEILISEARCH.INDEXES.CHANNELS).search(search.search, {
|
|
offset: search.start,
|
|
limit: search.count,
|
|
sort: buildSort(search.sort),
|
|
showRankingScore: true,
|
|
filter
|
|
})
|
|
|
|
return extractSearchQueryResult(result)
|
|
}
|
|
|
|
export function formatChannelForAPI (c: DBChannel, fromHost?: string): APIVideoChannel {
|
|
return {
|
|
id: c.id,
|
|
|
|
score: c._rankingScore,
|
|
|
|
url: c.url,
|
|
name: c.name,
|
|
host: c.host,
|
|
followingCount: c.followingCount,
|
|
followersCount: c.followersCount,
|
|
createdAt: new Date(c.createdAt),
|
|
updatedAt: new Date(c.updatedAt),
|
|
|
|
avatar: formatActorImageForAPI(c.avatar),
|
|
avatars: formatActorImagesForAPI(c.avatars, c.avatar),
|
|
|
|
banner: formatActorImageForAPI(c.banner),
|
|
banners: formatActorImagesForAPI(c.banners, c.banner),
|
|
|
|
displayName: c.displayName,
|
|
description: c.description,
|
|
support: c.support,
|
|
isLocal: fromHost === c.host,
|
|
|
|
videosCount: c.videosCount || 0,
|
|
|
|
ownerAccount: {
|
|
id: c.ownerAccount.id,
|
|
url: c.ownerAccount.url,
|
|
|
|
displayName: c.ownerAccount.displayName,
|
|
description: c.ownerAccount.description,
|
|
name: c.ownerAccount.name,
|
|
host: c.ownerAccount.host,
|
|
followingCount: c.ownerAccount.followingCount,
|
|
followersCount: c.ownerAccount.followersCount,
|
|
createdAt: new Date(c.ownerAccount.createdAt),
|
|
updatedAt: new Date(c.ownerAccount.updatedAt),
|
|
|
|
avatar: formatActorImageForAPI(c.ownerAccount.avatar),
|
|
avatars: formatActorImagesForAPI(c.ownerAccount.avatars, c.ownerAccount.avatar)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function formatChannelForDB (c: IndexableChannel): DBChannel {
|
|
if (!c.ownerAccount) return undefined
|
|
|
|
return {
|
|
primaryKey: buildDBChannelPrimaryKey(c),
|
|
|
|
id: c.id,
|
|
|
|
name: c.name,
|
|
host: c.host,
|
|
url: c.url,
|
|
|
|
avatar: formatActorImageForDB(c.avatar, c.host),
|
|
avatars: formatActorImagesForDB(c.avatars, c.host),
|
|
|
|
banner: formatActorImageForDB(c.banner, c.host),
|
|
banners: formatActorImagesForDB(c.banners, c.host),
|
|
|
|
displayName: c.displayName,
|
|
|
|
indexedAt: new Date().getTime(),
|
|
createdAt: new Date(c.createdAt).getTime(),
|
|
updatedAt: new Date(c.updatedAt).getTime(),
|
|
|
|
followingCount: c.followingCount,
|
|
followersCount: c.followersCount,
|
|
|
|
description: c.description,
|
|
support: c.support,
|
|
videosCount: c.videosCount,
|
|
|
|
handle: `${c.name}@${c.host}`,
|
|
|
|
ownerAccount: {
|
|
id: c.ownerAccount.id,
|
|
url: c.ownerAccount.url,
|
|
|
|
displayName: c.ownerAccount.displayName,
|
|
description: c.ownerAccount.description,
|
|
name: c.ownerAccount.name,
|
|
host: c.ownerAccount.host,
|
|
followingCount: c.ownerAccount.followingCount,
|
|
followersCount: c.ownerAccount.followersCount,
|
|
createdAt: new Date(c.ownerAccount.createdAt).getTime(),
|
|
updatedAt: new Date(c.ownerAccount.updatedAt).getTime(),
|
|
|
|
handle: `${c.ownerAccount.name}@${c.ownerAccount.host}`,
|
|
|
|
avatar: formatActorImageForDB(c.ownerAccount.avatar, c.ownerAccount.host),
|
|
avatars: formatActorImagesForDB(c.ownerAccount.avatars, c.ownerAccount.host)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function buildDBChannelPrimaryKey (c: { id: number, host: string }) {
|
|
return `${c.id}_${md5(c.host)}`
|
|
}
|
|
|
|
// Collisions are fine, we just want to generate a primary key in an efficient way
|
|
function md5 (value: string) {
|
|
return createHash('md5').update(value).digest('hex')
|
|
}
|