aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-02-12 16:23:19 +0100
committerChocobozzz <chocobozzz@cpy.re>2021-02-16 10:36:44 +0100
commita8b1b40485145ac1eae513a661d7dd6e0986ce96 (patch)
tree79436a042f1ed350278dd69e365f37ee623aa539 /server/lib
parent0472d474fdadd05211fb4f90ce275801db515d08 (diff)
downloadPeerTube-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.ts18
-rw-r--r--server/lib/files-cache/videos-preview-cache.ts15
-rw-r--r--server/lib/thumbnail.ts18
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'
5import * as request from 'request' 5import * as request from 'request'
6import * as sequelize from 'sequelize' 6import * as sequelize from 'sequelize'
7import { VideoLiveModel } from '@server/models/video/video-live' 7import { VideoLiveModel } from '@server/models/video/video-live'
8import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
8import { 9import {
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'
18import { VideoObject } from '../../../shared/models/activitypub/objects' 19import { ActivityIconObject, VideoObject } from '../../../shared/models/activitypub/objects'
19import { VideoPrivacy } from '../../../shared/models/videos' 20import { VideoPrivacy } from '../../../shared/models/videos'
20import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' 21import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
21import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' 22import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
@@ -76,7 +77,6 @@ import { sendCreateVideo, sendUpdateVideo } from './send'
76import { addVideoShares, shareVideoByServerAndChannel } from './share' 77import { addVideoShares, shareVideoByServerAndChannel } from './share'
77import { addVideoComments } from './video-comments' 78import { addVideoComments } from './video-comments'
78import { createRates } from './video-rates' 79import { createRates } from './video-rates'
79import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
80 80
81async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { 81async 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) {
822function getPreviewFromIcons (videoObject: VideoObject) { 820function 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
826function 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'
3import { VideoModel } from '../../models/video/video' 3import { VideoModel } from '../../models/video/video'
4import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' 4import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache'
5import { doRequestAndSaveToFile } from '@server/helpers/requests' 5import { doRequestAndSaveToFile } from '@server/helpers/requests'
6import { ThumbnailModel } from '@server/models/video/thumbnail'
7import { ThumbnailType } from '@shared/models'
8import { logger } from '@server/helpers/logger'
6 9
7class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { 10class 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
30function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) { 30function 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
38function createVideoMiniatureFromUrl (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) { 43function 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