Update data in DB when regenerate thumbnails

pull/3747/head
Chocobozzz 2021-04-08 10:35:49 +02:00
parent ca87329289
commit a0eeb45f14
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
6 changed files with 52 additions and 27 deletions

View File

@ -3,12 +3,13 @@ registerTSPaths()
import * as Bluebird from 'bluebird' import * as Bluebird from 'bluebird'
import * as program from 'commander' import * as program from 'commander'
import { pathExists } from 'fs-extra' import { pathExists, remove } from 'fs-extra'
import { processImage } from '@server/helpers/image-utils' import { processImage } from '@server/helpers/image-utils'
import { THUMBNAILS_SIZE } from '@server/initializers/constants' import { THUMBNAILS_SIZE } from '@server/initializers/constants'
import { VideoModel } from '@server/models/video/video' import { VideoModel } from '@server/models/video/video'
import { MVideo } from '@server/types/models' import { MVideo } from '@server/types/models'
import { initDatabaseModels } from '@server/initializers/database' import { initDatabaseModels } from '@server/initializers/database'
import { ActorImageModel } from '@server/models/account/actor-image'
program program
.description('Regenerate local thumbnails using preview files') .description('Regenerate local thumbnails using preview files')
@ -37,13 +38,8 @@ async function processVideo (videoArg: MVideo) {
const thumbnail = video.getMiniature() const thumbnail = video.getMiniature()
const preview = video.getPreview() const preview = video.getPreview()
const thumbnailPath = thumbnail.getPath()
const previewPath = preview.getPath() const previewPath = preview.getPath()
if (!await pathExists(thumbnailPath)) {
throw new Error(`Thumbnail ${thumbnailPath} does not exist on disk`)
}
if (!await pathExists(previewPath)) { if (!await pathExists(previewPath)) {
throw new Error(`Preview ${previewPath} does not exist on disk`) throw new Error(`Preview ${previewPath} does not exist on disk`)
} }
@ -52,5 +48,22 @@ async function processVideo (videoArg: MVideo) {
width: THUMBNAILS_SIZE.width, width: THUMBNAILS_SIZE.width,
height: THUMBNAILS_SIZE.height height: THUMBNAILS_SIZE.height
} }
const oldPath = thumbnail.getPath()
// Update thumbnail
thumbnail.filename = ActorImageModel.generateFilename()
thumbnail.width = size.width
thumbnail.height = size.height
const thumbnailPath = thumbnail.getPath()
await processImage(previewPath, thumbnailPath, size, true) await processImage(previewPath, thumbnailPath, size, true)
// Save new attributes
await thumbnail.save()
// Remove old thumbnail
await remove(oldPath)
// Don't federate, remote instances will refresh the thumbnails after a while
} }

View File

