X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Factivitypub%2Fvideos.ts;h=d182ca5a28e41df77dedf6bdf89c4676122d931a;hb=2ad9dcda240ee843c5e4a5b98cc94f7b2aab2c89;hp=6bc2258cc79d5ac1d07fcb40f91a18e94e4597f8;hpb=ca6d36227a9273f616a462d3aad6a721ab5dd627;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 6bc2258cc..d182ca5a2 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -68,7 +68,7 @@ import { MVideoAPWithoutCaption, MVideoFile, MVideoFullLight, - MVideoId, + MVideoId, MVideoImmutable, MVideoThumbnail } from '../../typings/models' import { MThumbnail } from '../../typings/models/video/thumbnail' @@ -197,27 +197,44 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' }) } - await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) + await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })) } -function getOrCreateVideoAndAccountAndChannel (options: { - videoObject: { id: string } | string, - syncParam?: SyncParam, - fetchType?: 'all', +type GetVideoResult = Promise<{ + video: T + created: boolean + autoBlacklisted?: boolean +}> + +type GetVideoParamAll = { + videoObject: { id: string } | string + syncParam?: SyncParam + fetchType?: 'all' allowRefresh?: boolean -}): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }> -function getOrCreateVideoAndAccountAndChannel (options: { - videoObject: { id: string } | string, - syncParam?: SyncParam, - fetchType?: VideoFetchByUrlType, +} + +type GetVideoParamImmutable = { + videoObject: { id: string } | string + syncParam?: SyncParam + fetchType: 'only-immutable-attributes' + allowRefresh: false +} + +type GetVideoParamOther = { + videoObject: { id: string } | string + syncParam?: SyncParam + fetchType?: 'all' | 'only-video' allowRefresh?: boolean -}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> -async function getOrCreateVideoAndAccountAndChannel (options: { - videoObject: { id: string } | string, - syncParam?: SyncParam, - fetchType?: VideoFetchByUrlType, - allowRefresh?: boolean // true by default -}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> { +} + +function getOrCreateVideoAndAccountAndChannel (options: GetVideoParamAll): GetVideoResult +function getOrCreateVideoAndAccountAndChannel (options: GetVideoParamImmutable): GetVideoResult +function getOrCreateVideoAndAccountAndChannel ( + options: GetVideoParamOther +): GetVideoResult +async function getOrCreateVideoAndAccountAndChannel ( + options: GetVideoParamAll | GetVideoParamImmutable | GetVideoParamOther +): GetVideoResult { // Default params const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } const fetchType = options.fetchType || 'all' @@ -225,18 +242,25 @@ async function getOrCreateVideoAndAccountAndChannel (options: { // Get video url const videoUrl = getAPId(options.videoObject) - let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType) + if (videoFromDatabase) { - if (videoFromDatabase.isOutdated() && allowRefresh === true) { + // If allowRefresh is true, we could not call this function using 'only-immutable-attributes' fetch type + if (allowRefresh === true && (videoFromDatabase as MVideoThumbnail).isOutdated()) { const refreshOptions = { - video: videoFromDatabase, + video: videoFromDatabase as MVideoThumbnail, fetchedType: fetchType, syncParam } - if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) - else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoFromDatabase.url } }) + if (syncParam.refreshVideo === true) { + videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) + } else { + await JobQueue.Instance.createJobWithPromise({ + type: 'activitypub-refresher', + payload: { type: 'video', url: videoFromDatabase.url } + }) + } } return { video: videoFromDatabase, created: false } @@ -255,10 +279,10 @@ async function getOrCreateVideoAndAccountAndChannel (options: { } async function updateVideoFromAP (options: { - video: MVideoAccountLightBlacklistAllFiles, - videoObject: VideoTorrentObject, - account: MAccountIdActor, - channel: MChannelDefault, + video: MVideoAccountLightBlacklistAllFiles + videoObject: VideoTorrentObject + account: MAccountIdActor + channel: MChannelDefault overrideTo?: string[] }) { const { video, videoObject, account, channel, overrideTo } = options @@ -289,7 +313,7 @@ async function updateVideoFromAP (options: { throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) } - const to = overrideTo ? overrideTo : videoObject.to + const to = overrideTo || videoObject.to const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) video.name = videoData.name video.uuid = videoData.uuid @@ -316,9 +340,11 @@ async function updateVideoFromAP (options: { if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) - const previewUrl = videoUpdated.getPreview().getFileUrl(videoUpdated) - const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) - await videoUpdated.addAndSaveThumbnail(previewModel, t) + if (videoUpdated.getPreview()) { + const previewUrl = videoUpdated.getPreview().getFileUrl(videoUpdated) + const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) + await videoUpdated.addAndSaveThumbnail(previewModel, t) + } { const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoUpdated, videoObject.url) @@ -412,8 +438,8 @@ async function updateVideoFromAP (options: { } async function refreshVideoIfNeeded (options: { - video: MVideoThumbnail, - fetchedType: VideoFetchByUrlType, + video: MVideoThumbnail + fetchedType: VideoFetchByUrlType syncParam: SyncParam }): Promise { if (!options.video.isOutdated()) return options.video @@ -507,6 +533,10 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc const video = VideoModel.build(videoData) as MVideoThumbnail const promiseThumbnail = createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) + .catch(err => { + logger.error('Cannot create miniature from url.', { err }) + return undefined + }) let thumbnailModel: MThumbnail if (waitThumbnail === true) { @@ -578,7 +608,11 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc }) if (waitThumbnail === false) { + // Error is already caught above + // eslint-disable-next-line @typescript-eslint/no-floating-promises promiseThumbnail.then(thumbnailModel => { + if (!thumbnailModel) return + thumbnailModel = videoCreated.id return thumbnailModel.save() @@ -588,24 +622,19 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc return { autoBlacklisted, videoCreated } } -async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { +function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED const duration = videoObject.duration.replace(/[^\d]+/, '') - let language: string | undefined - if (videoObject.language) { - language = videoObject.language.identifier - } + const language = videoObject.language?.identifier - let category: number | undefined - if (videoObject.category) { - category = parseInt(videoObject.category.identifier, 10) - } + const category = videoObject.category + ? parseInt(videoObject.category.identifier, 10) + : undefined - let licence: number | undefined - if (videoObject.licence) { - licence = parseInt(videoObject.licence.identifier, 10) - } + const licence = videoObject.licence + ? parseInt(videoObject.licence.identifier, 10) + : undefined const description = videoObject.content || null const support = videoObject.support || null @@ -628,7 +657,11 @@ async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, vide duration: parseInt(duration, 10), createdAt: new Date(videoObject.published), publishedAt: new Date(videoObject.published), - originallyPublishedAt: videoObject.originallyPublishedAt ? new Date(videoObject.originallyPublishedAt) : null, + + originallyPublishedAt: videoObject.originallyPublishedAt + ? new Date(videoObject.originallyPublishedAt) + : null, + updatedAt: new Date(videoObject.updated), views: videoObject.views, likes: 0, @@ -661,7 +694,7 @@ function videoFileActivityUrlToDBAttributes ( const mediaType = fileUrl.mediaType const attribute = { - extname: MIMETYPES.VIDEO.MIMETYPE_EXT[ mediaType ], + extname: MIMETYPES.VIDEO.MIMETYPE_EXT[mediaType], infoHash: parsed.infoHash, resolution: fileUrl.height, size: fileUrl.size,