diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2016-11-11 10:55:07 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2016-11-16 20:29:26 +0100 |
commit | 830bcd0f82c16b8b5f1259150a6d541a210693eb (patch) | |
tree | 0c53767ad759cb6891be7fdc3a79631e176fc68a | |
parent | ad4013d5c3b0e67c453f10962a5b1e3c9b563b74 (diff) | |
download | PeerTube-830bcd0f82c16b8b5f1259150a6d541a210693eb.tar.gz PeerTube-830bcd0f82c16b8b5f1259150a6d541a210693eb.tar.zst PeerTube-830bcd0f82c16b8b5f1259150a6d541a210693eb.zip |
Prerender opengraph tags in the server
-rw-r--r-- | client/src/index.html | 4 | ||||
-rw-r--r-- | server.js | 8 | ||||
-rw-r--r-- | server/controllers/client.js | 85 | ||||
-rw-r--r-- | server/controllers/index.js | 4 |
4 files changed, 95 insertions, 6 deletions
diff --git a/client/src/index.html b/client/src/index.html index 7ae8fc54f..aa7a6035d 100644 --- a/client/src/index.html +++ b/client/src/index.html | |||
@@ -6,6 +6,10 @@ | |||
6 | <meta charset="UTF-8"> | 6 | <meta charset="UTF-8"> |
7 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 7 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
8 | 8 | ||
9 | <!-- The following comment is used by the server to prerender OpenGraph tags --> | ||
10 | <!-- opengraph tags --> | ||
11 | <!-- Do not remove it! --> | ||
12 | |||
9 | <link rel="icon" type="image/png" href="/client/assets/favicon.png" /> | 13 | <link rel="icon" type="image/png" href="/client/assets/favicon.png" /> |
10 | 14 | ||
11 | <!-- TODO: bundle it with webpack when https://github.com/webpack/webpack/pull/1931 will be merged --> | 15 | <!-- TODO: bundle it with webpack when https://github.com/webpack/webpack/pull/1931 will be merged --> |
@@ -69,6 +69,7 @@ app.use(expressValidator({ | |||
69 | // API routes | 69 | // API routes |
70 | const apiRoute = '/api/' + constants.API_VERSION | 70 | const apiRoute = '/api/' + constants.API_VERSION |
71 | app.use(apiRoute, routes.api) | 71 | app.use(apiRoute, routes.api) |
72 | app.use('/', routes.client) | ||
72 | 73 | ||
73 | // Static files | 74 | // Static files |
74 | app.use('/client', express.static(path.join(__dirname, '/client/dist'), { maxAge: constants.STATIC_MAX_AGE })) | 75 | app.use('/client', express.static(path.join(__dirname, '/client/dist'), { maxAge: constants.STATIC_MAX_AGE })) |
@@ -88,12 +89,9 @@ app.use(constants.STATIC_PATHS.WEBSEED, cors(), express.static(videosPhysicalPat | |||
88 | const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR | 89 | const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR |
89 | app.use(constants.STATIC_PATHS.THUMBNAILS, express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })) | 90 | app.use(constants.STATIC_PATHS.THUMBNAILS, express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })) |
90 | 91 | ||
91 | // Client application | 92 | // Always serve index client page |
92 | app.use('/videos/embed', function (req, res, next) { | ||
93 | res.sendFile(path.join(__dirname, 'client/dist/standalone/videos/embed.html')) | ||
94 | }) | ||
95 | app.use('/*', function (req, res, next) { | 93 | app.use('/*', function (req, res, next) { |
96 | res.sendFile(path.join(__dirname, 'client/dist/index.html')) | 94 | res.sendFile(path.join(__dirname, './client/dist/index.html')) |
97 | }) | 95 | }) |
98 | 96 | ||
99 | // ----------- Tracker ----------- | 97 | // ----------- Tracker ----------- |
diff --git a/server/controllers/client.js b/server/controllers/client.js new file mode 100644 index 000000000..68ffdbcd5 --- /dev/null +++ b/server/controllers/client.js | |||
@@ -0,0 +1,85 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | const parallel = require('async/parallel') | ||
4 | const express = require('express') | ||
5 | const fs = require('fs') | ||
6 | const mongoose = require('mongoose') | ||
7 | const path = require('path') | ||
8 | |||
9 | const constants = require('../initializers/constants') | ||
10 | const middlewares = require('../middlewares') | ||
11 | const validators = middlewares.validators | ||
12 | const validatorsVideos = validators.videos | ||
13 | |||
14 | const Video = mongoose.model('Video') | ||
15 | const router = express.Router() | ||
16 | |||
17 | const opengraphComment = '<!-- opengraph tags -->' | ||
18 | const embedPath = path.join(__dirname, '../../client/dist/standalone/videos/embed.html') | ||
19 | const indexPath = path.join(__dirname, '../../client/dist/index.html') | ||
20 | |||
21 | // Special route that add OpenGraph tags | ||
22 | // Do not use a template engine for a so little thing | ||
23 | router.use('/videos/watch/:id', validatorsVideos.videosGet, generateWatchHtmlPage) | ||
24 | |||
25 | router.use('/videos/embed', function (req, res, next) { | ||
26 | res.sendFile(embedPath) | ||
27 | }) | ||
28 | |||
29 | // --------------------------------------------------------------------------- | ||
30 | |||
31 | module.exports = router | ||
32 | |||
33 | // --------------------------------------------------------------------------- | ||
34 | |||
35 | function addOpenGraphTags (htmlStringPage, video) { | ||
36 | const thumbnailUrl = constants.CONFIG.WEBSERVER.URL + video.thumbnailPath | ||
37 | const videoUrl = constants.CONFIG.WEBSERVER.URL + '/videos/watch/' | ||
38 | |||
39 | const metaTags = { | ||
40 | 'og:type': 'video', | ||
41 | 'og:title': video.name, | ||
42 | 'og:image': thumbnailUrl, | ||
43 | 'og:url': videoUrl, | ||
44 | 'og:description': video.description, | ||
45 | |||
46 | 'name': video.name, | ||
47 | 'description': video.description, | ||
48 | 'image': thumbnailUrl, | ||
49 | |||
50 | 'twitter:card': 'summary_large_image', | ||
51 | 'twitter:site': '@Chocobozzz', | ||
52 | 'twitter:title': video.name, | ||
53 | 'twitter:description': video.description, | ||
54 | 'twitter:image': thumbnailUrl | ||
55 | } | ||
56 | |||
57 | let tagsString = '' | ||
58 | Object.keys(metaTags).forEach(function (tagName) { | ||
59 | const tagValue = metaTags[tagName] | ||
60 | |||
61 | tagsString += '<meta property="' + tagName + '" content="' + tagValue + '" />' | ||
62 | }) | ||
63 | |||
64 | return htmlStringPage.replace(opengraphComment, tagsString) | ||
65 | } | ||
66 | |||
67 | function generateWatchHtmlPage (req, res, next) { | ||
68 | parallel({ | ||
69 | file: function (callback) { | ||
70 | fs.readFile(indexPath, callback) | ||
71 | }, | ||
72 | |||
73 | video: function (callback) { | ||
74 | Video.load(req.params.id, callback) | ||
75 | } | ||
76 | }, function (err, results) { | ||
77 | if (err) return next(err) | ||
78 | |||
79 | const html = results.file.toString() | ||
80 | const video = results.video.toFormatedJSON() | ||
81 | |||
82 | const htmlStringPageWithTags = addOpenGraphTags(html, video) | ||
83 | res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags) | ||
84 | }) | ||
85 | } | ||
diff --git a/server/controllers/index.js b/server/controllers/index.js index 6a3f3f98f..90b481e52 100644 --- a/server/controllers/index.js +++ b/server/controllers/index.js | |||
@@ -1,7 +1,9 @@ | |||
1 | 'use strict' | 1 | 'use strict' |
2 | 2 | ||
3 | const apiController = require('./api/') | 3 | const apiController = require('./api/') |
4 | const clientController = require('./client') | ||
4 | 5 | ||
5 | module.exports = { | 6 | module.exports = { |
6 | api: apiController | 7 | api: apiController, |
8 | client: clientController | ||
7 | } | 9 | } |