video-coloring-page.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. var express = require('express');
  2. var router = express.Router();
  3. const models = require('../../models');
  4. const common = require('./common');
  5. const utils = require('../../libs/utils');
  6. const redis = require('../../libs/redis');
  7. const config = require('../../config/app');
  8. const CACHE_PREFIX = "art_v2";
  9. // const CACHE_EXPIRES = 60; // 60s刷新一次
  10. const CACHE_EXPIRES = 600;
  11. const artSelect = 'name title desc seoTitle seoDescription width height date publishTime tags lastMod mystery hasSpecial useSpecialThumb publishVersion totalStartCount totalDoneCount completionRate';
  12. // 获得所有video coloring pages
  13. router.get('/', (req, res, next) => {
  14. (async function () {
  15. let uri = req.originalUrl.substring(1);
  16. let cacheKey = `${CACHE_PREFIX}_video-coloring-pages`;
  17. let htmlData = await redis.getAsync(cacheKey);
  18. htmlData = null;
  19. if (!htmlData) {
  20. let videos = await models.ArtVideoStory
  21. .find({ enabled: true, seoTitle: { $exists: true } })
  22. .populate({ path: 'contents', model: 'Art', select: 'name title width height date publishTime tags lastMod publishVersion' })
  23. .sort({ order: 'asc' })
  24. .lean()
  25. .exec();
  26. let host = config.cdnHost ?? config.resHost;
  27. for (let doc of videos) {
  28. doc.poster = `${host}/thumbs/coloring-page/vs-poster/320/${doc._id}.webp`;
  29. doc.size = doc.contents.length;
  30. if (doc.seoTitle) {
  31. try {
  32. let titleJson = JSON.parse(doc.seoTitle);
  33. doc.seoTitle = titleJson && titleJson['en'] ? titleJson['en'] : doc.name;
  34. } catch (e) {
  35. console.error(e.message);
  36. }
  37. } else {
  38. doc.seoTitle = doc.name;
  39. }
  40. if (doc.seoDescription) {
  41. try {
  42. let descJson = JSON.parse(doc.seoDescription);
  43. doc.seoDescription = descJson && descJson['en'] ? descJson['en'] : doc.seoTitle;
  44. } catch (e) {
  45. console.error(e.message);
  46. }
  47. } else {
  48. doc.seoDescription = doc.seoTitle;
  49. }
  50. common.organizeData(doc.contents);
  51. delete doc.seoDescription;
  52. let jsonStr = JSON.stringify(doc, (key, value) => {
  53. if (key == 'seoTitle' || key == 'seoDescription') {
  54. value = value.replace(/"/g, '\\\"');
  55. }
  56. return value;
  57. });
  58. doc.jsonStr = jsonStr;
  59. }
  60. pageId = 'Video Coloring Pages';
  61. const comments = await models.Comment.find({ approved: true, page: pageId }).sort({ createdAt: -1 });
  62. let data = {
  63. uri: req.originalUrl,
  64. data: videos,
  65. pageId,
  66. comments,
  67. dateFormat: common.dateFormat,
  68. };
  69. // 渲染EJS模板到内存中
  70. res.render('v2/video-coloring-pages', data, async (err, html) => {
  71. if (err) {
  72. // 如果渲染出错,调用next()传递错误
  73. return next(err);
  74. }
  75. // 渲染成功,存redis, 发送数据到客户端
  76. htmlData = html;
  77. try {
  78. await redis.set(cacheKey, htmlData, 'EX', CACHE_EXPIRES);
  79. } catch (e) {
  80. console.error(e);
  81. }
  82. res.send(htmlData);
  83. });
  84. } else {
  85. // 缓存命中, 直接发送缓存数据
  86. res.set({ 'X-From-Cache': 'true' });
  87. res.send(htmlData);
  88. }
  89. })().catch(next);
  90. });
  91. // video coloring page详情页路由
  92. router.get('/:id', function (req, res, next) {
  93. (async function () {
  94. let id = req.params.id;
  95. utils.validators.validateId(id);
  96. let cacheKey = `${CACHE_PREFIX}_video_${id}`;
  97. let htmlData = await redis.getAsync(cacheKey);
  98. htmlData = null;
  99. if (!htmlData) {
  100. // 专辑
  101. let doc = await models.ArtVideoStory
  102. .findById(id)
  103. .populate({ path: 'contents', model: 'Art', select: artSelect, populate: { path: 'user', select: 'username name' } })
  104. .lean()
  105. .exec();
  106. if (!doc) throw createError(404, 'Page Not Found!');
  107. let host = config.cdnHost ?? config.resHost;
  108. doc.poster = `${host}/thumbs/coloring-page/vs-poster/320/${doc._id}.webp`;
  109. doc.size = doc.contents.length;
  110. doc.timeCreate = common.dateFormat(doc.timeCreate);
  111. if (doc.seoTitle) {
  112. try {
  113. let titleJson = JSON.parse(doc.seoTitle);
  114. doc.seoTitle = titleJson && titleJson['en'] ? titleJson['en'] : doc.name;
  115. } catch (e) {
  116. console.error(e.message);
  117. }
  118. } else {
  119. doc.seoTitle = doc.name;
  120. }
  121. if (doc.seoDescription) {
  122. try {
  123. let descJson = JSON.parse(doc.seoDescription);
  124. doc.seoDescription = descJson && descJson['en'] ? descJson['en'] : doc.seoTitle;
  125. } catch (e) {
  126. console.error(e.message);
  127. }
  128. } else {
  129. doc.seoDescription = doc.seoTitle;
  130. }
  131. common.organizeData(doc.contents);
  132. const comments = await models.Comment.find({ approved: true, page: id }).sort({ createdAt: -1 });
  133. // deeplink 相关
  134. let applink = `https://art.pcoloring.com${req.originalUrl}`;
  135. let downlink = `https://art.pcoloring.com/app`;
  136. let data = {
  137. title: doc.seoTitle,
  138. description: doc.seoDescription,
  139. data: doc,
  140. uri: req.originalUrl,
  141. pageId: id,
  142. comments,
  143. applink,
  144. downlink,
  145. };
  146. // 渲染EJS模板到内存中
  147. res.render('v2/video-coloring-page', data, async (err, html) => {
  148. if (err) {
  149. // 如果渲染出错,调用next()传递错误
  150. return next(err);
  151. }
  152. // 渲染成功,存redis, 发送数据到客户端
  153. htmlData = html;
  154. try {
  155. await redis.set(cacheKey, htmlData, 'EX', CACHE_EXPIRES);
  156. } catch (e) {
  157. console.error(e);
  158. }
  159. res.send(htmlData);
  160. });
  161. } else {
  162. // 缓存命中, 直接发送缓存数据
  163. res.set({ 'X-From-Cache': 'true' });
  164. res.send(htmlData);
  165. }
  166. })().catch(next);
  167. });
  168. module.exports = router;