diff options
author | Chocobozzz <me@florianbigard.com> | 2021-02-12 16:23:19 +0100 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2021-02-16 10:36:44 +0100 |
commit | a8b1b40485145ac1eae513a661d7dd6e0986ce96 (patch) | |
tree | 79436a042f1ed350278dd69e365f37ee623aa539 /server/lib | |
parent | 0472d474fdadd05211fb4f90ce275801db515d08 (diff) | |
download | PeerTube-a8b1b40485145ac1eae513a661d7dd6e0986ce96.tar.gz PeerTube-a8b1b40485145ac1eae513a661d7dd6e0986ce96.tar.zst PeerTube-a8b1b40485145ac1eae513a661d7dd6e0986ce96.zip |
Generate a name for thumbnails
Allows aggressive caching
Diffstat (limited to 'server/lib')
-rw-r--r-- | server/lib/activitypub/videos.ts | 18 | ||||
-rw-r--r-- | server/lib/files-cache/videos-preview-cache.ts | 15 | ||||
-rw-r--r-- | server/lib/thumbnail.ts | 18 |
3 files changed, 34 insertions, 17 deletions
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 8545e5bad..b5a199e67 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts | |||
@@ -5,6 +5,7 @@ import { join } from 'path' | |||
5 | import * as request from 'request' | 5 | import * as request from 'request' |
6 | import * as sequelize from 'sequelize' | 6 | import * as sequelize from 'sequelize' |
7 | import { VideoLiveModel } from '@server/models/video/video-live' | 7 | import { VideoLiveModel } from '@server/models/video/video-live' |
8 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
8 | import { | 9 | import { |
9 | ActivityHashTagObject, | 10 | ActivityHashTagObject, |
10 | ActivityMagnetUrlObject, | 11 | ActivityMagnetUrlObject, |
@@ -15,7 +16,7 @@ import { | |||
15 | ActivityUrlObject, | 16 | ActivityUrlObject, |
16 | ActivityVideoUrlObject | 17 | ActivityVideoUrlObject |
17 | } from '../../../shared/index' | 18 | } from '../../../shared/index' |
18 | import { VideoObject } from '../../../shared/models/activitypub/objects' | 19 | import { ActivityIconObject, VideoObject } from '../../../shared/models/activitypub/objects' |
19 | import { VideoPrivacy } from '../../../shared/models/videos' | 20 | import { VideoPrivacy } from '../../../shared/models/videos' |
20 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
21 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 22 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
@@ -76,7 +77,6 @@ import { sendCreateVideo, sendUpdateVideo } from './send' | |||
76 | import { addVideoShares, shareVideoByServerAndChannel } from './share' | 77 | import { addVideoShares, shareVideoByServerAndChannel } from './share' |
77 | import { addVideoComments } from './video-comments' | 78 | import { addVideoComments } from './video-comments' |
78 | import { createRates } from './video-rates' | 79 | import { createRates } from './video-rates' |
79 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
80 | 80 | ||
81 | async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { | 81 | async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { |
82 | const video = videoArg as MVideoAP | 82 | const video = videoArg as MVideoAP |
@@ -360,7 +360,7 @@ async function updateVideoFromAP (options: { | |||
360 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) | 360 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) |
361 | 361 | ||
362 | if (videoUpdated.getPreview()) { | 362 | if (videoUpdated.getPreview()) { |
363 | const previewUrl = videoUpdated.getPreview().getFileUrl(videoUpdated) | 363 | const previewUrl = getPreviewUrl(getPreviewFromIcons(videoObject), video) |
364 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | 364 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) |
365 | await videoUpdated.addAndSaveThumbnail(previewModel, t) | 365 | await videoUpdated.addAndSaveThumbnail(previewModel, t) |
366 | } | 366 | } |
@@ -597,9 +597,7 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi | |||
597 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) | 597 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) |
598 | 598 | ||
599 | const previewIcon = getPreviewFromIcons(videoObject) | 599 | const previewIcon = getPreviewFromIcons(videoObject) |
600 | const previewUrl = previewIcon | 600 | const previewUrl = getPreviewUrl(previewIcon, videoCreated) |
601 | ? previewIcon.url | ||
602 | : buildRemoteVideoBaseUrl(videoCreated, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | ||
603 | const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | 601 | const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE) |
604 | 602 | ||
605 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) | 603 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) |
@@ -822,7 +820,11 @@ function getThumbnailFromIcons (videoObject: VideoObject) { | |||
822 | function getPreviewFromIcons (videoObject: VideoObject) { | 820 | function getPreviewFromIcons (videoObject: VideoObject) { |
823 | const validIcons = videoObject.icon.filter(i => i.width > PREVIEWS_SIZE.minWidth) | 821 | const validIcons = videoObject.icon.filter(i => i.width > PREVIEWS_SIZE.minWidth) |
824 | 822 | ||
825 | // FIXME: don't put a fallback here for compatibility with PeerTube <2.2 | ||
826 | |||
827 | return maxBy(validIcons, 'width') | 823 | return maxBy(validIcons, 'width') |
828 | } | 824 | } |
825 | |||
826 | function getPreviewUrl (previewIcon: ActivityIconObject, video: MVideoAccountLight) { | ||
827 | return previewIcon | ||
828 | ? previewIcon.url | ||
829 | : buildRemoteVideoBaseUrl(video, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | ||
830 | } | ||
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts index d0d4fc5b5..51146d718 100644 --- a/server/lib/files-cache/videos-preview-cache.ts +++ b/server/lib/files-cache/videos-preview-cache.ts | |||
@@ -3,6 +3,9 @@ import { FILES_CACHE } from '../../initializers/constants' | |||
3 | import { VideoModel } from '../../models/video/video' | 3 | import { VideoModel } from '../../models/video/video' |
4 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' | 4 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' |
5 | import { doRequestAndSaveToFile } from '@server/helpers/requests' | 5 | import { doRequestAndSaveToFile } from '@server/helpers/requests' |
6 | import { ThumbnailModel } from '@server/models/video/thumbnail' | ||
7 | import { ThumbnailType } from '@shared/models' | ||
8 | import { logger } from '@server/helpers/logger' | ||
6 | 9 | ||
7 | class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | 10 | class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { |
8 | 11 | ||
@@ -16,13 +19,13 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | |||
16 | return this.instance || (this.instance = new this()) | 19 | return this.instance || (this.instance = new this()) |
17 | } | 20 | } |
18 | 21 | ||
19 | async getFilePathImpl (videoUUID: string) { | 22 | async getFilePathImpl (filename: string) { |
20 | const video = await VideoModel.loadByUUID(videoUUID) | 23 | const thumbnail = await ThumbnailModel.loadWithVideoByName(filename, ThumbnailType.PREVIEW) |
21 | if (!video) return undefined | 24 | if (!thumbnail) return undefined |
22 | 25 | ||
23 | if (video.isOwned()) return { isOwned: true, path: video.getPreview().getPath() } | 26 | if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() } |
24 | 27 | ||
25 | return this.loadRemoteFile(videoUUID) | 28 | return this.loadRemoteFile(thumbnail.Video.uuid) |
26 | } | 29 | } |
27 | 30 | ||
28 | protected async loadRemoteFile (key: string) { | 31 | protected async loadRemoteFile (key: string) { |
@@ -37,6 +40,8 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | |||
37 | const remoteUrl = preview.getFileUrl(video) | 40 | const remoteUrl = preview.getFileUrl(video) |
38 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) | 41 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) |
39 | 42 | ||
43 | logger.debug('Fetched remote preview %s to %s.', remoteUrl, destPath) | ||
44 | |||
40 | return { isOwned: false, path: destPath } | 45 | return { isOwned: false, path: destPath } |
41 | } | 46 | } |
42 | } | 47 | } |
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts index dc86423f8..740b83acb 100644 --- a/server/lib/thumbnail.ts +++ b/server/lib/thumbnail.ts | |||
@@ -27,18 +27,28 @@ function createPlaylistMiniatureFromExisting ( | |||
27 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail }) | 27 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail }) |
28 | } | 28 | } |
29 | 29 | ||
30 | function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) { | 30 | function createPlaylistMiniatureFromUrl (downloadUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) { |
31 | const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size) | 31 | const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size) |
32 | const type = ThumbnailType.MINIATURE | 32 | const type = ThumbnailType.MINIATURE |
33 | 33 | ||
34 | const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height }) | 34 | // Only save the file URL if it is a remote playlist |
35 | const fileUrl = playlist.isOwned() | ||
36 | ? null | ||
37 | : downloadUrl | ||
38 | |||
39 | const thumbnailCreator = () => downloadImage(downloadUrl, basePath, filename, { width, height }) | ||
35 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) | 40 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) |
36 | } | 41 | } |
37 | 42 | ||
38 | function createVideoMiniatureFromUrl (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) { | 43 | function createVideoMiniatureFromUrl (downloadUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) { |
39 | const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) | 44 | const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) |
40 | const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height }) | ||
41 | 45 | ||
46 | // Only save the file URL if it is a remote video | ||
47 | const fileUrl = video.isOwned() | ||
48 | ? null | ||
49 | : downloadUrl | ||
50 | |||
51 | const thumbnailCreator = () => downloadImage(downloadUrl, basePath, filename, { width, height }) | ||
42 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) | 52 | return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) |
43 | } | 53 | } |
44 | 54 | ||