+async function videoLikesController (req: express.Request, res: express.Response) {
+ const video = res.locals.onlyImmutableVideo
+ const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video))
+
+ return activityPubResponse(activityPubContextify(json), res)
+}
+
+async function videoDislikesController (req: express.Request, res: express.Response) {
+ const video = res.locals.onlyImmutableVideo
+ const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video))
+
+ return activityPubResponse(activityPubContextify(json), res)
+}
+
+async function videoCommentsController (req: express.Request, res: express.Response) {
+ const video = res.locals.onlyImmutableVideo
+
+ const handler = async (start: number, count: number) => {
+ const result = await VideoCommentModel.listAndCountByVideoForAP(video, start, count)
+ return {
+ total: result.count,
+ data: result.rows.map(r => r.url)
+ }
+ }
+ const json = await activityPubCollectionPagination(getVideoCommentsActivityPubUrl(video), handler, req.query.page)
+
+ return activityPubResponse(activityPubContextify(json), res)
+}
+
+function videoChannelController (req: express.Request, res: express.Response) {
+ const videoChannel = res.locals.videoChannel
+
+ return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
+}
+
+async function videoChannelFollowersController (req: express.Request, res: express.Response) {
+ const videoChannel = res.locals.videoChannel
+ const activityPubResult = await actorFollowers(req, videoChannel.Actor)
+
+ return activityPubResponse(activityPubContextify(activityPubResult), res)
+}
+
+async function videoChannelFollowingController (req: express.Request, res: express.Response) {
+ const videoChannel = res.locals.videoChannel
+ const activityPubResult = await actorFollowing(req, videoChannel.Actor)
+
+ return activityPubResponse(activityPubContextify(activityPubResult), res)
+}
+
+async function videoCommentController (req: express.Request, res: express.Response) {
+ const videoComment = res.locals.videoCommentFull
+
+ if (videoComment.url.startsWith(WEBSERVER.URL) === false) return res.redirect(videoComment.url)
+
+ const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, undefined)
+ const isPublic = true // Comments are always public
+ let videoCommentObject = videoComment.toActivityPubObject(threadParentComments)
+
+ if (videoComment.Account) {
+ const audience = getAudience(videoComment.Account.Actor, isPublic)
+ videoCommentObject = audiencify(videoCommentObject, audience)
+
+ if (req.path.endsWith('/activity')) {
+ const data = buildCreateActivity(videoComment.url, videoComment.Account.Actor, videoCommentObject, audience)
+ return activityPubResponse(activityPubContextify(data), res)
+ }
+ }
+
+ return activityPubResponse(activityPubContextify(videoCommentObject), res)
+}
+
+async function videoRedundancyController (req: express.Request, res: express.Response) {
+ const videoRedundancy = res.locals.videoRedundancy
+ if (videoRedundancy.url.startsWith(WEBSERVER.URL) === false) return res.redirect(videoRedundancy.url)
+
+ const serverActor = await getServerActor()
+
+ const audience = getAudience(serverActor)
+ const object = audiencify(videoRedundancy.toActivityPubObject(), audience)
+
+ if (req.path.endsWith('/activity')) {
+ const data = buildCreateActivity(videoRedundancy.url, serverActor, object, audience)
+ return activityPubResponse(activityPubContextify(data, 'CacheFile'), res)
+ }
+
+ return activityPubResponse(activityPubContextify(object, 'CacheFile'), res)
+}
+
+async function videoPlaylistController (req: express.Request, res: express.Response) {
+ const playlist = res.locals.videoPlaylistFull
+
+ // We need more attributes
+ playlist.OwnerAccount = await AccountModel.load(playlist.ownerAccountId)
+
+ const json = await playlist.toActivityPubObject(req.query.page, null)
+ const audience = getAudience(playlist.OwnerAccount.Actor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC)
+ const object = audiencify(json, audience)
+
+ return activityPubResponse(activityPubContextify(object), res)
+}
+
+function videoPlaylistElementController (req: express.Request, res: express.Response) {
+ const videoPlaylistElement = res.locals.videoPlaylistElementAP
+
+ const json = videoPlaylistElement.toActivityPubObject()
+ return activityPubResponse(activityPubContextify(json), res)
+}
+
+// ---------------------------------------------------------------------------
+
+async function actorFollowing (req: express.Request, actor: MActorId) {
+ const handler = (start: number, count: number) => {
+ return ActorFollowModel.listAcceptedFollowingUrlsForApi([ actor.id ], undefined, start, count)
+ }
+
+ return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page)
+}
+
+async function actorFollowers (req: express.Request, actor: MActorId) {
+ const handler = (start: number, count: number) => {
+ return ActorFollowModel.listAcceptedFollowerUrlsForAP([ actor.id ], undefined, start, count)
+ }
+
+ return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page)
+}
+
+async function actorPlaylists (req: express.Request, options: { account: MAccountId } | { channel: MChannelId }) {
+ const handler = (start: number, count: number) => {
+ return VideoPlaylistModel.listPublicUrlsOfForAP(options, start, count)
+ }
+
+ return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page)
+}