@banou/media-player 0.6.0 → 0.6.2
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 +6 -6
- package/package.json +51 -51
- package/src/assets/picture-in-picture.svg +5 -5
- package/src/components/chrome.tsx +95 -95
- package/src/components/control-bar.tsx +333 -333
- package/src/components/overlay.tsx +91 -91
- package/src/components/playback-slider.tsx +174 -174
- package/src/components/progress-bar.tsx +251 -251
- package/src/components/settings.tsx +321 -321
- package/src/components/sound.tsx +100 -100
- package/src/components/tooltip-display.tsx +83 -83
- package/src/components/volume-slider.tsx +156 -156
- package/src/index.tsx +195 -195
- package/src/main.tsx +169 -169
- package/src/state-machines/data-source.ts +84 -84
- package/src/state-machines/index.ts +5 -5
- package/src/state-machines/media-properties.ts +82 -82
- package/src/state-machines/media-source.ts +129 -129
- package/src/state-machines/media.ts +255 -255
- package/src/state-machines/subtitles.ts +285 -285
- package/src/state-machines/thumbnails.ts +123 -123
- package/src/state-machines/utils.ts +94 -94
- package/src/utils/actor-utils.ts +19 -19
- package/src/utils/colors.ts +8 -8
- package/src/utils/context.ts +23 -23
- package/src/utils/fonts.ts +159 -159
- package/src/utils/index.ts +229 -229
- package/src/utils/languages.ts +262 -262
- package/src/utils/mp4box.ts +74 -74
- package/src/utils/time.ts +15 -15
- package/src/utils/use-local-storage.ts +30 -30
- package/src/utils/use-scrub.ts +40 -40
- package/src/utils/volume-utils.ts +39 -39
- package/src/utils/window-height.ts +19 -19
- package/src/vite-env.d.ts +1 -1
- package/tsconfig.json +28 -28
- package/tsconfig.node.json +9 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
## Media Player
|
|
2
|
-
|
|
3
|
-
A player that somehow manages to playback MKV files
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Todo: add support for multi audio tracks
|
|
1
|
+
## Media Player
|
|
2
|
+
|
|
3
|
+
A player that somehow manages to playback MKV files
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Todo: add support for multi audio tracks
|
package/package.json
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@banou/media-player",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "build/index.js",
|
|
7
|
-
"files": [
|
|
8
|
-
"build",
|
|
9
|
-
"tsconfig.json",
|
|
10
|
-
"tsconfig.node.json",
|
|
11
|
-
"src"
|
|
12
|
-
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"dev": "vite --port 4560",
|
|
15
|
-
"build-dev": "vite build --watch",
|
|
16
|
-
"build": "vite build && npm run types",
|
|
17
|
-
"build-for-dev": "vite build && npm run copy-dependencies && npm run types",
|
|
18
|
-
"copy-dependencies": "npm run copy-libass && npm run copy-worker && npm run copy-worker-wasm",
|
|
19
|
-
"copy-worker": "shx cp node_modules/libav-wasm/build/worker.js build/libav.js",
|
|
20
|
-
"copy-worker-wasm": "shx cp node_modules/libav-wasm/build/libav.wasm build/libav.wasm",
|
|
21
|
-
"copy-libass": "copyfiles -u 3 ./node_modules/jassub/dist/* build",
|
|
22
|
-
"types": "tsc"
|
|
23
|
-
},
|
|
24
|
-
"author": "Banou26",
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"@types/node": "^18.11.18",
|
|
27
|
-
"@types/react": "^18.0.27",
|
|
28
|
-
"@types/react-dom": "^18.0.10",
|
|
29
|
-
"@vitejs/plugin-react": "^4.3.4",
|
|
30
|
-
"concurrently": "^7.6.0",
|
|
31
|
-
"copyfiles": "^2.4.1",
|
|
32
|
-
"mime": "^3.0.0",
|
|
33
|
-
"shx": "^0.3.4",
|
|
34
|
-
"typescript": "^5.8.2",
|
|
35
|
-
"vite": "^6.2.1"
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"@emotion/react": "^11.14.0",
|
|
39
|
-
"@xstate/react": "^5.0.1",
|
|
40
|
-
"ass-compiler": "^0.1.15",
|
|
41
|
-
"jassub": "^1.7.18",
|
|
42
|
-
"libav-wasm": "^0.6.
|
|
43
|
-
"osra": "^0.1.2",
|
|
44
|
-
"p-queue": "^7.3.4",
|
|
45
|
-
"react": "^19.0.0",
|
|
46
|
-
"react-dom": "^19.0.0",
|
|
47
|
-
"react-feather": "^2.0.10",
|
|
48
|
-
"react-tooltip": "^5.28.0",
|
|
49
|
-
"xstate": "^5.19.1"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@banou/media-player",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"build",
|
|
9
|
+
"tsconfig.json",
|
|
10
|
+
"tsconfig.node.json",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "vite --port 4560",
|
|
15
|
+
"build-dev": "vite build --watch",
|
|
16
|
+
"build": "vite build && npm run types",
|
|
17
|
+
"build-for-dev": "vite build && npm run copy-dependencies && npm run types",
|
|
18
|
+
"copy-dependencies": "npm run copy-libass && npm run copy-worker && npm run copy-worker-wasm",
|
|
19
|
+
"copy-worker": "shx cp node_modules/libav-wasm/build/worker.js build/libav.js",
|
|
20
|
+
"copy-worker-wasm": "shx cp node_modules/libav-wasm/build/libav.wasm build/libav.wasm",
|
|
21
|
+
"copy-libass": "copyfiles -u 3 ./node_modules/jassub/dist/* build",
|
|
22
|
+
"types": "tsc"
|
|
23
|
+
},
|
|
24
|
+
"author": "Banou26",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^18.11.18",
|
|
27
|
+
"@types/react": "^18.0.27",
|
|
28
|
+
"@types/react-dom": "^18.0.10",
|
|
29
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
30
|
+
"concurrently": "^7.6.0",
|
|
31
|
+
"copyfiles": "^2.4.1",
|
|
32
|
+
"mime": "^3.0.0",
|
|
33
|
+
"shx": "^0.3.4",
|
|
34
|
+
"typescript": "^5.8.2",
|
|
35
|
+
"vite": "^6.2.1"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@emotion/react": "^11.14.0",
|
|
39
|
+
"@xstate/react": "^5.0.1",
|
|
40
|
+
"ass-compiler": "^0.1.15",
|
|
41
|
+
"jassub": "^1.7.18",
|
|
42
|
+
"libav-wasm": "^0.6.2",
|
|
43
|
+
"osra": "^0.1.2",
|
|
44
|
+
"p-queue": "^7.3.4",
|
|
45
|
+
"react": "^19.0.0",
|
|
46
|
+
"react-dom": "^19.0.0",
|
|
47
|
+
"react-feather": "^2.0.10",
|
|
48
|
+
"react-tooltip": "^5.28.0",
|
|
49
|
+
"xstate": "^5.19.1"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-picture-in-picture">
|
|
2
|
-
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
3
|
-
<path d="M11 19h-6a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v4" />
|
|
4
|
-
<path d="M14 14m0 1a1 1 0 0 1 1 -1h5a1 1 0 0 1 1 1v3a1 1 0 0 1 -1 1h-5a1 1 0 0 1 -1 -1z" />
|
|
5
|
-
</svg>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-picture-in-picture">
|
|
2
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
3
|
+
<path d="M11 19h-6a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v4" />
|
|
4
|
+
<path d="M14 14m0 1a1 1 0 0 1 1 -1h5a1 1 0 0 1 1 1v3a1 1 0 0 1 -1 1h-5a1 1 0 0 1 -1 -1z" />
|
|
5
|
+
</svg>
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
/// <reference types="@emotion/react/types/css-prop" />
|
|
2
|
-
import { MouseEventHandler, ReactNode, useContext, useRef, type HTMLAttributes } from 'react'
|
|
3
|
-
|
|
4
|
-
import { css } from '@emotion/react'
|
|
5
|
-
|
|
6
|
-
import { MediaMachineContext } from '../state-machines'
|
|
7
|
-
import { MediaPlayerContext } from '../utils/context'
|
|
8
|
-
import { togglePlay } from '../utils/actor-utils'
|
|
9
|
-
import { Overlay } from './overlay'
|
|
10
|
-
import ControlBar from './control-bar'
|
|
11
|
-
|
|
12
|
-
const style = css`
|
|
13
|
-
position: relative;
|
|
14
|
-
background-color: black;
|
|
15
|
-
display: flex;
|
|
16
|
-
justify-content: center;
|
|
17
|
-
align-items: center;
|
|
18
|
-
height: 100%;
|
|
19
|
-
width: 100%;
|
|
20
|
-
|
|
21
|
-
& > div:not(:last-of-type) {
|
|
22
|
-
position: absolute;
|
|
23
|
-
z-index: 2;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
canvas {
|
|
27
|
-
height: 100%;
|
|
28
|
-
width: 100%;
|
|
29
|
-
pointer-events: none;
|
|
30
|
-
position: absolute;
|
|
31
|
-
z-index: 1;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.video, video {
|
|
35
|
-
height: 100%;
|
|
36
|
-
width: 100%;
|
|
37
|
-
background-color: black;
|
|
38
|
-
object-fit: contain;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
&.hide {
|
|
42
|
-
cursor: none;
|
|
43
|
-
}
|
|
44
|
-
`
|
|
45
|
-
|
|
46
|
-
export type ChromeOptions = {
|
|
47
|
-
mediaInformation?: ReactNode
|
|
48
|
-
loadingInformation?: ReactNode
|
|
49
|
-
} & HTMLAttributes<HTMLDivElement>
|
|
50
|
-
|
|
51
|
-
export const Chrome = ({ children, mediaInformation, loadingInformation }: ChromeOptions) => {
|
|
52
|
-
const mediaActor = MediaMachineContext.useActorRef()
|
|
53
|
-
const mediaPlayerContext = useContext(MediaPlayerContext)
|
|
54
|
-
const isPaused = MediaMachineContext.useSelector((state) => state.context.media.paused)
|
|
55
|
-
const currentTime = MediaMachineContext.useSelector((state) => state.context.media.currentTime)
|
|
56
|
-
const duration = MediaMachineContext.useSelector((state) => state.context.media.duration)
|
|
57
|
-
|
|
58
|
-
const autoHide = useRef<number>()
|
|
59
|
-
const containerRef = useRef<HTMLDivElement>(null)
|
|
60
|
-
|
|
61
|
-
const mouseMove: MouseEventHandler<HTMLDivElement> = (ev) => {
|
|
62
|
-
mediaPlayerContext.update(({ ...mediaPlayerContext, hideUI: false }))
|
|
63
|
-
if (autoHide.current) clearInterval(autoHide.current)
|
|
64
|
-
const timeout = setTimeout(() => {
|
|
65
|
-
mediaPlayerContext.update(({ ...mediaPlayerContext, hideUI: true }))
|
|
66
|
-
}, 3_000) as unknown as number
|
|
67
|
-
autoHide.current = timeout
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const mouseOut: React.DOMAttributes<HTMLDivElement>['onMouseOut'] = (ev) => {
|
|
71
|
-
if (ev.currentTarget.parentElement !== ev.relatedTarget && ev.relatedTarget !== null) return
|
|
72
|
-
mediaPlayerContext.update(({ ...mediaPlayerContext, hideUI: true }))
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<div
|
|
77
|
-
css={style}
|
|
78
|
-
ref={containerRef}
|
|
79
|
-
onMouseMove={mouseMove}
|
|
80
|
-
onMouseOut={mouseOut}
|
|
81
|
-
className={mediaPlayerContext.hideUI ? 'hide' : ''}
|
|
82
|
-
>
|
|
83
|
-
<Overlay loadingInformation={loadingInformation}/>
|
|
84
|
-
<ControlBar mediaInformation={mediaInformation} containerRef={containerRef}/>
|
|
85
|
-
<div
|
|
86
|
-
className='video'
|
|
87
|
-
onClick={() => togglePlay(mediaActor, isPaused, duration, currentTime)}
|
|
88
|
-
>
|
|
89
|
-
{children}
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export default Chrome
|
|
1
|
+
/// <reference types="@emotion/react/types/css-prop" />
|
|
2
|
+
import { MouseEventHandler, ReactNode, useContext, useRef, type HTMLAttributes } from 'react'
|
|
3
|
+
|
|
4
|
+
import { css } from '@emotion/react'
|
|
5
|
+
|
|
6
|
+
import { MediaMachineContext } from '../state-machines'
|
|
7
|
+
import { MediaPlayerContext } from '../utils/context'
|
|
8
|
+
import { togglePlay } from '../utils/actor-utils'
|
|
9
|
+
import { Overlay } from './overlay'
|
|
10
|
+
import ControlBar from './control-bar'
|
|
11
|
+
|
|
12
|
+
const style = css`
|
|
13
|
+
position: relative;
|
|
14
|
+
background-color: black;
|
|
15
|
+
display: flex;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
align-items: center;
|
|
18
|
+
height: 100%;
|
|
19
|
+
width: 100%;
|
|
20
|
+
|
|
21
|
+
& > div:not(:last-of-type) {
|
|
22
|
+
position: absolute;
|
|
23
|
+
z-index: 2;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
canvas {
|
|
27
|
+
height: 100%;
|
|
28
|
+
width: 100%;
|
|
29
|
+
pointer-events: none;
|
|
30
|
+
position: absolute;
|
|
31
|
+
z-index: 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.video, video {
|
|
35
|
+
height: 100%;
|
|
36
|
+
width: 100%;
|
|
37
|
+
background-color: black;
|
|
38
|
+
object-fit: contain;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&.hide {
|
|
42
|
+
cursor: none;
|
|
43
|
+
}
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
export type ChromeOptions = {
|
|
47
|
+
mediaInformation?: ReactNode
|
|
48
|
+
loadingInformation?: ReactNode
|
|
49
|
+
} & HTMLAttributes<HTMLDivElement>
|
|
50
|
+
|
|
51
|
+
export const Chrome = ({ children, mediaInformation, loadingInformation }: ChromeOptions) => {
|
|
52
|
+
const mediaActor = MediaMachineContext.useActorRef()
|
|
53
|
+
const mediaPlayerContext = useContext(MediaPlayerContext)
|
|
54
|
+
const isPaused = MediaMachineContext.useSelector((state) => state.context.media.paused)
|
|
55
|
+
const currentTime = MediaMachineContext.useSelector((state) => state.context.media.currentTime)
|
|
56
|
+
const duration = MediaMachineContext.useSelector((state) => state.context.media.duration)
|
|
57
|
+
|
|
58
|
+
const autoHide = useRef<number>()
|
|
59
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
60
|
+
|
|
61
|
+
const mouseMove: MouseEventHandler<HTMLDivElement> = (ev) => {
|
|
62
|
+
mediaPlayerContext.update(({ ...mediaPlayerContext, hideUI: false }))
|
|
63
|
+
if (autoHide.current) clearInterval(autoHide.current)
|
|
64
|
+
const timeout = setTimeout(() => {
|
|
65
|
+
mediaPlayerContext.update(({ ...mediaPlayerContext, hideUI: true }))
|
|
66
|
+
}, 3_000) as unknown as number
|
|
67
|
+
autoHide.current = timeout
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const mouseOut: React.DOMAttributes<HTMLDivElement>['onMouseOut'] = (ev) => {
|
|
71
|
+
if (ev.currentTarget.parentElement !== ev.relatedTarget && ev.relatedTarget !== null) return
|
|
72
|
+
mediaPlayerContext.update(({ ...mediaPlayerContext, hideUI: true }))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
css={style}
|
|
78
|
+
ref={containerRef}
|
|
79
|
+
onMouseMove={mouseMove}
|
|
80
|
+
onMouseOut={mouseOut}
|
|
81
|
+
className={mediaPlayerContext.hideUI ? 'hide' : ''}
|
|
82
|
+
>
|
|
83
|
+
<Overlay loadingInformation={loadingInformation}/>
|
|
84
|
+
<ControlBar mediaInformation={mediaInformation} containerRef={containerRef}/>
|
|
85
|
+
<div
|
|
86
|
+
className='video'
|
|
87
|
+
onClick={() => togglePlay(mediaActor, isPaused, duration, currentTime)}
|
|
88
|
+
>
|
|
89
|
+
{children}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default Chrome
|