X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fthumbnail.ts;h=f33bd31799b302a904591cb2fdcfb7d4cbcae1f6;hb=52d6c2e0bf0893e39d0a89fccebad684e9d61ce5;hp=cf2040cbf6416225432d005fe5a31c0201f0ac47;hpb=557b13ae24019d9ab214bbea7eaa0f892c8f4b05;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index cf2040cbf..f33bd3179 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts @@ -1,12 +1,29 @@ +import { remove } from 'fs-extra' import { join } from 'path' -import { AfterDestroy, AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' -import { LAZY_STATIC_PATHS, STATIC_PATHS, WEBSERVER } from '../../initializers/constants' +import { + AfterDestroy, + AllowNull, + BeforeCreate, + BeforeUpdate, + BelongsTo, + Column, + CreatedAt, + DataType, + Default, + ForeignKey, + Model, + Table, + UpdatedAt +} from 'sequelize-typescript' +import { afterCommitIfTransaction } from '@server/helpers/database-utils' +import { MThumbnail, MThumbnailVideo, MVideo } from '@server/types/models' +import { AttributesOnly } from '@shared/typescript-utils' +import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' import { logger } from '../../helpers/logger' -import { remove } from 'fs-extra' import { CONFIG } from '../../initializers/config' +import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, WEBSERVER } from '../../initializers/constants' import { VideoModel } from './video' import { VideoPlaylistModel } from './video-playlist' -import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' @Table({ tableName: 'thumbnail', @@ -17,10 +34,14 @@ import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' { fields: [ 'videoPlaylistId' ], unique: true + }, + { + fields: [ 'filename', 'type' ], + unique: true } ] }) -export class ThumbnailModel extends Model { +export class ThumbnailModel extends Model>> { @AllowNull(false) @Column @@ -41,7 +62,7 @@ export class ThumbnailModel extends Model { type: ThumbnailType @AllowNull(true) - @Column + @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max)) fileUrl: string @AllowNull(true) @@ -78,7 +99,10 @@ export class ThumbnailModel extends Model { @UpdatedAt updatedAt: Date - private static types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { + // If this thumbnail replaced existing one, track the old name + previousThumbnailFilename: string + + private static readonly types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { [ThumbnailType.MINIATURE]: { label: 'miniature', directory: CONFIG.STORAGE.THUMBNAILS_DIR, @@ -91,32 +115,82 @@ export class ThumbnailModel extends Model { } } + @BeforeCreate + @BeforeUpdate + static removeOldFile (instance: ThumbnailModel, options) { + return afterCommitIfTransaction(options.transaction, () => instance.removePreviousFilenameIfNeeded()) + } + @AfterDestroy static removeFiles (instance: ThumbnailModel) { logger.info('Removing %s file %s.', ThumbnailModel.types[instance.type].label, instance.filename) // Don't block the transaction instance.removeThumbnail() - .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 generateDefaultPreviewName (videoUUID: string) { - return videoUUID + '.jpg' + static loadByFilename (filename: string, thumbnailType: ThumbnailType): Promise { + const query = { + where: { + filename, + type: thumbnailType + } + } + + return ThumbnailModel.findOne(query) } - getFileUrl () { - if (this.fileUrl) return this.fileUrl + static loadWithVideoByFilename (filename: string, thumbnailType: ThumbnailType): Promise { + const query = { + where: { + filename, + type: thumbnailType + }, + include: [ + { + model: VideoModel.unscoped(), + required: true + } + ] + } - const staticPath = ThumbnailModel.types[this.type].staticPath - return WEBSERVER.URL + staticPath + this.filename + return ThumbnailModel.findOne(query) + } + + static buildPath (type: ThumbnailType, filename: string) { + const directory = ThumbnailModel.types[type].directory + + return join(directory, filename) + } + + getFileUrl (video: MVideo) { + const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename + + if (video.isOwned()) return WEBSERVER.URL + staticPath + + return this.fileUrl } getPath () { - const directory = ThumbnailModel.types[this.type].directory - return join(directory, this.filename) + return ThumbnailModel.buildPath(this.type, this.filename) + } + + getPreviousPath () { + return ThumbnailModel.buildPath(this.type, this.previousThumbnailFilename) } removeThumbnail () { return remove(this.getPath()) } + + removePreviousFilenameIfNeeded () { + if (!this.previousThumbnailFilename) return + + const previousPath = this.getPreviousPath() + remove(previousPath) + .catch(err => logger.error('Cannot remove previous thumbnail file %s.', previousPath, { err })) + + this.previousThumbnailFilename = undefined + } }