common.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. const { format } = require('date-fns');
  2. const config = require('../../config/app');
  3. const models = require('../../models');
  4. /**
  5. * 清理填色页标签数组。
  6. * 执行以下过滤操作:
  7. * 1. 去除重复的标签。
  8. * 2. 移除包含中文字符的标签。
  9. * 3. 移除以 "album" 开头的标签(不区分大小写)。
  10. * 4. 移除以数字开头的标签。
  11. *
  12. * @param {string[]} tags - 原始标签数组。
  13. * @returns {string[]} 过滤和去重后的标签数组。
  14. */
  15. function cleanAndFilterTags(tags) {
  16. if (!Array.isArray(tags)) {
  17. console.warn("Input is not an array. Returning empty array.");
  18. return [];
  19. }
  20. // 1. 使用 Set 去除重复项,并转换为小写以进行后续统一比较
  21. const uniqueTags = new Set(tags.map(tag => typeof tag === 'string' ? tag.trim().toLowerCase() : ''));
  22. const filteredTags = [];
  23. // 正则表达式用于匹配中文字符
  24. const chineseRegex = /[\u4e00-\u9fa5]/;
  25. // 正则表达式用于匹配数字开头
  26. const startsWithNumberRegex = /^[0-9]/;
  27. for (const tag of uniqueTags) {
  28. // 确保标签非空
  29. if (!tag) {
  30. continue;
  31. }
  32. // 2. 移除中文标签
  33. if (chineseRegex.test(tag)) {
  34. continue;
  35. }
  36. // 3. 移除以 "album" 开头的标签
  37. if (tag.startsWith('album')) { // 已经在转换为小写后,所以直接用'album'
  38. continue;
  39. }
  40. // 4. 移除以"ps_"开头的标签
  41. if (tag.startsWith('ps_')) {
  42. continue;
  43. }
  44. // 5. 移除以数字开头的标签
  45. if (startsWithNumberRegex.test(tag)) {
  46. continue;
  47. }
  48. filteredTags.push(tag);
  49. }
  50. return filteredTags;
  51. }
  52. function dateFormat(date) {
  53. return format(new Date(date), 'MMMM do, yyyy');
  54. }
  55. const organizeData = (data) => {
  56. data.forEach(doc => {
  57. let host = config.cdnHost ?? config.resHost;
  58. let publishVersion = doc.publishVersion || 0;
  59. let version = publishVersion + 1500;
  60. doc.thumb = `${host}/thumbs/coloring-page/page/480/${doc._id}.webp`;
  61. doc.work = `${host}/thumbs/coloring-page/work/480/${doc._id}.webp`;
  62. doc.zip = `${host}/zips/v2/number_mini/${version}/${doc._id}.zip`;
  63. if (doc.title) {
  64. try {
  65. let titleJson = JSON.parse(doc.title);
  66. doc.title = titleJson && titleJson['en'] ? titleJson['en'] : doc.name;
  67. } catch (e) {
  68. console.error(e.message);
  69. }
  70. } else {
  71. doc.title = doc.name;
  72. }
  73. doc.publishTime = format(new Date(doc.publishTime), 'MMMM do, yyyy');
  74. doc.tags = cleanAndFilterTags(doc.tags);
  75. doc.uri = `/coloring-page/${doc._id}`;
  76. delete doc.hasSpecial;
  77. delete doc.useSpecialThumb;
  78. delete doc.publishVersion;
  79. delete doc.desc;
  80. })
  81. }
  82. const organizeDetail = (doc) => {
  83. let host = config.cdnHost ?? config.resHost;
  84. let publishVersion = doc.publishVersion || 0;
  85. let version = publishVersion + 1500;
  86. doc.poster = `${host}/thumbs/coloring-page/page/640/${doc._id}.webp`;
  87. doc.thumb = `${host}/thumbs/coloring-page/page/480/${doc._id}.webp`;
  88. doc.work = `${host}/thumbs/coloring-page/work/480/${doc._id}.webp`;
  89. doc.zip = `${host}/zips/v2/number_mini/${version}/${doc._id}.zip`
  90. doc.user.avatar = `/thumbs/v1/avatar/128/${doc.user._id}.webp`;
  91. if (doc.title) {
  92. try {
  93. let titleJson = JSON.parse(doc.title);
  94. doc.title = titleJson && titleJson['en'] ? titleJson['en'] : doc.name;
  95. } catch (e) {
  96. console.error(e.message);
  97. }
  98. } else {
  99. doc.title = doc.name;
  100. }
  101. if (doc.desc) {
  102. try {
  103. let descJson = JSON.parse(doc.desc);
  104. doc.desc = descJson && descJson['en'] ? descJson['en'] : '';
  105. } catch (e) {
  106. console.error(e.message);
  107. }
  108. }
  109. if (doc.seoTitle) {
  110. try {
  111. let seoTitleJson = JSON.parse(doc.seoTitle);
  112. doc.seoTitle = seoTitleJson && seoTitleJson['en'] ? seoTitleJson['en'] : '';
  113. } catch (e) {
  114. console.error(e.message);
  115. }
  116. }
  117. if (doc.seoDescription) {
  118. try {
  119. let seoDescriptionJson = JSON.parse(doc.seoDescription);
  120. doc.seoDescription = seoDescriptionJson && seoDescriptionJson['en'] ? seoDescriptionJson['en'] : '';
  121. } catch (e) {
  122. console.error(e.message);
  123. }
  124. }
  125. doc.publishTime = format(new Date(doc.publishTime), 'MMMM do, yyyy');
  126. doc.tags = cleanAndFilterTags(doc.tags);
  127. doc.downlink = `${host}/thumbs/coloring-page/page/1200/${doc._id}.webp`;
  128. delete doc.hasSpecial;
  129. delete doc.useSpecialThumb;
  130. delete doc.publishVersion;
  131. }
  132. // 替换URI中的page参数
  133. function replaceUriParams(uri, page) {
  134. if (!uri.includes('page=')) {
  135. if (uri.includes('?')) uri += `&page=${page}`;
  136. else uri += `?page=${page}`
  137. } else {
  138. // 使用正则表达式替换page参数
  139. uri = uri.replace(/(page=)\d+/, `page=${page}`);
  140. }
  141. if (page == 1) {
  142. uri = uri.replace(/(?:\?|&)((page)=\d+)/g, '');
  143. }
  144. // 返回替换后的URI
  145. return uri;
  146. }
  147. const userMap = {};
  148. async function getUserIdByUsername(username) {
  149. let userId = userMap[username];
  150. if (!userId) {
  151. let doc = await models.User.findOne({ username });
  152. if (doc) {
  153. userId = doc._id;
  154. userMap[username] = userId;
  155. }
  156. }
  157. return userId;
  158. }
  159. module.exports = {
  160. organizeData,
  161. organizeDetail,
  162. replaceUriParams,
  163. getUserIdByUsername,
  164. dateFormat,
  165. }