X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;ds=sidebyside;f=server%2Fmodels%2Fvideo%2Fformatter%2Fvideo-format-utils.ts;h=ba49e41aedab8de0068110f1d8aed04fc643f27a;hb=3c10840fa90fc88fc98e8169faf4745ff6c80893;hp=5ddbf74dac0bf6d4ca49273b8efbf028e3565889;hpb=e5dbd5084e7ae91ce118c0bccd5b84c47b88c55f;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/formatter/video-format-utils.ts b/server/models/video/formatter/video-format-utils.ts index 5ddbf74da..ba49e41ae 100644 --- a/server/models/video/formatter/video-format-utils.ts +++ b/server/models/video/formatter/video-format-utils.ts @@ -1,11 +1,21 @@ +import { uuidToShort } from '@server/helpers/uuid' import { generateMagnetUri } from '@server/helpers/webtorrent' -import { getLocalVideoFileMetadataUrl } from '@server/lib/video-paths' +import { getLocalVideoFileMetadataUrl } from '@server/lib/video-urls' +import { VideosCommonQueryAfterSanitize } from '@shared/models' import { VideoFile } from '@shared/models/videos/video-file.model' import { ActivityTagObject, ActivityUrlObject, VideoObject } from '../../../../shared/models/activitypub/objects' -import { Video, VideoDetails } from '../../../../shared/models/videos' +import { Video, VideoDetails, VideoInclude } from '../../../../shared/models/videos' import { VideoStreamingPlaylist } from '../../../../shared/models/videos/video-streaming-playlist.model' import { isArray } from '../../../helpers/custom-validators/misc' -import { MIMETYPES, WEBSERVER } from '../../../initializers/constants' +import { + MIMETYPES, + VIDEO_CATEGORIES, + VIDEO_LANGUAGES, + VIDEO_LICENCES, + VIDEO_PRIVACIES, + VIDEO_STATES, + WEBSERVER +} from '../../../initializers/constants' import { getLocalVideoCommentsActivityPubUrl, getLocalVideoDislikesActivityPubUrl, @@ -13,6 +23,7 @@ import { getLocalVideoSharesActivityPubUrl } from '../../../lib/activitypub/url' import { + MServer, MStreamingPlaylistRedundanciesOpt, MVideo, MVideoAP, @@ -21,41 +32,62 @@ import { MVideoFormattableDetails } from '../../../types/models' import { MVideoFileRedundanciesOpt } from '../../../types/models/video/video-file' -import { VideoModel } from '../video' import { VideoCaptionModel } from '../video-caption' export type VideoFormattingJSONOptions = { completeDescription?: boolean - additionalAttributes: { + + additionalAttributes?: { state?: boolean waitTranscoding?: boolean scheduledUpdate?: boolean blacklistInfo?: boolean + files?: boolean + blockedOwner?: boolean + } +} + +function guessAdditionalAttributesFromQuery (query: VideosCommonQueryAfterSanitize): VideoFormattingJSONOptions { + if (!query || !query.include) return {} + + return { + additionalAttributes: { + state: !!(query.include & VideoInclude.NOT_PUBLISHED_STATE), + waitTranscoding: !!(query.include & VideoInclude.NOT_PUBLISHED_STATE), + scheduledUpdate: !!(query.include & VideoInclude.NOT_PUBLISHED_STATE), + blacklistInfo: !!(query.include & VideoInclude.BLACKLISTED), + files: !!(query.include & VideoInclude.FILES), + blockedOwner: !!(query.include & VideoInclude.BLOCKED_OWNER) + } } } -function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { +function videoModelToFormattedJSON (video: MVideoFormattable, options: VideoFormattingJSONOptions = {}): Video { const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined const videoObject: Video = { id: video.id, uuid: video.uuid, + shortUUID: uuidToShort(video.uuid), + + url: video.url, + name: video.name, category: { id: video.category, - label: VideoModel.getCategoryLabel(video.category) + label: getCategoryLabel(video.category) }, licence: { id: video.licence, - label: VideoModel.getLicenceLabel(video.licence) + label: getLicenceLabel(video.licence) }, language: { id: video.language, - label: VideoModel.getLanguageLabel(video.language) + label: getLanguageLabel(video.language) }, privacy: { id: video.privacy, - label: VideoModel.getPrivacyLabel(video.privacy) + label: getPrivacyLabel(video.privacy) }, nsfw: video.nsfw, @@ -89,47 +121,57 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFor pluginData: (video as any).pluginData } - if (options) { - if (options.additionalAttributes.state === true) { - videoObject.state = { - id: video.state, - label: VideoModel.getStateLabel(video.state) - } + const add = options.additionalAttributes + if (add?.state === true) { + videoObject.state = { + id: video.state, + label: getStateLabel(video.state) } + } - if (options.additionalAttributes.waitTranscoding === true) { - videoObject.waitTranscoding = video.waitTranscoding - } + if (add?.waitTranscoding === true) { + videoObject.waitTranscoding = video.waitTranscoding + } - if (options.additionalAttributes.scheduledUpdate === true && video.ScheduleVideoUpdate) { - videoObject.scheduledUpdate = { - updateAt: video.ScheduleVideoUpdate.updateAt, - privacy: video.ScheduleVideoUpdate.privacy || undefined - } + if (add?.scheduledUpdate === true && video.ScheduleVideoUpdate) { + videoObject.scheduledUpdate = { + updateAt: video.ScheduleVideoUpdate.updateAt, + privacy: video.ScheduleVideoUpdate.privacy || undefined } + } - if (options.additionalAttributes.blacklistInfo === true) { - videoObject.blacklisted = !!video.VideoBlacklist - videoObject.blacklistedReason = video.VideoBlacklist ? video.VideoBlacklist.reason : null - } + if (add?.blacklistInfo === true) { + videoObject.blacklisted = !!video.VideoBlacklist + videoObject.blacklistedReason = video.VideoBlacklist ? video.VideoBlacklist.reason : null + } + + if (add?.blockedOwner === true) { + videoObject.blockedOwner = video.VideoChannel.Account.isBlocked() + + const server = video.VideoChannel.Account.Actor.Server as MServer + videoObject.blockedServer = !!(server?.isBlocked()) + } + + if (add?.files === true) { + videoObject.streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists) + videoObject.files = videoFilesModelToFormattedJSON(video, video.VideoFiles) } return videoObject } function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): VideoDetails { - const formattedJson = video.toFormattedJSON({ + const videoJSON = video.toFormattedJSON({ additionalAttributes: { scheduledUpdate: true, - blacklistInfo: true + blacklistInfo: true, + files: true } - }) + }) as Video & Required> const tags = video.Tags ? video.Tags.map(t => t.name) : [] - const streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists) - - const detailsJson = { + const detailsJSON = { support: video.support, descriptionPath: video.getDescriptionAPIPath(), channel: video.VideoChannel.toFormattedJSON(), @@ -140,23 +182,17 @@ function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): Vid waitTranscoding: video.waitTranscoding, state: { id: video.state, - label: VideoModel.getStateLabel(video.state) + label: getStateLabel(video.state) }, - trackerUrls: video.getTrackerUrls(), - - files: [], - streamingPlaylists + trackerUrls: video.getTrackerUrls() } - // Format and sort video files - detailsJson.files = videoFilesModelToFormattedJSON(video, video.VideoFiles) - - return Object.assign(formattedJson, detailsJson) + return Object.assign(videoJSON, detailsJSON) } function streamingPlaylistsModelToFormattedJSON ( - video: MVideoFormattableDetails, + video: MVideoFormattable, playlists: MStreamingPlaylistRedundanciesOpt[] ): VideoStreamingPlaylist[] { if (isArray(playlists) === false) return [] @@ -172,8 +208,8 @@ function streamingPlaylistsModelToFormattedJSON ( return { id: playlist.id, type: playlist.type, - playlistUrl: playlist.playlistUrl, - segmentsSha256Url: playlist.segmentsSha256Url, + playlistUrl: playlist.getMasterPlaylistUrl(video), + segmentsSha256Url: playlist.getSha256SegmentsUrl(video), redundancies, files } @@ -187,7 +223,7 @@ function sortByResolutionDesc (fileA: MVideoFile, fileB: MVideoFile) { } function videoFilesModelToFormattedJSON ( - video: MVideoFormattableDetails, + video: MVideoFormattable, videoFiles: MVideoFileRedundanciesOpt[], includeMagnet = true ): VideoFile[] { @@ -195,14 +231,14 @@ function videoFilesModelToFormattedJSON ( ? video.getTrackerUrls() : [] - return [ ...videoFiles ] + return (videoFiles || []) .filter(f => !f.isLive()) .sort(sortByResolutionDesc) .map(videoFile => { return { resolution: { id: videoFile.resolution, - label: videoFile.resolution + 'p' + label: videoFile.resolution === 0 ? 'Audio' : `${videoFile.resolution}p` }, magnetUri: includeMagnet && videoFile.hasTorrent() @@ -230,7 +266,7 @@ function addVideoFilesInAPAcc ( ) { const trackerUrls = video.getTrackerUrls() - const sortedFiles = [ ...files ] + const sortedFiles = (files || []) .filter(f => !f.isLive()) .sort(sortByResolutionDesc) @@ -283,7 +319,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { if (video.language) { language = { identifier: video.language, - name: VideoModel.getLanguageLabel(video.language) + name: getLanguageLabel(video.language) } } @@ -291,7 +327,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { if (video.category) { category = { identifier: video.category + '', - name: VideoModel.getCategoryLabel(video.category) + name: getCategoryLabel(video.category) } } @@ -299,7 +335,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { if (video.licence) { licence = { identifier: video.licence + '', - name: VideoModel.getLicenceLabel(video.licence) + name: getLicenceLabel(video.licence) } } @@ -321,7 +357,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { type: 'Link', name: 'sha256', mediaType: 'application/json' as 'application/json', - href: playlist.segmentsSha256Url + href: playlist.getSha256SegmentsUrl(video) }) addVideoFilesInAPAcc(tag, video, playlist.VideoFiles || []) @@ -329,7 +365,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { url.push({ type: 'Link', mediaType: 'application/x-mpegURL' as 'application/x-mpegURL', - href: playlist.playlistUrl, + href: playlist.getMasterPlaylistUrl(video), tag }) } @@ -425,10 +461,38 @@ function getActivityStreamDuration (duration: number) { return 'PT' + duration + 'S' } +function getCategoryLabel (id: number) { + return VIDEO_CATEGORIES[id] || 'Misc' +} + +function getLicenceLabel (id: number) { + return VIDEO_LICENCES[id] || 'Unknown' +} + +function getLanguageLabel (id: string) { + return VIDEO_LANGUAGES[id] || 'Unknown' +} + +function getPrivacyLabel (id: number) { + return VIDEO_PRIVACIES[id] || 'Unknown' +} + +function getStateLabel (id: number) { + return VIDEO_STATES[id] || 'Unknown' +} + export { videoModelToFormattedJSON, videoModelToFormattedDetailsJSON, videoFilesModelToFormattedJSON, videoModelToActivityPubObject, - getActivityStreamDuration + getActivityStreamDuration, + + guessAdditionalAttributesFromQuery, + + getCategoryLabel, + getLicenceLabel, + getLanguageLabel, + getPrivacyLabel, + getStateLabel }