ニジカ投稿局 https://tv.nizika.tv
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

191 lines
5.4 KiB

  1. import express from 'express'
  2. import { extname } from 'path'
  3. import { Feed } from '@peertube/feed'
  4. import { cacheRouteFactory } from '@server/middlewares/index.js'
  5. import { VideoModel } from '@server/models/video/video.js'
  6. import { VideoInclude, VideoResolution } from '@peertube/peertube-models'
  7. import { buildNSFWFilter } from '../../helpers/express-utils.js'
  8. import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../../initializers/constants.js'
  9. import {
  10. asyncMiddleware,
  11. commonVideosFiltersValidator,
  12. feedsFormatValidator,
  13. setDefaultVideosSort,
  14. setFeedFormatContentType,
  15. feedsAccountOrChannelFiltersValidator,
  16. videosSortValidator,
  17. videoSubscriptionFeedsValidator
  18. } from '../../middlewares/index.js'
  19. import { buildFeedMetadata, getCommonVideoFeedAttributes, getVideosForFeeds, initFeed, sendFeed } from './shared/index.js'
  20. import { getVideoFileMimeType } from '@server/lib/video-file.js'
  21. const videoFeedsRouter = express.Router()
  22. const { middleware: cacheRouteMiddleware } = cacheRouteFactory({
  23. headerBlacklist: [ 'Content-Type' ]
  24. })
  25. // ---------------------------------------------------------------------------
  26. videoFeedsRouter.get('/videos.:format',
  27. videosSortValidator,
  28. setDefaultVideosSort,
  29. feedsFormatValidator,
  30. setFeedFormatContentType,
  31. cacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
  32. commonVideosFiltersValidator,
  33. asyncMiddleware(feedsAccountOrChannelFiltersValidator),
  34. asyncMiddleware(generateVideoFeed)
  35. )
  36. videoFeedsRouter.get('/subscriptions.:format',
  37. videosSortValidator,
  38. setDefaultVideosSort,
  39. feedsFormatValidator,
  40. setFeedFormatContentType,
  41. cacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
  42. commonVideosFiltersValidator,
  43. asyncMiddleware(videoSubscriptionFeedsValidator),
  44. asyncMiddleware(generateVideoFeedForSubscriptions)
  45. )
  46. // ---------------------------------------------------------------------------
  47. export {
  48. videoFeedsRouter
  49. }
  50. // ---------------------------------------------------------------------------
  51. async function generateVideoFeed (req: express.Request, res: express.Response) {
  52. const account = res.locals.account
  53. const videoChannel = res.locals.videoChannel
  54. const { name, description, imageUrl, accountImageUrl, link, accountLink } = await buildFeedMetadata({ videoChannel, account })
  55. const feed = initFeed({
  56. name,
  57. description,
  58. link,
  59. isPodcast: false,
  60. imageUrl,
  61. author: { name, link: accountLink, imageUrl: accountImageUrl },
  62. resourceType: 'videos',
  63. queryString: new URL(WEBSERVER.URL + req.url).search
  64. })
  65. const data = await getVideosForFeeds({
  66. sort: req.query.sort,
  67. nsfw: buildNSFWFilter(res, req.query.nsfw),
  68. isLocal: req.query.isLocal,
  69. include: req.query.include | VideoInclude.FILES,
  70. accountId: account?.id,
  71. videoChannelId: videoChannel?.id
  72. })
  73. addVideosToFeed(feed, data)
  74. // Now the feed generation is done, let's send it!
  75. return sendFeed(feed, req, res)
  76. }
  77. async function generateVideoFeedForSubscriptions (req: express.Request, res: express.Response) {
  78. const account = res.locals.account
  79. const { name, description, imageUrl, link } = await buildFeedMetadata({ account })
  80. const feed = initFeed({
  81. name,
  82. description,
  83. link,
  84. isPodcast: false,
  85. imageUrl,
  86. resourceType: 'videos',
  87. queryString: new URL(WEBSERVER.URL + req.url).search
  88. })
  89. const data = await getVideosForFeeds({
  90. sort: req.query.sort,
  91. nsfw: buildNSFWFilter(res, req.query.nsfw),
  92. isLocal: req.query.isLocal,
  93. include: req.query.include | VideoInclude.FILES,
  94. displayOnlyForFollower: {
  95. actorId: res.locals.user.Account.Actor.id,
  96. orLocalVideos: false
  97. },
  98. user: res.locals.user
  99. })
  100. addVideosToFeed(feed, data)
  101. // Now the feed generation is done, let's send it!
  102. return sendFeed(feed, req, res)
  103. }
  104. // ---------------------------------------------------------------------------
  105. function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
  106. /**
  107. * Adding video items to the feed object, one at a time
  108. */
  109. for (const video of videos) {
  110. const formattedVideoFiles = video.getFormattedAllVideoFilesJSON(false)
  111. const torrents = formattedVideoFiles.map(videoFile => ({
  112. title: video.name,
  113. url: videoFile.torrentUrl,
  114. size_in_bytes: videoFile.size
  115. }))
  116. const videoFiles = formattedVideoFiles.map(videoFile => {
  117. return {
  118. type: getVideoFileMimeType(extname(videoFile.fileUrl), videoFile.resolution.id === VideoResolution.H_NOVIDEO),
  119. medium: 'video',
  120. height: videoFile.resolution.id,
  121. fileSize: videoFile.size,
  122. url: videoFile.fileUrl,
  123. framerate: videoFile.fps,
  124. duration: video.duration,
  125. lang: video.language
  126. }
  127. })
  128. feed.addItem({
  129. ...getCommonVideoFeedAttributes(video),
  130. id: WEBSERVER.URL + video.getWatchStaticPath(),
  131. author: [
  132. {
  133. name: video.VideoChannel.getDisplayName(),
  134. link: video.VideoChannel.getClientUrl()
  135. }
  136. ],
  137. torrents,
  138. // Enclosure
  139. video: videoFiles.length !== 0
  140. ? {
  141. url: videoFiles[0].url,
  142. length: videoFiles[0].fileSize,
  143. type: videoFiles[0].type
  144. }
  145. : undefined,
  146. // Media RSS
  147. videos: videoFiles,
  148. embed: {
  149. url: WEBSERVER.URL + video.getEmbedStaticPath(),
  150. allowFullscreen: true
  151. },
  152. player: {
  153. url: WEBSERVER.URL + video.getWatchStaticPath()
  154. },
  155. community: {
  156. statistics: {
  157. views: video.views
  158. }
  159. }
  160. })
  161. }
  162. }