Add pixel size to tooltip and gif support with FFmpeg for avatar upload (#3329)

* Add avatar pixel size upload in tooltip

* Add gif support for avatar

* Add ffmpeg GIF process

Co-authored-by: kimsible <kimsible@users.noreply.github.com>
This commit is contained in:
Kimsible 2020-11-25 09:26:31 +01:00 committed by GitHub
parent c07fac202d
commit 123f619336
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 8 deletions

View File

@ -4,7 +4,8 @@
<img [src]="actor.avatarUrl" alt="Avatar" /> <img [src]="actor.avatarUrl" alt="Avatar" />
<div class="actor-img-edit-container"> <div class="actor-img-edit-container">
<div class="actor-img-edit-button" [ngbTooltip]="'(extensions: '+ avatarExtensions +', '+ maxSizeText +': '+ maxAvatarSizeInBytes +')'" placement="right" container="body"> <div class="actor-img-edit-button" [ngbTooltip]="avatarFormat"
placement="right" container="body">
<my-global-icon iconName="edit"></my-global-icon> <my-global-icon iconName="edit"></my-global-icon>
<label for="avatarfile" i18n>Change your avatar</label> <label for="avatarfile" i18n>Change your avatar</label>
<input #avatarfileInput type="file" title=" " name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange()"/> <input #avatarfileInput type="file" title=" " name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange()"/>

View File

@ -17,16 +17,12 @@ export class ActorAvatarInfoComponent implements OnInit {
@Output() avatarChange = new EventEmitter<FormData>() @Output() avatarChange = new EventEmitter<FormData>()
maxSizeText: string
private serverConfig: ServerConfig private serverConfig: ServerConfig
constructor ( constructor (
private serverService: ServerService, private serverService: ServerService,
private notifier: Notifier private notifier: Notifier
) { ) { }
this.maxSizeText = $localize`max size`
}
ngOnInit (): void { ngOnInit (): void {
this.serverConfig = this.serverService.getTmpConfig() this.serverConfig = this.serverService.getTmpConfig()
@ -58,4 +54,8 @@ export class ActorAvatarInfoComponent implements OnInit {
get avatarExtensions () { get avatarExtensions () {
return this.serverConfig.avatar.file.extensions.join(', ') return this.serverConfig.avatar.file.extensions.join(', ')
} }
get avatarFormat () {
return `${$localize`max size`}: 192*192px, ${this.maxAvatarSizeInBytes} ${$localize`extensions`}: ${this.avatarExtensions}`
}
} }

View File

@ -355,6 +355,40 @@ function convertWebPToJPG (path: string, destination: string): Promise<void> {
}) })
} }
function processGIF (
path: string,
destination: string,
newSize: { width: number, height: number },
keepOriginal = false
): Promise<void> {
return new Promise<void>(async (res, rej) => {
if (path === destination) {
throw new Error('FFmpeg needs an input path different that the output path.')
}
logger.debug('Processing gif %s to %s.', path, destination)
try {
const command = ffmpeg(path)
.fps(20)
.size(`${newSize.width}x${newSize.height}`)
.output(destination)
command.on('error', (err, stdout, stderr) => {
logger.error('Error in ffmpeg gif resizing process.', { stdout, stderr })
return rej(err)
})
.on('end', async () => {
if (keepOriginal !== true) await remove(path)
res()
})
.run()
} catch (err) {
return rej(err)
}
})
}
function runLiveTranscoding (rtmpUrl: string, outPath: string, resolutions: number[], fps, deleteSegments: boolean) { function runLiveTranscoding (rtmpUrl: string, outPath: string, resolutions: number[], fps, deleteSegments: boolean) {
const command = getFFmpeg(rtmpUrl) const command = getFFmpeg(rtmpUrl)
command.inputOption('-fflags nobuffer') command.inputOption('-fflags nobuffer')
@ -474,6 +508,7 @@ export {
getAudioStreamCodec, getAudioStreamCodec,
runLiveMuxing, runLiveMuxing,
convertWebPToJPG, convertWebPToJPG,
processGIF,
getVideoStreamSize, getVideoStreamSize,
getVideoFileResolution, getVideoFileResolution,
getMetadataFromFile, getMetadataFromFile,

View File

@ -1,5 +1,6 @@
import { extname } from 'path'
import { remove, rename } from 'fs-extra' import { remove, rename } from 'fs-extra'
import { convertWebPToJPG } from './ffmpeg-utils' import { convertWebPToJPG, processGIF } from './ffmpeg-utils'
import { logger } from './logger' import { logger } from './logger'
const Jimp = require('jimp') const Jimp = require('jimp')
@ -10,6 +11,13 @@ async function processImage (
newSize: { width: number, height: number }, newSize: { width: number, height: number },
keepOriginal = false keepOriginal = false
) { ) {
const extension = extname(path)
// Use FFmpeg to process GIF
if (extension === '.gif') {
return processGIF(path, destination, newSize, keepOriginal)
}
if (path === destination) { if (path === destination) {
throw new Error('Jimp needs an input path different that the output path.') throw new Error('Jimp needs an input path different that the output path.')
} }

View File

@ -291,7 +291,7 @@ const CONSTRAINTS_FIELDS = {
PRIVATE_KEY: { min: 10, max: 5000 }, // Length PRIVATE_KEY: { min: 10, max: 5000 }, // Length
URL: { min: 3, max: 2000 }, // Length URL: { min: 3, max: 2000 }, // Length
AVATAR: { AVATAR: {
EXTNAME: [ '.png', '.jpeg', '.jpg' ], EXTNAME: [ '.png', '.jpeg', '.jpg', '.gif' ],
FILE_SIZE: { FILE_SIZE: {
max: 2 * 1024 * 1024 // 2MB max: 2 * 1024 * 1024 // 2MB
} }