diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 50a437b3d..2be364cc8 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' // --------------------------------------------------------------------------- -const LAST_MIGRATION_VERSION = 365 +const LAST_MIGRATION_VERSION = 370 // --------------------------------------------------------------------------- diff --git a/server/initializers/migrations/0370-thumbnail.ts b/server/initializers/migrations/0370-thumbnail.ts new file mode 100644 index 000000000..384ca1a15 --- /dev/null +++ b/server/initializers/migrations/0370-thumbnail.ts @@ -0,0 +1,50 @@ +import * as Sequelize from 'sequelize' + +async function up (utils: { + transaction: Sequelize.Transaction, + queryInterface: Sequelize.QueryInterface, + sequelize: Sequelize.Sequelize, + db: any +}): Promise { + { + const query = ` +CREATE TABLE IF NOT EXISTS "thumbnail" +( + "id" SERIAL, + "filename" VARCHAR(255) NOT NULL, + "height" INTEGER DEFAULT NULL, + "width" INTEGER DEFAULT NULL, + "type" INTEGER NOT NULL, + "fileUrl" VARCHAR(255), + "videoId" INTEGER REFERENCES "video" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + "videoPlaylistId" INTEGER REFERENCES "videoPlaylist" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, + "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, + PRIMARY KEY ("id") +);` + await utils.sequelize.query(query) + } + + { + // All video thumbnails + const query = 'INSERT INTO "thumbnail" ("filename", "type", "videoId", "height", "width", "createdAt", "updatedAt")' + + 'SELECT uuid || \'.jpg\', 1, id, 110, 200, NOW(), NOW() FROM "video"' + await utils.sequelize.query(query) + } + + { + // All video previews + const query = 'INSERT INTO "thumbnail" ("filename", "type", "videoId", "height", "width", "createdAt", "updatedAt")' + + 'SELECT uuid || \'.jpg\', 2, id, 315, 560, NOW(), NOW() FROM "video"' + await utils.sequelize.query(query) + } +} + +function down (options) { + throw new Error('Not implemented.') +} + +export { + up, + down +} diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index ed0177a67..2d48848fe 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts @@ -108,7 +108,10 @@ async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo return sequelizeTypescript.transaction(async t => { const cacheFile = await VideoRedundancyModel.loadByUrl(cacheFileObject.id) - if (!cacheFile) throw new Error('Unknown video cache ' + cacheFileObject.id) + if (!cacheFile) { + logger.debug('Cannot undo unknown video cache %s.', cacheFileObject.id) + return + } if (cacheFile.actorId !== byActor.id) throw new Error('Cannot delete redundancy ' + cacheFile.url + ' of another actor.') diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts index 4ba521b97..950b14c3b 100644 --- a/server/lib/thumbnail.ts +++ b/server/lib/thumbnail.ts @@ -20,19 +20,19 @@ function createPlaylistMiniatureFromExisting (inputPath: string, playlist: Video return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail }) } -function createPlaylistMiniatureFromUrl (url: string, playlist: VideoPlaylistModel, size?: ImageSize) { +function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: VideoPlaylistModel, size?: ImageSize) { const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size) const type = ThumbnailType.MINIATURE - const thumbnailCreator = () => downloadImage(url, basePath, filename, { width, height }) - return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, url }) + const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height }) + return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) } -function createVideoMiniatureFromUrl (url: string, video: VideoModel, type: ThumbnailType, size?: ImageSize) { +function createVideoMiniatureFromUrl (fileUrl: string, video: VideoModel, type: ThumbnailType, size?: ImageSize) { const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) - const thumbnailCreator = () => downloadImage(url, basePath, filename, { width, height }) + const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height }) - return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, url }) + return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) } function createVideoMiniatureFromExisting (inputPath: string, video: VideoModel, type: ThumbnailType, size?: ImageSize) { @@ -51,7 +51,7 @@ function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, t return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail }) } -function createPlaceholderThumbnail (url: string, video: VideoModel, type: ThumbnailType, size: ImageSize) { +function createPlaceholderThumbnail (fileUrl: string, video: VideoModel, type: ThumbnailType, size: ImageSize) { const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() @@ -60,7 +60,7 @@ function createPlaceholderThumbnail (url: string, video: VideoModel, type: Thumb thumbnail.height = height thumbnail.width = width thumbnail.type = type - thumbnail.url = url + thumbnail.fileUrl = fileUrl return thumbnail } @@ -132,10 +132,10 @@ async function createThumbnailFromFunction (parameters: { height: number, width: number, type: ThumbnailType, - url?: string, + fileUrl?: string, existingThumbnail?: ThumbnailModel }) { - const { thumbnailCreator, filename, width, height, type, existingThumbnail, url = null } = parameters + const { thumbnailCreator, filename, width, height, type, existingThumbnail, fileUrl = null } = parameters const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() @@ -143,7 +143,7 @@ async function createThumbnailFromFunction (parameters: { thumbnail.height = height thumbnail.width = width thumbnail.type = type - thumbnail.url = url + thumbnail.fileUrl = fileUrl await thumbnailCreator() diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index ec945893f..206e9a3d6 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts @@ -42,7 +42,7 @@ export class ThumbnailModel extends Model { @AllowNull(true) @Column - url: string + fileUrl: string @ForeignKey(() => VideoModel) @Column @@ -100,8 +100,8 @@ export class ThumbnailModel extends Model { return videoUUID + '.jpg' } - getUrl () { - if (this.url) return this.url + getFileUrl () { + if (this.fileUrl) return this.fileUrl const staticPath = ThumbnailModel.types[this.type].staticPath return WEBSERVER.URL + staticPath + this.filename diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index 877fcbc57..b947eb16f 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts @@ -328,7 +328,7 @@ function videoModelToActivityPubObject (video: VideoModel): VideoTorrentObject { subtitleLanguage, icon: { type: 'Image', - url: miniature.getUrl(), + url: miniature.getFileUrl(), mediaType: 'image/jpeg', width: miniature.width, height: miniature.height