@banou/media-player 0.6.1 → 0.7.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.
Files changed (119) hide show
  1. package/README.md +148 -3
  2. package/dist/engine/index.d.ts +10 -0
  3. package/dist/engine/index.js +2 -0
  4. package/dist/engine/picture-in-picture.d.ts +27 -0
  5. package/dist/engine/playback.d.ts +45 -0
  6. package/dist/engine/source-buffer.d.ts +12 -0
  7. package/dist/engine/subtitles.d.ts +36 -0
  8. package/dist/engine/thumbnails.d.ts +22 -0
  9. package/dist/engine-Dmc7JSd9.js +470 -0
  10. package/dist/index.d.ts +12 -0
  11. package/dist/index.js +1566 -0
  12. package/dist/react/components/chrome.d.ts +9 -0
  13. package/dist/react/components/control-bar.d.ts +2 -0
  14. package/dist/react/components/overlay.d.ts +4 -0
  15. package/dist/react/components/playback-slider.d.ts +2 -0
  16. package/dist/react/components/progress-bar.d.ts +2 -0
  17. package/dist/react/components/settings.d.ts +2 -0
  18. package/dist/react/components/sound.d.ts +7 -0
  19. package/{build → dist/react}/components/tooltip-display.d.ts +8 -8
  20. package/dist/react/components/volume-slider.d.ts +6 -0
  21. package/dist/react/hooks/use-drag-value.d.ts +23 -0
  22. package/dist/react/hooks/use-picture-in-picture.d.ts +2 -0
  23. package/dist/react/hooks/use-playback.d.ts +6 -0
  24. package/dist/react/hooks/use-thumbnails.d.ts +11 -0
  25. package/dist/react/player.d.ts +25 -0
  26. package/dist/react/source-feature.d.ts +84 -0
  27. package/dist/react/video-player.d.ts +43 -0
  28. package/dist/utils/source.d.ts +30 -0
  29. package/dist/utils/track-label.d.ts +19 -0
  30. package/dist/utils/volume-utils.d.ts +6 -0
  31. package/package.json +49 -37
  32. package/src/lib/engine/index.ts +14 -0
  33. package/src/lib/engine/picture-in-picture.ts +250 -0
  34. package/src/lib/engine/playback.ts +352 -0
  35. package/src/lib/engine/source-buffer.ts +61 -0
  36. package/src/lib/engine/subtitles.ts +210 -0
  37. package/src/lib/engine/thumbnails.ts +137 -0
  38. package/src/lib/globals.d.ts +8 -0
  39. package/src/lib/index.tsx +36 -0
  40. package/src/lib/react/components/chrome.tsx +126 -0
  41. package/src/{components → lib/react/components}/control-bar.tsx +74 -96
  42. package/src/lib/react/components/overlay.tsx +121 -0
  43. package/src/{components → lib/react/components}/playback-slider.tsx +30 -52
  44. package/src/{components → lib/react/components}/progress-bar.tsx +128 -41
  45. package/src/lib/react/components/settings.tsx +391 -0
  46. package/src/lib/react/components/sound.tsx +133 -0
  47. package/src/{components → lib/react/components}/tooltip-display.tsx +11 -8
  48. package/src/{components → lib/react/components}/volume-slider.tsx +32 -46
  49. package/src/lib/react/hooks/use-drag-value.ts +73 -0
  50. package/src/lib/react/hooks/use-picture-in-picture.ts +36 -0
  51. package/src/lib/react/hooks/use-playback.ts +134 -0
  52. package/src/lib/react/hooks/use-thumbnails.ts +77 -0
  53. package/src/lib/react/player.ts +20 -0
  54. package/src/lib/react/source-feature.ts +90 -0
  55. package/src/lib/react/video-player.tsx +119 -0
  56. package/src/lib/utils/source.ts +60 -0
  57. package/src/lib/utils/track-label.ts +36 -0
  58. package/src/lib/utils/volume-utils.ts +13 -0
  59. package/build/components/chrome.d.ts +0 -7
  60. package/build/components/control-bar.d.ts +0 -6
  61. package/build/components/overlay.d.ts +0 -4
  62. package/build/components/playback-slider.d.ts +0 -2
  63. package/build/components/progress-bar.d.ts +0 -1
  64. package/build/components/settings.d.ts +0 -2
  65. package/build/components/sound.d.ts +0 -4
  66. package/build/components/volume-slider.d.ts +0 -6
  67. package/build/index.d.ts +0 -26
  68. package/build/index.js +0 -3416
  69. package/build/main.d.ts +0 -1
  70. package/build/state-machines/data-source.d.ts +0 -27
  71. package/build/state-machines/index.d.ts +0 -34038
  72. package/build/state-machines/media-properties.d.ts +0 -45
  73. package/build/state-machines/media-source.d.ts +0 -34
  74. package/build/state-machines/media.d.ts +0 -8558
  75. package/build/state-machines/subtitles.d.ts +0 -56
  76. package/build/state-machines/thumbnails.d.ts +0 -24
  77. package/build/state-machines/utils.d.ts +0 -26
  78. package/build/utils/actor-utils.d.ts +0 -2
  79. package/build/utils/context.d.ts +0 -14
  80. package/build/utils/index.d.ts +0 -4
  81. package/build/utils/languages.d.ts +0 -260
  82. package/build/utils/mp4box.d.ts +0 -61
  83. package/build/utils/use-local-storage.d.ts +0 -3
  84. package/build/utils/use-scrub.d.ts +0 -11
  85. package/build/utils/volume-utils.d.ts +0 -17
  86. package/build/utils/window-height.d.ts +0 -2
  87. package/src/components/chrome.tsx +0 -95
  88. package/src/components/overlay.tsx +0 -91
  89. package/src/components/settings.tsx +0 -322
  90. package/src/components/sound.tsx +0 -101
  91. package/src/index.tsx +0 -195
  92. package/src/main.tsx +0 -169
  93. package/src/state-machines/data-source.ts +0 -84
  94. package/src/state-machines/index.ts +0 -5
  95. package/src/state-machines/media-properties.ts +0 -82
  96. package/src/state-machines/media-source.ts +0 -129
  97. package/src/state-machines/media.ts +0 -255
  98. package/src/state-machines/subtitles.ts +0 -285
  99. package/src/state-machines/thumbnails.ts +0 -123
  100. package/src/state-machines/utils.ts +0 -94
  101. package/src/utils/actor-utils.ts +0 -19
  102. package/src/utils/context.ts +0 -23
  103. package/src/utils/index.ts +0 -229
  104. package/src/utils/languages.ts +0 -262
  105. package/src/utils/mp4box.ts +0 -74
  106. package/src/utils/use-local-storage.ts +0 -30
  107. package/src/utils/use-scrub.ts +0 -40
  108. package/src/utils/volume-utils.ts +0 -39
  109. package/src/utils/window-height.ts +0 -19
  110. package/src/vite-env.d.ts +0 -1
  111. package/tsconfig.json +0 -28
  112. package/tsconfig.node.json +0 -9
  113. /package/{build → dist}/utils/colors.d.ts +0 -0
  114. /package/{build → dist}/utils/fonts.d.ts +0 -0
  115. /package/{build → dist}/utils/time.d.ts +0 -0
  116. /package/src/{assets → lib/assets}/picture-in-picture.svg +0 -0
  117. /package/src/{utils → lib/utils}/colors.ts +0 -0
  118. /package/src/{utils → lib/utils}/fonts.ts +0 -0
  119. /package/src/{utils → lib/utils}/time.ts +0 -0
