mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-13 15:56:15 -08:00
152 lines
3.8 KiB
TypeScript
152 lines
3.8 KiB
TypeScript
import type { InputOptions, RuntimeOptions, ThumbnailEvents } from './types'
|
|
import Emitter from './emitter'
|
|
import { startExtraction } from './extraction'
|
|
import { connectInput, releaseInput, setupInput } from './input'
|
|
import { cleanupAll, closeState, releaseMedia, stateFor } from './lifecycle'
|
|
import { thumbnailPolicy } from './policy'
|
|
import { createSheet, downloadSheet, screenshotPoints } from './sheet'
|
|
import { loadSource } from './source'
|
|
|
|
export default class ArtplayerToolThumbnail extends Emitter<ThumbnailEvents> {
|
|
declare processing: boolean
|
|
declare option: RuntimeOptions
|
|
declare video: HTMLVideoElement
|
|
declare duration: number
|
|
declare density: number | undefined
|
|
declare file: File | undefined
|
|
declare videoUrl: string | undefined
|
|
declare thumbnailUrl: string | undefined
|
|
|
|
constructor(option: InputOptions = {}) {
|
|
super()
|
|
this.processing = false
|
|
// setup validates the temporary empty options before construction can succeed.
|
|
this.option = {} as RuntimeOptions
|
|
try {
|
|
this.setup(Object.assign({}, ArtplayerToolThumbnail.DEFAULTS, option))
|
|
this.video = ArtplayerToolThumbnail.creatVideo()
|
|
stateFor(this).video = this.video
|
|
this.duration = 0
|
|
this.inputChange = this.inputChange.bind(this)
|
|
this.ondrop = this.ondrop.bind(this)
|
|
connectInput(this, ArtplayerToolThumbnail.ondragover)
|
|
}
|
|
catch (error) {
|
|
closeState(this, 'construction failed')
|
|
try {
|
|
releaseInput(this)
|
|
}
|
|
catch {}
|
|
try {
|
|
releaseMedia(this)
|
|
}
|
|
catch {}
|
|
throw error
|
|
}
|
|
}
|
|
|
|
static get DEFAULTS() {
|
|
return {
|
|
delay: 300,
|
|
number: 60,
|
|
width: 160,
|
|
height: 90,
|
|
column: 10,
|
|
begin: 0,
|
|
end: Number.NaN,
|
|
}
|
|
}
|
|
|
|
static ondragover(event: DragEvent) {
|
|
event.preventDefault()
|
|
}
|
|
|
|
ondrop(event: DragEvent) {
|
|
if (stateFor(this).closed)
|
|
return
|
|
event.preventDefault()
|
|
const file = event.dataTransfer!.files[0]
|
|
this.loadVideo(file)
|
|
}
|
|
|
|
setup(option: InputOptions = {}) {
|
|
if (!stateFor(this).closed)
|
|
setupInput(this, option)
|
|
return this
|
|
}
|
|
|
|
static creatVideo() {
|
|
const video = document.createElement('video')
|
|
video.style.position = 'absolute'
|
|
video.style.top = '-9999px'
|
|
video.style.left = '-9999px'
|
|
video.muted = true
|
|
video.controls = true
|
|
try {
|
|
document.body.appendChild(video)
|
|
}
|
|
catch (error) {
|
|
if (video.parentNode)
|
|
video.parentNode.removeChild(video)
|
|
throw error
|
|
}
|
|
return video
|
|
}
|
|
|
|
inputChange(event: Event) {
|
|
if (stateFor(this).closed)
|
|
return
|
|
const { resetInput } = thumbnailPolicy(this.option)
|
|
const file = this.option.fileInput.files![0]
|
|
this.loadVideo(file)
|
|
if (resetInput)
|
|
(event.target as HTMLInputElement).value = ''
|
|
}
|
|
|
|
loadVideo(file?: File | null) {
|
|
loadSource(this, file)
|
|
}
|
|
|
|
start() {
|
|
return startExtraction(this)
|
|
}
|
|
|
|
creatScreenshotDate() {
|
|
return screenshotPoints(this.option, this.duration)
|
|
}
|
|
|
|
creatCanvas() {
|
|
return createSheet(this.option)
|
|
}
|
|
|
|
download() {
|
|
if (stateFor(this).closed)
|
|
return this
|
|
this.errorHandle(
|
|
this.file && this.thumbnailUrl,
|
|
'Download does not seem to be ready, please create preview first',
|
|
)
|
|
this.errorHandle(!this.processing, 'There is currently a task in progress, please wait a moment...')
|
|
const name = downloadSheet(this.file!, this.thumbnailUrl!)
|
|
this.emit('download', name)
|
|
return this
|
|
}
|
|
|
|
errorHandle(condition: unknown, msg: string) {
|
|
if (!condition) {
|
|
this.emit('error', msg)
|
|
throw new Error(msg)
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
if (!closeState(this))
|
|
return
|
|
cleanupAll([
|
|
() => releaseInput(this),
|
|
() => releaseMedia(this),
|
|
() => this.emit('destroy'),
|
|
])
|
|
}
|
|
}
|