From c2bd7a6fcff652b149b24a642314c88e56a07f48 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 12 Mar 2021 17:04:49 +0100 Subject: [PATCH] Add regenrate thumbnails scripts --- package.json | 1 + scripts/regenerate-thumbnails.ts | 54 +++++++++++ server/tests/cli/index.ts | 1 + server/tests/cli/regenerate-thumbnails.ts | 110 ++++++++++++++++++++++ support/doc/tools.md | 10 ++ 5 files changed, 176 insertions(+) create mode 100644 scripts/regenerate-thumbnails.ts create mode 100644 server/tests/cli/regenerate-thumbnails.ts diff --git a/package.json b/package.json index 345106ce1..72b95e842 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "start:server": "node dist/server --no-client", "update-host": "node ./dist/scripts/update-host.js", "create-transcoding-job": "node ./dist/scripts/create-transcoding-job.js", + "regenerate-thumbnails": "node ./dist/scripts/regenerate-thumbnails.js", "create-import-video-file-job": "node ./dist/scripts/create-import-video-file-job.js", "print-transcode-command": "node ./dist/scripts/print-transcode-command.js", "test": "scripty", diff --git a/scripts/regenerate-thumbnails.ts b/scripts/regenerate-thumbnails.ts new file mode 100644 index 000000000..b0071efe0 --- /dev/null +++ b/scripts/regenerate-thumbnails.ts @@ -0,0 +1,54 @@ +import { registerTSPaths } from '../server/helpers/register-ts-paths' +registerTSPaths() + +import * as Bluebird from 'bluebird' +import * as program from 'commander' +import { pathExists } from 'fs-extra' +import { processImage } from '@server/helpers/image-utils' +import { THUMBNAILS_SIZE } from '@server/initializers/constants' +import { VideoModel } from '@server/models/video/video' +import { MVideo } from '@server/types/models' +import { initDatabaseModels } from '@server/initializers/database' + +program + .description('Regenerate local thumbnails using preview files') + .parse(process.argv) + +run() + .then(() => process.exit(0)) + .catch(err => console.error(err)) + +async function run () { + await initDatabaseModels(true) + + const videos = await VideoModel.listLocal() + + await Bluebird.map(videos, v => { + return processVideo(v) + .catch(err => console.error('Cannot process video %s.', v.url, err)) + }, { concurrency: 20 }) +} + +async function processVideo (videoArg: MVideo) { + const video = await VideoModel.loadWithFiles(videoArg.id) + + const thumbnail = video.getMiniature() + const preview = video.getPreview() + + const thumbnailPath = thumbnail.getPath() + const previewPath = preview.getPath() + + if (!await pathExists(thumbnailPath)) { + throw new Error(`Thumbnail ${thumbnailPath} does not exist on disk`) + } + + if (!await pathExists(previewPath)) { + throw new Error(`Preview ${previewPath} does not exist on disk`) + } + + const size = { + width: THUMBNAILS_SIZE.width, + height: THUMBNAILS_SIZE.height + } + await processImage(previewPath, thumbnailPath, size, true) +} diff --git a/server/tests/cli/index.ts b/server/tests/cli/index.ts index 242589010..7e6eebd17 100644 --- a/server/tests/cli/index.ts +++ b/server/tests/cli/index.ts @@ -6,5 +6,6 @@ import './peertube' import './plugins' import './print-transcode-command' import './prune-storage' +import './regenerate-thumbnails' import './reset-password' import './update-host' diff --git a/server/tests/cli/regenerate-thumbnails.ts b/server/tests/cli/regenerate-thumbnails.ts new file mode 100644 index 000000000..56005518a --- /dev/null +++ b/server/tests/cli/regenerate-thumbnails.ts @@ -0,0 +1,110 @@ +import 'mocha' +import { expect } from 'chai' +import { writeFile } from 'fs-extra' +import { basename, join } from 'path' +import { Video } from '@shared/models' +import { + buildServerDirectory, + cleanupTests, + doubleFollow, + execCLI, + flushAndRunMultipleServers, + getEnvCli, + getVideo, + makeRawRequest, + ServerInfo, + setAccessTokensToServers, + uploadVideoAndGetId, + waitJobs +} from '../../../shared/extra-utils' +import { HttpStatusCode } from '@shared/core-utils' + +describe('Test regenerate thumbnails script', function () { + let servers: ServerInfo[] + + let video1: Video + let video2: Video + let remoteVideo: Video + + let thumbnail1Path: string + let thumbnailRemotePath: string + + before(async function () { + this.timeout(60000) + + servers = await flushAndRunMultipleServers(2) + await setAccessTokensToServers(servers) + + await doubleFollow(servers[0], servers[1]) + + { + const videoUUID1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 1' })).uuid + video1 = await (getVideo(servers[0].url, videoUUID1).then(res => res.body)) + + thumbnail1Path = join(buildServerDirectory(servers[0], 'thumbnails'), basename(video1.thumbnailPath)) + + const videoUUID2 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 2' })).uuid + video2 = await (getVideo(servers[0].url, videoUUID2).then(res => res.body)) + } + + { + const videoUUID = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 3' })).uuid + await waitJobs(servers) + + remoteVideo = await (getVideo(servers[0].url, videoUUID).then(res => res.body)) + + thumbnailRemotePath = join(buildServerDirectory(servers[0], 'thumbnails'), basename(remoteVideo.thumbnailPath)) + } + + await writeFile(thumbnail1Path, '') + await writeFile(thumbnailRemotePath, '') + }) + + it('Should have empty thumbnails', async function () { + { + const res = await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.OK_200) + expect(res.body).to.have.lengthOf(0) + } + + { + const res = await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.OK_200) + expect(res.body).to.not.have.lengthOf(0) + } + + { + const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) + expect(res.body).to.have.lengthOf(0) + } + }) + + it('Should regenerate thumbnails from the CLI', async function () { + this.timeout(15000) + + const env = getEnvCli(servers[0]) + await execCLI(`${env} npm run regenerate-thumbnails`) + }) + + it('Should have regenerated thumbbnails', async function () { + { + const res1 = await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.OK_200) + expect(res1.body).to.not.have.lengthOf(0) + + const res2 = await makeRawRequest(join(servers[0].url, video1.previewPath), HttpStatusCode.OK_200) + expect(res2.body).to.not.have.lengthOf(0) + } + + { + const res = await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.OK_200) + expect(res.body).to.not.have.lengthOf(0) + } + + { + const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) + expect(res.body).to.have.lengthOf(0) + } + }) + + after(async function () { + await cleanupTests(servers) + }) +}) diff --git a/support/doc/tools.md b/support/doc/tools.md index da32506bd..175c22cd8 100644 --- a/support/doc/tools.md +++ b/support/doc/tools.md @@ -15,6 +15,7 @@ - [peertube-redundancy.js](#peertube-redundancyjs) - [Server tools](#server-tools) - [parse-log](#parse-log) + - [regenerate-thumbnails.js](#regenerate-thumbnailsjs) - [create-transcoding-job.js](#create-transcoding-jobjs) - [create-import-video-file-job.js](#create-import-video-file-jobjs) - [prune-storage.js](#prune-storagejs) @@ -251,6 +252,15 @@ $ cd /var/www/peertube/peertube-latest $ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run parse-log -- --level debug --not-tags http sql ``` +### regenerate-thumbnails.js + +Regenerating local video thumbnails could be useful because new PeerTube releases may increase thumbnail sizes: + +``` +$ cd /var/www/peertube/peertube-latest +$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run regenerate-thumbnails +``` + ### create-transcoding-job.js You can use this script to force transcoding of an existing video. PeerTube needs to be running.