@@ -1,322 +0,0 @@
1
- import { useEffect, useMemo, useRef, useState } from "react"
2
- import { css } from "@emotion/react"
3
- import { ChevronLeft, ChevronRight, Settings } from "react-feather"
4
-
5
- import { MediaMachineContext } from "../state-machines"
6
- import { TooltipDisplay } from "./tooltip-display"
7
- import { fonts } from "../utils/fonts"
8
- import PlaybackSlider from "./playback-slider"
9
- import useLocalStorage, { booleanType } from "../utils/use-local-storage"
10
-
11
- const style = css`
12
- position: relative;
13
-
14
- .popover {
15
- position: absolute;
16
- right: 50%;
17
- transform: translateX(50%);
18
-
19
- overflow-y: auto;
20
- width: 180px;
21
- height: 160px;
22
- top: -180px;
23
- @media (min-width: 768px) {
24
- width: 250px;
25
- height: 160px;
26
- }
27
-
28
- display: flex;
29
- flex-direction: column;
30
-
31
- border-radius: 8px;
32
- background-color: rgba(28,28,28,0.95);
33
- ${fonts.bMedium.regular}
34
-
35
- z-index: 4;
36
-
37
- > div {
38
- display: flex;
39
- align-items: center;
40
- justify-content: space-between;
41
-
42
- color: #fff;
43
- outline: none;
44
-
45
- padding: 8px 6px 8px 12px;
46
-
47
- width: 100%;
48
-
49
- :first-of-type {
50
- border-radius: 8px 8px 0 0;
51
- }
52
- :last-of-type {
53
- border-radius: 0 0 8px 8px;
54
- }
55
- :not(&.no-hover) {
56
- cursor: pointer;
57
- }
58
- :not(&.no-hover):hover {
59
- background-color: rgba(255,255,255,.1);
60
- }
61
-
62
- > div {
63
- display: flex;
64
- align-items: center;
65
- justify-content: center;
66
-
67
- .secondary {
68
- color: #eee;
69
- ${fonts.bSmall.regular}
70
- }
71
- }
72
- }
73
-
74
- .back {
75
- display: flex;
76
- align-items: center;
77
- justify-content: flex-start;
78
- border-bottom: 1px solid #4D4D4E;
79
-
80
- svg {
81
- transform: translateX(-4px);
82
- transition: transform 0.2s ease-in-out;
83
- }
84
-
85
- :hover {
86
- svg {
87
- transform: translateX(-8px);
88
- }
89
- }
90
- }
91
- }
92
-
93
- .playback-rate {
94
- .slider {
95
- width: 100%;
96
- }
97
- .options {
98
- display: grid;
99
- grid-template-columns: 1fr 1fr 1fr 1fr;
100
- align-items: center;
101
-
102
- padding: 8px 12px;
103
-
104
- > div {
105
- display: flex;
106
- align-items: center;
107
- border-radius: 4px;
108
-
109
- padding: 8px 6px;
110
- height: 100%;
111
-
112
- cursor: pointer;
113
- :hover {
114
- background-color: rgba(255,255,255,.1);
115
- }
116
- }
117
- }
118
- }
119
-
120
- .subtitle {
121
- .description {
122
- word-break: break-word;
123
- }
124
- }
125
- `
126
-
127
- enum PopoverContent {
128
- Default,
129
- PlaybackRate,
130
- Advanced,
131
- SelectNewSources,
132
- Subtitles
133
- }
134
-
135
- const SettingsAction = () => {
136
- const mediaActor = MediaMachineContext.useActorRef()
137
- const playbackRate = MediaMachineContext.useSelector((state) => state.context.media.playbackRate)
138
- const subtitleStreams = MediaMachineContext.useSelector((state) => state.context.subtitleStreams)
139
- const selectedSubtitleStreamIndex = MediaMachineContext.useSelector((state) => state.context.selectedSubtitleStreamIndex)
140
- const [hideMediaStats, setHideMediaStats] = useLocalStorage('hideMediaStats', 'false') as [booleanType, (newValue: booleanType) => void]
141
-
142
- const [isOpenPopover, setIsOpenPopover] = useState(false)
143
- const [popoverContent, setPopoverContent] = useState(PopoverContent.Default)
144
- const settingsContainerRef = useRef<HTMLDivElement>(null)
145
-
146
- const togglePopover = () => {
147
- setIsOpenPopover(!isOpenPopover)
148
- setPopoverContent(PopoverContent.Default)
149
- }
150
-
151
- const setPlaybackRate = (rate: number) => {
152
- mediaActor.send({ type: 'SET_PLAYBACK_RATE', playbackRate: rate })
153
- setPopoverContent(PopoverContent.Default)
154
- }
155
-
156
- useEffect(() => {
157
- const handleClickOutside = (ev: MouseEvent) => {
158
- if (
159
- isOpenPopover &&
160
- settingsContainerRef.current &&
161
- !settingsContainerRef.current.contains(ev.target as Node)
162
- ) {
163
- togglePopover()
164
- }
165
- }
166
- document.addEventListener('mousedown', handleClickOutside)
167
- return () => document.removeEventListener('mousedown', handleClickOutside)
168
- }, [isOpenPopover])
169
-
170
- const languagesWithStreamIndex = useMemo(
171
- () => subtitleStreams.map(({ header }) => ({ streamIndex: header.streamIndex, language: header.parsed.info.Title })),
172
- [subtitleStreams.length]
173
- )
174
-
175
- const setLanguage = (languageWithStreamIndex: { streamIndex: number | undefined, language?: string }) => () => {
176
- mediaActor.send({ type: 'SELECT_SUBTITLE_STREAM', streamIndex: languageWithStreamIndex.streamIndex })
177
- togglePopover()
178
- }
179
-
180
- const changePopoverContent = (newPopoverContent: PopoverContent) => () => {
181
- setPopoverContent(newPopoverContent)
182
- }
183
-
184
- return (
185
- <div css={style} ref={settingsContainerRef}>
186
- <TooltipDisplay
187
- id='settings'
188
- disabled={isOpenPopover}
189
- text={
190
- <button
191
- className='settings'
192
- type='button'
193
- onClick={togglePopover}
194
- >
195
- <Settings />
196
- </button>
197
- }
198
- toolTipText={
199
- <span>
200
- Settings
201
- </span>
202
- }
203
- />
204
- {
205
- isOpenPopover && popoverContent === PopoverContent.Default && (
206
- <div className='popover menu'>
207
- <div onClick={changePopoverContent(PopoverContent.Advanced)}>
208
- <span>Advanced</span>
209
- <div>
210
- <ChevronRight />
211
- </div>
212
- </div>
213
- {/* <div onClick={changePopoverContent(PopoverContent.SelectNewSources)}>
214
- <div>Select new sources</div>
215
- <div>
216
- <ChevronRight />
217
- </div>
218
- </div> */}
219
- <div onClick={changePopoverContent(PopoverContent.Subtitles)}>
220
- <div>Subtitles</div>
221
- <div>
222
- <ChevronRight />
223
- </div>
224
- </div>
225
- <div onClick={changePopoverContent(PopoverContent.PlaybackRate)}>
226
- <div>Playback speed</div>
227
- <div>
228
- <span className='secondary'>
229
- {
230
- playbackRate === 1
231
- ? '(Default)'
232
- : playbackRate.toFixed(2)
233
- }
234
- </span>
235
- <ChevronRight />
236
- </div>
237
- </div>
238
- </div>
239
- )
240
- }
241
- {
242
- isOpenPopover && popoverContent === PopoverContent.PlaybackRate && (
243
- <div className='popover playback-rate'>
244
- <div className="back" onClick={changePopoverContent(PopoverContent.Default)}>
245
- <ChevronLeft />
246
- <span>Plackback speed</span>
247
- </div>
248
- <div className="slider no-hover">
249
- <PlaybackSlider />
250
- </div>
251
- <div className="options no-hover">
252
- <div onClick={() => setPlaybackRate(0.5)}>
253
- 0.5x
254
- </div>
255
- <div onClick={() => setPlaybackRate(1)}>
256
- 1x
257
- </div>
258
- <div onClick={() => setPlaybackRate(1.5)}>
259
- 1.5x
260
- </div>
261
- <div onClick={() => setPlaybackRate(2)}>
262
- 2x
263
- </div>
264
- </div>
265
- </div>
266
- )
267
- }
268
- {
269
- isOpenPopover && popoverContent === PopoverContent.Advanced && (
270
- <div className='popover advanced'>
271
- <div className="back" onClick={changePopoverContent(PopoverContent.Default)}>
272
- <ChevronLeft />
273
- <span>Advanced</span>
274
- </div>
275
- <div onClick={() => setHideMediaStats(hideMediaStats === 'true' ? 'false' : 'true')}>
276
- <span>Hide stats</span>
277
- <span>{hideMediaStats === 'true' ? '✓' : ''}</span>
278
- </div>
279
- </div>
280
- )
281
- }
282
- {
283
- isOpenPopover && popoverContent === PopoverContent.SelectNewSources && (
284
- <div className='popover sources'>
285
- <div className="back" onClick={changePopoverContent(PopoverContent.Default)}>
286
- <ChevronLeft />
287
- <span>Select new sources</span>
288
- </div>
289
- </div>
290
- )
291
- }
292
- {
293
- isOpenPopover && popoverContent === PopoverContent.Subtitles && (
294
- <div className='popover subtitle'>
295
- <div className="back" onClick={changePopoverContent(PopoverContent.Default)}>
296
- <ChevronLeft />
297
- <span>Subtitles</span>
298
- </div>
299
- <div onClick={setLanguage({ streamIndex: undefined })}>
300
- <span>Disable</span>
301
- <span>{selectedSubtitleStreamIndex === undefined ? '✓' : ''}</span>
302
- </div>
303
- {
304
- languagesWithStreamIndex.map((languageWithStreamIndex) => (
305
- <div
306
- key={languageWithStreamIndex.streamIndex}
307
- onClick={setLanguage(languageWithStreamIndex)}
308
- className="description"
309
- >
310
- <span>{languageWithStreamIndex.language}</span>
311
- <span>{selectedSubtitleStreamIndex === languageWithStreamIndex.streamIndex ? '✓' : ''}</span>
312
- </div>
313
- ))
314
- }
315
- </div>
316
- )
317
- }
318
- </div>
319
- )
320
- }
321
-
322
- export default SettingsAction
@@ -1,101 +0,0 @@
1
- import { Volume1, Volume2, VolumeX } from "react-feather"
2
- import { css } from "@emotion/react"
3
-
4
- import { MediaMachineContext } from "../state-machines"
5
- import { TooltipDisplay } from "./tooltip-display"
6
- import { fonts } from "../utils/fonts"
7
- import VolumeSlider from "./volume-slider"
8
- import { MutableRefObject, useMemo } from 'react'
9
- import { linearToLogVolume, logToLinearVolume } from "../utils/volume-utils"
10
-
11
- const style = css`
12
- position: relative;
13
- display: flex;
14
- align-items: center;
15
-
16
- .volume-slider-container {
17
- display: flex;
18
- align-items: center;
19
-
20
- width: 0;
21
- margin-right: 0;
22
- overflow: hidden;
23
- pointer-events: none;
24
-
25
- transition: margin .2s cubic-bezier(0.4,0,1,1), width .2s cubic-bezier(0.4,0,1,1);
26
- -webkit-transition: margin .2s cubic-bezier(0.4,0,1,1), width .2s cubic-bezier(0.4,0,1,1);
27
-
28
- .volume-slider-background {
29
- display: flex;
30
- flex-direction: row;
31
- align-items: center;
32
-
33
- border-radius: 4px;
34
-
35
- .volume-value {
36
- ${fonts.bMedium.regular};
37
- color: #ffffff;
38
- }
39
- }
40
- }
41
-
42
- &:hover .volume-slider-container {
43
- width: 9rem;
44
-
45
- transition: margin .2s cubic-bezier(0,0,0.2,1), width .2s cubic-bezier(0,0,0.2,1);
46
- -webkit-transition: margin .2s cubic-bezier(0,0,0.2,1), width .2s cubic-bezier(0,0,0.2,1);
47
-
48
- pointer-events: auto;
49
- }
50
- `
51
-
52
- // todo: try to find a better type for `ref`
53
- const Sound = ({ ref }: { ref: any }) => {
54
- const mediaActor = MediaMachineContext.useActorRef()
55
- const volume = MediaMachineContext.useSelector((state) => state.context.media.volume)
56
- const muted = MediaMachineContext.useSelector((state) => state.context.media.muted)
57
-
58
- const linearVolume = useMemo(() => logToLinearVolume(volume), [volume])
59
- const setVolume = (newLinearVolume: number, muted: boolean) =>
60
- mediaActor.send({
61
- type: 'SET_VOLUME',
62
- muted,
63
- volume: linearToLogVolume(newLinearVolume)
64
- })
65
-
66
- return (
67
- <div css={style}>
68
- <TooltipDisplay
69
- id='sound'
70
- text={
71
- <button
72
- className='sound'
73
- type='button'
74
- onClick={() => setVolume(linearVolume, !muted)}
75
- ref={ref}
76
- >
77
- {muted || volume === 0
78
- ? <VolumeX size={18} color='#fff' />
79
- : volume <= 0.5
80
- ? <Volume1 size={18} color='#fff' />
81
- : <Volume2 size={18} color='#fff' />
82
- }
83
- </button>
84
- }
85
- toolTipText={
86
- <span>{muted ? 'Unmute (m)' : 'Mute (m)'}</span>
87
- }
88
- />
89
- <div className='volume-slider-container'>
90
- <div className='volume-slider-background'>
91
- <VolumeSlider
92
- value={muted ? 0 : linearVolume}
93
- onChange={linearValue => setVolume(linearValue, false)}
94
- />
95
- </div>
96
- </div>
97
- </div>
98
- )
99
- }
100
-
101
- export default Sound
package/src/index.tsx DELETED
@@ -1,195 +0,0 @@
1
- /// <reference types="@emotion/react/types/css-prop" />
2
- import type { ClassAttributes, MutableRefObject, ReactNode, RefCallback } from 'react'
3
- import type { MediaPlayerContextType } from './utils/context'
4
-
5
- import { useCallback, useContext, useEffect, useState } from 'react'
6
- import { css } from '@emotion/react'
7
-
8
- import { MediaMachineContext } from './state-machines'
9
- import { MediaPlayerContext, DownloadedRange } from './utils/context'
10
- import useLocalStorage, { booleanType } from './utils/use-local-storage'
11
- import Chrome from './components/chrome'
12
-
13
- const BUFFER_SIZE = 2_500_000
14
-
15
- const FKNVideoRootStyle = css`
16
- display: flex;
17
- justify-content: center;
18
- background-color: #111;
19
- height: 100%;
20
- width: 100%;
21
- overflow: hidden;
22
- `
23
-
24
- export type FKNVideoOptions = {
25
- title?: string
26
- downloadedRanges?: DownloadedRange[]
27
- read?: (offset: number, size: number) => Promise<ArrayBuffer>
28
- size?: number
29
- bufferSize?: number
30
- autoplay?: boolean
31
- mediaInformation?: ReactNode
32
- loadingInformation?: ReactNode
33
- publicPath: string
34
- jassubWorkerUrl: string
35
- jassubWasmUrl: string
36
- jassubModernWasmUrl: string
37
- libavWorkerUrl: string
38
- }
39
-
40
- export const FKNVideoRoot = (
41
- { options, videoElement, children }:
42
- { options: FKNVideoOptions, videoElement: HTMLVideoElement | undefined, children: ReactNode }
43
- ) => {
44
- const mediaPlayerContext = useContext(MediaPlayerContext)
45
- const mediaActor = MediaMachineContext.useActorRef()
46
- const status = MediaMachineContext.useSelector((state) => state.value)
47
- const volume = MediaMachineContext.useSelector((state) => state.context.media.volume)
48
- const muted = MediaMachineContext.useSelector((state) => state.context.media.muted)
49
- const isReady = MediaMachineContext.useSelector((state) => state.context.isReady)
50
- const duration = MediaMachineContext.useSelector((state) => state.context.media.duration)
51
- const [mediaVolume, setMediaVolume] = useLocalStorage('mediaVolume', '1') as [string, (newValue: string) => void]
52
- const [mediaMute, setMediaMute] = useLocalStorage('mediaMute', 'false') as [booleanType, (newValue: booleanType) => void]
53
- const [firstRender, setFirstRender] = useState(true)
54
-
55
- useEffect(() => {
56
- mediaActor.send({
57
- type: 'MEDIA_SOURCE_OPTIONS',
58
- mediaSourceOptions: {}
59
- })
60
- }, [])
61
-
62
- useEffect(() => {
63
- if (!options.autoplay || duration === undefined) return
64
- mediaActor.send({ type: 'PLAY' })
65
- }, [duration, options.autoplay])
66
-
67
- useEffect(
68
- () => {
69
- if (!mediaActor || !isReady || !mediaPlayerContext.downloadedRanges) return
70
- mediaActor.send({
71
- type: 'DOWNLOADED_RANGES_UPDATED',
72
- downloadedRanges: mediaPlayerContext.downloadedRanges
73
- })
74
- },
75
- [
76
- mediaActor,
77
- isReady,
78
- (
79
- mediaPlayerContext
80
- .downloadedRanges
81
- ?.map(range => `${range.startByteOffset}-${range.endByteOffset}`)
82
- ?? []
83
- ).join(',')
84
- ]
85
- )
86
-
87
- useEffect(() => {
88
- const { size, read, publicPath, libavWorkerUrl, jassubWasmUrl } = options
89
- if (!read || !size || !publicPath || !libavWorkerUrl || !jassubWasmUrl) return
90
-
91
- mediaActor.send({
92
- type: 'REMUXER_OPTIONS',
93
- remuxerOptions: {
94
- publicPath,
95
- workerUrl: libavWorkerUrl,
96
- bufferSize: options.bufferSize ?? BUFFER_SIZE,
97
- length: size,
98
- read
99
- }
100
- })
101
- }, [options.read, options.size, options.publicPath, options.libavWorkerUrl, options.bufferSize])
102
-
103
- useEffect(() => {
104
- const { jassubWorkerUrl, jassubWasmUrl, jassubModernWasmUrl } = options
105
- if (!jassubWorkerUrl || !jassubWasmUrl || !jassubModernWasmUrl) return
106
-
107
- mediaActor.send({
108
- type: 'SUBTITLES_RENDERER_OPTIONS',
109
- subtitlesRendererOptions: {
110
- workerUrl: jassubWorkerUrl,
111
- wasmUrl: jassubWasmUrl,
112
- modernWasmUrl: jassubModernWasmUrl
113
- }
114
- })
115
- }, [options.publicPath, options.jassubWorkerUrl, options.jassubWasmUrl])
116
-
117
- useEffect(() => {
118
- if (!videoElement) return
119
- mediaActor.send({
120
- type: 'SET_VIDEO_ELEMENT',
121
- videoElement,
122
- })
123
- }, [videoElement])
124
-
125
- useEffect(() => {
126
- if (!isReady) return
127
- if (firstRender) {
128
- mediaActor.send({
129
- type: 'SET_VOLUME',
130
- muted: mediaMute === 'true',
131
- volume:
132
- isNaN(Number(mediaVolume))
133
- ? 1
134
- : Number(mediaVolume)
135
- })
136
- setFirstRender(false)
137
- } else {
138
- setMediaVolume(volume.toString())
139
- setMediaMute(muted ? 'true' : 'false')
140
- }
141
- }, [isReady, volume, muted, firstRender])
142
-
143
- useEffect(() => {
144
- if (status !== 'OK') return
145
- return () => {
146
- mediaActor.send({ type: 'DESTROY' })
147
- }
148
- }, [status])
149
-
150
- return (
151
- <div css={FKNVideoRootStyle}>
152
- <Chrome mediaInformation={options.mediaInformation} loadingInformation={options.loadingInformation}>
153
- {children}
154
- </Chrome>
155
- </div>
156
- )
157
- }
158
-
159
- const FKNVideo = (
160
- { ref, ...options }:
161
- FKNVideoOptions & { ref?: RefCallback<HTMLVideoElement> | MutableRefObject<HTMLVideoElement | null> }
162
- ) => {
163
- const updateContextFunction = (context: Parameters<MediaPlayerContextType['update']>[0]) => setMediaPlayerContext({ ...context, update: updateContextFunction })
164
- const [chromeContext, setMediaPlayerContext] = useState<MediaPlayerContextType>({ update: updateContextFunction } as MediaPlayerContextType)
165
-
166
- const [videoElement, setVideoElement] = useState<HTMLVideoElement | undefined>()
167
-
168
- const refFunction: ClassAttributes<HTMLVideoElement>['ref'] = useCallback((element: HTMLVideoElement | null) => {
169
- if (typeof ref === 'function') ref(element)
170
- else if (ref && 'current' in ref) ref.current = element
171
- setVideoElement(element ?? undefined)
172
- }, [])
173
-
174
- useEffect(() => {
175
- setMediaPlayerContext((previousContext) => ({
176
- ...previousContext,
177
- videoElement,
178
- title: options?.title,
179
- size: options?.size,
180
- downloadedRanges: options?.downloadedRanges
181
- }))
182
- }, [videoElement, options?.title, options?.size, options?.downloadedRanges])
183
-
184
- return (
185
- <MediaPlayerContext.Provider value={chromeContext}>
186
- <MediaMachineContext.Provider>
187
- <FKNVideoRoot options={options} videoElement={videoElement}>
188
- <video ref={refFunction} controls={false}/>
189
- </FKNVideoRoot>
190
- </MediaMachineContext.Provider>
191
- </MediaPlayerContext.Provider>
192
- )
193
- }
194
-
195
- export default FKNVideo