myetv-player 1.0.0 β 1.0.6
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/.github/workflows/codeql.yml +100 -0
- package/README.md +36 -58
- package/SECURITY.md +50 -0
- package/css/myetv-player.css +301 -218
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +1713 -1503
- package/dist/myetv-player.min.js +1670 -1471
- package/package.json +6 -1
- package/plugins/README.md +1016 -0
- package/plugins/cloudflare/README.md +1068 -0
- package/plugins/cloudflare/myetv-player-cloudflare-stream-plugin.js +556 -0
- package/plugins/facebook/README.md +1024 -0
- package/plugins/facebook/myetv-player-facebook-plugin.js +437 -0
- package/plugins/gamepad-remote-controller/README.md +816 -0
- package/plugins/gamepad-remote-controller/myetv-player-gamepad-remote-plugin.js +678 -0
- package/plugins/google-adsense-ads/README.md +1 -0
- package/plugins/google-adsense-ads/g-adsense-ads-plugin.js +158 -0
- package/plugins/google-ima-ads/README.md +1 -0
- package/plugins/google-ima-ads/g-ima-ads-plugin.js +355 -0
- package/plugins/twitch/README.md +1185 -0
- package/plugins/twitch/myetv-player-twitch-plugin.js +569 -0
- package/plugins/vast-vpaid-ads/README.md +1 -0
- package/plugins/vast-vpaid-ads/vast-vpaid-ads-plugin.js +346 -0
- package/plugins/vimeo/README.md +1416 -0
- package/plugins/vimeo/myetv-player-vimeo.js +640 -0
- package/plugins/youtube/README.md +851 -0
- package/plugins/youtube/myetv-player-youtube-plugin.js +1714 -210
- package/scss/README.md +160 -0
- package/scss/_menus.scss +840 -672
- package/scss/_responsive.scss +67 -105
- package/scss/_volume.scss +67 -105
- package/src/README.md +559 -0
- package/src/controls.js +16 -4
- package/src/core.js +1192 -1062
- package/src/i18n.js +27 -1
- package/src/quality.js +478 -436
- package/src/subtitles.js +2 -2
package/src/README.md
CHANGED
|
@@ -1 +1,560 @@
|
|
|
1
|
+
# MYETV Video Player - Modular Source Documentation
|
|
1
2
|
|
|
3
|
+
**Modular build system for MYETV video player**
|
|
4
|
+
|
|
5
|
+
Created by [MYETV](https://www.myetv.tv) - [Oskar Cosimo](https://oskarcosimo.com)
|
|
6
|
+
|
|
7
|
+
## π Project Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
myetv-player/
|
|
11
|
+
βββ src/ # JavaScript source modules
|
|
12
|
+
β βββ core.js # Main module and initialization
|
|
13
|
+
β βββ events.js # Event management system
|
|
14
|
+
β βββ controls.js # UI controls and auto-hide
|
|
15
|
+
β βββ quality.js # Video quality management
|
|
16
|
+
β βββ subtitles.js # Custom subtitle system
|
|
17
|
+
β βββ chapters.js # Timeline chapter markers
|
|
18
|
+
β βββ fullscreen.js # Fullscreen and Picture-in-Picture
|
|
19
|
+
β βββ playlist.js # Video playlist management
|
|
20
|
+
β βββ watermark.js # Watermark/logo overlay
|
|
21
|
+
β βββ streaming.js # DASH/HLS adaptive support
|
|
22
|
+
β βββ plugins.js # Extensible plugin system
|
|
23
|
+
β βββ i18n.js # Internationalization
|
|
24
|
+
β βββ utils.js # Utility functions
|
|
25
|
+
βββ build.js # Node.js build script
|
|
26
|
+
βββ package.json # npm configuration
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## π Build System
|
|
30
|
+
|
|
31
|
+
### Installing Dependencies
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Available Commands
|
|
38
|
+
|
|
39
|
+
The project uses npm scripts defined in `package.json`:
|
|
40
|
+
|
|
41
|
+
**Build JavaScript:**
|
|
42
|
+
```bash
|
|
43
|
+
npm run build # Full build (JS + SCSS)
|
|
44
|
+
npm run build:js # JavaScript only
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Build SCSS:**
|
|
48
|
+
```bash
|
|
49
|
+
npm run build:scss # CSS expanded + minified
|
|
50
|
+
npm run build:scss:expanded # CSS expanded only
|
|
51
|
+
npm run build:scss:min # CSS minified only
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Watch Mode (Development):**
|
|
55
|
+
```bash
|
|
56
|
+
npm run watch:scss # Watch SCSS without source maps
|
|
57
|
+
npm run watch:scss:dev # Watch SCSS with source maps
|
|
58
|
+
npm run dev # Alias for watch:scss:dev
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Build Process
|
|
62
|
+
|
|
63
|
+
The `build.js` script performs the following operations:
|
|
64
|
+
|
|
65
|
+
1. **JavaScript Build:**
|
|
66
|
+
- Reads modules from `/src/` folder in specified order
|
|
67
|
+
- Extracts global code from `i18n.js` and `plugins.js`
|
|
68
|
+
- Removes module headers and footers
|
|
69
|
+
- Concatenates all modules into single `MYETVvideoplayer` class
|
|
70
|
+
- Adds CommonJS and AMD exports
|
|
71
|
+
- Generates `dist/myetv-player.js`
|
|
72
|
+
|
|
73
|
+
2. **JavaScript Minification:**
|
|
74
|
+
- Removes comments and whitespace
|
|
75
|
+
- Generates `dist/myetv-player.min.js`
|
|
76
|
+
|
|
77
|
+
3. **SCSS Build:**
|
|
78
|
+
- Compiles SCSS to expanded CSS (`css/myetv-player.css`)
|
|
79
|
+
- Compiles SCSS to minified CSS (`css/myetv-player.min.css`)
|
|
80
|
+
- Reports file size statistics
|
|
81
|
+
|
|
82
|
+
### Module Concatenation Order
|
|
83
|
+
|
|
84
|
+
Modules are processed in the order defined in `build.js`:
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
const moduleOrder = [
|
|
88
|
+
'core.js', // 1. Constructor and base initialization
|
|
89
|
+
'events.js', // 2. Custom event system
|
|
90
|
+
'controls.js', // 3. UI controls and auto-hide
|
|
91
|
+
'quality.js', // 4. Video quality selection
|
|
92
|
+
'subtitles.js', // 5. Custom subtitle system
|
|
93
|
+
'chapters.js', // 6. Timeline markers
|
|
94
|
+
'fullscreen.js', // 7. Fullscreen/PiP
|
|
95
|
+
'playlist.js', // 8. Playlist navigation
|
|
96
|
+
'watermark.js', // 9. Logo overlay
|
|
97
|
+
'streaming.js', // 10. Adaptive streaming
|
|
98
|
+
'plugins.js', // 11. Plugin system
|
|
99
|
+
'utils.js' // 12. Utility functions
|
|
100
|
+
];
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## π¦ JavaScript Modules
|
|
104
|
+
|
|
105
|
+
### 1. **core.js** - Main Module
|
|
106
|
+
**Responsibility:** Player initialization, constructor, options configuration
|
|
107
|
+
|
|
108
|
+
**Main features:**
|
|
109
|
+
- Constructor `constructor(videoElement, options)`
|
|
110
|
+
- DOM elements initialization
|
|
111
|
+
- Default options configuration
|
|
112
|
+
- HTML5 video events setup
|
|
113
|
+
- Poster and autoplay management
|
|
114
|
+
|
|
115
|
+
**Supported options:**
|
|
116
|
+
- `showQualitySelector`, `showSpeedControl`, `showFullscreen`
|
|
117
|
+
- `showPictureInPicture`, `showSubtitles`, `autoHide`
|
|
118
|
+
- `poster`, `showPosterOnEnd`, `keyboardControls`
|
|
119
|
+
- `showSeekTooltip`, `showTitleOverlay`, `debug`
|
|
120
|
+
- `autoplay`, `defaultQuality`, `language`
|
|
121
|
+
|
|
122
|
+
### 2. **events.js** - Event System
|
|
123
|
+
**Responsibility:** Player custom event management
|
|
124
|
+
|
|
125
|
+
**Public API:**
|
|
126
|
+
- `addEventListener(eventType, callback)` - Register listener
|
|
127
|
+
- `removeEventListener(eventType, callback)` - Remove listener
|
|
128
|
+
- `triggerEvent(eventType, data)` - Emit custom event
|
|
129
|
+
|
|
130
|
+
**Available events:**
|
|
131
|
+
- `play`, `pause`, `ended`, `timeupdate`
|
|
132
|
+
- `volumechange`, `qualitychange`, `subtitlechange`
|
|
133
|
+
- `fullscreenchange`, `pipchange`, `playlistchange`
|
|
134
|
+
|
|
135
|
+
### 3. **controls.js** - UI Controls
|
|
136
|
+
**Responsibility:** Video controls creation and management, auto-hide system
|
|
137
|
+
|
|
138
|
+
**Main features:**
|
|
139
|
+
- HTML controls generation (play/pause, volume, timeline)
|
|
140
|
+
- Intelligent auto-hide system
|
|
141
|
+
- Hover and touch events management
|
|
142
|
+
- Interactive progress bar with seek
|
|
143
|
+
- Volume controls with vertical mobile slider
|
|
144
|
+
- Seek tooltip with time preview
|
|
145
|
+
|
|
146
|
+
**Key methods:**
|
|
147
|
+
- `createControls()` - Generate HTML controls structure
|
|
148
|
+
- `initAutoHide()` - Configure auto-hide system
|
|
149
|
+
- `showControlsNow()` / `hideControlsNow()` - Visibility control
|
|
150
|
+
|
|
151
|
+
### 4. **quality.js** - Quality Management
|
|
152
|
+
**Responsibility:** Video quality selection, resolution monitoring, adaptive quality
|
|
153
|
+
|
|
154
|
+
**Main features:**
|
|
155
|
+
- Current video quality detection
|
|
156
|
+
- Quality switching with position preservation
|
|
157
|
+
- Automatic selection based on connection
|
|
158
|
+
- Real-time quality monitoring
|
|
159
|
+
- Quality selection UI menu
|
|
160
|
+
|
|
161
|
+
**Public API:**
|
|
162
|
+
- `initializeQualityMonitoring()` - Start monitoring
|
|
163
|
+
- `getCurrentPlayingQuality()` - Get current quality
|
|
164
|
+
- `changeQuality(newQuality)` - Change video quality
|
|
165
|
+
- `setDefaultQuality(quality)` - Set default quality
|
|
166
|
+
- `getAvailableQualities()` - List available qualities
|
|
167
|
+
|
|
168
|
+
### 5. **subtitles.js** - Subtitles
|
|
169
|
+
**Responsibility:** Custom subtitle system with SRT rendering
|
|
170
|
+
|
|
171
|
+
**Main features:**
|
|
172
|
+
- Native SRT parser
|
|
173
|
+
- Custom subtitle overlay
|
|
174
|
+
- Multi-track support
|
|
175
|
+
- Responsive rendering with configurable styles
|
|
176
|
+
- Accurate time synchronization
|
|
177
|
+
|
|
178
|
+
**Public API:**
|
|
179
|
+
- `initializeSubtitles()` - Initialize subtitle system
|
|
180
|
+
- `enableSubtitleTrack(trackIndex)` - Enable subtitle track
|
|
181
|
+
- `disableSubtitles()` - Disable subtitles
|
|
182
|
+
- `getAvailableSubtitles()` - List available tracks
|
|
183
|
+
- `isSubtitlesEnabled()` - Subtitle status
|
|
184
|
+
|
|
185
|
+
**SRT Parsing:**
|
|
186
|
+
- `parseCustomSRT(srtText)` - Convert SRT to object array
|
|
187
|
+
- `customTimeToSeconds(timeString)` - Timestamp conversion
|
|
188
|
+
|
|
189
|
+
### 6. **chapters.js** - Chapter Markers
|
|
190
|
+
**Responsibility:** Timeline chapter marker system with tooltips
|
|
191
|
+
|
|
192
|
+
**Main features:**
|
|
193
|
+
- Chapter parsing from JSON or string format
|
|
194
|
+
- Visual timeline markers
|
|
195
|
+
- Tooltip with title and thumbnail
|
|
196
|
+
- Click for quick navigation
|
|
197
|
+
- Supported format: `"00:00:00|Title|image.jpg"`
|
|
198
|
+
|
|
199
|
+
**Public API:**
|
|
200
|
+
- `initializeChapters()` - Initialize chapter system
|
|
201
|
+
- `parseChapters(chaptersData)` - Parse chapter format
|
|
202
|
+
- `renderChapterMarkers()` - Create DOM markers
|
|
203
|
+
- `jumpToChapter(index)` - Jump to specific chapter
|
|
204
|
+
|
|
205
|
+
**Options format:**
|
|
206
|
+
```javascript
|
|
207
|
+
chapters: [
|
|
208
|
+
{time: 0, title: "Intro", image: "intro.jpg"},
|
|
209
|
+
{time: 150, title: "Chapter 2", image: "ch2.jpg"}
|
|
210
|
+
]
|
|
211
|
+
// Or string format
|
|
212
|
+
chapters: "0:00:00|Intro|intro.jpg,0:02:30|Chapter 2|ch2.jpg"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 7. **fullscreen.js** - Fullscreen/PiP
|
|
216
|
+
**Responsibility:** Fullscreen and Picture-in-Picture management
|
|
217
|
+
|
|
218
|
+
**Public API:**
|
|
219
|
+
- `isFullscreenActive()` - Check fullscreen status
|
|
220
|
+
- `checkPiPSupport()` - Check browser PiP support
|
|
221
|
+
- `enterFullscreen()` - Enter fullscreen mode
|
|
222
|
+
- `exitFullscreen()` - Exit fullscreen
|
|
223
|
+
- `enterPictureInPicture()` - Activate PiP
|
|
224
|
+
- `exitPictureInPicture()` - Deactivate PiP
|
|
225
|
+
- `toggleFullscreen()` - Toggle fullscreen
|
|
226
|
+
- `togglePictureInPicture()` - Toggle PiP
|
|
227
|
+
|
|
228
|
+
**Cross-browser compatibility:**
|
|
229
|
+
- Vendor prefix support (webkit, moz)
|
|
230
|
+
- Fallback for unsupported browsers
|
|
231
|
+
|
|
232
|
+
### 8. **playlist.js** - Playlist Management
|
|
233
|
+
**Responsibility:** Multi-element video playlist navigation
|
|
234
|
+
|
|
235
|
+
**Main features:**
|
|
236
|
+
- Automatic playlist detection via data attributes
|
|
237
|
+
- Next/previous navigation
|
|
238
|
+
- Playlist UI buttons
|
|
239
|
+
- Video change events
|
|
240
|
+
|
|
241
|
+
**Data Attributes:**
|
|
242
|
+
```html
|
|
243
|
+
<video data-playlist-id="myPlaylist" data-playlist-index="0"></video>
|
|
244
|
+
<video data-playlist-id="myPlaylist" data-playlist-index="1"></video>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Public API:**
|
|
248
|
+
- `detectPlaylist()` - Detect playlist from DOM
|
|
249
|
+
- `playNextVideo()` - Play next video
|
|
250
|
+
- `playPreviousVideo()` - Play previous video
|
|
251
|
+
- `loadPlaylistData()` - Load playlist data
|
|
252
|
+
|
|
253
|
+
### 9. **watermark.js** - Logo Overlay
|
|
254
|
+
**Responsibility:** Customizable logo/watermark overlay
|
|
255
|
+
|
|
256
|
+
**Main features:**
|
|
257
|
+
- Logo overlay with clickable link
|
|
258
|
+
- 4 supported positions (topleft, topright, bottomleft, bottomright)
|
|
259
|
+
- Optional auto-hide with controls
|
|
260
|
+
- Customizable tooltip
|
|
261
|
+
|
|
262
|
+
**Public API:**
|
|
263
|
+
- `initializeWatermark()` - Create watermark overlay
|
|
264
|
+
- `setWatermark(url, link, position, title)` - Configure watermark
|
|
265
|
+
- `removeWatermark()` - Remove watermark
|
|
266
|
+
- `setWatermarkPosition(position)` - Change position
|
|
267
|
+
- `setWatermarkAutoHide(hide)` - Configure auto-hide
|
|
268
|
+
- `getWatermarkSettings()` - Get current configuration
|
|
269
|
+
|
|
270
|
+
**Initialization options:**
|
|
271
|
+
```javascript
|
|
272
|
+
{
|
|
273
|
+
watermarkUrl: 'logo.png',
|
|
274
|
+
watermarkLink: 'https://example.com',
|
|
275
|
+
watermarkPosition: 'bottomright',
|
|
276
|
+
watermarkTitle: 'Brand Name',
|
|
277
|
+
hideWatermark: true // Auto-hide with controls
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### 10. **streaming.js** - Adaptive Streaming
|
|
282
|
+
**Responsibility:** DASH/HLS adaptive streaming support
|
|
283
|
+
|
|
284
|
+
**Main features:**
|
|
285
|
+
- Dynamic loading of dash.js and hls.js libraries
|
|
286
|
+
- Automatic stream type detection (DASH/HLS)
|
|
287
|
+
- DASH and HLS player management
|
|
288
|
+
- Fallback to standard HTML5 video
|
|
289
|
+
|
|
290
|
+
**Public API:**
|
|
291
|
+
- `loadAdaptiveLibraries()` - Load streaming libraries
|
|
292
|
+
- `detectStreamType(src)` - Detect stream type from URL
|
|
293
|
+
- `initializeDashPlayer(src)` - Initialize DASH player
|
|
294
|
+
- `initializeHlsPlayer(src)` - Initialize HLS player
|
|
295
|
+
|
|
296
|
+
**Configuration options:**
|
|
297
|
+
```javascript
|
|
298
|
+
{
|
|
299
|
+
adaptiveStreaming: true,
|
|
300
|
+
dashLibUrl: 'https://cdn.dashjs.org/latest/dash.all.min.js',
|
|
301
|
+
hlsLibUrl: 'https://cdn.jsdelivr.net/npm/hls.js@latest'
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Supported formats:**
|
|
306
|
+
- DASH: `.mpd`
|
|
307
|
+
- HLS: `.m3u8`
|
|
308
|
+
- MP4, WebM, OGG (native fallback)
|
|
309
|
+
|
|
310
|
+
### 11. **plugins.js** - Plugin System
|
|
311
|
+
**Responsibility:** Extensible plugin architecture
|
|
312
|
+
|
|
313
|
+
**Main features:**
|
|
314
|
+
- Global plugin registry
|
|
315
|
+
- Automatic plugin initialization
|
|
316
|
+
- Plugin API with player access
|
|
317
|
+
- Plugin lifecycle management
|
|
318
|
+
|
|
319
|
+
**Global API:**
|
|
320
|
+
```javascript
|
|
321
|
+
// Global plugin registration
|
|
322
|
+
registerPlugin('myPlugin', function(player, options) {
|
|
323
|
+
// Plugin code
|
|
324
|
+
return {
|
|
325
|
+
name: 'myPlugin',
|
|
326
|
+
init: function() { /* ... */ },
|
|
327
|
+
destroy: function() { /* ... */ }
|
|
328
|
+
};
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Player API:**
|
|
333
|
+
- `initializePlugins()` - Load all registered plugins
|
|
334
|
+
- `registerPlugin(name, plugin)` - Register plugin (instance method)
|
|
335
|
+
- `getPlugin(name)` - Get plugin reference
|
|
336
|
+
- `unregisterPlugin(name)` - Remove plugin
|
|
337
|
+
|
|
338
|
+
**Plugin structure:**
|
|
339
|
+
```javascript
|
|
340
|
+
window.registerPlugin('example', function(player, options) {
|
|
341
|
+
return {
|
|
342
|
+
name: 'example',
|
|
343
|
+
version: '1.0.0',
|
|
344
|
+
init: function() {
|
|
345
|
+
console.log('Plugin initialized');
|
|
346
|
+
},
|
|
347
|
+
destroy: function() {
|
|
348
|
+
console.log('Plugin destroyed');
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### 12. **utils.js** - Utility Functions
|
|
355
|
+
**Responsibility:** Generic helper functions
|
|
356
|
+
|
|
357
|
+
**Utility methods:**
|
|
358
|
+
- `getBufferedTime()` - Get video buffering time
|
|
359
|
+
- `clearTitleTimeout()` - Clear title timeout
|
|
360
|
+
- `skipTime(seconds)` - Skip forward/backward N seconds
|
|
361
|
+
- `updateTimeDisplay()` - Update current time display
|
|
362
|
+
- `formatTime(seconds)` - Format seconds to HH:MM:SS
|
|
363
|
+
|
|
364
|
+
**Time format:**
|
|
365
|
+
- Duration < 1 hour: `M:SS`
|
|
366
|
+
- Duration >= 1 hour: `H:MM:SS`
|
|
367
|
+
|
|
368
|
+
### 13. **i18n.js** - Internationalization
|
|
369
|
+
**Responsibility:** Multi-language translation system
|
|
370
|
+
|
|
371
|
+
**Supported languages:**
|
|
372
|
+
- Italian (`it`)
|
|
373
|
+
- English (`en`)
|
|
374
|
+
- Spanish (`es`)
|
|
375
|
+
- French (`fr`)
|
|
376
|
+
- German (`de`)
|
|
377
|
+
- Portuguese (`pt`)
|
|
378
|
+
- Russian (`ru`)
|
|
379
|
+
- Chinese (`zh`)
|
|
380
|
+
- Japanese (`ja`)
|
|
381
|
+
- Arabic (`ar`)
|
|
382
|
+
|
|
383
|
+
**VideoPlayerI18n Class:**
|
|
384
|
+
```javascript
|
|
385
|
+
class VideoPlayerI18n {
|
|
386
|
+
constructor()
|
|
387
|
+
setLanguage(lang)
|
|
388
|
+
getCurrentLanguage()
|
|
389
|
+
t(key) // Translate key
|
|
390
|
+
getAvailableLanguages()
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Translation keys:**
|
|
395
|
+
- UI Controls: `play_pause`, `mute_unmute`, `volume`, `fullscreen`
|
|
396
|
+
- Subtitles: `subtitles`, `subtitlesenable`, `subtitlesdisable`
|
|
397
|
+
- Quality: `video_quality`, `auto`
|
|
398
|
+
- Playlist: `next_video`, `prev_video`, `playlist_next`, `playlist_prev`
|
|
399
|
+
|
|
400
|
+
## π§ Basic Usage
|
|
401
|
+
|
|
402
|
+
### Player Initialization
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
// HTML
|
|
406
|
+
<video id="myVideo" width="800" height="450">
|
|
407
|
+
<source src="video-1080p.mp4" data-quality="1080p" type="video/mp4">
|
|
408
|
+
<source src="video-720p.mp4" data-quality="720p" type="video/mp4">
|
|
409
|
+
<track kind="subtitles" src="subs-en.srt" srclang="en" label="English">
|
|
410
|
+
</video>
|
|
411
|
+
|
|
412
|
+
// JavaScript
|
|
413
|
+
const player = new MYETVvideoplayer('myVideo', {
|
|
414
|
+
showQualitySelector: true,
|
|
415
|
+
showSubtitles: true,
|
|
416
|
+
autoHide: true,
|
|
417
|
+
autoHideDelay: 3000,
|
|
418
|
+
language: 'en',
|
|
419
|
+
defaultQuality: 'auto',
|
|
420
|
+
watermarkUrl: 'logo.png',
|
|
421
|
+
watermarkPosition: 'bottomright',
|
|
422
|
+
chapters: [
|
|
423
|
+
{time: 0, title: "Intro"},
|
|
424
|
+
{time: 120, title: "Main Content"}
|
|
425
|
+
],
|
|
426
|
+
debug: true
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Custom Events
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
player.addEventListener('qualitychange', function(data) {
|
|
434
|
+
console.log('Quality changed to:', data.quality);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
player.addEventListener('subtitlechange', function(data) {
|
|
438
|
+
console.log('Subtitles:', data.enabled ? 'enabled' : 'disabled');
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
player.addEventListener('ended', function() {
|
|
442
|
+
console.log('Video ended');
|
|
443
|
+
});
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Programmatic API
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
// Playback control
|
|
450
|
+
player.play();
|
|
451
|
+
player.pause();
|
|
452
|
+
player.skipTime(10); // Forward 10 seconds
|
|
453
|
+
|
|
454
|
+
// Quality management
|
|
455
|
+
player.changeQuality('720p');
|
|
456
|
+
const qualities = player.getAvailableQualities();
|
|
457
|
+
|
|
458
|
+
// Subtitles
|
|
459
|
+
player.enableSubtitleTrack(0);
|
|
460
|
+
player.disableSubtitles();
|
|
461
|
+
|
|
462
|
+
// Fullscreen/PiP
|
|
463
|
+
player.toggleFullscreen();
|
|
464
|
+
player.enterPictureInPicture();
|
|
465
|
+
|
|
466
|
+
// Playlist
|
|
467
|
+
player.playNextVideo();
|
|
468
|
+
player.playPreviousVideo();
|
|
469
|
+
|
|
470
|
+
// Watermark
|
|
471
|
+
player.setWatermark('new-logo.png', 'https://link.com', 'topright');
|
|
472
|
+
player.removeWatermark();
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## π οΈ Development and Modification
|
|
476
|
+
|
|
477
|
+
### Adding a New Module
|
|
478
|
+
|
|
479
|
+
1. Create module file in `/src/newmodule.js`
|
|
480
|
+
2. Use standard format:
|
|
481
|
+
|
|
482
|
+
```javascript
|
|
483
|
+
// NewModule Module for MYETV Video Player
|
|
484
|
+
// Conservative modularization - original code preserved exactly
|
|
485
|
+
// Created by https://www.myetv.tv https://oskarcosimo.com
|
|
486
|
+
|
|
487
|
+
initializeNewFeature() {
|
|
488
|
+
// Initialization code
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
newMethod() {
|
|
492
|
+
// Public method
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Private helper methods (if needed)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
3. Add module to `build.js` in `moduleOrder` array:
|
|
499
|
+
|
|
500
|
+
```javascript
|
|
501
|
+
const moduleOrder = [
|
|
502
|
+
'core.js',
|
|
503
|
+
'events.js',
|
|
504
|
+
// ... other modules
|
|
505
|
+
'newmodule.js', // β New module
|
|
506
|
+
'utils.js'
|
|
507
|
+
];
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
4. Run build:
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
npm run build
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Modifying an Existing Module
|
|
517
|
+
|
|
518
|
+
1. Edit source file in `/src/`
|
|
519
|
+
2. Maintain existing method structure
|
|
520
|
+
3. Test locally
|
|
521
|
+
4. Rebuild:
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
npm run build
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Debug and Testing
|
|
528
|
+
|
|
529
|
+
Enable **debug mode** for detailed logs:
|
|
530
|
+
|
|
531
|
+
```javascript
|
|
532
|
+
const player = new MYETVvideoplayer('video', {
|
|
533
|
+
debug: true
|
|
534
|
+
});
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
Console output will provide:
|
|
538
|
+
- Module initialization
|
|
539
|
+
- Event triggers
|
|
540
|
+
- Loading errors
|
|
541
|
+
- Component status
|
|
542
|
+
|
|
543
|
+
## π License and Credits
|
|
544
|
+
|
|
545
|
+
- **Author:** MYETV - Oskar Cosimo
|
|
546
|
+
- **License:** MIT
|
|
547
|
+
- **Repository:** [github.com/OskarCosimo/myetv-video-player-opensource](https://github.com/OskarCosimo/myetv-video-player-opensource)
|
|
548
|
+
- **Website:** [myetv.tv](https://www.myetv.tv) | [oskarcosimo.com](https://oskarcosimo.com)
|
|
549
|
+
|
|
550
|
+
## π Useful Links
|
|
551
|
+
|
|
552
|
+
- **Dash.js Documentation:** [dashjs.org](https://dashjs.org)
|
|
553
|
+
- **HLS.js Documentation:** [github.com/video-dev/hls.js](https://github.com/video-dev/hls.js)
|
|
554
|
+
- **Sass Documentation:** [sass-lang.com](https://sass-lang.com)
|
|
555
|
+
- **HTML5 Video API:** [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement)
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
**Version for this document:** 1.0.0
|
|
560
|
+
**Last updated of this document:** October 2025
|
package/src/controls.js
CHANGED
|
@@ -59,6 +59,16 @@ initAutoHide() {
|
|
|
59
59
|
this.controls.addEventListener('mouseleave', (e) => {
|
|
60
60
|
if (this.autoHideDebug) {
|
|
61
61
|
if (this.options.debug) console.log('Mouse EXITS controls - restart timer');
|
|
62
|
+
|
|
63
|
+
// Touch events for mobile devices
|
|
64
|
+
this.container.addEventListener('touchstart', () => {
|
|
65
|
+
this.showControlsNow();
|
|
66
|
+
this.resetAutoHideTimer();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
this.container.addEventListener('touchend', () => {
|
|
70
|
+
this.resetAutoHideTimer();
|
|
71
|
+
});
|
|
62
72
|
}
|
|
63
73
|
this.onMouseLeaveControls(e);
|
|
64
74
|
});
|
|
@@ -102,7 +112,8 @@ resetAutoHideTimer() {
|
|
|
102
112
|
this.autoHideTimer = null;
|
|
103
113
|
}
|
|
104
114
|
|
|
105
|
-
|
|
115
|
+
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
116
|
+
if (this.mouseOverControls && !isTouchDevice) {
|
|
106
117
|
if (this.autoHideDebug) {
|
|
107
118
|
if (this.options.debug) console.log('Not starting timer - mouse on controls');
|
|
108
119
|
}
|
|
@@ -147,8 +158,9 @@ showControlsNow() {
|
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
hideControlsNow() {
|
|
150
|
-
// Don't hide if mouse is still over controls
|
|
151
|
-
|
|
161
|
+
// Don't hide if mouse is still over controls (allow hiding on touch devices)
|
|
162
|
+
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
163
|
+
if (this.mouseOverControls && !isTouchDevice) {
|
|
152
164
|
if (this.autoHideDebug && this.options.debug) console.log('βΈοΈ Not hiding - mouse still over controls');
|
|
153
165
|
return;
|
|
154
166
|
}
|
|
@@ -359,7 +371,7 @@ createControls() {
|
|
|
359
371
|
<span class="icon mute-icon hidden">π</span>
|
|
360
372
|
</button>
|
|
361
373
|
|
|
362
|
-
<div class="volume-container" data-
|
|
374
|
+
<div class="volume-container" data-mobile-slider="${this.options.volumeSlider}">
|
|
363
375
|
<input type="range" class="volume-slider" min="0" max="100" value="100" data-tooltip="volume">
|
|
364
376
|
</div>
|
|
365
377
|
|