@banou/media-player 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -10
- package/build/components/chrome.d.ts +4 -0
- package/build/components/control-bar.d.ts +5 -0
- package/build/components/overlay.d.ts +1 -0
- package/build/components/progress-bar.d.ts +1 -0
- package/build/components/settings.d.ts +2 -0
- package/build/components/sound.d.ts +4 -0
- package/build/components/tooltip-display.d.ts +20 -0
- package/build/components/volume-slider.d.ts +6 -0
- package/build/index.d.ts +23 -48
- package/build/index.js +2576 -2250
- package/build/main.d.ts +1 -1
- package/build/state-machines/data-source.d.ts +27 -0
- package/build/state-machines/index.d.ts +33185 -0
- package/build/state-machines/media-properties.d.ts +45 -0
- package/build/state-machines/media-source.d.ts +34 -0
- package/build/state-machines/media.d.ts +8344 -0
- package/build/state-machines/subtitles.d.ts +53 -0
- package/build/state-machines/thumbnails.d.ts +24 -0
- package/build/state-machines/utils.d.ts +26 -0
- package/build/utils/actor-utils.d.ts +2 -0
- package/build/utils/colors.d.ts +8 -0
- package/build/utils/context.d.ts +14 -0
- package/build/utils/fonts.d.ts +28 -0
- package/build/{utils.d.ts → utils/index.d.ts} +4 -12
- package/build/utils/languages.d.ts +260 -0
- package/build/{mp4box.d.ts → utils/mp4box.d.ts} +61 -61
- package/build/utils/time.d.ts +2 -0
- package/build/utils/use-local-storage.d.ts +3 -0
- package/build/{use-scrub.d.ts → utils/use-scrub.d.ts} +11 -11
- package/build/utils/volume-utils.d.ts +17 -0
- package/build/utils/window-height.d.ts +2 -0
- package/package.json +15 -12
- package/src/assets/picture-in-picture.svg +5 -0
- package/src/components/chrome.tsx +89 -0
- package/src/components/control-bar.tsx +330 -0
- package/src/components/overlay.tsx +28 -0
- package/src/components/progress-bar.tsx +252 -0
- package/src/components/settings.tsx +269 -0
- package/src/components/sound.tsx +101 -0
- package/src/components/tooltip-display.tsx +83 -0
- package/src/components/volume-slider.tsx +156 -0
- package/src/index.tsx +145 -435
- package/src/main.tsx +66 -39
- package/src/state-machines/data-source.ts +83 -0
- package/src/state-machines/index.ts +5 -0
- package/src/state-machines/media-properties.ts +78 -0
- package/src/state-machines/media-source.ts +129 -0
- package/src/state-machines/media.ts +245 -0
- package/src/state-machines/subtitles.ts +247 -0
- package/src/state-machines/thumbnails.ts +123 -0
- package/src/state-machines/utils.ts +94 -0
- package/src/utils/actor-utils.ts +19 -0
- package/src/utils/colors.ts +9 -0
- package/src/utils/context.ts +23 -0
- package/src/utils/fonts.ts +156 -0
- package/src/{utils.ts → utils/index.ts} +2 -26
- package/src/utils/time.ts +16 -0
- package/src/utils/use-local-storage.ts +30 -0
- package/src/utils/volume-utils.ts +39 -0
- package/src/utils/window-height.ts +19 -0
- package/tsconfig.json +4 -2
- package/build/chrome/bottom.d.ts +0 -22
- package/build/chrome/index.d.ts +0 -28
- package/build/chrome/overlay.d.ts +0 -9
- package/build/languages.d.ts +0 -260
- package/build/use-local-storage.d.ts +0 -6
- package/src/chrome/bottom.tsx +0 -697
- package/src/chrome/index.tsx +0 -203
- package/src/chrome/overlay.tsx +0 -104
- package/src/use-local-storage.ts +0 -32
- /package/src/{languages.ts → utils/languages.ts} +0 -0
- /package/src/{mp4box.ts → utils/mp4box.ts} +0 -0
- /package/src/{use-scrub.ts → utils/use-scrub.ts} +0 -0
package/src/chrome/index.tsx
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/// <reference types="@emotion/react/types/css-prop" />
|
|
2
|
-
import type { ClassAttributes, HTMLAttributes, MouseEventHandler, MutableRefObject, ReactNode } from 'react'
|
|
3
|
-
import type { Attachment, FKNVideoControl, Subtitle, TransmuxError } from '..'
|
|
4
|
-
|
|
5
|
-
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
6
|
-
import JASSUB from 'jassub'
|
|
7
|
-
import { css } from '@emotion/react'
|
|
8
|
-
import Overlay from './overlay'
|
|
9
|
-
import Bottom from './bottom'
|
|
10
|
-
|
|
11
|
-
const style = css`
|
|
12
|
-
--background-padding: 2rem;
|
|
13
|
-
display: grid;
|
|
14
|
-
grid-template-rows: 1fr;
|
|
15
|
-
overflow: hidden;
|
|
16
|
-
|
|
17
|
-
&.hide {
|
|
18
|
-
cursor: none;
|
|
19
|
-
|
|
20
|
-
.bottom {
|
|
21
|
-
opacity: 0;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.bottom {
|
|
26
|
-
&.hide {
|
|
27
|
-
opacity: 0 !important;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
`
|
|
31
|
-
|
|
32
|
-
export type ChromeOptions = {
|
|
33
|
-
publicPath: string
|
|
34
|
-
customOverlay?: ReactNode
|
|
35
|
-
isPlaying?: boolean
|
|
36
|
-
loading?: boolean
|
|
37
|
-
duration?: number
|
|
38
|
-
loadedTime?: [number, number]
|
|
39
|
-
currentTime?: number
|
|
40
|
-
pictureInPicture: () => void
|
|
41
|
-
fullscreen: () => void
|
|
42
|
-
play: () => void
|
|
43
|
-
seek: (time: number) => void
|
|
44
|
-
getVolume: () => number | undefined
|
|
45
|
-
setVolume: (volume: number) => void
|
|
46
|
-
attachments: Attachment[] | undefined
|
|
47
|
-
tracks: Subtitle[]
|
|
48
|
-
video: MutableRefObject<HTMLVideoElement | undefined>
|
|
49
|
-
videoReactive: HTMLVideoElement | undefined,
|
|
50
|
-
errors: TransmuxError[]
|
|
51
|
-
customControls?: FKNVideoControl[]
|
|
52
|
-
libassWorkerUrl: string
|
|
53
|
-
wasmUrl: string
|
|
54
|
-
needsInitialInteraction?: boolean
|
|
55
|
-
} & HTMLAttributes<HTMLDivElement>
|
|
56
|
-
|
|
57
|
-
export default ({
|
|
58
|
-
customOverlay,
|
|
59
|
-
publicPath,
|
|
60
|
-
isPlaying,
|
|
61
|
-
loading,
|
|
62
|
-
duration,
|
|
63
|
-
loadedTime,
|
|
64
|
-
currentTime,
|
|
65
|
-
pictureInPicture,
|
|
66
|
-
fullscreen,
|
|
67
|
-
play,
|
|
68
|
-
seek,
|
|
69
|
-
getVolume,
|
|
70
|
-
setVolume,
|
|
71
|
-
attachments,
|
|
72
|
-
tracks,
|
|
73
|
-
video,
|
|
74
|
-
videoReactive,
|
|
75
|
-
errors,
|
|
76
|
-
customControls,
|
|
77
|
-
libassWorkerUrl,
|
|
78
|
-
wasmUrl,
|
|
79
|
-
needsInitialInteraction,
|
|
80
|
-
...rest
|
|
81
|
-
}: ChromeOptions) => {
|
|
82
|
-
const [canvasElement, setCanvasElement] = useState<HTMLCanvasElement | undefined>()
|
|
83
|
-
const [canvasInitialized, setCanvasInitialized] = useState(false)
|
|
84
|
-
const [isFullscreen, setFullscreen] = useState(false)
|
|
85
|
-
const [hidden, setHidden] = useState(false)
|
|
86
|
-
const autoHide = useRef<number>()
|
|
87
|
-
const [isSubtitleMenuHidden, setIsSubtitleMenuHidden] = useState(true)
|
|
88
|
-
const [jassub, setJassub] = useState<JASSUB>()
|
|
89
|
-
const [currentSubtitleTrack, setCurrentSubtitleTrack] = useState<number | undefined>()
|
|
90
|
-
const subtitleTrack = useMemo(
|
|
91
|
-
() => currentSubtitleTrack !== undefined ? tracks[currentSubtitleTrack] : undefined,
|
|
92
|
-
[currentSubtitleTrack, currentSubtitleTrack !== undefined && tracks[currentSubtitleTrack]?.data]
|
|
93
|
-
)
|
|
94
|
-
const [isErrorMenuHidden, setIsErrorMenuHidden] = useState(true)
|
|
95
|
-
|
|
96
|
-
const mouseMove: MouseEventHandler<HTMLDivElement> = (ev) => {
|
|
97
|
-
setHidden(false)
|
|
98
|
-
if (autoHide.current) clearInterval(autoHide.current)
|
|
99
|
-
const timeout = setTimeout(() => {
|
|
100
|
-
setHidden(true)
|
|
101
|
-
}, 3_000) as unknown as number
|
|
102
|
-
autoHide.current = timeout
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// hide automatically after 3 seconds, in case the user doesn't move the mouse on init
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
setTimeout(() => {
|
|
108
|
-
setHidden(true)
|
|
109
|
-
}, 3_000)
|
|
110
|
-
}, [])
|
|
111
|
-
|
|
112
|
-
const mouseOut: React.DOMAttributes<HTMLDivElement>['onMouseOut'] = (ev) => {
|
|
113
|
-
const root = canvasElement?.parentElement?.parentElement
|
|
114
|
-
if (!root?.contains(ev?.relatedTarget as Element)) {
|
|
115
|
-
setHidden(true)
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
if (ev.currentTarget.parentElement !== ev.relatedTarget && ev.relatedTarget !== null) return
|
|
119
|
-
setHidden(true)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const togglePlay = () => {
|
|
123
|
-
if (!isSubtitleMenuHidden) return
|
|
124
|
-
play()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const toggleFullscreen = () => {
|
|
128
|
-
if (!canvasElement || !jassub) return
|
|
129
|
-
setFullscreen(value => !value)
|
|
130
|
-
fullscreen()
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
useEffect(() => {
|
|
134
|
-
if (!video.current || !canvasElement || jassub || !subtitleTrack?.data || !attachments) return
|
|
135
|
-
const fonts = attachments.map(({ filename, data }) => [
|
|
136
|
-
filename.toLowerCase().replaceAll('-', ' ').split('.').at(0),
|
|
137
|
-
data
|
|
138
|
-
])
|
|
139
|
-
const jassubInstance = new JASSUB({
|
|
140
|
-
video: video.current,
|
|
141
|
-
canvas: canvasElement,
|
|
142
|
-
subContent: subtitleTrack.data,
|
|
143
|
-
fonts: fonts.filter(Boolean).map(([,filename]) => filename as string),
|
|
144
|
-
availableFonts: { ...Object.fromEntries(fonts), 'liberation sans': `${publicPath}default.woff2` },
|
|
145
|
-
workerUrl: libassWorkerUrl, // Link to WebAssembly-based file "libassjs-worker.js",
|
|
146
|
-
modernWasmUrl: wasmUrl
|
|
147
|
-
})
|
|
148
|
-
setJassub(jassubInstance)
|
|
149
|
-
}, [canvasElement, attachments, subtitleTrack?.data])
|
|
150
|
-
|
|
151
|
-
useEffect(() => {
|
|
152
|
-
if (!tracks.length) return
|
|
153
|
-
setCurrentSubtitleTrack(0)
|
|
154
|
-
}, [tracks.length])
|
|
155
|
-
|
|
156
|
-
useEffect(() => {
|
|
157
|
-
if (!jassub) return
|
|
158
|
-
if (!subtitleTrack) {
|
|
159
|
-
jassub.freeTrack()
|
|
160
|
-
return
|
|
161
|
-
}
|
|
162
|
-
jassub.setTrack(subtitleTrack.data)
|
|
163
|
-
const parent = canvasElement?.parentElement
|
|
164
|
-
if (!parent || canvasInitialized) return
|
|
165
|
-
setCanvasInitialized(true)
|
|
166
|
-
}, [jassub, subtitleTrack, canvasInitialized])
|
|
167
|
-
|
|
168
|
-
const setCanvasRef: ClassAttributes<HTMLCanvasElement>['ref'] = (canvasElem) => {
|
|
169
|
-
if (!canvasElem) return
|
|
170
|
-
setCanvasElement(canvasElem)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return (
|
|
174
|
-
<div {...rest} css={style} onMouseMove={mouseMove} onMouseOut={mouseOut} className={`chrome ${rest.className ?? ''} ${hidden ? 'hide' : ''}`}>
|
|
175
|
-
<Overlay needsInitialInteraction={needsInitialInteraction} loading={loading} togglePlay={togglePlay} setCanvasRef={setCanvasRef}/>
|
|
176
|
-
{customOverlay}
|
|
177
|
-
<Bottom
|
|
178
|
-
className={`bottom ${needsInitialInteraction ? 'hide' : ''}`}
|
|
179
|
-
toggleFullscreen={toggleFullscreen}
|
|
180
|
-
togglePlay={togglePlay}
|
|
181
|
-
isFullscreen={isFullscreen}
|
|
182
|
-
pictureInPicture={pictureInPicture}
|
|
183
|
-
video={video}
|
|
184
|
-
videoReactive={videoReactive}
|
|
185
|
-
seek={seek}
|
|
186
|
-
setCurrentSubtitleTrack={setCurrentSubtitleTrack}
|
|
187
|
-
isSubtitleMenuHidden={isSubtitleMenuHidden}
|
|
188
|
-
setIsSubtitleMenuHidden={setIsSubtitleMenuHidden}
|
|
189
|
-
isErrorMenuHidden={isErrorMenuHidden}
|
|
190
|
-
setIsErrorMenuHidden={setIsErrorMenuHidden}
|
|
191
|
-
setVolume={setVolume}
|
|
192
|
-
subtitleTrack={subtitleTrack}
|
|
193
|
-
tracks={tracks}
|
|
194
|
-
currentTime={currentTime}
|
|
195
|
-
duration={duration}
|
|
196
|
-
isPlaying={isPlaying}
|
|
197
|
-
loadedTime={loadedTime}
|
|
198
|
-
errors={errors}
|
|
199
|
-
customControls={customControls}
|
|
200
|
-
/>
|
|
201
|
-
</div>
|
|
202
|
-
)
|
|
203
|
-
}
|
package/src/chrome/overlay.tsx
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/// <reference types="@emotion/react/types/css-prop" />
|
|
2
|
-
import type { ClassAttributes } from 'react'
|
|
3
|
-
|
|
4
|
-
import { css } from '@emotion/react'
|
|
5
|
-
|
|
6
|
-
const style = css`
|
|
7
|
-
position: relative;
|
|
8
|
-
display: grid;
|
|
9
|
-
grid-column: 1;
|
|
10
|
-
grid-row: 1;
|
|
11
|
-
display: grid;
|
|
12
|
-
height: 100%;
|
|
13
|
-
width: 100%;
|
|
14
|
-
justify-items: center;
|
|
15
|
-
align-items: center;
|
|
16
|
-
|
|
17
|
-
canvas {
|
|
18
|
-
pointer-events: none;
|
|
19
|
-
position: absolute;
|
|
20
|
-
inset: 0;
|
|
21
|
-
grid-column: 1;
|
|
22
|
-
grid-row: 1;
|
|
23
|
-
height: 100%;
|
|
24
|
-
width: 100%;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.loading {
|
|
28
|
-
grid-column: 1;
|
|
29
|
-
grid-row: 1;
|
|
30
|
-
}
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
export type OverlayOptions = {
|
|
34
|
-
loading?: boolean
|
|
35
|
-
togglePlay: (ev: any) => void
|
|
36
|
-
setCanvasRef: ClassAttributes<HTMLCanvasElement>['ref'],
|
|
37
|
-
needsInitialInteraction?: boolean
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export default ({ loading, needsInitialInteraction, togglePlay, setCanvasRef }: OverlayOptions) => {
|
|
41
|
-
return (
|
|
42
|
-
<div css={style} onClick={togglePlay}>
|
|
43
|
-
<canvas ref={setCanvasRef}/>
|
|
44
|
-
{
|
|
45
|
-
needsInitialInteraction
|
|
46
|
-
? (
|
|
47
|
-
<svg
|
|
48
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
49
|
-
width="60"
|
|
50
|
-
height="60"
|
|
51
|
-
viewBox="0 0 60 60"
|
|
52
|
-
fill="black"
|
|
53
|
-
stroke="currentColor"
|
|
54
|
-
strokeWidth="3"
|
|
55
|
-
strokeLinecap="round"
|
|
56
|
-
strokeLinejoin="round"
|
|
57
|
-
className="feather feather-play"
|
|
58
|
-
>
|
|
59
|
-
<polygon points="12 7 45 28 12 50 12 7"></polygon>
|
|
60
|
-
</svg>
|
|
61
|
-
)
|
|
62
|
-
: (
|
|
63
|
-
loading
|
|
64
|
-
? (
|
|
65
|
-
<svg
|
|
66
|
-
className="loading"
|
|
67
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
68
|
-
style={{
|
|
69
|
-
display: 'block',
|
|
70
|
-
shapeRendering: 'auto',
|
|
71
|
-
animationPlayState: 'running',
|
|
72
|
-
animationDelay: '0s',
|
|
73
|
-
}}
|
|
74
|
-
width="100" height="100"
|
|
75
|
-
viewBox="0 0 100 100"
|
|
76
|
-
preserveAspectRatio="xMidYMid"
|
|
77
|
-
>
|
|
78
|
-
<circle
|
|
79
|
-
cx="50"
|
|
80
|
-
cy="50"
|
|
81
|
-
fill="none"
|
|
82
|
-
stroke="currentColor"
|
|
83
|
-
strokeWidth="9"
|
|
84
|
-
r="35"
|
|
85
|
-
strokeDasharray="164.93361431346415 56.97787143782138"
|
|
86
|
-
style={{ animationPlayState: 'running', animationDelay: '0s' }}>
|
|
87
|
-
<animateTransform
|
|
88
|
-
attributeName="transform"
|
|
89
|
-
type="rotate"
|
|
90
|
-
repeatCount="indefinite"
|
|
91
|
-
dur="1s"
|
|
92
|
-
values="0 50 50;360 50 50"
|
|
93
|
-
keyTimes="0;1"
|
|
94
|
-
style={{ animationPlayState: 'running', animationDelay: '0s' }}
|
|
95
|
-
/>
|
|
96
|
-
</circle>
|
|
97
|
-
</svg>
|
|
98
|
-
)
|
|
99
|
-
: null
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
</div>
|
|
103
|
-
)
|
|
104
|
-
}
|
package/src/use-local-storage.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
|
|
3
|
-
const useNamespacedLocalStorage = <T extends { [key: PropertyKey]: string | boolean | number | undefined | null | object | any[] }>(namespace: string) => {
|
|
4
|
-
const [state, setState] = useState<T>(() => {
|
|
5
|
-
const storedValue = localStorage.getItem(namespace)
|
|
6
|
-
return (
|
|
7
|
-
storedValue
|
|
8
|
-
? JSON.parse(storedValue)
|
|
9
|
-
: {}
|
|
10
|
-
)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
localStorage.setItem(namespace, JSON.stringify(state));
|
|
15
|
-
}, [namespace, state])
|
|
16
|
-
|
|
17
|
-
return <T2 extends keyof T, T3 extends T[T2]>(key: T2, value: T[T2]) => {
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
setState(state => ({ ...state, [key]: value }))
|
|
20
|
-
}, [])
|
|
21
|
-
return [
|
|
22
|
-
state[key],
|
|
23
|
-
(newValue: T3 | ((oldValue: T3) => T3)) =>
|
|
24
|
-
typeof newValue === 'function'
|
|
25
|
-
// @ts-expect-error
|
|
26
|
-
? setState(state => ({ ...state, [key]: newValue(state[key]) }))
|
|
27
|
-
: setState(state => ({ ...state, [key]: newValue }))
|
|
28
|
-
] as const
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export default useNamespacedLocalStorage
|
|
File without changes
|
|
File without changes
|
|
File without changes
|