mirror of https://github.com/Chocobozzz/PeerTube
feat-1332 code cleanup
parent
ce0372c81e
commit
b8fac1fc0c
|
@ -1,5 +1,5 @@
|
|||
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation, Output, EventEmitter } from '@angular/core';
|
||||
import videojs from 'video.js';
|
||||
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild, Output, EventEmitter, ViewEncapsulation } from '@angular/core'
|
||||
import videojs from 'video.js'
|
||||
|
||||
@Component({
|
||||
selector: 'my-frame-selector',
|
||||
|
@ -11,31 +11,28 @@ import videojs from 'video.js';
|
|||
</div>
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['./frame-selector.component.scss'],
|
||||
styleUrls: [ './frame-selector.component.scss' ],
|
||||
/* eslint-disable @angular-eslint/use-component-view-encapsulation */
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
standalone: true
|
||||
})
|
||||
|
||||
export class FrameSelectorComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('frameSelector', { static: true }) target: ElementRef;
|
||||
@ViewChild('frameSelector', { static: true }) target: ElementRef
|
||||
|
||||
@Input() source: string
|
||||
|
||||
@Output() timeChanged = new EventEmitter<number>();
|
||||
@Output() timeChanged = new EventEmitter<number>()
|
||||
|
||||
private player: videojs.Player;
|
||||
|
||||
constructor(
|
||||
) { }
|
||||
|
||||
async ngOnInit() {
|
||||
private player: videojs.Player
|
||||
|
||||
ngOnInit () {
|
||||
|
||||
// Configuring the player, optimizing for frame selection
|
||||
let options = {
|
||||
sources: [{
|
||||
const options = {
|
||||
sources: [ {
|
||||
src: this.source
|
||||
}],
|
||||
} ],
|
||||
controlBar: {
|
||||
fullscreenToggle: false
|
||||
},
|
||||
|
@ -43,40 +40,40 @@ export class FrameSelectorComponent implements OnInit, OnDestroy {
|
|||
controls: true,
|
||||
muted: true,
|
||||
fluid: true,
|
||||
aspectRatio: "16:9",
|
||||
aspectRatio: '16:9',
|
||||
playsinline: true,
|
||||
userActions: {
|
||||
hotkeys: (event: videojs.KeyboardEvent) => {
|
||||
|
||||
// Space -pause/play
|
||||
if (event.key === " ") {
|
||||
if (event.key === ' ') {
|
||||
|
||||
if (this.player.paused()) {
|
||||
|
||||
this.player.play();
|
||||
this.player.play()
|
||||
|
||||
} else {
|
||||
this.player.pause();
|
||||
this.player.pause()
|
||||
}
|
||||
}
|
||||
|
||||
// Allow more accurate frame selection
|
||||
if (event.key === "ArrowRight") {
|
||||
if (event.key === 'ArrowRight') {
|
||||
|
||||
// Stop the video
|
||||
this.player.pause()
|
||||
|
||||
// Forward
|
||||
let step = 0.5
|
||||
const step = 0.5
|
||||
this.player.currentTime(this.player.currentTime() + step)
|
||||
}
|
||||
if (event.key === "ArrowLeft") {
|
||||
if (event.key === 'ArrowLeft') {
|
||||
|
||||
// Stop the video
|
||||
this.player.pause();
|
||||
this.player.pause()
|
||||
|
||||
// Back
|
||||
let step = 0.5
|
||||
const step = 0.5
|
||||
this.player.currentTime(this.player.currentTime() - step)
|
||||
}
|
||||
}
|
||||
|
@ -84,30 +81,30 @@ export class FrameSelectorComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
// Create the player
|
||||
this.player = await videojs(this.target.nativeElement, options)
|
||||
this.player = videojs(this.target.nativeElement, options)
|
||||
|
||||
// Awaiting then calling instead of call back. Makes it easier to reference
|
||||
// Waiting then calling instead of call back. Makes it easier to reference
|
||||
// the event emitter
|
||||
this.onPlayerReady()
|
||||
|
||||
}
|
||||
|
||||
// Dispose the player OnDestroy
|
||||
ngOnDestroy() {
|
||||
ngOnDestroy () {
|
||||
if (this.player) {
|
||||
this.player.dispose();
|
||||
this.player.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
onTimeChanged(value: number) {
|
||||
this.timeChanged.emit(value);
|
||||
onTimeChanged (value: number) {
|
||||
this.timeChanged.emit(value)
|
||||
}
|
||||
|
||||
onPlayerReady() {
|
||||
onPlayerReady () {
|
||||
|
||||
this.player.on('timeupdate', () => {
|
||||
// Event listener that will emit the current time
|
||||
this.onTimeChanged(this.player.currentTime())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { imageToDataURL } from '../../../../../root-helpers/images'
|
||||
import { BytesPipe } from '../../../../shared/shared-main/angular/bytes.pipe'
|
||||
|
||||
|
@ -13,11 +13,10 @@ import {
|
|||
} from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import {
|
||||
AuthService,
|
||||
ConfirmService,
|
||||
Notifier,
|
||||
RestExtractor,
|
||||
ServerService,
|
||||
ServerService
|
||||
} from '../../../../core'
|
||||
import { VideoDetails } from '../../../../shared/shared-main/video/video-details.model'
|
||||
import { VideoFileTokenService } from '../../../../shared/shared-main/video/video-file-token.service'
|
||||
|
@ -29,12 +28,12 @@ import {
|
|||
ServerErrorCode
|
||||
} from '@peertube/peertube-models'
|
||||
import { videoRequiresFileToken } from '../../../../../root-helpers/video'
|
||||
import { FrameSelectorComponent } from './frame-selector.component';
|
||||
import { ReactiveFileComponent } from '@app/shared/shared-forms/reactive-file.component';
|
||||
import { FrameSelectorComponent } from './frame-selector.component'
|
||||
import { ReactiveFileComponent } from '@app/shared/shared-forms/reactive-file.component'
|
||||
|
||||
@Component({
|
||||
selector: 'my-thumbnail-manager',
|
||||
styleUrls: ['./thumbnail-manager.component.scss'],
|
||||
styleUrls: [ './thumbnail-manager.component.scss' ],
|
||||
templateUrl: './thumbnail-manager.component.html',
|
||||
standalone: true,
|
||||
imports: [ CommonModule, FrameSelectorComponent, ReactiveFileComponent ],
|
||||
|
@ -48,8 +47,8 @@ import { ReactiveFileComponent } from '@app/shared/shared-forms/reactive-file.co
|
|||
})
|
||||
export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
||||
|
||||
previewWidth = "360px"
|
||||
previewHeight = "200px"
|
||||
previewWidth = '360px'
|
||||
previewHeight = '200px'
|
||||
|
||||
imageSrc: string
|
||||
allowedExtensionsMessage = ''
|
||||
|
@ -60,16 +59,16 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
file: Blob
|
||||
|
||||
// State Toggle (Upload, Select Frame)
|
||||
selectingFromVideo: boolean = false
|
||||
selectingFromVideo = false
|
||||
|
||||
source: string
|
||||
|
||||
currentTime: number = 0
|
||||
currentTime = 0
|
||||
|
||||
videoId: string
|
||||
videoDetails: VideoDetails
|
||||
|
||||
constructor(
|
||||
constructor (
|
||||
private confirmService: ConfirmService,
|
||||
private notifier: Notifier,
|
||||
private restExtractor: RestExtractor,
|
||||
|
@ -82,31 +81,30 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
this.maxSizeText = $localize`max size`
|
||||
}
|
||||
|
||||
|
||||
// Section - Upload
|
||||
get videoImageExtensions() {
|
||||
// Section - Upload
|
||||
get videoImageExtensions () {
|
||||
return this.serverConfig.video.image.extensions
|
||||
}
|
||||
|
||||
get maxVideoImageSize() {
|
||||
get maxVideoImageSize () {
|
||||
return this.serverConfig.video.image.size.max
|
||||
}
|
||||
|
||||
get maxVideoImageSizeInBytes() {
|
||||
get maxVideoImageSizeInBytes () {
|
||||
return this.bytesPipe.transform(this.maxVideoImageSize)
|
||||
}
|
||||
|
||||
getReactiveFileButtonTooltip() {
|
||||
getReactiveFileButtonTooltip () {
|
||||
return $localize`(extensions: ${this.videoImageExtensions}, ${this.maxSizeText}\: ${this.maxVideoImageSizeInBytes})`
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
ngOnInit () {
|
||||
this.serverConfig = this.serverService.getHTMLConfig()
|
||||
|
||||
this.allowedExtensionsMessage = this.videoImageExtensions.join(', ')
|
||||
}
|
||||
|
||||
onFileChanged(file: Blob) {
|
||||
onFileChanged (file: Blob) {
|
||||
this.file = file
|
||||
|
||||
this.propagateChange(this.file)
|
||||
|
@ -115,20 +113,20 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
|
||||
propagateChange = (_: any) => { /* empty */ }
|
||||
|
||||
writeValue(file: any) {
|
||||
writeValue (file: any) {
|
||||
this.file = file
|
||||
this.updatePreview()
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: any) => void) {
|
||||
registerOnChange (fn: (_: any) => void) {
|
||||
this.propagateChange = fn
|
||||
}
|
||||
|
||||
registerOnTouched() {
|
||||
registerOnTouched () {
|
||||
// Unused
|
||||
}
|
||||
|
||||
private updatePreview() {
|
||||
private updatePreview () {
|
||||
if (this.file) {
|
||||
imageToDataURL(this.file).then(result => this.imageSrc = result)
|
||||
}
|
||||
|
@ -137,7 +135,7 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
|
||||
// Section - Select From Frame
|
||||
|
||||
selectFromVideo() {
|
||||
selectFromVideo () {
|
||||
|
||||
this.selectingFromVideo = true
|
||||
|
||||
|
@ -153,33 +151,30 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
})
|
||||
}
|
||||
|
||||
resetSelectFromVideo() {
|
||||
resetSelectFromVideo () {
|
||||
|
||||
this.selectingFromVideo = false
|
||||
}
|
||||
|
||||
selectFrame() {
|
||||
selectFrame () {
|
||||
|
||||
this.selectingFromVideo = false
|
||||
|
||||
this.videoService.setThumbnailAtTimecode(
|
||||
this.videoDetails.id.toString(),
|
||||
this.currentTime.toString()).subscribe((response) => {
|
||||
|
||||
this.videoService.setThumbnailAtTimecode(this.videoDetails.id.toString(), this.currentTime.toString())
|
||||
.subscribe((response) => {
|
||||
this.imageSrc = response
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
getCurrentTime() {
|
||||
getCurrentTime () {
|
||||
return this.currentTime
|
||||
}
|
||||
|
||||
setCurrentTime(value: number) {
|
||||
this.currentTime = value;
|
||||
setCurrentTime (value: number) {
|
||||
this.currentTime = value
|
||||
}
|
||||
|
||||
private loadVideo(options: {
|
||||
private loadVideo (options: {
|
||||
videoId: string
|
||||
}) {
|
||||
const { videoId } = options
|
||||
|
@ -191,22 +186,22 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
|
||||
return this.videoFileTokenService.getVideoFileToken({ videoUUID: video.uuid })
|
||||
.pipe(map((token) => ({ video, videoFileToken: token.token })))
|
||||
})).subscribe({
|
||||
|
||||
}))
|
||||
.subscribe({
|
||||
next: ({ video, videoFileToken }) => {
|
||||
this.onVideoFetched({
|
||||
video,
|
||||
videoFileToken
|
||||
}).catch(err => {
|
||||
this.handleGlobalError(err)
|
||||
})
|
||||
},
|
||||
error: async err => {
|
||||
error: err => {
|
||||
this.handleRequestError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private async onVideoFetched(options: {
|
||||
private onVideoFetched (options: {
|
||||
video: VideoDetails
|
||||
videoFileToken: string
|
||||
}) {
|
||||
|
@ -217,10 +212,10 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
|
||||
this.videoDetails = video
|
||||
|
||||
let videoFiles = video.getFiles()
|
||||
const videoFiles = video.getFiles()
|
||||
|
||||
if (videoFiles == null) {
|
||||
if (videoFiles.length == 0) {
|
||||
if (videoFiles.length === 0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -228,10 +223,10 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
let url: string = videoFiles[0].fileUrl
|
||||
|
||||
if (videoFileToken != null) {
|
||||
url = addQueryParams(url, { videoFileToken: videoFileToken })
|
||||
url = addQueryParams(url, { videoFileToken })
|
||||
}
|
||||
|
||||
this.source = url
|
||||
this.source = url
|
||||
|
||||
console.log(url)
|
||||
}
|
||||
|
@ -239,14 +234,14 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
|
||||
// Section - Helpers
|
||||
|
||||
private handleGlobalError(err: any) {
|
||||
private handleGlobalError (err: any) {
|
||||
const errorMessage: string = typeof err === 'string' ? err : err.message
|
||||
if (!errorMessage) return
|
||||
|
||||
this.notifier.error(errorMessage)
|
||||
}
|
||||
|
||||
private async handleRequestError(err: any) {
|
||||
private async handleRequestError (err: any) {
|
||||
const errorBody = err.body as PeerTubeProblemDocument
|
||||
|
||||
if (errorBody?.code === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && errorBody.originUrl) {
|
||||
|
@ -270,4 +265,4 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
}
|
||||
|
||||
// End Section - Helpers
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@ import { VideoModel } from '@server/models/video/video.js'
|
|||
import { generateLocalVideoMiniature } from '../../../lib/thumbnail.js'
|
||||
import { MThumbnail, MVideoWithAllFiles } from '@server/types/models/index.js'
|
||||
import { ThumbnailType } from '@peertube/peertube-models'
|
||||
import { asyncMiddleware } from '@server/middlewares/index.js'
|
||||
|
||||
const thumbnailRouter = express.Router()
|
||||
|
||||
thumbnailRouter.put('/:id/thumbnail/:timecode',
|
||||
setThumbnailAtTimecode
|
||||
asyncMiddleware(setThumbnailAtTimecode)
|
||||
)
|
||||
|
||||
export {
|
||||
|
@ -34,15 +35,15 @@ async function setThumbnailAtTimecode (req: express.Request, res: express.Respon
|
|||
|
||||
let url: string
|
||||
|
||||
thumbnails.forEach((thumbnail) => {
|
||||
await Promise.all(thumbnails.map(async (thumbnail) => {
|
||||
|
||||
thumbnail.save()
|
||||
await thumbnail.save()
|
||||
|
||||
if (thumbnail.type === ThumbnailType.PREVIEW) {
|
||||
url = thumbnail.getOriginFileUrl(video)
|
||||
}
|
||||
|
||||
})
|
||||
}))
|
||||
|
||||
return res.json(url)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue