Support multiple avatars/banners

This commit is contained in:
Chocobozzz 2022-02-26 12:52:51 +01:00
parent 1e0538bab0
commit 4129b2f3dc
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
7 changed files with 104 additions and 31 deletions

@ -1 +1 @@
Subproject commit 3e8c3fcdb063e2d8f4b3ba04fdcdeda588538751 Subproject commit 28216aa41a392ae3b3f87871fefa22dadc471cf6

View File

@ -7,8 +7,8 @@
:title="linkTitle" :title="linkTitle"
> >
<img <img
v-if="actor.avatar && !avatarError" v-if="avatarUrl && !avatarError"
:src="actor.avatar.url" :src="avatarUrl"
alt="" alt=""
:class="{ account: isAccount }" :class="{ account: isAccount }"
@error="setAvatarError()" @error="setAvatarError()"
@ -39,6 +39,20 @@
}, },
computed: { computed: {
avatarUrl (): string {
const avatars = this.actor.avatars
if (avatars.length === 0) return ''
avatars.sort((a1, a2) => {
if (a1.width < a2.width) return -1
if (a1.width > a2.width) return 1
return 0
})
return avatars[0].url
},
linkTitle (): string { linkTitle (): string {
if (this.type === 'channel') return this.$gettext('Go on this channel page') if (this.type === 'channel') return this.$gettext('Go on this channel page')

View File

@ -5,7 +5,12 @@ import { DBChannel, EnhancedVideoChannel, IndexableChannel } from '../../types/c
import { ChannelsSearchQuery } from '../../types/search-query/channel-search.model' import { ChannelsSearchQuery } from '../../types/search-query/channel-search.model'
import { buildSort, extractQueryResult } from './elastic-search-queries' import { buildSort, extractQueryResult } from './elastic-search-queries'
import { buildChannelOrAccountCommonMapping, buildMultiMatchBool } from './shared' import { buildChannelOrAccountCommonMapping, buildMultiMatchBool } from './shared'
import { formatAvatarForAPI, formatAvatarForDB } from './shared/elastic-search-avatar' import {
formatActorImageForAPI,
formatActorImageForDB,
formatActorImagesForAPI,
formatActorImagesForDB
} from './shared/elastic-search-avatar'
async function queryChannels (search: ChannelsSearchQuery) { async function queryChannels (search: ChannelsSearchQuery) {
const bool: any = {} const bool: any = {}
@ -86,7 +91,12 @@ function formatChannelForAPI (c: DBChannel, fromHost?: string): EnhancedVideoCha
followersCount: c.followersCount, followersCount: c.followersCount,
createdAt: c.createdAt, createdAt: c.createdAt,
updatedAt: c.updatedAt, updatedAt: c.updatedAt,
avatar: formatAvatarForAPI(c),
avatar: formatActorImageForAPI(c.avatar),
avatars: formatActorImagesForAPI(c.avatars, c.avatar),
banner: formatActorImageForAPI(c.banner),
banners: formatActorImagesForAPI(c.banners, c.banner),
displayName: c.displayName, displayName: c.displayName,
description: c.description, description: c.description,
@ -106,7 +116,8 @@ function formatChannelForAPI (c: DBChannel, fromHost?: string): EnhancedVideoCha
createdAt: c.ownerAccount.createdAt, createdAt: c.ownerAccount.createdAt,
updatedAt: c.ownerAccount.updatedAt, updatedAt: c.ownerAccount.updatedAt,
avatar: formatAvatarForAPI(c.ownerAccount) avatar: formatActorImageForAPI(c.ownerAccount.avatar),
avatars: formatActorImagesForAPI(c.ownerAccount.avatars, c.ownerAccount.avatar)
} }
} }
} }
@ -119,7 +130,11 @@ function formatChannelForDB (c: IndexableChannel): DBChannel {
host: c.host, host: c.host,
url: c.url, url: c.url,
avatar: formatAvatarForDB(c), 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, displayName: c.displayName,
@ -151,7 +166,8 @@ function formatChannelForDB (c: IndexableChannel): DBChannel {
handle: `${c.ownerAccount.name}@${c.ownerAccount.host}`, handle: `${c.ownerAccount.name}@${c.ownerAccount.host}`,
avatar: formatAvatarForDB(c.ownerAccount) avatar: formatActorImageForDB(c.ownerAccount.avatar, c.ownerAccount.host),
avatars: formatActorImagesForDB(c.ownerAccount.avatars, c.ownerAccount.host)
} }
} }
} }

View File

