parent
0472d474fd
commit
a8b1b40485
|
@ -13,6 +13,7 @@ import { getUUIDFromFilename } from '../server/helpers/utils'
|
||||||
import { ThumbnailModel } from '../server/models/video/thumbnail'
|
import { ThumbnailModel } from '../server/models/video/thumbnail'
|
||||||
import { AvatarModel } from '../server/models/avatar/avatar'
|
import { AvatarModel } from '../server/models/avatar/avatar'
|
||||||
import { uniq, values } from 'lodash'
|
import { uniq, values } from 'lodash'
|
||||||
|
import { ThumbnailType } from '@shared/models'
|
||||||
|
|
||||||
run()
|
run()
|
||||||
.then(() => process.exit(0))
|
.then(() => process.exit(0))
|
||||||
|
@ -39,8 +40,8 @@ async function run () {
|
||||||
|
|
||||||
await pruneDirectory(CONFIG.STORAGE.REDUNDANCY_DIR, doesRedundancyExist),
|
await pruneDirectory(CONFIG.STORAGE.REDUNDANCY_DIR, doesRedundancyExist),
|
||||||
|
|
||||||
await pruneDirectory(CONFIG.STORAGE.PREVIEWS_DIR, doesThumbnailExist(true)),
|
await pruneDirectory(CONFIG.STORAGE.PREVIEWS_DIR, doesThumbnailExist(true, ThumbnailType.PREVIEW)),
|
||||||
await pruneDirectory(CONFIG.STORAGE.THUMBNAILS_DIR, doesThumbnailExist(false)),
|
await pruneDirectory(CONFIG.STORAGE.THUMBNAILS_DIR, doesThumbnailExist(false, ThumbnailType.MINIATURE)),
|
||||||
|
|
||||||
await pruneDirectory(CONFIG.STORAGE.AVATARS_DIR, doesAvatarExist)
|
await pruneDirectory(CONFIG.STORAGE.AVATARS_DIR, doesAvatarExist)
|
||||||
)
|
)
|
||||||
|
@ -92,9 +93,9 @@ function doesVideoExist (keepOnlyOwned: boolean) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doesThumbnailExist (keepOnlyOwned: boolean) {
|
function doesThumbnailExist (keepOnlyOwned: boolean, type: ThumbnailType) {
|
||||||
return async (file: string) => {
|
return async (file: string) => {
|
||||||
const thumbnail = await ThumbnailModel.loadByName(file)
|
const thumbnail = await ThumbnailModel.loadWithVideoByName(file, type)
|
||||||
if (!thumbnail) return false
|
if (!thumbnail) return false
|
||||||
|
|
||||||
if (keepOnlyOwned) {
|
if (keepOnlyOwned) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ lazyStaticRouter.use(
|
||||||
)
|
)
|
||||||
|
|
||||||
lazyStaticRouter.use(
|
lazyStaticRouter.use(
|
||||||
LAZY_STATIC_PATHS.PREVIEWS + ':uuid.jpg',
|
LAZY_STATIC_PATHS.PREVIEWS + ':filename',
|
||||||
asyncMiddleware(getPreview)
|
asyncMiddleware(getPreview)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ async function getAvatar (req: express.Request, res: express.Response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPreview (req: express.Request, res: express.Response) {
|
async function getPreview (req: express.Request, res: express.Response) {
|
||||||
const result = await VideosPreviewCache.Instance.getFilePath(req.params.uuid)
|
const result = await VideosPreviewCache.Instance.getFilePath(req.params.filename)
|
||||||
if (!result) return res.sendStatus(HttpStatusCode.NOT_FOUND_404)
|
if (!result) return res.sendStatus(HttpStatusCode.NOT_FOUND_404)
|
||||||
|
|
||||||
return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE.SERVER })
|
return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE.SERVER })
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
import * as cors from 'cors'
|
import * as cors from 'cors'
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { getRegisteredPlugins, getRegisteredThemes } from '@server/controllers/api/config'
|
||||||
|
import { serveIndexHTML } from '@server/lib/client-html'
|
||||||
|
import { getTorrentFilePath, getVideoFilePath } from '@server/lib/video-paths'
|
||||||
|
import { MVideoFile, MVideoFullLight } from '@server/types/models'
|
||||||
|
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
||||||
|
import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type'
|
||||||
|
import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo'
|
||||||
|
import { root } from '../helpers/core-utils'
|
||||||
|
import { CONFIG, isEmailEnabled } from '../initializers/config'
|
||||||
import {
|
import {
|
||||||
CONSTRAINTS_FIELDS,
|
CONSTRAINTS_FIELDS,
|
||||||
DEFAULT_THEME_NAME,
|
DEFAULT_THEME_NAME,
|
||||||
|
@ -11,24 +21,13 @@ import {
|
||||||
STATIC_PATHS,
|
STATIC_PATHS,
|
||||||
WEBSERVER
|
WEBSERVER
|
||||||
} from '../initializers/constants'
|
} from '../initializers/constants'
|
||||||
import { cacheRoute } from '../middlewares/cache'
|
|
||||||
import { asyncMiddleware, videosDownloadValidator } from '../middlewares'
|
|
||||||
import { VideoModel } from '../models/video/video'
|
|
||||||
import { UserModel } from '../models/account/user'
|
|
||||||
import { VideoCommentModel } from '../models/video/video-comment'
|
|
||||||
import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo'
|
|
||||||
import { join } from 'path'
|
|
||||||
import { root } from '../helpers/core-utils'
|
|
||||||
import { getEnabledResolutions } from '../lib/video-transcoding'
|
|
||||||
import { CONFIG, isEmailEnabled } from '../initializers/config'
|
|
||||||
import { getPreview, getVideoCaption } from './lazy-static'
|
|
||||||
import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type'
|
|
||||||
import { MVideoFile, MVideoFullLight } from '@server/types/models'
|
|
||||||
import { getTorrentFilePath, getVideoFilePath } from '@server/lib/video-paths'
|
|
||||||
import { getThemeOrDefault } from '../lib/plugins/theme-utils'
|
import { getThemeOrDefault } from '../lib/plugins/theme-utils'
|
||||||
import { getRegisteredPlugins, getRegisteredThemes } from '@server/controllers/api/config'
|
import { getEnabledResolutions } from '../lib/video-transcoding'
|
||||||
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
import { asyncMiddleware, videosDownloadValidator } from '../middlewares'
|
||||||
import { serveIndexHTML } from '@server/lib/client-html'
|
import { cacheRoute } from '../middlewares/cache'
|
||||||
|
import { UserModel } from '../models/account/user'
|
||||||
|
import { VideoModel } from '../models/video/video'
|
||||||
|
import { VideoCommentModel } from '../models/video/video-comment'
|
||||||
|
|
||||||
const staticRouter = express.Router()
|
const staticRouter = express.Router()
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const LAST_MIGRATION_VERSION = 570
|
const LAST_MIGRATION_VERSION = 575
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
|
||||||
|
async function up (utils: {
|
||||||
|
transaction: Sequelize.Transaction
|
||||||
|
queryInterface: Sequelize.QueryInterface
|
||||||
|
sequelize: Sequelize.Sequelize
|
||||||
|
db: any
|
||||||
|
}): Promise<void> {
|
||||||
|
{
|
||||||
|
const query = 'DELETE FROM "thumbnail" s1 ' +
|
||||||
|
'USING (SELECT MIN(id) as id, "filename", "type" FROM "thumbnail" GROUP BY "filename", "type" HAVING COUNT(*) > 1) s2 ' +
|
||||||
|
'WHERE s1."filename" = s2."filename" AND s1."type" = s2."type" AND s1.id <> s2.id'
|
||||||
|
await utils.sequelize.query(query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function down (options) {
|
||||||
|
throw new Error('Not implemented.')
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
up,
|
||||||
|
down
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import { join } from 'path'
|
||||||
import * as request from 'request'
|
import * as request from 'request'
|
||||||
import * as sequelize from 'sequelize'
|
import * as sequelize from 'sequelize'
|
||||||
import { VideoLiveModel } from '@server/models/video/video-live'
|
import { VideoLiveModel } from '@server/models/video/video-live'
|
||||||
|
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
|
||||||
import {
|
import {
|
||||||
ActivityHashTagObject,
|
ActivityHashTagObject,
|
||||||
ActivityMagnetUrlObject,
|
ActivityMagnetUrlObject,
|
||||||
|
@ -15,7 +16,7 @@ import {
|
||||||
ActivityUrlObject,
|
ActivityUrlObject,
|
||||||
ActivityVideoUrlObject
|
ActivityVideoUrlObject
|
||||||
} from '../../../shared/index'
|
} from '../../../shared/index'
|
||||||
import { VideoObject } from '../../../shared/models/activitypub/objects'
|
import { ActivityIconObject, VideoObject } from '../../../shared/models/activitypub/objects'
|
||||||
import { VideoPrivacy } from '../../../shared/models/videos'
|
import { VideoPrivacy } from '../../../shared/models/videos'
|
||||||
import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
|
import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
|
||||||
import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
|
import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
|
||||||
|
@ -76,7 +77,6 @@ import { sendCreateVideo, sendUpdateVideo } from './send'
|
||||||
import { addVideoShares, shareVideoByServerAndChannel } from './share'
|
import { addVideoShares, shareVideoByServerAndChannel } from './share'
|
||||||
import { addVideoComments } from './video-comments'
|
import { addVideoComments } from './video-comments'
|
||||||
import { createRates } from './video-rates'
|
import { createRates } from './video-rates'
|
||||||
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
|
|
||||||
|
|
||||||
async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) {
|
async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) {
|
||||||
const video = videoArg as MVideoAP
|
const video = videoArg as MVideoAP
|
||||||
|
@ -360,7 +360,7 @@ async function updateVideoFromAP (options: {
|
||||||
if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t)
|
if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t)
|
||||||
|
|
||||||
if (videoUpdated.getPreview()) {
|
if (videoUpdated.getPreview()) {
|
||||||
const previewUrl = videoUpdated.getPreview().getFileUrl(videoUpdated)
|
const previewUrl = getPreviewUrl(getPreviewFromIcons(videoObject), video)
|
||||||
const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE)
|
const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE)
|
||||||
await videoUpdated.addAndSaveThumbnail(previewModel, t)
|
await videoUpdated.addAndSaveThumbnail(previewModel, t)
|
||||||
}
|
}
|
||||||
|
@ -597,9 +597,7 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi
|
||||||
if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t)
|
if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t)
|
||||||
|
|
||||||
const previewIcon = getPreviewFromIcons(videoObject)
|
const previewIcon = getPreviewFromIcons(videoObject)
|
||||||
const previewUrl = previewIcon
|
const previewUrl = getPreviewUrl(previewIcon, videoCreated)
|
||||||
? previewIcon.url
|
|
||||||
: buildRemoteVideoBaseUrl(videoCreated, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName()))
|
|
||||||
const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE)
|
const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE)
|
||||||
|
|
||||||
if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t)
|
if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t)
|
||||||
|
@ -822,7 +820,11 @@ function getThumbnailFromIcons (videoObject: VideoObject) {
|
||||||
function getPreviewFromIcons (videoObject: VideoObject) {
|
function getPreviewFromIcons (videoObject: VideoObject) {
|
||||||
const validIcons = videoObject.icon.filter(i => i.width > PREVIEWS_SIZE.minWidth)
|
const validIcons = videoObject.icon.filter(i => i.width > PREVIEWS_SIZE.minWidth)
|
||||||
|
|
||||||
// FIXME: don't put a fallback here for compatibility with PeerTube <2.2
|
|
||||||
|
|
||||||
return maxBy(validIcons, 'width')
|
return maxBy(validIcons, 'width')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPreviewUrl (previewIcon: ActivityIconObject, video: MVideoAccountLight) {
|
||||||
|
return previewIcon
|
||||||
|
? previewIcon.url
|
||||||
|
: buildRemoteVideoBaseUrl(video, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName()))
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ import { FILES_CACHE } from '../../initializers/constants'
|
||||||
import { VideoModel } from '../../models/video/video'
|
import { VideoModel } from '../../models/video/video'
|
||||||
import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache'
|
import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache'
|
||||||
import { doRequestAndSaveToFile } from '@server/helpers/requests'
|
import { doRequestAndSaveToFile } from '@server/helpers/requests'
|
||||||
|
import { ThumbnailModel } from '@server/models/video/thumbnail'
|
||||||
|
import { ThumbnailType } from '@shared/models'
|
||||||
|
import { logger } from '@server/helpers/logger'
|
||||||
|
|
||||||
class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
|
class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
|
||||||
|
|
||||||
|
@ -16,13 +19,13 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
|
||||||
return this.instance || (this.instance = new this())
|
return this.instance || (this.instance = new this())
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFilePathImpl (videoUUID: string) {
|
async getFilePathImpl (filename: string) {
|
||||||
const video = await VideoModel.loadByUUID(videoUUID)
|
const thumbnail = await ThumbnailModel.loadWithVideoByName(filename, ThumbnailType.PREVIEW)
|
||||||
if (!video) return undefined
|
if (!thumbnail) return undefined
|
||||||
|
|
||||||
if (video.isOwned()) return { isOwned: true, path: video.getPreview().getPath() }
|
if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() }
|
||||||
|
|
||||||
return this.loadRemoteFile(videoUUID)
|
return this.loadRemoteFile(thumbnail.Video.uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async loadRemoteFile (key: string) {
|
protected async loadRemoteFile (key: string) {
|
||||||
|
@ -37,6 +40,8 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
|
||||||
const remoteUrl = preview.getFileUrl(video)
|
const remoteUrl = preview.getFileUrl(video)
|
||||||
await doRequestAndSaveToFile({ uri: remoteUrl }, destPath)
|
await doRequestAndSaveToFile({ uri: remoteUrl }, destPath)
|
||||||
|
|
||||||
|
logger.debug('Fetched remote preview %s to %s.', remoteUrl, destPath)
|
||||||
|
|
||||||
return { isOwned: false, path: destPath }
|
return { isOwned: false, path: destPath }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,18 +27,28 @@ function createPlaylistMiniatureFromExisting (
|
||||||
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail })
|
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail })
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) {
|
function createPlaylistMiniatureFromUrl (downloadUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) {
|
||||||
const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size)
|
const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size)
|
||||||
const type = ThumbnailType.MINIATURE
|
const type = ThumbnailType.MINIATURE
|
||||||
|
|
||||||
const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height })
|
// Only save the file URL if it is a remote playlist
|
||||||
|
const fileUrl = playlist.isOwned()
|
||||||
|
? null
|
||||||
|
: downloadUrl
|
||||||
|
|
||||||
|
const thumbnailCreator = () => downloadImage(downloadUrl, basePath, filename, { width, height })
|
||||||
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl })
|
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl })
|
||||||
}
|
}
|
||||||
|
|
||||||
function createVideoMiniatureFromUrl (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) {
|
function createVideoMiniatureFromUrl (downloadUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) {
|
||||||
const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
|
const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
|
||||||
const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height })
|
|
||||||
|
|
||||||
|
// Only save the file URL if it is a remote video
|
||||||
|
const fileUrl = video.isOwned()
|
||||||
|
? null
|
||||||
|
: downloadUrl
|
||||||
|
|
||||||
|
const thumbnailCreator = () => downloadImage(downloadUrl, basePath, filename, { width, height })
|
||||||
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl })
|
return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { remove } from 'fs-extra'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import {
|
import {
|
||||||
AfterDestroy,
|
AfterDestroy,
|
||||||
|
@ -12,15 +13,14 @@ import {
|
||||||
Table,
|
Table,
|
||||||
UpdatedAt
|
UpdatedAt
|
||||||
} from 'sequelize-typescript'
|
} from 'sequelize-typescript'
|
||||||
import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, WEBSERVER } from '../../initializers/constants'
|
import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
|
||||||
|
import { MThumbnailVideo, MVideoAccountLight } from '@server/types/models'
|
||||||
|
import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { remove } from 'fs-extra'
|
|
||||||
import { CONFIG } from '../../initializers/config'
|
import { CONFIG } from '../../initializers/config'
|
||||||
|
import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, WEBSERVER } from '../../initializers/constants'
|
||||||
import { VideoModel } from './video'
|
import { VideoModel } from './video'
|
||||||
import { VideoPlaylistModel } from './video-playlist'
|
import { VideoPlaylistModel } from './video-playlist'
|
||||||
import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
|
|
||||||
import { MVideoAccountLight } from '@server/types/models'
|
|
||||||
import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
|
|
||||||
|
|
||||||
@Table({
|
@Table({
|
||||||
tableName: 'thumbnail',
|
tableName: 'thumbnail',
|
||||||
|
@ -31,6 +31,10 @@ import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
|
||||||
{
|
{
|
||||||
fields: [ 'videoPlaylistId' ],
|
fields: [ 'videoPlaylistId' ],
|
||||||
unique: true
|
unique: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fields: [ 'filename', 'type' ],
|
||||||
|
unique: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -114,20 +118,23 @@ export class ThumbnailModel extends Model {
|
||||||
.catch(err => logger.error('Cannot remove thumbnail file %s.', instance.filename, err))
|
.catch(err => logger.error('Cannot remove thumbnail file %s.', instance.filename, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadByName (filename: string) {
|
static loadWithVideoByName (filename: string, thumbnailType: ThumbnailType): Promise<MThumbnailVideo> {
|
||||||
const query = {
|
const query = {
|
||||||
where: {
|
where: {
|
||||||
filename
|
filename,
|
||||||
|
type: thumbnailType
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: VideoModel.unscoped(),
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
return ThumbnailModel.findOne(query)
|
return ThumbnailModel.findOne(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
static generateDefaultPreviewName (videoUUID: string) {
|
|
||||||
return videoUUID + '.jpg'
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileUrl (video: MVideoAccountLight) {
|
getFileUrl (video: MVideoAccountLight) {
|
||||||
const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename
|
const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ import { VideoShareModel } from './video-share'
|
||||||
import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
|
import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
|
||||||
import { VideoTagModel } from './video-tag'
|
import { VideoTagModel } from './video-tag'
|
||||||
import { VideoViewModel } from './video-view'
|
import { VideoViewModel } from './video-view'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
export enum ScopeNames {
|
export enum ScopeNames {
|
||||||
AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS',
|
AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS',
|
||||||
|
@ -1827,7 +1828,7 @@ export class VideoModel extends Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
generateThumbnailName () {
|
generateThumbnailName () {
|
||||||
return this.uuid + '.jpg'
|
return uuidv4() + '.jpg'
|
||||||
}
|
}
|
||||||
|
|
||||||
getMiniature () {
|
getMiniature () {
|
||||||
|
@ -1837,7 +1838,7 @@ export class VideoModel extends Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
generatePreviewName () {
|
generatePreviewName () {
|
||||||
return this.uuid + '.jpg'
|
return uuidv4() + '.jpg'
|
||||||
}
|
}
|
||||||
|
|
||||||
hasPreview () {
|
hasPreview () {
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
import { PickWith } from '@shared/core-utils'
|
||||||
import { ThumbnailModel } from '../../../models/video/thumbnail'
|
import { ThumbnailModel } from '../../../models/video/thumbnail'
|
||||||
|
import { MVideo } from './video'
|
||||||
|
|
||||||
|
type Use<K extends keyof ThumbnailModel, M> = PickWith<ThumbnailModel, K, M>
|
||||||
|
|
||||||
|
// ############################################################################
|
||||||
|
|
||||||
export type MThumbnail = Omit<ThumbnailModel, 'Video' | 'VideoPlaylist'>
|
export type MThumbnail = Omit<ThumbnailModel, 'Video' | 'VideoPlaylist'>
|
||||||
|
|
||||||
|
// ############################################################################
|
||||||
|
|
||||||
|
export type MThumbnailVideo =
|
||||||
|
MThumbnail &
|
||||||
|
Use<'Video', MVideo>
|
||||||
|
|
Loading…
Reference in New Issue