Init commit
This commit is contained in:
215
server/core/controllers/feeds/video-feeds.ts
Normal file
215
server/core/controllers/feeds/video-feeds.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
import { Feed } from '@peertube/feed'
|
||||
import { buildDownloadFilesUrl } from '@peertube/peertube-core-utils'
|
||||
import { VideoInclude, VideoResolution } from '@peertube/peertube-models'
|
||||
import { getVideoFileMimeType } from '@server/lib/video-file.js'
|
||||
import { cacheRouteFactory } from '@server/middlewares/index.js'
|
||||
import { VideoModel } from '@server/models/video/video.js'
|
||||
import express from 'express'
|
||||
import { extname } from 'path'
|
||||
import { buildNSFWFilters } from '../../helpers/express-utils.js'
|
||||
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../../initializers/constants.js'
|
||||
import {
|
||||
asyncMiddleware,
|
||||
commonVideosFiltersValidatorFactory,
|
||||
feedsAccountOrChannelFiltersValidator,
|
||||
feedsFormatValidator,
|
||||
setDefaultVideosSort,
|
||||
setFeedFormatContentType,
|
||||
videosSortValidator,
|
||||
videoSubscriptionFeedsValidator
|
||||
} from '../../middlewares/index.js'
|
||||
import {
|
||||
buildFeedMetadata,
|
||||
getCommonVideoFeedAttributes,
|
||||
getPodcastFeedUrlCustomTag,
|
||||
getVideosForFeeds,
|
||||
initFeed,
|
||||
sendFeed
|
||||
} from './shared/index.js'
|
||||
|
||||
const videoFeedsRouter = express.Router()
|
||||
|
||||
const { middleware: cacheRouteMiddleware } = cacheRouteFactory({
|
||||
headerBlacklist: [ 'Content-Type' ]
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
videoFeedsRouter.get(
|
||||
'/videos.:format',
|
||||
videosSortValidator,
|
||||
setDefaultVideosSort,
|
||||
feedsFormatValidator,
|
||||
setFeedFormatContentType,
|
||||
cacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
|
||||
commonVideosFiltersValidatorFactory(),
|
||||
asyncMiddleware(feedsAccountOrChannelFiltersValidator),
|
||||
asyncMiddleware(generateVideoFeed)
|
||||
)
|
||||
|
||||
videoFeedsRouter.get(
|
||||
'/subscriptions.:format',
|
||||
videosSortValidator,
|
||||
setDefaultVideosSort,
|
||||
feedsFormatValidator,
|
||||
setFeedFormatContentType,
|
||||
cacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
|
||||
commonVideosFiltersValidatorFactory(),
|
||||
asyncMiddleware(videoSubscriptionFeedsValidator),
|
||||
asyncMiddleware(generateVideoFeedForSubscriptions)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
videoFeedsRouter
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function generateVideoFeed (req: express.Request, res: express.Response) {
|
||||
const account = res.locals.account
|
||||
const videoChannel = res.locals.videoChannel
|
||||
|
||||
const { name, description, imageUrl, ownerImageUrl, link, ownerLink } = await buildFeedMetadata({ videoChannel, account })
|
||||
|
||||
const feed = await initFeed({
|
||||
name,
|
||||
description,
|
||||
link,
|
||||
isPodcast: false,
|
||||
imageUrl: ownerImageUrl || imageUrl,
|
||||
author: { name, link: ownerLink },
|
||||
resourceType: 'videos',
|
||||
queryString: new URL(WEBSERVER.URL + req.url).search,
|
||||
|
||||
customXMLNS: [
|
||||
{
|
||||
name: 'podcast',
|
||||
value: 'https://podcastindex.org/namespace/1.0'
|
||||
}
|
||||
],
|
||||
customTags: videoChannel
|
||||
? [ getPodcastFeedUrlCustomTag(videoChannel) ]
|
||||
: []
|
||||
})
|
||||
|
||||
const data = await getVideosForFeeds({
|
||||
...buildNSFWFilters({ req, res }),
|
||||
|
||||
sort: req.query.sort,
|
||||
isLocal: req.query.isLocal,
|
||||
include: req.query.include | VideoInclude.FILES,
|
||||
accountId: account?.id,
|
||||
videoChannelId: videoChannel?.id
|
||||
})
|
||||
|
||||
addVideosToFeed(feed, data)
|
||||
|
||||
// Now the feed generation is done, let's send it!
|
||||
return sendFeed(feed, req, res)
|
||||
}
|
||||
|
||||
async function generateVideoFeedForSubscriptions (req: express.Request, res: express.Response) {
|
||||
const account = res.locals.account
|
||||
const { name, description, imageUrl, link } = await buildFeedMetadata({ account })
|
||||
|
||||
const feed = await initFeed({
|
||||
name,
|
||||
description,
|
||||
link,
|
||||
isPodcast: false,
|
||||
imageUrl,
|
||||
resourceType: 'videos',
|
||||
queryString: new URL(WEBSERVER.URL + req.url).search
|
||||
})
|
||||
|
||||
const data = await getVideosForFeeds({
|
||||
...buildNSFWFilters({ req, res }),
|
||||
|
||||
sort: req.query.sort,
|
||||
isLocal: req.query.isLocal,
|
||||
include: req.query.include | VideoInclude.FILES,
|
||||
displayOnlyForFollower: {
|
||||
actorId: res.locals.user.Account.Actor.id,
|
||||
orLocalVideos: false
|
||||
},
|
||||
user: res.locals.user
|
||||
})
|
||||
|
||||
addVideosToFeed(feed, data)
|
||||
|
||||
// Now the feed generation is done, let's send it!
|
||||
return sendFeed(feed, req, res)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
|
||||
/**
|
||||
* Adding video items to the feed object, one at a time
|
||||
*/
|
||||
for (const video of videos) {
|
||||
const formattedVideoFiles = video.getFormattedAllVideoFilesJSON(false)
|
||||
|
||||
const torrents = formattedVideoFiles.map(videoFile => ({
|
||||
title: video.name,
|
||||
url: videoFile.torrentUrl,
|
||||
size_in_bytes: videoFile.size
|
||||
}))
|
||||
|
||||
const videoFiles = formattedVideoFiles.map(videoFile => {
|
||||
return {
|
||||
type: getVideoFileMimeType(extname(videoFile.fileUrl), videoFile.resolution.id === VideoResolution.H_NOVIDEO),
|
||||
medium: 'video',
|
||||
height: videoFile.resolution.id,
|
||||
fileSize: videoFile.size,
|
||||
url: videoFile.fileUrl,
|
||||
framerate: videoFile.fps,
|
||||
duration: video.duration,
|
||||
lang: video.language
|
||||
}
|
||||
})
|
||||
|
||||
const { videoFile: bestFile, separatedAudioFile: bestAudioFile } = video.getMaxQualityAudioAndVideoFiles()
|
||||
const bestFiles = [ bestFile, bestAudioFile ].filter(f => !!f)
|
||||
|
||||
feed.addItem({
|
||||
...getCommonVideoFeedAttributes(video),
|
||||
|
||||
id: WEBSERVER.URL + video.getWatchStaticPath(),
|
||||
author: [
|
||||
{
|
||||
name: video.VideoChannel.getDisplayName(),
|
||||
link: video.VideoChannel.getClientUrl()
|
||||
}
|
||||
],
|
||||
torrents,
|
||||
|
||||
// Enclosure
|
||||
video: bestFiles.length !== 0
|
||||
? {
|
||||
url: buildDownloadFilesUrl({ baseUrl: WEBSERVER.URL, videoFiles: bestFiles.map(f => f.id), videoUUID: video.uuid }),
|
||||
length: bestFiles.reduce((p, f) => p + f.size, 0),
|
||||
type: getVideoFileMimeType('.mp4', bestFile.resolution === VideoResolution.H_NOVIDEO)
|
||||
}
|
||||
: undefined,
|
||||
|
||||
// Media RSS
|
||||
videos: videoFiles,
|
||||
|
||||
embed: {
|
||||
url: WEBSERVER.URL + video.getEmbedStaticPath(),
|
||||
allowFullscreen: true
|
||||
},
|
||||
player: {
|
||||
url: WEBSERVER.URL + video.getWatchStaticPath()
|
||||
},
|
||||
community: {
|
||||
statistics: {
|
||||
views: video.views
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user