@ -3,6 +3,7 @@ import { maxBy, minBy } from 'lodash'
import * as magnetUtil from 'magnet-uri' import * as magnetUtil from 'magnet-uri'
import { basename, join } from 'path' import { basename, join } from 'path'
import { Transaction } from 'sequelize/types' import { Transaction } from 'sequelize/types'
import { ActorImageModel } from '@server/models/account/actor-image'
import { TrackerModel } from '@server/models/server/tracker' import { TrackerModel } from '@server/models/server/tracker'
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 { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
@ -899,7 +900,7 @@ function getPreviewFromIcons (videoObject: VideoObject) {
function getPreviewUrl (previewIcon: ActivityIconObject, video: MVideoWithHost) { function getPreviewUrl (previewIcon: ActivityIconObject, video: MVideoWithHost) {
return previewIcon return previewIcon
? previewIcon.url ? previewIcon.url
: buildRemoteVideoBaseUrl(video, join(LAZY_STATIC_PATHS.PREVIEWS, video.generatePreviewName())) : buildRemoteVideoBaseUrl(video, join(LAZY_STATIC_PATHS.PREVIEWS, ActorImageModel.generateFilename()))
} }
function getTrackerUrls (object: VideoObject, video: MVideoWithHost) { function getTrackerUrls (object: VideoObject, video: MVideoWithHost) {

View File

@ -1,4 +1,5 @@
import { join } from 'path' import { join } from 'path'
import { ActorImageModel } from '@server/models/account/actor-image'
import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' import { ThumbnailType } from '../../shared/models/videos/thumbnail.type'
import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils'
import { processImage } from '../helpers/image-utils' import { processImage } from '../helpers/image-utils'
@ -200,7 +201,7 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si
: undefined : undefined
if (type === ThumbnailType.MINIATURE) { if (type === ThumbnailType.MINIATURE) {
const filename = video.generateThumbnailName() const filename = ActorImageModel.generateFilename()
const basePath = CONFIG.STORAGE.THUMBNAILS_DIR const basePath = CONFIG.STORAGE.THUMBNAILS_DIR
return { return {
@ -214,7 +215,7 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si
} }
if (type === ThumbnailType.PREVIEW) { if (type === ThumbnailType.PREVIEW) {
const filename = video.generatePreviewName() const filename = ActorImageModel.generateFilename()
const basePath = CONFIG.STORAGE.PREVIEWS_DIR const basePath = CONFIG.STORAGE.PREVIEWS_DIR
return { return {

View File

@ -1,6 +1,7 @@
import { remove } from 'fs-extra' import { remove } from 'fs-extra'
import { join } from 'path' import { join } from 'path'
import { AfterDestroy, AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AfterDestroy, AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { v4 as uuidv4 } from 'uuid'
import { MActorImageFormattable } from '@server/types/models' import { MActorImageFormattable } from '@server/types/models'
import { ActorImageType } from '@shared/models' import { ActorImageType } from '@shared/models'
import { ActorImage } from '../../../shared/models/actors/actor-image.model' import { ActorImage } from '../../../shared/models/actors/actor-image.model'
@ -53,6 +54,10 @@ export class ActorImageModel extends Model {
.catch(err => logger.error('Cannot remove actor image file %s.', instance.filename, err)) .catch(err => logger.error('Cannot remove actor image file %s.', instance.filename, err))
} }
static generateFilename () {
return uuidv4() + '.jpg'
}
static loadByName (filename: string) { static loadByName (filename: string) {
const query = { const query = {
where: { where: {

View File

@ -24,7 +24,6 @@ import {
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { v4 as uuidv4 } from 'uuid'
import { buildNSFWFilter } from '@server/helpers/express-utils' import { buildNSFWFilter } from '@server/helpers/express-utils'
import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video' import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video'
import { LiveManager } from '@server/lib/live-manager' import { LiveManager } from '@server/lib/live-manager'
@ -1871,20 +1870,12 @@ export class VideoModel extends Model {
this.Thumbnails.push(savedThumbnail) this.Thumbnails.push(savedThumbnail)
} }
generateThumbnailName () {
return uuidv4() + '.jpg'
}
getMiniature () { getMiniature () {
if (Array.isArray(this.Thumbnails) === false) return undefined if (Array.isArray(this.Thumbnails) === false) return undefined
return this.Thumbnails.find(t => t.type === ThumbnailType.MINIATURE) return this.Thumbnails.find(t => t.type === ThumbnailType.MINIATURE)
} }
generatePreviewName () {
return uuidv4() + '.jpg'
}
hasPreview () { hasPreview () {
return !!this.getPreview() return !!this.getPreview()
} }

View File

@ -2,7 +2,7 @@ import 'mocha'
import { expect } from 'chai' import { expect } from 'chai'
import { writeFile } from 'fs-extra' import { writeFile } from 'fs-extra'
import { basename, join } from 'path' import { basename, join } from 'path'
import { Video } from '@shared/models' import { Video, VideoDetails } from '@shared/models'
import { import {
buildServerDirectory, buildServerDirectory,
cleanupTests, cleanupTests,
@ -19,6 +19,17 @@ import {
} from '../../../shared/extra-utils' } from '../../../shared/extra-utils'
import { HttpStatusCode } from '@shared/core-utils' import { HttpStatusCode } from '@shared/core-utils'
async function testThumbnail (server: ServerInfo, videoId: number | string) {
const res = await getVideo(server.url, videoId)
const video: VideoDetails = res.body
const res1 = await makeRawRequest(join(server.url, video.thumbnailPath), HttpStatusCode.OK_200)
expect(res1.body).to.not.have.lengthOf(0)
const res2 = await makeRawRequest(join(server.url, video.thumbnailPath), HttpStatusCode.OK_200)
expect(res2.body).to.not.have.lengthOf(0)
}
describe('Test regenerate thumbnails script', function () { describe('Test regenerate thumbnails script', function () {
let servers: ServerInfo[] let servers: ServerInfo[]
@ -84,18 +95,21 @@ describe('Test regenerate thumbnails script', function () {
await execCLI(`${env} npm run regenerate-thumbnails`) await execCLI(`${env} npm run regenerate-thumbnails`)
}) })
it('Should have regenerated local thumbnails', async function () { it('Should have generated new thumbnail files', async function () {
{ await testThumbnail(servers[0], video1.uuid)
const res1 = await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.OK_200) await testThumbnail(servers[0], video2.uuid)
expect(res1.body).to.not.have.lengthOf(0)
const res2 = await makeRawRequest(join(servers[0].url, video1.previewPath), HttpStatusCode.OK_200) const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200)
expect(res2.body).to.not.have.lengthOf(0) expect(res.body).to.have.lengthOf(0)
})
it('Should have deleted old thumbnail files', async function () {
{
await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.NOT_FOUND_404)
} }
{ {
const res = await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.OK_200) await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.NOT_FOUND_404)
expect(res.body).to.not.have.lengthOf(0)
} }
{ {