@frameset/plex-player 1.0.6 → 2.0.1

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.
@@ -1,225 +0,0 @@
1
- /**
2
- * PlexPlayer - Core Module
3
- * Handles video element and basic playback functionality
4
- */
5
- const PlexPlayerCore = (function() {
6
- 'use strict';
7
-
8
- let container = null;
9
- let video = null;
10
- let player = null;
11
- let state = {
12
- isPlaying: false,
13
- currentTime: 0,
14
- duration: 0,
15
- playbackRate: 1
16
- };
17
-
18
- function init(playerInstance) {
19
- player = playerInstance;
20
- container = player.container;
21
-
22
- createVideoElement();
23
- bindEvents();
24
-
25
- // Apply initial settings
26
- if (player.options.muted) {
27
- video.muted = true;
28
- }
29
- if (player.options.volume !== undefined) {
30
- video.volume = player.options.volume;
31
- }
32
- if (player.options.loop) {
33
- video.loop = true;
34
- }
35
- if (player.options.poster) {
36
- video.poster = player.options.poster;
37
- }
38
- if (player.options.preload) {
39
- video.preload = player.options.preload;
40
- }
41
- }
42
-
43
- function createVideoElement() {
44
- video = document.createElement('video');
45
- video.className = 'plex-video';
46
- video.setAttribute('playsinline', '');
47
- video.setAttribute('webkit-playsinline', '');
48
- container.insertBefore(video, container.firstChild);
49
- }
50
-
51
- function bindEvents() {
52
- video.addEventListener('play', onPlay);
53
- video.addEventListener('pause', onPause);
54
- video.addEventListener('ended', onEnded);
55
- video.addEventListener('timeupdate', onTimeUpdate);
56
- video.addEventListener('progress', onProgress);
57
- video.addEventListener('loadedmetadata', onLoadedMetadata);
58
- video.addEventListener('error', onError);
59
- video.addEventListener('waiting', onWaiting);
60
- video.addEventListener('canplay', onCanPlay);
61
- }
62
-
63
- function onPlay() {
64
- state.isPlaying = true;
65
- container.classList.add('plex-playing');
66
- container.classList.remove('plex-paused');
67
- player._emit('play');
68
- }
69
-
70
- function onPause() {
71
- state.isPlaying = false;
72
- container.classList.remove('plex-playing');
73
- container.classList.add('plex-paused');
74
- player._emit('pause');
75
- }
76
-
77
- function onEnded() {
78
- state.isPlaying = false;
79
- container.classList.remove('plex-playing');
80
- player._emit('ended');
81
- }
82
-
83
- function onTimeUpdate() {
84
- state.currentTime = video.currentTime;
85
- state.duration = video.duration;
86
- player._emit('timeupdate', {
87
- currentTime: video.currentTime,
88
- duration: video.duration
89
- });
90
- }
91
-
92
- function onProgress() {
93
- const buffered = video.buffered;
94
- let loaded = 0;
95
- if (buffered.length > 0) {
96
- loaded = buffered.end(buffered.length - 1) / video.duration * 100;
97
- }
98
- player._emit('progress', { buffered: loaded });
99
- }
100
-
101
- function onLoadedMetadata() {
102
- state.duration = video.duration;
103
- player._emit('loadedmetadata', { duration: video.duration });
104
- }
105
-
106
- function onError(e) {
107
- player._emit('error', {
108
- code: video.error?.code,
109
- message: video.error?.message
110
- });
111
- }
112
-
113
- function onWaiting() {
114
- container.classList.add('plex-loading');
115
- player._emit('waiting');
116
- }
117
-
118
- function onCanPlay() {
119
- container.classList.remove('plex-loading');
120
- player._emit('canplay');
121
- }
122
-
123
- // Public API
124
- function load(src) {
125
- video.src = src;
126
- video.load();
127
-
128
- if (player.options.autoplay) {
129
- play();
130
- }
131
- }
132
-
133
- function play() {
134
- return video.play();
135
- }
136
-
137
- function pause() {
138
- video.pause();
139
- }
140
-
141
- function togglePlay() {
142
- if (video.paused) {
143
- play();
144
- } else {
145
- pause();
146
- }
147
- }
148
-
149
- function seek(time) {
150
- video.currentTime = Math.max(0, Math.min(time, video.duration));
151
- }
152
-
153
- function seekPercent(percent) {
154
- const time = (percent / 100) * video.duration;
155
- seek(time);
156
- }
157
-
158
- function setPlaybackRate(rate) {
159
- video.playbackRate = rate;
160
- state.playbackRate = rate;
161
- player._emit('ratechange', { rate });
162
- }
163
-
164
- function getPlaybackRate() {
165
- return video.playbackRate;
166
- }
167
-
168
- function getCurrentTime() {
169
- return video.currentTime;
170
- }
171
-
172
- function getDuration() {
173
- return video.duration;
174
- }
175
-
176
- function isPlaying() {
177
- return !video.paused && !video.ended;
178
- }
179
-
180
- function isPaused() {
181
- return video.paused;
182
- }
183
-
184
- function getVideo() {
185
- return video;
186
- }
187
-
188
- function destroy() {
189
- video.removeEventListener('play', onPlay);
190
- video.removeEventListener('pause', onPause);
191
- video.removeEventListener('ended', onEnded);
192
- video.removeEventListener('timeupdate', onTimeUpdate);
193
- video.removeEventListener('progress', onProgress);
194
- video.removeEventListener('loadedmetadata', onLoadedMetadata);
195
- video.removeEventListener('error', onError);
196
- video.removeEventListener('waiting', onWaiting);
197
- video.removeEventListener('canplay', onCanPlay);
198
- video.remove();
199
- }
200
-
201
- return {
202
- init,
203
- load,
204
- play,
205
- pause,
206
- togglePlay,
207
- seek,
208
- seekPercent,
209
- setPlaybackRate,
210
- getPlaybackRate,
211
- getCurrentTime,
212
- getDuration,
213
- isPlaying,
214
- isPaused,
215
- getVideo,
216
- destroy
217
- };
218
- })();
219
-
220
- // Export for ES modules
221
- if (typeof module !== 'undefined' && module.exports) {
222
- module.exports = { PlexPlayerCore };
223
- }
224
-
225
- export { PlexPlayerCore };
@@ -1,277 +0,0 @@
1
- /**
2
- * @frameset/plex-player - React Component
3
- * Professional Video Player by FRAMESET Studio
4
- * https://frameset.dev
5
- */
6
-
7
- import React, {
8
- useEffect,
9
- useRef,
10
- useImperativeHandle,
11
- forwardRef,
12
- useState,
13
- useCallback,
14
- createContext,
15
- useContext,
16
- } from 'react';
17
-
18
- // Import core player
19
- import PlexPlayer from '../core/index.js';
20
-
21
- // Context for nested components
22
- const PlexPlayerContext = createContext(null);
23
-
24
- /**
25
- * Hook to access player instance from child components
26
- */
27
- export const usePlexPlayer = () => {
28
- const player = useContext(PlexPlayerContext);
29
- return player;
30
- };
31
-
32
- /**
33
- * PlexPlayer React Component
34
- */
35
- export const PlexPlayerReact = forwardRef(function PlexPlayerReact(props, ref) {
36
- const {
37
- src,
38
- playlist,
39
- className = '',
40
- style = {},
41
- autoplay = false,
42
- muted = false,
43
- loop = false,
44
- volume = 1,
45
- poster,
46
- preload = 'metadata',
47
- keyboard = true,
48
- touch = true,
49
- pip = true,
50
- cast = true,
51
- fullscreen = true,
52
- controlsHideDelay = 3000,
53
- theme,
54
- subtitles,
55
- ads,
56
- i18n,
57
- // Event callbacks
58
- onPlay,
59
- onPause,
60
- onEnded,
61
- onTimeUpdate,
62
- onProgress,
63
- onVolumeChange,
64
- onFullscreenChange,
65
- onError,
66
- onReady,
67
- // Children for custom overlays
68
- children,
69
- ...restProps
70
- } = props;
71
-
72
- const containerRef = useRef(null);
73
- const playerRef = useRef(null);
74
- const [isReady, setIsReady] = useState(false);
75
-
76
- // Initialize player
77
- useEffect(() => {
78
- if (!containerRef.current) return;
79
-
80
- // Create player instance
81
- const player = new PlexPlayer({
82
- container: containerRef.current,
83
- autoplay,
84
- muted,
85
- loop,
86
- volume,
87
- poster,
88
- preload,
89
- keyboard,
90
- touch,
91
- pip,
92
- cast,
93
- fullscreen,
94
- controlsHideDelay,
95
- theme,
96
- subtitles,
97
- ads,
98
- i18n,
99
- });
100
-
101
- playerRef.current = player;
102
-
103
- // Bind events
104
- if (onPlay) player.on('play', onPlay);
105
- if (onPause) player.on('pause', onPause);
106
- if (onEnded) player.on('ended', onEnded);
107
- if (onTimeUpdate) {
108
- player.on('timeupdate', (data) => onTimeUpdate(data.currentTime));
109
- }
110
- if (onProgress) {
111
- player.on('progress', (data) => onProgress(data.buffered));
112
- }
113
- if (onVolumeChange) {
114
- player.on('volumechange', (data) => onVolumeChange(data.volume, data.muted));
115
- }
116
- if (onFullscreenChange) {
117
- player.on('fullscreenchange', (data) => onFullscreenChange(data.isFullscreen));
118
- }
119
- if (onError) {
120
- player.on('error', onError);
121
- }
122
-
123
- setIsReady(true);
124
-
125
- if (onReady) {
126
- onReady(player);
127
- }
128
-
129
- // Cleanup
130
- return () => {
131
- player.destroy();
132
- playerRef.current = null;
133
- };
134
- }, []);
135
-
136
- // Load source when src changes
137
- useEffect(() => {
138
- if (!playerRef.current || !isReady) return;
139
-
140
- if (src) {
141
- playerRef.current.load(src);
142
- }
143
- }, [src, isReady]);
144
-
145
- // Load playlist when playlist changes
146
- useEffect(() => {
147
- if (!playerRef.current || !isReady || !playlist) return;
148
-
149
- playerRef.current.loadPlaylist(playlist);
150
- }, [playlist, isReady]);
151
-
152
- // Update volume
153
- useEffect(() => {
154
- if (playerRef.current && isReady) {
155
- playerRef.current.setVolume(volume);
156
- }
157
- }, [volume, isReady]);
158
-
159
- // Update muted
160
- useEffect(() => {
161
- if (playerRef.current && isReady) {
162
- if (muted) {
163
- playerRef.current.mute();
164
- } else {
165
- playerRef.current.unmute();
166
- }
167
- }
168
- }, [muted, isReady]);
169
-
170
- // Expose player methods via ref
171
- useImperativeHandle(ref, () => ({
172
- play: () => playerRef.current?.play(),
173
- pause: () => playerRef.current?.pause(),
174
- togglePlay: () => playerRef.current?.togglePlay(),
175
- seek: (time) => playerRef.current?.seek(time),
176
- seekPercent: (percent) => playerRef.current?.seekPercent(percent),
177
- setVolume: (vol) => playerRef.current?.setVolume(vol),
178
- getVolume: () => playerRef.current?.getVolume(),
179
- mute: () => playerRef.current?.mute(),
180
- unmute: () => playerRef.current?.unmute(),
181
- toggleMute: () => playerRef.current?.toggleMute(),
182
- isMuted: () => playerRef.current?.isMuted(),
183
- setPlaybackRate: (rate) => playerRef.current?.setPlaybackRate(rate),
184
- enterFullscreen: () => playerRef.current?.enterFullscreen(),
185
- exitFullscreen: () => playerRef.current?.exitFullscreen(),
186
- toggleFullscreen: () => playerRef.current?.toggleFullscreen(),
187
- enterPiP: () => playerRef.current?.enterPiP(),
188
- exitPiP: () => playerRef.current?.exitPiP(),
189
- togglePiP: () => playerRef.current?.togglePiP(),
190
- cast: () => playerRef.current?.cast(),
191
- getState: () => playerRef.current?.getState(),
192
- getPlayer: () => playerRef.current,
193
- next: () => playerRef.current?.next(),
194
- previous: () => playerRef.current?.previous(),
195
- playAt: (index) => playerRef.current?.playAt(index),
196
- }));
197
-
198
- return (
199
- <PlexPlayerContext.Provider value={playerRef.current}>
200
- <div
201
- ref={containerRef}
202
- className={`plex-player-container ${className}`}
203
- style={{
204
- width: '100%',
205
- aspectRatio: '16 / 9',
206
- position: 'relative',
207
- ...style,
208
- }}
209
- {...restProps}
210
- >
211
- {children}
212
- </div>
213
- </PlexPlayerContext.Provider>
214
- );
215
- });
216
-
217
- // Additional hooks for convenience
218
- export const usePlexPlayerState = () => {
219
- const player = usePlexPlayer();
220
- const [state, setState] = useState(null);
221
-
222
- useEffect(() => {
223
- if (!player) return;
224
-
225
- const updateState = () => {
226
- setState(player.getState());
227
- };
228
-
229
- // Update on every timeupdate
230
- player.on('timeupdate', updateState);
231
- player.on('play', updateState);
232
- player.on('pause', updateState);
233
- player.on('volumechange', updateState);
234
- player.on('fullscreenchange', updateState);
235
-
236
- // Initial state
237
- updateState();
238
-
239
- return () => {
240
- player.off('timeupdate', updateState);
241
- player.off('play', updateState);
242
- player.off('pause', updateState);
243
- player.off('volumechange', updateState);
244
- player.off('fullscreenchange', updateState);
245
- };
246
- }, [player]);
247
-
248
- return state;
249
- };
250
-
251
- export const usePlexPlayerTime = () => {
252
- const player = usePlexPlayer();
253
- const [time, setTime] = useState({ current: 0, duration: 0 });
254
-
255
- useEffect(() => {
256
- if (!player) return;
257
-
258
- const updateTime = (data) => {
259
- setTime({
260
- current: data.currentTime,
261
- duration: data.duration,
262
- });
263
- };
264
-
265
- player.on('timeupdate', updateTime);
266
-
267
- return () => {
268
- player.off('timeupdate', updateTime);
269
- };
270
- }, [player]);
271
-
272
- return time;
273
- };
274
-
275
- // Named exports
276
- export { PlexPlayer };
277
- export default PlexPlayerReact;
package/src/styles.js DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * @frameset/plex-player - CSS Entry Point
3
- * Import this file to include all player styles
4
- */
5
- import '../css/main.css';
6
- import '../css/controls.css';
7
- import '../css/playlist.css';
8
- import '../css/settings.css';