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:
parent
c07fac202d
commit
123f619336
|
@ -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()"/>
|
||||||
|
|
|
@ -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}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.')
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue