diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/client.ts | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index aff00fe6e..a29b51c51 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -3,17 +3,24 @@ import * as express from 'express' | |||
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import * as validator from 'validator' | 4 | import * as validator from 'validator' |
5 | import { escapeHTML, readFileBufferPromise, root } from '../helpers/core-utils' | 5 | import { escapeHTML, readFileBufferPromise, root } from '../helpers/core-utils' |
6 | import { CONFIG, EMBED_SIZE, OPENGRAPH_AND_OEMBED_COMMENT, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers' | 6 | import { |
7 | ACCEPT_HEADERS, | ||
8 | CONFIG, | ||
9 | EMBED_SIZE, | ||
10 | OPENGRAPH_AND_OEMBED_COMMENT, | ||
11 | STATIC_MAX_AGE, | ||
12 | STATIC_PATHS | ||
13 | } from '../initializers' | ||
7 | import { asyncMiddleware } from '../middlewares' | 14 | import { asyncMiddleware } from '../middlewares' |
8 | import { VideoModel } from '../models/video/video' | 15 | import { VideoModel } from '../models/video/video' |
9 | import { VideoPrivacy } from '../../shared/models/videos' | 16 | import { VideoPrivacy } from '../../shared/models/videos' |
17 | import { I18N_LOCALES, is18nLocale, getDefaultLocale } from '../../shared/models' | ||
10 | 18 | ||
11 | const clientsRouter = express.Router() | 19 | const clientsRouter = express.Router() |
12 | 20 | ||
13 | const distPath = join(root(), 'client', 'dist') | 21 | const distPath = join(root(), 'client', 'dist') |
14 | const assetsImagesPath = join(root(), 'client', 'dist', 'assets', 'images') | 22 | const assetsImagesPath = join(root(), 'client', 'dist', 'assets', 'images') |
15 | const embedPath = join(distPath, 'standalone', 'videos', 'embed.html') | 23 | const embedPath = join(distPath, 'standalone', 'videos', 'embed.html') |
16 | const indexPath = join(distPath, 'index.html') | ||
17 | 24 | ||
18 | // Special route that add OpenGraph and oEmbed tags | 25 | // Special route that add OpenGraph and oEmbed tags |
19 | // Do not use a template engine for a so little thing | 26 | // Do not use a template engine for a so little thing |
@@ -45,6 +52,16 @@ clientsRouter.use('/client/*', (req: express.Request, res: express.Response, nex | |||
45 | res.sendStatus(404) | 52 | res.sendStatus(404) |
46 | }) | 53 | }) |
47 | 54 | ||
55 | // Always serve index client page (the client is a single page application, let it handle routing) | ||
56 | // Try to provide the right language index.html | ||
57 | clientsRouter.use('/(:language)?', function (req, res) { | ||
58 | if (req.accepts(ACCEPT_HEADERS) === 'html') { | ||
59 | return res.sendFile(getIndexPath(req, req.params.language)) | ||
60 | } | ||
61 | |||
62 | return res.status(404).end() | ||
63 | }) | ||
64 | |||
48 | // --------------------------------------------------------------------------- | 65 | // --------------------------------------------------------------------------- |
49 | 66 | ||
50 | export { | 67 | export { |
@@ -53,6 +70,19 @@ export { | |||
53 | 70 | ||
54 | // --------------------------------------------------------------------------- | 71 | // --------------------------------------------------------------------------- |
55 | 72 | ||
73 | function getIndexPath (req: express.Request, paramLang?: string) { | ||
74 | let lang: string | ||
75 | |||
76 | // Check param lang validity | ||
77 | if (paramLang && is18nLocale(paramLang)) { | ||
78 | lang = paramLang | ||
79 | } else { | ||
80 | lang = req.acceptsLanguages(Object.keys(I18N_LOCALES)) || getDefaultLocale() | ||
81 | } | ||
82 | |||
83 | return join(__dirname, '../../../client/dist/' + lang + '/index.html') | ||
84 | } | ||
85 | |||
56 | function addOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoModel) { | 86 | function addOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoModel) { |
57 | const previewUrl = CONFIG.WEBSERVER.URL + STATIC_PATHS.PREVIEWS + video.getPreviewName() | 87 | const previewUrl = CONFIG.WEBSERVER.URL + STATIC_PATHS.PREVIEWS + video.getPreviewName() |
58 | const videoUrl = CONFIG.WEBSERVER.URL + '/videos/watch/' + video.uuid | 88 | const videoUrl = CONFIG.WEBSERVER.URL + '/videos/watch/' + video.uuid |
@@ -142,18 +172,18 @@ async function generateWatchHtmlPage (req: express.Request, res: express.Respons | |||
142 | } else if (validator.isInt(videoId)) { | 172 | } else if (validator.isInt(videoId)) { |
143 | videoPromise = VideoModel.loadAndPopulateAccountAndServerAndTags(+videoId) | 173 | videoPromise = VideoModel.loadAndPopulateAccountAndServerAndTags(+videoId) |
144 | } else { | 174 | } else { |
145 | return res.sendFile(indexPath) | 175 | return res.sendFile(getIndexPath(req)) |
146 | } | 176 | } |
147 | 177 | ||
148 | let [ file, video ] = await Promise.all([ | 178 | let [ file, video ] = await Promise.all([ |
149 | readFileBufferPromise(indexPath), | 179 | readFileBufferPromise(getIndexPath(req)), |
150 | videoPromise | 180 | videoPromise |
151 | ]) | 181 | ]) |
152 | 182 | ||
153 | const html = file.toString() | 183 | const html = file.toString() |
154 | 184 | ||
155 | // Let Angular application handle errors | 185 | // Let Angular application handle errors |
156 | if (!video || video.privacy === VideoPrivacy.PRIVATE) return res.sendFile(indexPath) | 186 | if (!video || video.privacy === VideoPrivacy.PRIVATE) return res.sendFile(getIndexPath(req)) |
157 | 187 | ||
158 | const htmlStringPageWithTags = addOpenGraphAndOEmbedTags(html, video) | 188 | const htmlStringPageWithTags = addOpenGraphAndOEmbedTags(html, video) |
159 | res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags) | 189 | res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags) |