diff options
-rw-r--r-- | server/controllers/feeds.ts | 78 | ||||
-rw-r--r-- | server/tests/feeds/feeds.ts | 10 |
2 files changed, 58 insertions, 30 deletions
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts index 241715fb9..772fe734d 100644 --- a/server/controllers/feeds.ts +++ b/server/controllers/feeds.ts | |||
@@ -4,7 +4,8 @@ import { Feed } from '@peertube/feed' | |||
4 | import { mdToOneLinePlainText, toSafeHtml } from '@server/helpers/markdown' | 4 | import { mdToOneLinePlainText, toSafeHtml } from '@server/helpers/markdown' |
5 | import { getServerActor } from '@server/models/application/application' | 5 | import { getServerActor } from '@server/models/application/application' |
6 | import { getCategoryLabel } from '@server/models/video/formatter/video-format-utils' | 6 | import { getCategoryLabel } from '@server/models/video/formatter/video-format-utils' |
7 | import { VideoInclude } from '@shared/models' | 7 | import { MAccountDefault, MChannelBannerAccountDefault, MVideoFullLight } from '@server/types/models' |
8 | import { ActorImageType, VideoInclude } from '@shared/models' | ||
8 | import { buildNSFWFilter } from '../helpers/express-utils' | 9 | import { buildNSFWFilter } from '../helpers/express-utils' |
9 | import { CONFIG } from '../initializers/config' | 10 | import { CONFIG } from '../initializers/config' |
10 | import { MIMETYPES, PREVIEWS_SIZE, ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants' | 11 | import { MIMETYPES, PREVIEWS_SIZE, ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants' |
@@ -82,22 +83,12 @@ async function generateVideoCommentsFeed (req: express.Request, res: express.Res | |||
82 | videoChannelId: videoChannel ? videoChannel.id : undefined | 83 | videoChannelId: videoChannel ? videoChannel.id : undefined |
83 | }) | 84 | }) |
84 | 85 | ||
85 | let name: string | 86 | const { name, description, imageUrl } = buildFeedMetadata({ video, account, videoChannel }) |
86 | let description: string | ||
87 | 87 | ||
88 | if (videoChannel) { | ||
89 | name = videoChannel.getDisplayName() | ||
90 | description = videoChannel.description | ||
91 | } else if (account) { | ||
92 | name = account.getDisplayName() | ||
93 | description = account.description | ||
94 | } else { | ||
95 | name = video ? video.name : CONFIG.INSTANCE.NAME | ||
96 | description = video ? video.description : CONFIG.INSTANCE.DESCRIPTION | ||
97 | } | ||
98 | const feed = initFeed({ | 88 | const feed = initFeed({ |
99 | name, | 89 | name, |
100 | description, | 90 | description, |
91 | imageUrl, | ||
101 | resourceType: 'video-comments', | 92 | resourceType: 'video-comments', |
102 | queryString: new URL(WEBSERVER.URL + req.originalUrl).search | 93 | queryString: new URL(WEBSERVER.URL + req.originalUrl).search |
103 | }) | 94 | }) |
@@ -137,23 +128,12 @@ async function generateVideoFeed (req: express.Request, res: express.Response) { | |||
137 | const videoChannel = res.locals.videoChannel | 128 | const videoChannel = res.locals.videoChannel |
138 | const nsfw = buildNSFWFilter(res, req.query.nsfw) | 129 | const nsfw = buildNSFWFilter(res, req.query.nsfw) |
139 | 130 | ||
140 | let name: string | 131 | const { name, description, imageUrl } = buildFeedMetadata({ videoChannel, account }) |
141 | let description: string | ||
142 | |||
143 | if (videoChannel) { | ||
144 | name = videoChannel.getDisplayName() | ||
145 | description = videoChannel.description | ||
146 | } else if (account) { | ||
147 | name = account.getDisplayName() | ||
148 | description = account.description | ||
149 | } else { | ||
150 | name = CONFIG.INSTANCE.NAME | ||
151 | description = CONFIG.INSTANCE.DESCRIPTION | ||
152 | } | ||
153 | 132 | ||
154 | const feed = initFeed({ | 133 | const feed = initFeed({ |
155 | name, | 134 | name, |
156 | description, | 135 | description, |
136 | imageUrl, | ||
157 | resourceType: 'videos', | 137 | resourceType: 'videos', |
158 | queryString: new URL(WEBSERVER.URL + req.url).search | 138 | queryString: new URL(WEBSERVER.URL + req.url).search |
159 | }) | 139 | }) |
@@ -190,12 +170,13 @@ async function generateVideoFeedForSubscriptions (req: express.Request, res: exp | |||
190 | const start = 0 | 170 | const start = 0 |
191 | const account = res.locals.account | 171 | const account = res.locals.account |
192 | const nsfw = buildNSFWFilter(res, req.query.nsfw) | 172 | const nsfw = buildNSFWFilter(res, req.query.nsfw) |
193 | const name = account.getDisplayName() | 173 | |
194 | const description = account.description | 174 | const { name, description, imageUrl } = buildFeedMetadata({ account }) |
195 | 175 | ||
196 | const feed = initFeed({ | 176 | const feed = initFeed({ |
197 | name, | 177 | name, |
198 | description, | 178 | description, |
179 | imageUrl, | ||
199 | resourceType: 'videos', | 180 | resourceType: 'videos', |
200 | queryString: new URL(WEBSERVER.URL + req.url).search | 181 | queryString: new URL(WEBSERVER.URL + req.url).search |
201 | }) | 182 | }) |
@@ -229,11 +210,12 @@ async function generateVideoFeedForSubscriptions (req: express.Request, res: exp | |||
229 | function initFeed (parameters: { | 210 | function initFeed (parameters: { |
230 | name: string | 211 | name: string |
231 | description: string | 212 | description: string |
213 | imageUrl: string | ||
232 | resourceType?: 'videos' | 'video-comments' | 214 | resourceType?: 'videos' | 'video-comments' |
233 | queryString?: string | 215 | queryString?: string |
234 | }) { | 216 | }) { |
235 | const webserverUrl = WEBSERVER.URL | 217 | const webserverUrl = WEBSERVER.URL |
236 | const { name, description, resourceType, queryString } = parameters | 218 | const { name, description, resourceType, queryString, imageUrl } = parameters |
237 | 219 | ||
238 | return new Feed({ | 220 | return new Feed({ |
239 | title: name, | 221 | title: name, |
@@ -241,7 +223,7 @@ function initFeed (parameters: { | |||
241 | // updated: TODO: somehowGetLatestUpdate, // optional, default = today | 223 | // updated: TODO: somehowGetLatestUpdate, // optional, default = today |
242 | id: webserverUrl, | 224 | id: webserverUrl, |
243 | link: webserverUrl, | 225 | link: webserverUrl, |
244 | image: webserverUrl + '/client/assets/images/icons/icon-96x96.png', | 226 | image: imageUrl, |
245 | favicon: webserverUrl + '/client/assets/images/favicon.png', | 227 | favicon: webserverUrl + '/client/assets/images/favicon.png', |
246 | copyright: `All rights reserved, unless otherwise specified in the terms specified at ${webserverUrl}/about` + | 228 | copyright: `All rights reserved, unless otherwise specified in the terms specified at ${webserverUrl}/about` + |
247 | ` and potential licenses granted by each content's rightholder.`, | 229 | ` and potential licenses granted by each content's rightholder.`, |
@@ -369,3 +351,39 @@ function sendFeed (feed: Feed, req: express.Request, res: express.Response) { | |||
369 | 351 | ||
370 | return res.send(feed.rss2()).end() | 352 | return res.send(feed.rss2()).end() |
371 | } | 353 | } |
354 | |||
355 | function buildFeedMetadata (options: { | ||
356 | videoChannel?: MChannelBannerAccountDefault | ||
357 | account?: MAccountDefault | ||
358 | video?: MVideoFullLight | ||
359 | }) { | ||
360 | const { video, videoChannel, account } = options | ||
361 | |||
362 | let imageUrl = WEBSERVER.URL + '/client/assets/images/icons/icon-96x96.png' | ||
363 | let name: string | ||
364 | let description: string | ||
365 | |||
366 | if (videoChannel) { | ||
367 | name = videoChannel.getDisplayName() | ||
368 | description = videoChannel.description | ||
369 | |||
370 | if (videoChannel.Actor.hasImage(ActorImageType.AVATAR)) { | ||
371 | imageUrl = WEBSERVER.URL + videoChannel.Actor.Avatars[0].getStaticPath() | ||
372 | } | ||
373 | } else if (account) { | ||
374 | name = account.getDisplayName() | ||
375 | description = account.description | ||
376 | |||
377 | if (account.Actor.hasImage(ActorImageType.AVATAR)) { | ||
378 | imageUrl = WEBSERVER.URL + account.Actor.Avatars[0].getStaticPath() | ||
379 | } | ||
380 | } else if (video) { | ||
381 | name = video.name | ||
382 | description = video.description | ||
383 | } else { | ||
384 | name = CONFIG.INSTANCE.NAME | ||
385 | description = CONFIG.INSTANCE.DESCRIPTION | ||
386 | } | ||
387 | |||
388 | return { name, description, imageUrl } | ||
389 | } | ||
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 1d3c03d67..0ddb641e6 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -9,6 +9,7 @@ import { | |||
9 | createSingleServer, | 9 | createSingleServer, |
10 | doubleFollow, | 10 | doubleFollow, |
11 | makeGetRequest, | 11 | makeGetRequest, |
12 | makeRawRequest, | ||
12 | PeerTubeServer, | 13 | PeerTubeServer, |
13 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
14 | setDefaultChannelAvatar, | 15 | setDefaultChannelAvatar, |
@@ -306,6 +307,15 @@ describe('Test syndication feeds', () => { | |||
306 | 307 | ||
307 | await stopFfmpeg(ffmpeg) | 308 | await stopFfmpeg(ffmpeg) |
308 | }) | 309 | }) |
310 | |||
311 | it('Should have the channel avatar as feed icon', async function () { | ||
312 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) | ||
313 | |||
314 | const jsonObj = JSON.parse(json) | ||
315 | const imageUrl = jsonObj.icon | ||
316 | expect(imageUrl).to.include('/lazy-static/avatars/') | ||
317 | await makeRawRequest(imageUrl) | ||
318 | }) | ||
309 | }) | 319 | }) |
310 | 320 | ||
311 | describe('Video comments feed', function () { | 321 | describe('Video comments feed', function () { |