mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-19 03:11:20 -08:00
refactor(core): CORE-01 migrate utility contracts to TypeScript
This commit is contained in:
1 parent
e005e5f249
commit
d3c695024a
33 files changed
+1269
-305
No files matched your search
@@ -1,25 +0,0 @@
|
||||
export class ArtPlayerError extends Error {
|
||||
constructor(message, context) {
|
||||
super(message)
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, context || this.constructor)
|
||||
}
|
||||
this.name = 'ArtPlayerError'
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandle(condition, msg) {
|
||||
if (!condition) {
|
||||
throw new ArtPlayerError(msg)
|
||||
}
|
||||
return condition
|
||||
}
|
||||
|
||||
// Handle internal play rejections without changing the public play/toggle promises.
|
||||
// Values without catch (including synchronous pause results) pass through unchanged.
|
||||
export function silencePromise(value) {
|
||||
if (value && typeof value.catch === 'function') {
|
||||
return value.catch(() => {})
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
type StackFrame = ((...args: never[]) => unknown) | (abstract new (...args: never[]) => object)
|
||||
|
||||
export class ArtPlayerError extends Error {
|
||||
constructor(message?: string, context?: StackFrame) {
|
||||
super(message)
|
||||
if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, context || this.constructor)
|
||||
}
|
||||
this.name = 'ArtPlayerError'
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandle<T>(condition: T, msg?: string): T {
|
||||
if (!condition) {
|
||||
throw new ArtPlayerError(msg)
|
||||
}
|
||||
return condition
|
||||
}
|
||||
|
||||
// Handle internal play rejections without changing the public play/toggle promises.
|
||||
// Values without catch (including synchronous pause results) pass through unchanged.
|
||||
export function silencePromise<T>(value: T): T extends Promise<infer Result> ? Promise<Result | undefined> : T
|
||||
export function silencePromise(value: unknown): unknown {
|
||||
const candidate = value as { catch?: unknown } | null | undefined
|
||||
if (candidate && typeof candidate.catch === 'function') {
|
||||
return candidate.catch(() => {})
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
export function getExt(url) {
|
||||
if (url.includes('?')) {
|
||||
return getExt(url.split('?')[0])
|
||||
}
|
||||
|
||||
if (url.includes('#')) {
|
||||
return getExt(url.split('#')[0])
|
||||
}
|
||||
|
||||
return url.trim().toLowerCase().split('.').pop()
|
||||
}
|
||||
|
||||
export function download(url, name) {
|
||||
const elink = document.createElement('a')
|
||||
elink.style.display = 'none'
|
||||
elink.href = url
|
||||
elink.download = name
|
||||
document.body.appendChild(elink)
|
||||
elink.click()
|
||||
document.body.removeChild(elink)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export function getExt(url: string): string {
|
||||
const end = url.search(/[?#]/)
|
||||
const clean = (end < 0 ? url : url.slice(0, end)).trim().toLowerCase()
|
||||
return clean.slice(clean.lastIndexOf('.') + 1)
|
||||
}
|
||||
|
||||
export function download(url: string, name: string): void {
|
||||
const elink = document.createElement('a')
|
||||
elink.style.display = 'none'
|
||||
elink.href = url
|
||||
elink.download = name
|
||||
document.body.appendChild(elink)
|
||||
try {
|
||||
elink.click()
|
||||
}
|
||||
finally {
|
||||
elink.remove()
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
export function clamp(num, a, b) {
|
||||
return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b))
|
||||
}
|
||||
|
||||
export function capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
export function secondToTime(second) {
|
||||
if (!second)
|
||||
return '00:00'
|
||||
const add0 = num => (num < 10 ? `0${num}` : String(num))
|
||||
const hour = Math.floor(second / 3600)
|
||||
const min = Math.floor((second - hour * 3600) / 60)
|
||||
const sec = Math.floor(second - hour * 3600 - min * 60)
|
||||
return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':')
|
||||
}
|
||||
|
||||
export function escape(str) {
|
||||
return str.replace(
|
||||
/[&<>'"]/g,
|
||||
tag =>
|
||||
({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'\'': ''',
|
||||
'"': '"',
|
||||
})[tag] || tag,
|
||||
)
|
||||
}
|
||||
|
||||
export function unescape(str) {
|
||||
const map = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
''': '\'',
|
||||
'"': '"',
|
||||
}
|
||||
const reg = new RegExp(`(${Object.keys(map).join('|')})`, 'g')
|
||||
return str.replace(reg, tag => map[tag] || tag)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
export function clamp(num: number, a: number, b: number): number {
|
||||
return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b))
|
||||
}
|
||||
|
||||
export function capitalize(str: string): string {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
export function secondToTime(second: number): string {
|
||||
if (!second)
|
||||
return '00:00'
|
||||
const add0 = (num: number) => (num < 10 ? `0${num}` : String(num))
|
||||
const hour = Math.floor(second / 3600)
|
||||
const min = Math.floor((second - hour * 3600) / 60)
|
||||
const sec = Math.floor(second - hour * 3600 - min * 60)
|
||||
return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':')
|
||||
}
|
||||
|
||||
const escapeMap: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'\'': ''',
|
||||
'"': '"',
|
||||
}
|
||||
const unescapeMap: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
''': '\'',
|
||||
'"': '"',
|
||||
}
|
||||
const unescapePattern = /(&|<|>|'|")/g
|
||||
|
||||
export function escape(str: string): string {
|
||||
return str.replace(
|
||||
/[&<>'"]/g,
|
||||
tag => escapeMap[tag] || tag,
|
||||
)
|
||||
}
|
||||
|
||||
export function unescape(str: string): string {
|
||||
return str.replace(unescapePattern, tag => unescapeMap[tag] || tag)
|
||||
}
|
||||
File renamed without changes.
@@ -1,30 +0,0 @@
|
||||
export const def = Object.defineProperty
|
||||
|
||||
const { hasOwnProperty } = Object.prototype
|
||||
export function has(obj, name) {
|
||||
return hasOwnProperty.call(obj, name)
|
||||
}
|
||||
|
||||
export function get(obj, name) {
|
||||
return Object.getOwnPropertyDescriptor(obj, name)
|
||||
}
|
||||
|
||||
export function mergeDeep(...objects) {
|
||||
const isObject = item => item && typeof item === 'object' && !Array.isArray(item)
|
||||
return objects.reduce((prev, obj) => {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const pVal = prev[key]
|
||||
const oVal = obj[key]
|
||||
if (Array.isArray(pVal) && Array.isArray(oVal)) {
|
||||
prev[key] = pVal.concat(...oVal)
|
||||
}
|
||||
else if (isObject(pVal) && isObject(oVal)) {
|
||||
prev[key] = mergeDeep(pVal, oVal)
|
||||
}
|
||||
else {
|
||||
prev[key] = oVal
|
||||
}
|
||||
})
|
||||
return prev
|
||||
}, {})
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
export const def = Object.defineProperty
|
||||
|
||||
const { hasOwnProperty } = Object.prototype
|
||||
export function has(obj: object, name: PropertyKey): boolean {
|
||||
return hasOwnProperty.call(obj, name)
|
||||
}
|
||||
|
||||
export function get(obj: object, name: PropertyKey): PropertyDescriptor | undefined {
|
||||
return Object.getOwnPropertyDescriptor(obj, name)
|
||||
}
|
||||
|
||||
export function mergeDeep<T extends object[]>(...objects: T): T[number] {
|
||||
const isObject = (item: unknown): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item)
|
||||
const result = objects.reduce<Record<string, unknown>>((prev, obj) => {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const pVal = prev[key]
|
||||
const oVal: unknown = (obj as Record<string, unknown>)[key]
|
||||
let value: unknown
|
||||
if (Array.isArray(pVal) && Array.isArray(oVal)) {
|
||||
value = pVal.concat(...oVal)
|
||||
}
|
||||
else if (isObject(pVal) && isObject(oVal)) {
|
||||
value = mergeDeep(pVal, oVal)
|
||||
}
|
||||
else {
|
||||
value = oVal
|
||||
}
|
||||
// Treat keys as data rather than invoking inherited setters such as __proto__.
|
||||
def(prev, key, { value, enumerable: true, configurable: true, writable: true })
|
||||
})
|
||||
return prev
|
||||
}, {})
|
||||
// Preserve the existing generic API; dynamic keys are handled only inside this boundary.
|
||||
return result as T[number]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
function fixSrt(srt) {
|
||||
return srt.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g, (_, $1, $2) => {
|
||||
function fixSrt(srt: string): string {
|
||||
return srt.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g, (_match: string, $1: string, $2: string) => {
|
||||
let ms = $2.slice(0, 3)
|
||||
if ($2.length === 1) {
|
||||
ms = `${$2}00`
|
||||
@@ -11,7 +11,7 @@ function fixSrt(srt) {
|
||||
})
|
||||
}
|
||||
|
||||
export function srtToVtt(srtText) {
|
||||
export function srtToVtt(srtText: string): string {
|
||||
return 'WEBVTT \r\n\r\n'.concat(
|
||||
fixSrt(srtText)
|
||||
.replace(/\{\\([ibu])\}/g, '</$1>')
|
||||
@@ -24,7 +24,7 @@ export function srtToVtt(srtText) {
|
||||
)
|
||||
}
|
||||
|
||||
export function vttToBlob(vttText) {
|
||||
export function vttToBlob(vttText: string): string {
|
||||
return URL.createObjectURL(
|
||||
new Blob([vttText], {
|
||||
type: 'text/vtt',
|
||||
@@ -32,7 +32,7 @@ export function vttToBlob(vttText) {
|
||||
)
|
||||
}
|
||||
|
||||
export function assToVtt(ass) {
|
||||
export function assToVtt(ass: string): string {
|
||||
const reAss = new RegExp(
|
||||
'Dialogue:\\s\\d,'
|
||||
+ '(\\d+:\\d\\d:\\d\\d.\\d\\d),'
|
||||
@@ -76,10 +76,11 @@ export function assToVtt(ass) {
|
||||
const m = line.match(reAss)
|
||||
if (!m)
|
||||
return null
|
||||
const [, start = '', end = '', , , text = ''] = m
|
||||
return {
|
||||
start: fixTime(m[1].trim()),
|
||||
end: fixTime(m[2].trim()),
|
||||
text: m[5]
|
||||
start: fixTime(start.trim()),
|
||||
end: fixTime(end.trim()),
|
||||
text: text
|
||||
.replace(/\{[\s\S]*?\}/g, '')
|
||||
.replace(/(\\N)/g, '\n')
|
||||
.trim()
|
||||
@@ -1,32 +0,0 @@
|
||||
export function sleep(ms = 0) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
export function debounce(func, duration) {
|
||||
let timeout
|
||||
|
||||
return function (...args) {
|
||||
const effect = () => {
|
||||
timeout = null
|
||||
return func.apply(this, args)
|
||||
}
|
||||
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(effect, duration)
|
||||
}
|
||||
}
|
||||
|
||||
export function throttle(func, duration) {
|
||||
let shouldWait = false
|
||||
|
||||
return function (...args) {
|
||||
if (!shouldWait) {
|
||||
func.apply(this, args)
|
||||
shouldWait = true
|
||||
|
||||
setTimeout(() => {
|
||||
shouldWait = false
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
export function sleep(ms = 0): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
export function debounce<Receiver, Args extends unknown[]>(func: (this: Receiver, ...args: Args) => unknown, duration: number) {
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
return function (this: Receiver, ...args: Args): void {
|
||||
const effect = () => {
|
||||
timeout = undefined
|
||||
return func.apply(this, args)
|
||||
}
|
||||
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(effect, duration)
|
||||
}
|
||||
}
|
||||
|
||||
export function throttle<Receiver, Args extends unknown[]>(func: (this: Receiver, ...args: Args) => unknown, duration: number) {
|
||||
let shouldWait = false
|
||||
|
||||
return function (this: Receiver, ...args: Args): void {
|
||||
if (!shouldWait) {
|
||||
func.apply(this, args)
|
||||
shouldWait = true
|
||||
|
||||
setTimeout(() => {
|
||||
shouldWait = false
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user