diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
index 82c371f4d..d6aca10e7 100644
--- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
+++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
@@ -164,7 +164,8 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV
baseUrl: `${environment.originServerUrl}/videos/embed/${entry.video.uuid}`,
title: false,
warningTitle: false
- })
+ }),
+ entry.video.name
)
}
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts
index 7a98cab3b..ce115dfab 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -815,6 +815,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
? this.videoService.getVideoViewUrl(video.uuid)
: null,
embedUrl: video.embedUrl,
+ embedTitle: video.name,
isLive: video.isLive,
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
index e34836a18..eeb9f128b 100644
--- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
+++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
@@ -117,7 +117,8 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV
warningTitle: false,
startTime: abuse.video.startAt,
stopTime: abuse.video.endAt
- })
+ }),
+ abuse.video.name
)
}
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
index 5b06c0bc7..4ca6f52ad 100644
--- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
+++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
@@ -61,7 +61,8 @@ export class VideoReportComponent extends FormReactive implements OnInit {
baseUrl: this.video.embedUrl,
title: false,
warningTitle: false
- })
+ }),
+ this.video.name
)
)
}
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.ts b/client/src/app/shared/shared-share-modal/video-share.component.ts
index b06ff3751..e8760bfcc 100644
--- a/client/src/app/shared/shared-share-modal/video-share.component.ts
+++ b/client/src/app/shared/shared-share-modal/video-share.component.ts
@@ -86,14 +86,14 @@ export class VideoShareComponent {
const options = this.getVideoOptions(this.video.embedUrl)
const embedUrl = buildVideoLink(options)
- return buildVideoOrPlaylistEmbed(embedUrl)
+ return buildVideoOrPlaylistEmbed(embedUrl, this.video.name)
}
getPlaylistIframeCode () {
const options = this.getPlaylistOptions(this.playlist.embedUrl)
const embedUrl = buildPlaylistLink(options)
- return buildVideoOrPlaylistEmbed(embedUrl)
+ return buildVideoOrPlaylistEmbed(embedUrl, this.playlist.displayName)
}
getVideoUrl () {
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts
index e6d614c47..1d335805b 100644
--- a/client/src/assets/player/peertube-player-manager.ts
+++ b/client/src/assets/player/peertube-player-manager.ts
@@ -98,6 +98,7 @@ export interface CommonOptions extends CustomizationOptions {
videoViewUrl: string
embedUrl: string
+ embedTitle: string
isLive: boolean
@@ -165,7 +166,7 @@ export class PeertubePlayerManager {
PeertubePlayerManager.alreadyPlayed = true
})
- self.addContextMenu(mode, player, options.common.embedUrl)
+ self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle)
player.bezels()
@@ -203,7 +204,7 @@ export class PeertubePlayerManager {
videojs(newVideoElement, videojsOptions, function (this: videojs.Player) {
const player = this
- self.addContextMenu(mode, player, options.common.embedUrl)
+ self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle)
PeertubePlayerManager.onPlayerChange(player)
})
@@ -492,7 +493,7 @@ export class PeertubePlayerManager {
return children
}
- private static addContextMenu (mode: PlayerMode, player: videojs.Player, videoEmbedUrl: string) {
+ private static addContextMenu (mode: PlayerMode, player: videojs.Player, videoEmbedUrl: string, videoEmbedTitle: string) {
const content = [
{
label: player.localize('Copy the video URL'),
@@ -509,7 +510,7 @@ export class PeertubePlayerManager {
{
label: player.localize('Copy embed code'),
listener: () => {
- copyToClipboard(buildVideoOrPlaylistEmbed(videoEmbedUrl))
+ copyToClipboard(buildVideoOrPlaylistEmbed(videoEmbedUrl, videoEmbedTitle))
}
}
]
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts
index 6767459ce..d7451fa1d 100644
--- a/client/src/assets/player/utils.ts
+++ b/client/src/assets/player/utils.ts
@@ -1,4 +1,5 @@
import { VideoFile } from '@shared/models'
+import { escapeHTML } from '@shared/core-utils/renderer'
function toTitleCase (str: string) {
return str.charAt(0).toUpperCase() + str.slice(1)
@@ -170,9 +171,11 @@ function secondsToTime (seconds: number, full = false, symbol?: string) {
return time
}
-function buildVideoOrPlaylistEmbed (embedUrl: string) {
+function buildVideoOrPlaylistEmbed (embedUrl: string, embedTitle: string) {
+ const title = escapeHTML(embedTitle)
return ''
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index c87270027..614a1cc0b 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -545,7 +545,8 @@ export class PeerTubeEmbed {
serverUrl: window.location.origin,
language: navigator.language,
- embedUrl: window.location.origin + videoInfo.embedPath
+ embedUrl: window.location.origin + videoInfo.embedPath,
+ embedTitle: videoInfo.name
},
webtorrent: {
diff --git a/server/controllers/services.ts b/server/controllers/services.ts
index d0217c30a..189e1651b 100644
--- a/server/controllers/services.ts
+++ b/server/controllers/services.ts
@@ -3,6 +3,7 @@ import { EMBED_SIZE, PREVIEWS_SIZE, WEBSERVER, THUMBNAILS_SIZE } from '../initia
import { asyncMiddleware, oembedValidator } from '../middlewares'
import { accountNameWithHostGetValidator } from '../middlewares/validators'
import { MChannelSummary } from '@server/types/models'
+import { escapeHTML } from '@shared/core-utils/renderer'
const servicesRouter = express.Router()
@@ -79,6 +80,7 @@ function buildOEmbed (options: {
const embedUrl = webserverUrl + embedPath
let embedWidth = EMBED_SIZE.width
let embedHeight = EMBED_SIZE.height
+ const embedTitle = escapeHTML(title)
let thumbnailUrl = previewPath
? webserverUrl + previewPath
@@ -96,7 +98,7 @@ function buildOEmbed (options: {
}
const html = ``
+ `title="${embedTitle}" src="${embedUrl}" frameborder="0" allowfullscreen>`
const json: any = {
type: 'video',
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts
index 0bd84ffaa..b93868c12 100644
--- a/server/helpers/core-utils.ts
+++ b/server/helpers/core-utils.ts
@@ -154,24 +154,6 @@ function root () {
return rootPath
}
-// Thanks: https://stackoverflow.com/a/12034334
-function escapeHTML (stringParam) {
- if (!stringParam) return ''
-
- const entityMap = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- '\'': ''',
- '/': '/',
- '`': '`',
- '=': '='
- }
-
- return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s])
-}
-
function pageToStartAndCount (page: number, itemsPerPage: number) {
const start = (page - 1) * itemsPerPage
@@ -278,7 +260,6 @@ export {
objectConverter,
root,
- escapeHTML,
pageToStartAndCount,
sanitizeUrl,
sanitizeHost,
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index f19ec7df0..fcc11c7b2 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -5,7 +5,8 @@ import validator from 'validator'
import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n'
import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes'
import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos'
-import { escapeHTML, isTestInstance, sha256 } from '../helpers/core-utils'
+import { isTestInstance, sha256 } from '../helpers/core-utils'
+import { escapeHTML } from '@shared/core-utils/renderer'
import { logger } from '../helpers/logger'
import { CONFIG } from '../initializers/config'
import {
diff --git a/server/tests/api/server/services.ts b/server/tests/api/server/services.ts
index df910c111..6202eb66c 100644
--- a/server/tests/api/server/services.ts
+++ b/server/tests/api/server/services.ts
@@ -20,6 +20,7 @@ const expect = chai.expect
describe('Test services', function () {
let server: ServerInfo = null
let playlistUUID: string
+ let playlistDisplayName: string
let video: Video
before(async function () {
@@ -52,6 +53,7 @@ describe('Test services', function () {
})
playlistUUID = res.body.videoPlaylist.uuid
+ playlistDisplayName = 'The Life and Times of Scrooge McDuck'
await addVideoInPlaylist({
url: server.url,
@@ -69,7 +71,7 @@ describe('Test services', function () {
const res = await getOEmbed(server.url, oembedUrl)
const expectedHtml = ''
const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath
@@ -88,7 +90,7 @@ describe('Test services', function () {
const res = await getOEmbed(server.url, oembedUrl)
const expectedHtml = ''
expect(res.body.html).to.equal(expectedHtml)
@@ -109,7 +111,7 @@ describe('Test services', function () {
const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
const expectedHtml = ''
expect(res.body.html).to.equal(expectedHtml)
diff --git a/shared/core-utils/renderer/html.ts b/shared/core-utils/renderer/html.ts
index 1220848a0..de4ad47ac 100644
--- a/shared/core-utils/renderer/html.ts
+++ b/shared/core-utils/renderer/html.ts
@@ -19,3 +19,21 @@ export const SANITIZE_OPTIONS = {
}
}
}
+
+// Thanks: https://stackoverflow.com/a/12034334
+export function escapeHTML (stringParam: string) {
+ if (!stringParam) return ''
+
+ const entityMap = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ '\'': ''',
+ '/': '/',
+ '`': '`',
+ '=': '='
+ }
+
+ return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s])
+}