+ static async getDefaultHTMLPage (req: express.Request, res: express.Response, paramLang?: string) {
+ const html = paramLang
+ ? await ClientHtml.getIndexHTML(req, res, paramLang)
+ : await ClientHtml.getIndexHTML(req, res)
+
+ let customHtml = ClientHtml.addTitleTag(html)
+ customHtml = ClientHtml.addDescriptionTag(customHtml)
+
+ return customHtml
+ }
+
+ static async getWatchHTMLPage (videoId: string, req: express.Request, res: express.Response) {
+ // Let Angular application handle errors
+ if (!validator.isInt(videoId) && !validator.isUUID(videoId, 4)) {
+ res.status(HttpStatusCode.NOT_FOUND_404)
+ return ClientHtml.getIndexHTML(req, res)
+ }
+
+ const [ html, video ] = await Promise.all([
+ ClientHtml.getIndexHTML(req, res),
+ VideoModel.loadWithBlacklist(videoId)
+ ])
+
+ // Let Angular application handle errors
+ if (!video || video.privacy === VideoPrivacy.PRIVATE || video.privacy === VideoPrivacy.INTERNAL || video.VideoBlacklist) {
+ res.status(HttpStatusCode.NOT_FOUND_404)
+ return html
+ }
+
+ let customHtml = ClientHtml.addTitleTag(html, escapeHTML(video.name))
+ customHtml = ClientHtml.addDescriptionTag(customHtml, escapeHTML(video.description))
+
+ const url = WEBSERVER.URL + video.getWatchStaticPath()
+ const originUrl = video.url
+ const title = escapeHTML(video.name)
+ const siteName = escapeHTML(CONFIG.INSTANCE.NAME)
+ const description = escapeHTML(video.description)
+
+ const image = {
+ url: WEBSERVER.URL + video.getPreviewStaticPath()
+ }
+
+ const embed = {
+ url: WEBSERVER.URL + video.getEmbedStaticPath(),
+ createdAt: video.createdAt.toISOString(),
+ duration: getActivityStreamDuration(video.duration),
+ views: video.views
+ }
+
+ const ogType = 'video'
+ const twitterCard = CONFIG.SERVICES.TWITTER.WHITELISTED ? 'player' : 'summary_large_image'
+ const schemaType = 'VideoObject'
+
+ customHtml = ClientHtml.addTags(customHtml, {
+ url,
+ originUrl,
+ siteName,
+ title,
+ description,
+ image,
+ embed,
+ ogType,
+ twitterCard,
+ schemaType
+ })
+
+ return customHtml
+ }
+
+ static async getWatchPlaylistHTMLPage (videoPlaylistId: string, req: express.Request, res: express.Response) {
+ // Let Angular application handle errors
+ if (!validator.isInt(videoPlaylistId) && !validator.isUUID(videoPlaylistId, 4)) {
+ res.status(HttpStatusCode.NOT_FOUND_404)
+ return ClientHtml.getIndexHTML(req, res)
+ }
+
+ const [ html, videoPlaylist ] = await Promise.all([
+ ClientHtml.getIndexHTML(req, res),
+ VideoPlaylistModel.loadWithAccountAndChannel(videoPlaylistId, null)
+ ])
+
+ // Let Angular application handle errors
+ if (!videoPlaylist || videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) {
+ res.status(HttpStatusCode.NOT_FOUND_404)
+ return html
+ }
+
+ let customHtml = ClientHtml.addTitleTag(html, escapeHTML(videoPlaylist.name))
+ customHtml = ClientHtml.addDescriptionTag(customHtml, escapeHTML(videoPlaylist.description))
+
+ const url = videoPlaylist.getWatchUrl()
+ const originUrl = videoPlaylist.url
+ const title = escapeHTML(videoPlaylist.name)
+ const siteName = escapeHTML(CONFIG.INSTANCE.NAME)
+ const description = escapeHTML(videoPlaylist.description)
+
+ const image = {
+ url: videoPlaylist.getThumbnailUrl()
+ }
+
+ const embed = {
+ url: WEBSERVER.URL + videoPlaylist.getEmbedStaticPath(),
+ createdAt: videoPlaylist.createdAt.toISOString()
+ }
+
+ const list = {
+ numberOfItems: videoPlaylist.get('videosLength') as number
+ }
+
+ const ogType = 'video'
+ const twitterCard = CONFIG.SERVICES.TWITTER.WHITELISTED ? 'player' : 'summary'
+ const schemaType = 'ItemList'
+
+ customHtml = ClientHtml.addTags(customHtml, {
+ url,
+ originUrl,
+ siteName,
+ embed,
+ title,
+ description,
+ image,
+ list,
+ ogType,
+ twitterCard,
+ schemaType
+ })
+
+ return customHtml
+ }
+
+ static async getAccountHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
+ return this.getAccountOrChannelHTMLPage(() => AccountModel.loadByNameWithHost(nameWithHost), req, res)
+ }
+
+ static async getVideoChannelHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
+ return this.getAccountOrChannelHTMLPage(() => VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost), req, res)
+ }
+
+ static async getEmbedHTML () {
+ const path = ClientHtml.getEmbedPath()
+
+ if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]