vidply 1.0.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/LICENSE +22 -0
- package/README.md +461 -0
- package/dist/vidply.css +1717 -0
- package/dist/vidply.esm.js +5558 -0
- package/dist/vidply.esm.js.map +7 -0
- package/dist/vidply.esm.min.js +17 -0
- package/dist/vidply.esm.min.meta.json +336 -0
- package/dist/vidply.js +5575 -0
- package/dist/vidply.js.map +7 -0
- package/dist/vidply.min.css +6 -0
- package/dist/vidply.min.js +17 -0
- package/dist/vidply.min.meta.json +332 -0
- package/package.json +54 -0
- package/src/controls/CaptionManager.js +250 -0
- package/src/controls/ControlBar.js +1870 -0
- package/src/controls/KeyboardManager.js +196 -0
- package/src/controls/SettingsDialog.js +417 -0
- package/src/controls/TranscriptManager.js +728 -0
- package/src/core/Player.js +1108 -0
- package/src/features/PlaylistManager.js +437 -0
- package/src/i18n/i18n.js +66 -0
- package/src/i18n/translations.js +511 -0
- package/src/icons/Icons.js +183 -0
- package/src/index.js +34 -0
- package/src/renderers/HLSRenderer.js +302 -0
- package/src/renderers/HTML5Renderer.js +298 -0
- package/src/renderers/VimeoRenderer.js +257 -0
- package/src/renderers/YouTubeRenderer.js +274 -0
- package/src/styles/vidply.css +1711 -0
- package/src/utils/DOMUtils.js +154 -0
- package/src/utils/EventEmitter.js +53 -0
- package/src/utils/TimeUtils.js +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
GNU GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 2, June 1991
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2025 Matthias Peltzer
|
|
5
|
+
|
|
6
|
+
This program is free software; you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU General Public License as published by
|
|
8
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
This program is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU General Public License along
|
|
17
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
18
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
Full license text: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
package/README.md
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# <img src="favicon.svg" width="32" alt="VidPly" /> VidPly
|
|
2
|
+
|
|
3
|
+
**Universal, Accessible Video & Audio Player**
|
|
4
|
+
|
|
5
|
+
A modern, feature-rich video player built with vanilla ES6 JavaScript. Combines the best accessibility features from AblePlayer with the streaming capabilities of MediaElement.js.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
### Core Media Support
|
|
14
|
+
- **Audio & Video Playback** - Native HTML5 support
|
|
15
|
+
- **Multiple Formats** - MP3, OGG, WAV, MP4, WebM
|
|
16
|
+
- **YouTube Integration** - Embed with unified controls
|
|
17
|
+
- **Vimeo Integration** - Seamless Vimeo support
|
|
18
|
+
- **HLS Streaming** - Adaptive bitrate streaming
|
|
19
|
+
- **Playlists** - Audio/video playlist support
|
|
20
|
+
|
|
21
|
+
### Accessibility Features
|
|
22
|
+
- **Full Keyboard Navigation** - WCAG 2.1 compliant
|
|
23
|
+
- **Screen Reader Support** - Complete ARIA labels
|
|
24
|
+
- **Customizable Shortcuts** - User-definable hotkeys
|
|
25
|
+
- **High Contrast Mode** - Windows HCM support
|
|
26
|
+
- **Focus Indicators** - Clear visual focus states
|
|
27
|
+
- **Live Announcements** - Screen reader updates
|
|
28
|
+
|
|
29
|
+
### Captions & Subtitles
|
|
30
|
+
- **WebVTT Support** - Standard caption format
|
|
31
|
+
- **Multiple Languages** - Multi-track support
|
|
32
|
+
- **Customizable Display** - Font, size, color, opacity
|
|
33
|
+
- **Caption Positioning** - Flexible placement
|
|
34
|
+
- **Auto-generated Transcripts** - Interactive text
|
|
35
|
+
|
|
36
|
+
### Playback Features
|
|
37
|
+
- **Adjustable Speed** - 0.25x to 2x playback
|
|
38
|
+
- **Seek Controls** - Forward/backward navigation
|
|
39
|
+
- **Volume Control** - 0-100% with mute
|
|
40
|
+
- **Loop Playback** - Single or playlist loop
|
|
41
|
+
- **Fullscreen Mode** - Native fullscreen API
|
|
42
|
+
- **Picture-in-Picture** - PiP support
|
|
43
|
+
|
|
44
|
+
### Internationalization
|
|
45
|
+
Built-in support for:
|
|
46
|
+
- English
|
|
47
|
+
- Spanish
|
|
48
|
+
- French
|
|
49
|
+
- German
|
|
50
|
+
- Japanese
|
|
51
|
+
- Easy to add more languages
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
### Build from Source
|
|
56
|
+
|
|
57
|
+
First, build the player:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Install dependencies
|
|
61
|
+
npm install
|
|
62
|
+
|
|
63
|
+
# Build production files
|
|
64
|
+
npm run build
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This creates minified files in the `dist/` folder.
|
|
68
|
+
|
|
69
|
+
### Option 1: Using Built Files (Recommended for Production)
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<!DOCTYPE html>
|
|
73
|
+
<html>
|
|
74
|
+
<head>
|
|
75
|
+
<link rel="stylesheet" href="dist/vidply.min.css">
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<video data-vidply src="video.mp4" width="800" height="450">
|
|
79
|
+
<track kind="subtitles" src="captions.vtt" srclang="en" label="English">
|
|
80
|
+
</video>
|
|
81
|
+
|
|
82
|
+
<script type="module">
|
|
83
|
+
import Player from './dist/vidply.esm.min.js';
|
|
84
|
+
// Auto-initialized via data-vidply attribute
|
|
85
|
+
</script>
|
|
86
|
+
</body>
|
|
87
|
+
</html>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Option 2: Traditional Script Tag (IIFE)
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<link rel="stylesheet" href="dist/vidply.min.css">
|
|
94
|
+
<script src="dist/vidply.min.js"></script>
|
|
95
|
+
|
|
96
|
+
<video id="my-video" src="video.mp4"></video>
|
|
97
|
+
|
|
98
|
+
<script>
|
|
99
|
+
const player = new VidPly.Player('#my-video', {
|
|
100
|
+
controls: true,
|
|
101
|
+
autoplay: false,
|
|
102
|
+
volume: 0.8,
|
|
103
|
+
language: 'en'
|
|
104
|
+
});
|
|
105
|
+
</script>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Option 3: Development (Source Files)
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
import Player from './src/index.js';
|
|
112
|
+
|
|
113
|
+
const player = new Player('#my-video', {
|
|
114
|
+
controls: true,
|
|
115
|
+
autoplay: false,
|
|
116
|
+
volume: 0.8,
|
|
117
|
+
language: 'en'
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Quick Start
|
|
122
|
+
|
|
123
|
+
### 1. Build the Player
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install
|
|
127
|
+
npm run build
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 2. Add to Your Page
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<link rel="stylesheet" href="dist/vidply.min.css">
|
|
134
|
+
<script type="module">
|
|
135
|
+
import Player from './dist/vidply.esm.min.js';
|
|
136
|
+
</script>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 3. Create a Video Player
|
|
140
|
+
|
|
141
|
+
```html
|
|
142
|
+
<video data-vidply width="800" height="450">
|
|
143
|
+
<source src="video.mp4" type="video/mp4">
|
|
144
|
+
<track kind="subtitles" src="captions-en.vtt" srclang="en" label="English">
|
|
145
|
+
<track kind="subtitles" src="captions-es.vtt" srclang="es" label="Español">
|
|
146
|
+
</video>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
That's it! The player auto-initializes.
|
|
150
|
+
|
|
151
|
+
### YouTube Player
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<video data-vidply src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Vimeo Player
|
|
158
|
+
|
|
159
|
+
```html
|
|
160
|
+
<video data-vidply src="https://vimeo.com/VIDEO_ID"></video>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Audio Player
|
|
164
|
+
|
|
165
|
+
```html
|
|
166
|
+
<audio data-vidply>
|
|
167
|
+
<source src="audio.mp3" type="audio/mpeg">
|
|
168
|
+
</audio>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### HLS Streaming
|
|
172
|
+
|
|
173
|
+
```html
|
|
174
|
+
<video data-vidply src="https://example.com/stream.m3u8"></video>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Configuration Options
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
const player = new Player('#video', {
|
|
181
|
+
// Display
|
|
182
|
+
width: 800,
|
|
183
|
+
height: 450,
|
|
184
|
+
poster: 'poster.jpg',
|
|
185
|
+
responsive: true,
|
|
186
|
+
|
|
187
|
+
// Playback
|
|
188
|
+
autoplay: false,
|
|
189
|
+
loop: false,
|
|
190
|
+
muted: false,
|
|
191
|
+
volume: 0.8,
|
|
192
|
+
playbackSpeed: 1.0,
|
|
193
|
+
startTime: 0,
|
|
194
|
+
|
|
195
|
+
// Controls
|
|
196
|
+
controls: true,
|
|
197
|
+
hideControlsDelay: 3000,
|
|
198
|
+
playPauseButton: true,
|
|
199
|
+
progressBar: true,
|
|
200
|
+
volumeControl: true,
|
|
201
|
+
speedButton: true,
|
|
202
|
+
captionsButton: true,
|
|
203
|
+
fullscreenButton: true,
|
|
204
|
+
pipButton: true,
|
|
205
|
+
|
|
206
|
+
// Captions
|
|
207
|
+
captions: true,
|
|
208
|
+
captionsDefault: false,
|
|
209
|
+
captionsFontSize: '100%',
|
|
210
|
+
captionsFontFamily: 'sans-serif',
|
|
211
|
+
captionsColor: '#FFFFFF',
|
|
212
|
+
captionsBackgroundColor: '#000000',
|
|
213
|
+
captionsOpacity: 0.8,
|
|
214
|
+
|
|
215
|
+
// Keyboard
|
|
216
|
+
keyboard: true,
|
|
217
|
+
keyboardShortcuts: {
|
|
218
|
+
'play-pause': [' ', 'p', 'k'],
|
|
219
|
+
'seek-forward': ['ArrowRight', 'l'],
|
|
220
|
+
'seek-backward': ['ArrowLeft', 'j'],
|
|
221
|
+
'volume-up': ['ArrowUp'],
|
|
222
|
+
'volume-down': ['ArrowDown'],
|
|
223
|
+
'mute': ['m'],
|
|
224
|
+
'fullscreen': ['f'],
|
|
225
|
+
'captions': ['c']
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
// Accessibility
|
|
229
|
+
screenReaderAnnouncements: true,
|
|
230
|
+
focusHighlight: true,
|
|
231
|
+
|
|
232
|
+
// Internationalization
|
|
233
|
+
language: 'en',
|
|
234
|
+
|
|
235
|
+
// Callbacks
|
|
236
|
+
onReady: () => console.log('Ready!'),
|
|
237
|
+
onPlay: () => console.log('Playing!'),
|
|
238
|
+
onPause: () => console.log('Paused!'),
|
|
239
|
+
onEnded: () => console.log('Ended!'),
|
|
240
|
+
|
|
241
|
+
// Advanced
|
|
242
|
+
debug: false,
|
|
243
|
+
pauseOthersOnPlay: true
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Keyboard Shortcuts
|
|
248
|
+
|
|
249
|
+
| Key | Action |
|
|
250
|
+
|-----|--------|
|
|
251
|
+
| <kbd>Space</kbd> / <kbd>K</kbd> | Play/Pause |
|
|
252
|
+
| <kbd>F</kbd> | Toggle Fullscreen |
|
|
253
|
+
| <kbd>M</kbd> | Mute/Unmute |
|
|
254
|
+
| <kbd>↑</kbd> / <kbd>↓</kbd> | Volume Up/Down |
|
|
255
|
+
| <kbd>←</kbd> / <kbd>→</kbd> | Seek -10s / +10s |
|
|
256
|
+
| <kbd>J</kbd> / <kbd>L</kbd> | Seek -30s / +30s |
|
|
257
|
+
| <kbd>C</kbd> | Toggle Captions |
|
|
258
|
+
| <kbd><</kbd> / <kbd>></kbd> | Decrease/Increase Speed |
|
|
259
|
+
| <kbd>S</kbd> | Open Settings |
|
|
260
|
+
|
|
261
|
+
## API Reference
|
|
262
|
+
|
|
263
|
+
### Playback Control
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
player.play() // Start playback
|
|
267
|
+
player.pause() // Pause playback
|
|
268
|
+
player.stop() // Stop and reset
|
|
269
|
+
player.toggle() // Toggle play/pause
|
|
270
|
+
player.seek(30) // Seek to 30 seconds
|
|
271
|
+
player.seekForward(10) // Skip forward 10 seconds
|
|
272
|
+
player.seekBackward(10) // Skip backward 10 seconds
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Volume Control
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
player.setVolume(0.5) // Set volume (0-1)
|
|
279
|
+
player.getVolume() // Get current volume
|
|
280
|
+
player.mute() // Mute audio
|
|
281
|
+
player.unmute() // Unmute audio
|
|
282
|
+
player.toggleMute() // Toggle mute state
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Playback Speed
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
player.setPlaybackSpeed(1.5) // Set speed (0.25-2.0)
|
|
289
|
+
player.getPlaybackSpeed() // Get current speed
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Fullscreen
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
player.enterFullscreen() // Enter fullscreen
|
|
296
|
+
player.exitFullscreen() // Exit fullscreen
|
|
297
|
+
player.toggleFullscreen() // Toggle fullscreen
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Captions
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
player.enableCaptions() // Enable captions
|
|
304
|
+
player.disableCaptions() // Disable captions
|
|
305
|
+
player.toggleCaptions() // Toggle captions
|
|
306
|
+
|
|
307
|
+
// Switch between caption tracks
|
|
308
|
+
player.captionManager.switchTrack(0) // Switch to first track
|
|
309
|
+
player.captionManager.getAvailableTracks() // Get all tracks
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Settings
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
player.showSettings() // Open settings dialog
|
|
316
|
+
player.hideSettings() // Close settings dialog
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### State Information
|
|
320
|
+
|
|
321
|
+
```javascript
|
|
322
|
+
player.getCurrentTime() // Get current time
|
|
323
|
+
player.getDuration() // Get duration
|
|
324
|
+
player.isPlaying() // Check if playing
|
|
325
|
+
player.isPaused() // Check if paused
|
|
326
|
+
player.isEnded() // Check if ended
|
|
327
|
+
player.isMuted() // Check if muted
|
|
328
|
+
player.isFullscreen() // Check if fullscreen
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Event Listeners
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
player.on('ready', () => {})
|
|
335
|
+
player.on('play', () => {})
|
|
336
|
+
player.on('pause', () => {})
|
|
337
|
+
player.on('ended', () => {})
|
|
338
|
+
player.on('timeupdate', (time) => {})
|
|
339
|
+
player.on('volumechange', (volume) => {})
|
|
340
|
+
player.on('playbackspeedchange', (speed) => {})
|
|
341
|
+
player.on('fullscreenchange', (isFullscreen) => {})
|
|
342
|
+
player.on('captionsenabled', (track) => {})
|
|
343
|
+
player.on('captionsdisabled', () => {})
|
|
344
|
+
player.on('error', (error) => {})
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Cleanup
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
player.destroy() // Remove player and cleanup
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Customization
|
|
354
|
+
|
|
355
|
+
### Custom Styling
|
|
356
|
+
|
|
357
|
+
```css
|
|
358
|
+
/* Override default colors */
|
|
359
|
+
.vidply-player {
|
|
360
|
+
--vidply-primary-color: #3b82f6;
|
|
361
|
+
--vidply-background: rgba(0, 0, 0, 0.8);
|
|
362
|
+
--vidply-text-color: #ffffff;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* Custom progress bar */
|
|
366
|
+
.vidply-progress-played {
|
|
367
|
+
background: linear-gradient(90deg, #667eea, #764ba2);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* Custom buttons */
|
|
371
|
+
.vidply-button:hover {
|
|
372
|
+
background: rgba(59, 130, 246, 0.2);
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Add Custom Language
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
import { i18n } from './src/i18n/i18n.js';
|
|
380
|
+
|
|
381
|
+
i18n.addTranslation('pt', {
|
|
382
|
+
player: {
|
|
383
|
+
play: 'Reproduzir',
|
|
384
|
+
pause: 'Pausar',
|
|
385
|
+
// ... more translations
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
i18n.setLanguage('pt');
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## 🔧 Build Process
|
|
393
|
+
|
|
394
|
+
VidPly uses a modern build system with esbuild for JavaScript and clean-css for CSS.
|
|
395
|
+
|
|
396
|
+
### Available Scripts
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
npm run build # Build everything (JS + CSS)
|
|
400
|
+
npm run build:js # Build JavaScript only
|
|
401
|
+
npm run build:css # Build CSS only
|
|
402
|
+
npm run watch # Watch mode for development
|
|
403
|
+
npm run clean # Clean dist directory
|
|
404
|
+
npm run dev # Start dev server
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Output Files
|
|
408
|
+
|
|
409
|
+
- `dist/vidply.esm.js` - ES Module (development)
|
|
410
|
+
- `dist/vidply.esm.min.js` - ES Module (production)
|
|
411
|
+
- `dist/vidply.js` - IIFE (development)
|
|
412
|
+
- `dist/vidply.min.js` - IIFE (production)
|
|
413
|
+
- `dist/vidply.css` - Styles (unminified)
|
|
414
|
+
- `dist/vidply.min.css` - Styles (minified)
|
|
415
|
+
|
|
416
|
+
See [BUILD.md](docs/BUILD.md) for detailed build documentation.
|
|
417
|
+
|
|
418
|
+
## Browser Support
|
|
419
|
+
|
|
420
|
+
- Chrome 90+
|
|
421
|
+
- Firefox 88+
|
|
422
|
+
- Safari 14+
|
|
423
|
+
- Edge 90+
|
|
424
|
+
- iOS Safari 14+
|
|
425
|
+
- Android Chrome 90+
|
|
426
|
+
|
|
427
|
+
## License
|
|
428
|
+
|
|
429
|
+
GNU General Public License v2.0 or later
|
|
430
|
+
|
|
431
|
+
Copyright (C) 2024 Matthias Peltzer
|
|
432
|
+
|
|
433
|
+
This program is free software; you can redistribute it and/or modify
|
|
434
|
+
it under the terms of the GNU General Public License as published by
|
|
435
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
436
|
+
(at your option) any later version.
|
|
437
|
+
|
|
438
|
+
See [LICENSE](LICENSE) for full license text.
|
|
439
|
+
|
|
440
|
+
## Contributing
|
|
441
|
+
|
|
442
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
443
|
+
|
|
444
|
+
## Support
|
|
445
|
+
|
|
446
|
+
- Getting Started: See [GETTING_STARTED.md](docs/GETTING_STARTED.md)
|
|
447
|
+
- Usage Examples: See [USAGE.md](docs/USAGE.md)
|
|
448
|
+
- Playlist Guide: See [PLAYLIST.md](docs/PLAYLIST.md)
|
|
449
|
+
- Build Guide: See [BUILD.md](docs/BUILD.md)
|
|
450
|
+
- Issues: Report on GitHub
|
|
451
|
+
- Discussions: GitHub Discussions
|
|
452
|
+
|
|
453
|
+
## Credits
|
|
454
|
+
|
|
455
|
+
Inspired by:
|
|
456
|
+
- [AblePlayer](https://github.com/ableplayer/ableplayer) - Accessibility features
|
|
457
|
+
- [MediaElement.js](https://github.com/mediaelement/mediaelement) - Streaming support
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
Made with Vanilla JavaScript by Matthias Peltzer
|