X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fvideo-format-utils.ts;h=77b8bcfe349d37d0862893f36e377ec3ef12525d;hb=684cdacbbd775b5f404dd7b373e02dd21baf5ff0;hp=67395e5c0ced50d4a1b15c84fe52b83635cae2fc;hpb=22f18a4a197513c4cae685717829637cae853ae2;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index 67395e5c0..77b8bcfe3 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts @@ -1,14 +1,14 @@ import { Video, VideoDetails } from '../../../shared/models/videos' import { VideoModel } from './video' -import { ActivityTagObject, ActivityUrlObject, VideoTorrentObject } from '../../../shared/models/activitypub/objects' +import { ActivityTagObject, ActivityUrlObject, VideoObject } from '../../../shared/models/activitypub/objects' import { MIMETYPES, WEBSERVER } from '../../initializers/constants' import { VideoCaptionModel } from './video-caption' import { - getVideoCommentsActivityPubUrl, - getVideoDislikesActivityPubUrl, - getVideoLikesActivityPubUrl, - getVideoSharesActivityPubUrl -} from '../../lib/activitypub' + getLocalVideoCommentsActivityPubUrl, + getLocalVideoDislikesActivityPubUrl, + getLocalVideoLikesActivityPubUrl, + getLocalVideoSharesActivityPubUrl +} from '../../lib/activitypub/url' import { isArray } from '../../helpers/custom-validators/misc' import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model' import { @@ -19,20 +19,22 @@ import { MVideoFile, MVideoFormattable, MVideoFormattableDetails -} from '../../typings/models' -import { MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file' +} from '../../types/models' +import { MVideoFileRedundanciesOpt } from '../../types/models/video/video-file' import { VideoFile } from '@shared/models/videos/video-file.model' import { generateMagnetUri } from '@server/helpers/webtorrent' +import { extractVideo } from '@server/helpers/video' export type VideoFormattingJSONOptions = { completeDescription?: boolean additionalAttributes: { - state?: boolean, - waitTranscoding?: boolean, - scheduledUpdate?: boolean, + state?: boolean + waitTranscoding?: boolean + scheduledUpdate?: boolean blacklistInfo?: boolean } } + function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined @@ -57,7 +59,11 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFor label: VideoModel.getPrivacyLabel(video.privacy) }, nsfw: video.nsfw, - description: options && options.completeDescription === true ? video.description : video.getTruncatedDescription(), + + description: options && options.completeDescription === true + ? video.description + : video.getTruncatedDescription(), + isLocal: video.isOwned(), duration: video.duration, views: video.views, @@ -71,12 +77,17 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFor publishedAt: video.publishedAt, originallyPublishedAt: video.originallyPublishedAt, + isLive: video.isLive, + account: video.VideoChannel.Account.toFormattedSummaryJSON(), channel: video.VideoChannel.toFormattedSummaryJSON(), - userHistory: userHistory ? { - currentTime: userHistory.currentTime - } : undefined + userHistory: userHistory + ? { currentTime: userHistory.currentTime } + : undefined, + + // Can be added by external plugins + pluginData: (video as any).pluginData } if (options) { @@ -173,20 +184,28 @@ function streamingPlaylistsModelToFormattedJSON (video: MVideo, playlists: MStre }) } +function sortByResolutionDesc (fileA: MVideoFile, fileB: MVideoFile) { + if (fileA.resolution < fileB.resolution) return 1 + if (fileA.resolution === fileB.resolution) return 0 + return -1 +} + function videoFilesModelToFormattedJSON ( model: MVideo | MStreamingPlaylistVideo, baseUrlHttp: string, baseUrlWs: string, videoFiles: MVideoFileRedundanciesOpt[] ): VideoFile[] { - return videoFiles - .map(videoFile => { - let resolutionLabel = videoFile.resolution + 'p' + const video = extractVideo(model) + return [ ...videoFiles ] + .filter(f => !f.isLive()) + .sort(sortByResolutionDesc) + .map(videoFile => { return { resolution: { id: videoFile.resolution, - label: resolutionLabel + label: videoFile.resolution + 'p' }, magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs), size: videoFile.size, @@ -194,14 +213,10 @@ function videoFilesModelToFormattedJSON ( torrentUrl: model.getTorrentUrl(videoFile, baseUrlHttp), torrentDownloadUrl: model.getTorrentDownloadUrl(videoFile, baseUrlHttp), fileUrl: model.getVideoFileUrl(videoFile, baseUrlHttp), - fileDownloadUrl: model.getVideoFileDownloadUrl(videoFile, baseUrlHttp) + fileDownloadUrl: model.getVideoFileDownloadUrl(videoFile, baseUrlHttp), + metadataUrl: video.getVideoFileMetadataUrl(videoFile, baseUrlHttp) } as VideoFile }) - .sort((a, b) => { - if (a.resolution.id < b.resolution.id) return 1 - if (a.resolution.id === b.resolution.id) return 0 - return -1 - }) } function addVideoFilesInAPAcc ( @@ -211,16 +226,29 @@ function addVideoFilesInAPAcc ( baseUrlWs: string, files: MVideoFile[] ) { - for (const file of files) { + const sortedFiles = [ ...files ] + .filter(f => !f.isLive()) + .sort(sortByResolutionDesc) + + for (const file of sortedFiles) { acc.push({ type: 'Link', - mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ file.extname ] as any, + mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[file.extname] as any, href: model.getVideoFileUrl(file, baseUrlHttp), height: file.resolution, size: file.size, fps: file.fps }) + acc.push({ + type: 'Link', + rel: [ 'metadata', MIMETYPES.VIDEO.EXT_MIMETYPE[file.extname] ], + mediaType: 'application/json' as 'application/json', + href: extractVideo(model).getVideoFileMetadataUrl(file, baseUrlHttp), + height: file.resolution, + fps: file.fps + }) + acc.push({ type: 'Link', mediaType: 'application/x-bittorrent' as 'application/x-bittorrent', @@ -237,7 +265,7 @@ function addVideoFilesInAPAcc ( } } -function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { +function videoModelToActivityPubObject (video: MVideoAP): VideoObject { const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() if (!video.Tags) video.Tags = [] @@ -282,10 +310,8 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) for (const playlist of (video.VideoStreamingPlaylists || [])) { - let tag: ActivityTagObject[] - - tag = playlist.p2pMediaLoaderInfohashes - .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) + const tag = playlist.p2pMediaLoaderInfohashes + .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) as ActivityTagObject[] tag.push({ type: 'Link', name: 'sha256', @@ -308,11 +334,12 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { for (const caption of video.VideoCaptions) { subtitleLanguage.push({ identifier: caption.language, - name: VideoCaptionModel.getLanguageLabel(caption.language) + name: VideoCaptionModel.getLanguageLabel(caption.language), + url: caption.getFileUrl(video) }) } - const miniature = video.getMiniature() + const icons = [ video.getMiniature(), video.getPreview() ] return { type: 'Video' as 'Video', @@ -327,28 +354,42 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { views: video.views, sensitive: video.nsfw, waitTranscoding: video.waitTranscoding, + isLiveBroadcast: video.isLive, + + liveSaveReplay: video.isLive + ? video.VideoLive.saveReplay + : null, + + permanentLive: video.isLive + ? video.VideoLive.permanentLive + : null, + state: video.state, commentsEnabled: video.commentsEnabled, downloadEnabled: video.downloadEnabled, published: video.publishedAt.toISOString(), - originallyPublishedAt: video.originallyPublishedAt ? video.originallyPublishedAt.toISOString() : null, + + originallyPublishedAt: video.originallyPublishedAt + ? video.originallyPublishedAt.toISOString() + : null, + updated: video.updatedAt.toISOString(), mediaType: 'text/markdown', - content: video.getTruncatedDescription(), + content: video.description, support: video.support, subtitleLanguage, - icon: { + icon: icons.map(i => ({ type: 'Image', - url: miniature.getFileUrl(video.isOwned()), + url: i.getFileUrl(video), mediaType: 'image/jpeg', - width: miniature.width, - height: miniature.height - }, + width: i.width, + height: i.height + })), url, - likes: getVideoLikesActivityPubUrl(video), - dislikes: getVideoDislikesActivityPubUrl(video), - shares: getVideoSharesActivityPubUrl(video), - comments: getVideoCommentsActivityPubUrl(video), + likes: getLocalVideoLikesActivityPubUrl(video), + dislikes: getLocalVideoDislikesActivityPubUrl(video), + shares: getLocalVideoSharesActivityPubUrl(video), + comments: getLocalVideoCommentsActivityPubUrl(video), attributedTo: [ { type: 'Person',