Prerender opengraph tags in the server
authorChocobozzz <florian.bigard@gmail.com>
Fri, 11 Nov 2016 09:55:07 +0000 (10:55 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Wed, 16 Nov 2016 19:29:26 +0000 (20:29 +0100)
client/src/index.html
server.js
server/controllers/client.js [new file with mode: 0644]
server/controllers/index.js

index 7ae8fc54f4f6946e74127e99b3eb691f230dbf15..aa7a6035d7f8aa28b51614bb81b54b9d5a80b285 100644 (file)
@@ -6,6 +6,10 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
 
+    <!-- The following comment is used by the server to prerender OpenGraph tags -->
+    <!-- opengraph tags -->
+    <!-- Do not remove it! -->
+
     <link rel="icon" type="image/png" href="/client/assets/favicon.png" />
 
     <!-- TODO: bundle it with webpack when https://github.com/webpack/webpack/pull/1931 will be merged -->
index 65cf69f7db034f9a5b71e3f1440258afea031049..d3d3661add49ceec6ed25750ba999a065beaacb9 100644 (file)
--- a/server.js
+++ b/server.js
@@ -69,6 +69,7 @@ app.use(expressValidator({
 // API routes
 const apiRoute = '/api/' + constants.API_VERSION
 app.use(apiRoute, routes.api)
+app.use('/', routes.client)
 
 // Static files
 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
 const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR
 app.use(constants.STATIC_PATHS.THUMBNAILS, express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE }))
 
-// Client application
-app.use('/videos/embed', function (req, res, next) {
-  res.sendFile(path.join(__dirname, 'client/dist/standalone/videos/embed.html'))
-})
+// Always serve index client page
 app.use('/*', function (req, res, next) {
-  res.sendFile(path.join(__dirname, 'client/dist/index.html'))
+  res.sendFile(path.join(__dirname, './client/dist/index.html'))
 })
 
 // ----------- Tracker -----------
diff --git a/server/controllers/client.js b/server/controllers/client.js
new file mode 100644 (file)
index 0000000..68ffdbc
--- /dev/null
@@ -0,0 +1,85 @@
+'use strict'
+
+const parallel = require('async/parallel')
+const express = require('express')
+const fs = require('fs')
+const mongoose = require('mongoose')
+const path = require('path')
+
+const constants = require('../initializers/constants')
+const middlewares = require('../middlewares')
+const validators = middlewares.validators
+const validatorsVideos = validators.videos
+
+const Video = mongoose.model('Video')
+const router = express.Router()
+
+const opengraphComment = '<!-- opengraph tags -->'
+const embedPath = path.join(__dirname, '../../client/dist/standalone/videos/embed.html')
+const indexPath = path.join(__dirname, '../../client/dist/index.html')
+
+// Special route that add OpenGraph tags
+// Do not use a template engine for a so little thing
+router.use('/videos/watch/:id', validatorsVideos.videosGet, generateWatchHtmlPage)
+
+router.use('/videos/embed', function (req, res, next) {
+  res.sendFile(embedPath)
+})
+
+// ---------------------------------------------------------------------------
+
+module.exports = router
+
+// ---------------------------------------------------------------------------
+
+function addOpenGraphTags (htmlStringPage, video) {
+  const thumbnailUrl = constants.CONFIG.WEBSERVER.URL + video.thumbnailPath
+  const videoUrl = constants.CONFIG.WEBSERVER.URL + '/videos/watch/'
+
+  const metaTags = {
+    'og:type': 'video',
+    'og:title': video.name,
+    'og:image': thumbnailUrl,
+    'og:url': videoUrl,
+    'og:description': video.description,
+
+    'name': video.name,
+    'description': video.description,
+    'image': thumbnailUrl,
+
+    'twitter:card': 'summary_large_image',
+    'twitter:site': '@Chocobozzz',
+    'twitter:title': video.name,
+    'twitter:description': video.description,
+    'twitter:image': thumbnailUrl
+  }
+
+  let tagsString = ''
+  Object.keys(metaTags).forEach(function (tagName) {
+    const tagValue = metaTags[tagName]
+
+    tagsString += '<meta property="' + tagName + '" content="' + tagValue + '" />'
+  })
+
+  return htmlStringPage.replace(opengraphComment, tagsString)
+}
+
+function generateWatchHtmlPage (req, res, next) {
+  parallel({
+    file: function (callback) {
+      fs.readFile(indexPath, callback)
+    },
+
+    video: function (callback) {
+      Video.load(req.params.id, callback)
+    }
+  }, function (err, results) {
+    if (err) return next(err)
+
+    const html = results.file.toString()
+    const video = results.video.toFormatedJSON()
+
+    const htmlStringPageWithTags = addOpenGraphTags(html, video)
+    res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags)
+  })
+}
index 6a3f3f98f42172c90650f604b712a02b1e8024df..90b481e522070d20cae4ed074e0693454aafa8e9 100644 (file)
@@ -1,7 +1,9 @@
 'use strict'
 
 const apiController = require('./api/')
+const clientController = require('./client')
 
 module.exports = {
-  api: apiController
+  api: apiController,
+  client: clientController
 }