@ -1,6 +1,7 @@
import { AccountSummary, VideoChannelSummary } from '../../../../PeerTube/shared/models' import { AccountSummary, VideoChannelSummary } from '../../../../PeerTube/shared/models'
import { AdditionalActorAttributes } from '../../../types/actor.model' import { AdditionalActorAttributes } from '../../../types/actor.model'
import { buildAvatarMapping, formatAvatarForAPI, formatAvatarForDB } from './elastic-search-avatar' import { formatActorImageForDB } from './'
import { buildActorImageMapping, formatActorImageForAPI, formatActorImagesForAPI, formatActorImagesForDB } from './elastic-search-avatar'
function buildChannelOrAccountSummaryMapping () { function buildChannelOrAccountSummaryMapping () {
return { return {
@ -30,7 +31,12 @@ function buildChannelOrAccountSummaryMapping () {
}, },
avatar: { avatar: {
properties: buildAvatarMapping() properties: buildActorImageMapping()
},
// Introduced in 4.2
avatars: {
properties: buildActorImageMapping()
} }
} }
} }
@ -69,7 +75,8 @@ function formatActorSummaryForAPI (actor: (AccountSummary | VideoChannelSummary)
url: actor.url, url: actor.url,
host: actor.host, host: actor.host,
avatar: formatAvatarForAPI(actor) avatar: formatActorImageForAPI(actor.avatar),
avatars: formatActorImagesForAPI(actor.avatars, actor.avatar)
} }
} }
@ -83,7 +90,8 @@ function formatActorForDB (actor: AccountSummary | VideoChannelSummary) {
handle: `${actor.name}@${actor.host}`, handle: `${actor.name}@${actor.host}`,
avatar: formatAvatarForDB(actor) avatar: formatActorImageForDB(actor.avatar, actor.host),
avatars: formatActorImagesForDB(actor.avatars, actor.host)
} }
} }

View File

@ -1,34 +1,59 @@
import { ActorImage } from '../../../../PeerTube/shared/models' import { ActorImage } from '../../../../PeerTube/shared/models'
import { buildUrl } from '../../../helpers/utils' import { buildUrl } from '../../../helpers/utils'
function formatAvatarForAPI (obj: { avatar?: ActorImage & { url: string } }) { function formatActorImageForAPI (image?: ActorImage) {
if (!obj.avatar) return null if (!image) return null
return { return {
url: obj.avatar.url, url: image.url,
path: obj.avatar.path, path: image.path,
createdAt: obj.avatar.createdAt, width: image.width,
updatedAt: obj.avatar.updatedAt createdAt: image.createdAt,
updatedAt: image.updatedAt
} }
} }
function formatAvatarForDB (obj: { avatar?: ActorImage, host: string }) { function formatActorImagesForAPI (images?: ActorImage[], image?: ActorImage) {
if (!obj.avatar) return null // Does not exist in PeerTube < 4.2
if (!images) {
if (!image) return []
return [ image ]
}
return images.map(a => formatActorImageForAPI(a))
}
// ---------------------------------------------------------------------------
function formatActorImageForDB (image: ActorImage, host: string) {
if (!image) return null
return { return {
url: buildUrl(obj.host, obj.avatar.path), url: buildUrl(host, image.path),
path: obj.avatar.path, path: image.path,
createdAt: obj.avatar.createdAt, width: image.width,
updatedAt: obj.avatar.updatedAt createdAt: image.createdAt,
updatedAt: image.updatedAt
} }
} }
function buildAvatarMapping () { function formatActorImagesForDB (images: ActorImage[], host: string) {
if (!images) return null
return images.map(image => formatActorImageForDB(image, host))
}
// ---------------------------------------------------------------------------
function buildActorImageMapping () {
return { return {
path: { path: {
type: 'keyword' type: 'keyword'
}, },
width: {
type: 'long'
},
createdAt: { createdAt: {
type: 'date', type: 'date',
format: 'date_optional_time' format: 'date_optional_time'
@ -41,7 +66,11 @@ function buildAvatarMapping () {
} }
export { export {
formatAvatarForAPI, formatActorImageForAPI,
formatAvatarForDB, formatActorImagesForAPI,
buildAvatarMapping
formatActorImageForDB,
formatActorImagesForDB,
buildActorImageMapping
} }

View File

@ -2,8 +2,10 @@ import { ActorImage } from '../../PeerTube/shared/models'
export type AdditionalActorAttributes = { export type AdditionalActorAttributes = {
handle: string handle: string
avatar: ActorImageExtended
url: string url: string
avatar: ActorImageExtended
avatars: ActorImageExtended[]
} }
export type ActorImageExtended = ActorImage & { url: string } export type ActorImageExtended = ActorImage & { url: string }

View File

@ -13,7 +13,11 @@ export interface DBChannel extends Omit<VideoChannel, 'isLocal'> {
ownerAccount?: Account & AdditionalActorAttributes ownerAccount?: Account & AdditionalActorAttributes
avatar?: ActorImageExtended avatar: ActorImageExtended
avatars: ActorImageExtended[]
banner: ActorImageExtended
banners: ActorImageExtended[]
score?: number score?: number
} }