Fix playlist thumbnail generation
This commit is contained in:
parent
109d4a7f01
commit
53d4db2a8a
7 changed files with 25 additions and 19 deletions
|
@ -1,6 +1,6 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { join } from 'path'
|
|
||||||
import { scheduleRefreshIfNeeded } from '@server/lib/activitypub/playlists'
|
import { scheduleRefreshIfNeeded } from '@server/lib/activitypub/playlists'
|
||||||
|
import { VideoMiniaturePermanentFileCache } from '@server/lib/files-cache'
|
||||||
import { Hooks } from '@server/lib/plugins/hooks'
|
import { Hooks } from '@server/lib/plugins/hooks'
|
||||||
import { getServerActor } from '@server/models/application/application'
|
import { getServerActor } from '@server/models/application/application'
|
||||||
import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models'
|
import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models'
|
||||||
|
@ -18,7 +18,6 @@ import { resetSequelizeInstance } from '../../helpers/database-utils'
|
||||||
import { createReqFiles } from '../../helpers/express-utils'
|
import { createReqFiles } from '../../helpers/express-utils'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { getFormattedObjects } from '../../helpers/utils'
|
import { getFormattedObjects } from '../../helpers/utils'
|
||||||
import { CONFIG } from '../../initializers/config'
|
|
||||||
import { MIMETYPES, VIDEO_PLAYLIST_PRIVACIES } from '../../initializers/constants'
|
import { MIMETYPES, VIDEO_PLAYLIST_PRIVACIES } from '../../initializers/constants'
|
||||||
import { sequelizeTypescript } from '../../initializers/database'
|
import { sequelizeTypescript } from '../../initializers/database'
|
||||||
import { sendCreateVideoPlaylist, sendDeleteVideoPlaylist, sendUpdateVideoPlaylist } from '../../lib/activitypub/send'
|
import { sendCreateVideoPlaylist, sendDeleteVideoPlaylist, sendUpdateVideoPlaylist } from '../../lib/activitypub/send'
|
||||||
|
@ -496,7 +495,10 @@ async function generateThumbnailForPlaylist (videoPlaylist: MVideoPlaylistThumbn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, videoMiniature.filename)
|
// Ensure the file is on disk
|
||||||
|
const videoMiniaturePermanentFileCache = new VideoMiniaturePermanentFileCache()
|
||||||
|
const inputPath = await videoMiniaturePermanentFileCache.downloadRemoteFile(videoMiniature)
|
||||||
|
|
||||||
const thumbnailModel = await updateLocalPlaylistMiniatureFromExisting({
|
const thumbnailModel = await updateLocalPlaylistMiniatureFromExisting({
|
||||||
inputPath,
|
inputPath,
|
||||||
playlist: videoPlaylist,
|
playlist: videoPlaylist,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { retryTransactionWrapper } from '@server/helpers/database-utils'
|
||||||
import { logger, loggerTagsFactory } from '@server/helpers/logger'
|
import { logger, loggerTagsFactory } from '@server/helpers/logger'
|
||||||
import { CRAWL_REQUEST_CONCURRENCY } from '@server/initializers/constants'
|
import { CRAWL_REQUEST_CONCURRENCY } from '@server/initializers/constants'
|
||||||
import { sequelizeTypescript } from '@server/initializers/database'
|
import { sequelizeTypescript } from '@server/initializers/database'
|
||||||
import { updatePlaylistMiniatureFromUrl } from '@server/lib/thumbnail'
|
import { updateRemotePlaylistMiniatureFromUrl } from '@server/lib/thumbnail'
|
||||||
import { VideoPlaylistModel } from '@server/models/video/video-playlist'
|
import { VideoPlaylistModel } from '@server/models/video/video-playlist'
|
||||||
import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element'
|
import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element'
|
||||||
import { FilteredModelAttributes } from '@server/types'
|
import { FilteredModelAttributes } from '@server/types'
|
||||||
|
@ -104,7 +104,7 @@ async function updatePlaylistThumbnail (playlistObject: PlaylistObject, playlist
|
||||||
let thumbnailModel: MThumbnail
|
let thumbnailModel: MThumbnail
|
||||||
|
|
||||||
try {
|
try {
|
||||||
thumbnailModel = await updatePlaylistMiniatureFromUrl({ downloadUrl: playlistObject.icon.url, playlist })
|
thumbnailModel = await updateRemotePlaylistMiniatureFromUrl({ downloadUrl: playlistObject.icon.url, playlist })
|
||||||
await playlist.setAndSaveThumbnail(thumbnailModel, undefined)
|
await playlist.setAndSaveThumbnail(thumbnailModel, undefined)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn('Cannot set thumbnail of %s.', playlistObject.id, { err, ...lTags(playlistObject.id, playlist.uuid, playlist.url) })
|
logger.warn('Cannot set thumbnail of %s.', playlistObject.id, { err, ...lTags(playlistObject.id, playlist.uuid, playlist.url) })
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { CreationAttributes, Transaction } from 'sequelize/types'
|
import { CreationAttributes, Transaction } from 'sequelize/types'
|
||||||
import { deleteAllModels, filterNonExistingModels } from '@server/helpers/database-utils'
|
import { deleteAllModels, filterNonExistingModels } from '@server/helpers/database-utils'
|
||||||
import { logger, LoggerTagsFn } from '@server/helpers/logger'
|
import { logger, LoggerTagsFn } from '@server/helpers/logger'
|
||||||
import { updateRemoteThumbnail } from '@server/lib/thumbnail'
|
import { updateRemoteVideoThumbnail } from '@server/lib/thumbnail'
|
||||||
import { setVideoTags } from '@server/lib/video'
|
import { setVideoTags } from '@server/lib/video'
|
||||||
import { StoryboardModel } from '@server/models/video/storyboard'
|
import { StoryboardModel } from '@server/models/video/storyboard'
|
||||||
import { VideoCaptionModel } from '@server/models/video/video-caption'
|
import { VideoCaptionModel } from '@server/models/video/video-caption'
|
||||||
|
@ -48,7 +48,7 @@ export abstract class APVideoAbstractBuilder {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const miniatureModel = updateRemoteThumbnail({
|
const miniatureModel = updateRemoteVideoThumbnail({
|
||||||
fileUrl: miniatureIcon.url,
|
fileUrl: miniatureIcon.url,
|
||||||
video,
|
video,
|
||||||
type: ThumbnailType.MINIATURE,
|
type: ThumbnailType.MINIATURE,
|
||||||
|
@ -63,12 +63,12 @@ export abstract class APVideoAbstractBuilder {
|
||||||
const previewIcon = getPreviewFromIcons(this.videoObject)
|
const previewIcon = getPreviewFromIcons(this.videoObject)
|
||||||
if (!previewIcon) return
|
if (!previewIcon) return
|
||||||
|
|
||||||
const previewModel = updateRemoteThumbnail({
|
const previewModel = updateRemoteVideoThumbnail({
|
||||||
fileUrl: previewIcon.url,
|
fileUrl: previewIcon.url,
|
||||||
video,
|
video,
|
||||||
type: ThumbnailType.PREVIEW,
|
type: ThumbnailType.PREVIEW,
|
||||||
size: previewIcon,
|
size: previewIcon,
|
||||||
onDisk: false // Don't fetch the preview that could be big, create a placeholder instead
|
onDisk: false // Lazy download remote previews
|
||||||
})
|
})
|
||||||
|
|
||||||
await video.addAndSaveThumbnail(previewModel, t)
|
await video.addAndSaveThumbnail(previewModel, t)
|
||||||
|
|
|
@ -66,10 +66,10 @@ export abstract class AbstractPermanentFileCache <M extends ImageModel> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private async downloadRemoteFile (image: M) {
|
async downloadRemoteFile (image: M) {
|
||||||
logger.info('Download remote image %s lazily.', image.fileUrl)
|
logger.info('Download remote image %s lazily.', image.fileUrl)
|
||||||
|
|
||||||
await this.downloadImage({
|
const destination = await this.downloadImage({
|
||||||
filename: image.filename,
|
filename: image.filename,
|
||||||
fileUrl: image.fileUrl,
|
fileUrl: image.fileUrl,
|
||||||
size: this.getImageSize(image)
|
size: this.getImageSize(image)
|
||||||
|
@ -78,6 +78,8 @@ export abstract class AbstractPermanentFileCache <M extends ImageModel> {
|
||||||
image.onDisk = true
|
image.onDisk = true
|
||||||
image.save()
|
image.save()
|
||||||
.catch(err => logger.error('Cannot save new image disk state.', { err }))
|
.catch(err => logger.error('Cannot save new image disk state.', { err }))
|
||||||
|
|
||||||
|
return destination
|
||||||
}
|
}
|
||||||
|
|
||||||
private onServeError (options: {
|
private onServeError (options: {
|
||||||
|
|
|
@ -39,7 +39,7 @@ function updateLocalPlaylistMiniatureFromExisting (options: {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePlaylistMiniatureFromUrl (options: {
|
function updateRemotePlaylistMiniatureFromUrl (options: {
|
||||||
downloadUrl: string
|
downloadUrl: string
|
||||||
playlist: MVideoPlaylistThumbnail
|
playlist: MVideoPlaylistThumbnail
|
||||||
size?: ImageSize
|
size?: ImageSize
|
||||||
|
@ -127,7 +127,7 @@ function generateLocalVideoMiniature (options: {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function updateVideoMiniatureFromUrl (options: {
|
function updateLocalVideoMiniatureFromUrl (options: {
|
||||||
downloadUrl: string
|
downloadUrl: string
|
||||||
video: MVideoThumbnail
|
video: MVideoThumbnail
|
||||||
type: ThumbnailType
|
type: ThumbnailType
|
||||||
|
@ -159,7 +159,7 @@ function updateVideoMiniatureFromUrl (options: {
|
||||||
return updateThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl, onDisk: true })
|
return updateThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl, onDisk: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRemoteThumbnail (options: {
|
function updateRemoteVideoThumbnail (options: {
|
||||||
fileUrl: string
|
fileUrl: string
|
||||||
video: MVideoThumbnail
|
video: MVideoThumbnail
|
||||||
type: ThumbnailType
|
type: ThumbnailType
|
||||||
|
@ -189,10 +189,10 @@ function updateRemoteThumbnail (options: {
|
||||||
|
|
||||||
export {
|
export {
|
||||||
generateLocalVideoMiniature,
|
generateLocalVideoMiniature,
|
||||||
updateVideoMiniatureFromUrl,
|
updateLocalVideoMiniatureFromUrl,
|
||||||
updateLocalVideoMiniatureFromExisting,
|
updateLocalVideoMiniatureFromExisting,
|
||||||
updateRemoteThumbnail,
|
updateRemoteVideoThumbnail,
|
||||||
updatePlaylistMiniatureFromUrl,
|
updateRemotePlaylistMiniatureFromUrl,
|
||||||
updateLocalPlaylistMiniatureFromExisting
|
updateLocalPlaylistMiniatureFromExisting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import {
|
||||||
} from '@server/types/models'
|
} from '@server/types/models'
|
||||||
import { ThumbnailType, VideoImportCreate, VideoImportPayload, VideoImportState, VideoPrivacy, VideoState } from '@shared/models'
|
import { ThumbnailType, VideoImportCreate, VideoImportPayload, VideoImportState, VideoPrivacy, VideoState } from '@shared/models'
|
||||||
import { getLocalVideoActivityPubUrl } from './activitypub/url'
|
import { getLocalVideoActivityPubUrl } from './activitypub/url'
|
||||||
import { updateLocalVideoMiniatureFromExisting, updateVideoMiniatureFromUrl } from './thumbnail'
|
import { updateLocalVideoMiniatureFromExisting, updateLocalVideoMiniatureFromUrl } from './thumbnail'
|
||||||
import { VideoPasswordModel } from '@server/models/video/video-password'
|
import { VideoPasswordModel } from '@server/models/video/video-password'
|
||||||
|
|
||||||
class YoutubeDlImportError extends Error {
|
class YoutubeDlImportError extends Error {
|
||||||
|
@ -266,7 +266,7 @@ async function forgeThumbnail ({ inputPath, video, downloadUrl, type }: {
|
||||||
|
|
||||||
if (downloadUrl) {
|
if (downloadUrl) {
|
||||||
try {
|
try {
|
||||||
return await updateVideoMiniatureFromUrl({ downloadUrl, video, type })
|
return await updateLocalVideoMiniatureFromUrl({ downloadUrl, video, type })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn('Cannot process thumbnail %s from youtube-dl.', downloadUrl, { err })
|
logger.warn('Cannot process thumbnail %s from youtube-dl.', downloadUrl, { err })
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ async function downloadImage (options: {
|
||||||
|
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return destPath
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = downloadImage
|
module.exports = downloadImage
|
||||||
|
|
Loading…
Reference in a new issue