diff options
author | Chocobozzz <me@florianbigard.com> | 2023-07-26 10:19:51 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-07-26 10:19:51 +0200 |
commit | 3ffff82e87c4349b8a8354481c9b7ea696c886ef (patch) | |
tree | 00721fdef1c8e9833379f0fcad4303335cab2c81 /server/lib/client-html.ts | |
parent | d7c36709452280a8fe2a0354dac7073e1cded9a5 (diff) | |
download | PeerTube-3ffff82e87c4349b8a8354481c9b7ea696c886ef.tar.gz PeerTube-3ffff82e87c4349b8a8354481c9b7ea696c886ef.tar.zst PeerTube-3ffff82e87c4349b8a8354481c9b7ea696c886ef.zip |
Truncate html/og/card HTML description tags
Diffstat (limited to 'server/lib/client-html.ts')
-rw-r--r-- | server/lib/client-html.ts | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index be6df1792..8e0c9e328 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { pathExists, readFile } from 'fs-extra' | 2 | import { pathExists, readFile } from 'fs-extra' |
3 | import { truncate } from 'lodash' | ||
3 | import { join } from 'path' | 4 | import { join } from 'path' |
4 | import validator from 'validator' | 5 | import validator from 'validator' |
5 | import { isTestOrDevInstance } from '@server/helpers/core-utils' | 6 | import { isTestOrDevInstance } from '@server/helpers/core-utils' |
@@ -45,7 +46,7 @@ type Tags = { | |||
45 | 46 | ||
46 | escapedSiteName: string | 47 | escapedSiteName: string |
47 | escapedTitle: string | 48 | escapedTitle: string |
48 | escapedDescription: string | 49 | escapedTruncatedDescription: string |
49 | 50 | ||
50 | url: string | 51 | url: string |
51 | originUrl: string | 52 | originUrl: string |
@@ -111,10 +112,10 @@ class ClientHtml { | |||
111 | res.status(HttpStatusCode.NOT_FOUND_404) | 112 | res.status(HttpStatusCode.NOT_FOUND_404) |
112 | return html | 113 | return html |
113 | } | 114 | } |
114 | const description = mdToOneLinePlainText(video.description) | 115 | const escapedTruncatedDescription = buildEscapedTruncatedDescription(video.description) |
115 | 116 | ||
116 | let customHtml = ClientHtml.addTitleTag(html, video.name) | 117 | let customHtml = ClientHtml.addTitleTag(html, video.name) |
117 | customHtml = ClientHtml.addDescriptionTag(customHtml, description) | 118 | customHtml = ClientHtml.addDescriptionTag(customHtml, escapedTruncatedDescription) |
118 | 119 | ||
119 | const url = WEBSERVER.URL + video.getWatchStaticPath() | 120 | const url = WEBSERVER.URL + video.getWatchStaticPath() |
120 | const originUrl = video.url | 121 | const originUrl = video.url |
@@ -141,7 +142,7 @@ class ClientHtml { | |||
141 | originUrl, | 142 | originUrl, |
142 | escapedSiteName: escapeHTML(siteName), | 143 | escapedSiteName: escapeHTML(siteName), |
143 | escapedTitle: escapeHTML(title), | 144 | escapedTitle: escapeHTML(title), |
144 | escapedDescription: escapeHTML(description), | 145 | escapedTruncatedDescription, |
145 | disallowIndexation: video.privacy !== VideoPrivacy.PUBLIC, | 146 | disallowIndexation: video.privacy !== VideoPrivacy.PUBLIC, |
146 | image, | 147 | image, |
147 | embed, | 148 | embed, |
@@ -173,10 +174,10 @@ class ClientHtml { | |||
173 | return html | 174 | return html |
174 | } | 175 | } |
175 | 176 | ||
176 | const description = mdToOneLinePlainText(videoPlaylist.description) | 177 | const escapedTruncatedDescription = buildEscapedTruncatedDescription(videoPlaylist.description) |
177 | 178 | ||
178 | let customHtml = ClientHtml.addTitleTag(html, videoPlaylist.name) | 179 | let customHtml = ClientHtml.addTitleTag(html, videoPlaylist.name) |
179 | customHtml = ClientHtml.addDescriptionTag(customHtml, description) | 180 | customHtml = ClientHtml.addDescriptionTag(customHtml, escapedTruncatedDescription) |
180 | 181 | ||
181 | const url = WEBSERVER.URL + videoPlaylist.getWatchStaticPath() | 182 | const url = WEBSERVER.URL + videoPlaylist.getWatchStaticPath() |
182 | const originUrl = videoPlaylist.url | 183 | const originUrl = videoPlaylist.url |
@@ -205,7 +206,7 @@ class ClientHtml { | |||
205 | originUrl, | 206 | originUrl, |
206 | escapedSiteName: escapeHTML(siteName), | 207 | escapedSiteName: escapeHTML(siteName), |
207 | escapedTitle: escapeHTML(title), | 208 | escapedTitle: escapeHTML(title), |
208 | escapedDescription: escapeHTML(description), | 209 | escapedTruncatedDescription, |
209 | disallowIndexation: videoPlaylist.privacy !== VideoPlaylistPrivacy.PUBLIC, | 210 | disallowIndexation: videoPlaylist.privacy !== VideoPlaylistPrivacy.PUBLIC, |
210 | embed, | 211 | embed, |
211 | image, | 212 | image, |
@@ -276,10 +277,10 @@ class ClientHtml { | |||
276 | return ClientHtml.getIndexHTML(req, res) | 277 | return ClientHtml.getIndexHTML(req, res) |
277 | } | 278 | } |
278 | 279 | ||
279 | const description = mdToOneLinePlainText(entity.description) | 280 | const escapedTruncatedDescription = buildEscapedTruncatedDescription(entity.description) |
280 | 281 | ||
281 | let customHtml = ClientHtml.addTitleTag(html, entity.getDisplayName()) | 282 | let customHtml = ClientHtml.addTitleTag(html, entity.getDisplayName()) |
282 | customHtml = ClientHtml.addDescriptionTag(customHtml, description) | 283 | customHtml = ClientHtml.addDescriptionTag(customHtml, escapedTruncatedDescription) |
283 | 284 | ||
284 | const url = entity.getClientUrl() | 285 | const url = entity.getClientUrl() |
285 | const originUrl = entity.Actor.url | 286 | const originUrl = entity.Actor.url |
@@ -302,7 +303,7 @@ class ClientHtml { | |||
302 | originUrl, | 303 | originUrl, |
303 | escapedTitle: escapeHTML(title), | 304 | escapedTitle: escapeHTML(title), |
304 | escapedSiteName: escapeHTML(siteName), | 305 | escapedSiteName: escapeHTML(siteName), |
305 | escapedDescription: escapeHTML(description), | 306 | escapedTruncatedDescription, |
306 | image, | 307 | image, |
307 | ogType, | 308 | ogType, |
308 | twitterCard, | 309 | twitterCard, |
@@ -387,9 +388,9 @@ class ClientHtml { | |||
387 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.TITLE, titleTag) | 388 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.TITLE, titleTag) |
388 | } | 389 | } |
389 | 390 | ||
390 | private static addDescriptionTag (htmlStringPage: string, description?: string) { | 391 | private static addDescriptionTag (htmlStringPage: string, escapedTruncatedDescription?: string) { |
391 | const content = description || CONFIG.INSTANCE.SHORT_DESCRIPTION | 392 | const content = escapedTruncatedDescription || escapeHTML(CONFIG.INSTANCE.SHORT_DESCRIPTION) |
392 | const descriptionTag = `<meta name="description" content="${escapeHTML(content)}" />` | 393 | const descriptionTag = `<meta name="description" content="${content}" />` |
393 | 394 | ||
394 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.DESCRIPTION, descriptionTag) | 395 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.DESCRIPTION, descriptionTag) |
395 | } | 396 | } |
@@ -445,7 +446,7 @@ class ClientHtml { | |||
445 | } | 446 | } |
446 | 447 | ||
447 | metaTags['og:url'] = tags.url | 448 | metaTags['og:url'] = tags.url |
448 | metaTags['og:description'] = tags.escapedDescription | 449 | metaTags['og:description'] = tags.escapedTruncatedDescription |
449 | 450 | ||
450 | if (tags.embed) { | 451 | if (tags.embed) { |
451 | metaTags['og:video:url'] = tags.embed.url | 452 | metaTags['og:video:url'] = tags.embed.url |
@@ -461,7 +462,7 @@ class ClientHtml { | |||
461 | private static generateStandardMetaTags (tags: Tags) { | 462 | private static generateStandardMetaTags (tags: Tags) { |
462 | return { | 463 | return { |
463 | name: tags.escapedTitle, | 464 | name: tags.escapedTitle, |
464 | description: tags.escapedDescription, | 465 | description: tags.escapedTruncatedDescription, |
465 | image: tags.image.url | 466 | image: tags.image.url |
466 | } | 467 | } |
467 | } | 468 | } |
@@ -471,7 +472,7 @@ class ClientHtml { | |||
471 | 'twitter:card': tags.twitterCard, | 472 | 'twitter:card': tags.twitterCard, |
472 | 'twitter:site': CONFIG.SERVICES.TWITTER.USERNAME, | 473 | 'twitter:site': CONFIG.SERVICES.TWITTER.USERNAME, |
473 | 'twitter:title': tags.escapedTitle, | 474 | 'twitter:title': tags.escapedTitle, |
474 | 'twitter:description': tags.escapedDescription, | 475 | 'twitter:description': tags.escapedTruncatedDescription, |
475 | 'twitter:image': tags.image.url | 476 | 'twitter:image': tags.image.url |
476 | } | 477 | } |
477 | 478 | ||
@@ -494,7 +495,7 @@ class ClientHtml { | |||
494 | '@context': 'http://schema.org', | 495 | '@context': 'http://schema.org', |
495 | '@type': tags.schemaType, | 496 | '@type': tags.schemaType, |
496 | 'name': tags.escapedTitle, | 497 | 'name': tags.escapedTitle, |
497 | 'description': tags.escapedDescription, | 498 | 'description': tags.escapedTruncatedDescription, |
498 | 'image': tags.image.url, | 499 | 'image': tags.image.url, |
499 | 'url': tags.url | 500 | 'url': tags.url |
500 | } | 501 | } |
@@ -616,3 +617,7 @@ async function generateHTMLPage (req: express.Request, res: express.Response, pa | |||
616 | 617 | ||
617 | return sendHTML(html, res, true) | 618 | return sendHTML(html, res, true) |
618 | } | 619 | } |
620 | |||
621 | function buildEscapedTruncatedDescription (description: string) { | ||
622 | return truncate(mdToOneLinePlainText(description), { length: 200 }) | ||
623 | } | ||