bots.ts 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import * as express from 'express'
  2. import { asyncMiddleware } from '../middlewares'
  3. import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
  4. import { SitemapStream, streamToPromise } from 'sitemap'
  5. import { VideoModel } from '../models/video/video'
  6. import { VideoChannelModel } from '../models/video/video-channel'
  7. import { AccountModel } from '../models/account/account'
  8. import { cacheRoute } from '../middlewares/cache'
  9. import { buildNSFWFilter } from '../helpers/express-utils'
  10. import { truncate } from 'lodash'
  11. const botsRouter = express.Router()
  12. // Special route that add OpenGraph and oEmbed tags
  13. // Do not use a template engine for a so little thing
  14. botsRouter.use('/sitemap.xml',
  15. asyncMiddleware(cacheRoute()(ROUTE_CACHE_LIFETIME.SITEMAP)),
  16. asyncMiddleware(getSitemap)
  17. )
  18. // ---------------------------------------------------------------------------
  19. export {
  20. botsRouter
  21. }
  22. // ---------------------------------------------------------------------------
  23. async function getSitemap (req: express.Request, res: express.Response) {
  24. let urls = getSitemapBasicUrls()
  25. urls = urls.concat(await getSitemapLocalVideoUrls())
  26. urls = urls.concat(await getSitemapVideoChannelUrls())
  27. urls = urls.concat(await getSitemapAccountUrls())
  28. const sitemapStream = new SitemapStream({ hostname: WEBSERVER.URL })
  29. for (const url of urls) {
  30. sitemapStream.write({ url })
  31. }
  32. sitemapStream.end()
  33. const xml = await streamToPromise(sitemapStream)
  34. res.header('Content-Type', 'application/xml')
  35. res.send(xml)
  36. }
  37. async function getSitemapVideoChannelUrls () {
  38. const rows = await VideoChannelModel.listLocalsForSitemap('createdAt')
  39. return rows.map(channel => ({
  40. url: WEBSERVER.URL + '/video-channels/' + channel.Actor.preferredUsername
  41. }))
  42. }
  43. async function getSitemapAccountUrls () {
  44. const rows = await AccountModel.listLocalsForSitemap('createdAt')
  45. return rows.map(channel => ({
  46. url: WEBSERVER.URL + '/accounts/' + channel.Actor.preferredUsername
  47. }))
  48. }
  49. async function getSitemapLocalVideoUrls () {
  50. const { data } = await VideoModel.listForApi({
  51. start: 0,
  52. count: undefined,
  53. sort: 'createdAt',
  54. includeLocalVideos: true,
  55. nsfw: buildNSFWFilter(),
  56. filter: 'local',
  57. withFiles: false,
  58. countVideos: false
  59. })
  60. return data.map(v => ({
  61. url: WEBSERVER.URL + '/videos/watch/' + v.uuid,
  62. video: [
  63. {
  64. title: v.name,
  65. // Sitemap description should be < 2000 characters
  66. description: truncate(v.description || v.name, { length: 2000, omission: '...' }),
  67. player_loc: WEBSERVER.URL + '/videos/embed/' + v.uuid,
  68. thumbnail_loc: WEBSERVER.URL + v.getMiniatureStaticPath()
  69. }
  70. ]
  71. }))
  72. }
  73. function getSitemapBasicUrls () {
  74. const paths = [
  75. '/about/instance',
  76. '/videos/local'
  77. ]
  78. return paths.map(p => ({ url: WEBSERVER.URL + p }))
  79. }