vidply 1.0.31 → 1.0.32

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 CHANGED
@@ -1,708 +1,708 @@
1
- # <img src="favicon.svg" width="32" alt="VidPly" /> VidPly
2
-
3
- **Universal, Accessible Video & Audio Player**
4
-
5
- A modern, feature-rich media player built with vanilla ES6 JavaScript. Combines the best accessibility features from AblePlayer with the streaming capabilities of MediaElement.js. Fully internationalized with support for 5 languages and complete WCAG 2.1 AA compliance.
6
-
7
- ![License](https://img.shields.io/badge/license-GPL--2.0--or--later-blue.svg)
8
- ![ES6](https://img.shields.io/badge/ES6-Module-yellow.svg)
9
- ![WCAG](https://img.shields.io/badge/WCAG-2.1%20AA-green.svg)
10
- ![Version](https://img.shields.io/badge/version-1.0.18-brightgreen.svg)
11
-
12
- ## Live Demos
13
-
14
- Try VidPly in action:
15
- - **[Main Demo](https://matthiaspeltzer.github.io/vidply/demo/demo.html)** - Full-featured video player showcase
16
- - **[Audio Playlist](https://matthiaspeltzer.github.io/vidply/demo/playlist-audio.html)** - Audio player with playlist support
17
- - **[Video Playlist](https://matthiaspeltzer.github.io/vidply/demo/playlist-video.html)** - Video playlist with thumbnails
18
- - **[HLS Streaming](https://matthiaspeltzer.github.io/vidply/demo/hls-test.html)** - Adaptive bitrate streaming demo
19
-
20
- ## Why VidPly?
21
-
22
- - **Zero Dependencies** - Pure vanilla JavaScript, no frameworks required
23
- - **Accessibility First** - WCAG 2.1 AA compliant with full keyboard and screen reader support
24
- - **Multilingual** - Built-in translations for 5 languages with easy extensibility
25
- - **Fully Customizable** - CSS variables and comprehensive API
26
- - **Modern Build** - ES6 modules with tree-shaking support
27
- - **Production Ready** - Thoroughly tested with real-world media content
28
-
29
- ## Features
30
-
31
- ### Core Media Support
32
- - **Audio & Video Playback** - Native HTML5 support for both media types
33
- - **Multiple Formats** - MP3, OGG, WAV (audio) / MP4, WebM (video)
34
- - **YouTube Integration** - Embed YouTube videos with unified controls
35
- - **Vimeo Integration** - Seamless Vimeo player integration
36
- - **HLS Streaming** - Adaptive bitrate streaming with quality selection
37
- - **Playlists** - Full playlist support with auto-advance and navigation
38
- - Audio playlists with track info
39
- - Video playlists with thumbnails
40
- - Previous/Next controls
41
- - Visual playlist panel
42
- - **Fullscreen Mode**: YouTube-style horizontal carousel
43
- - Auto-show/hide based on playback state
44
- - Swipeable touch interface
45
- - Responsive card layout
46
-
47
- ### Accessibility Features (WCAG 2.1 AA Compliant)
48
- - **Full Keyboard Navigation** - All features accessible via keyboard, custom shortcuts, menu navigation with Arrow keys
49
- - **Screen Reader Support** - Complete ARIA labels (`aria-controls`, `aria-expanded`, `aria-haspopup`), live regions
50
- - **Interactive Transcripts** - Click-to-seek, searchable, auto-scroll with proper semantic HTML
51
- - **Sign Language Overlay** - Picture-in-picture with drag/resize, keyboard accessible
52
- - **Audio Description** - Alternate audio track with visual content descriptions
53
- - **Caption Styling** - Fully customizable (font, size, color, opacity, edge style)
54
- - **High Contrast Mode** - Windows HCM support, color-independent design
55
- - **Focus Management** - Logical focus order, programmatic focus handling, visible indicators
56
- - **Touch Accessibility** - 44x44px minimum touch targets, swipeable interfaces
57
-
58
- ### Captions & Subtitles
59
- - **WebVTT Support** - Standard caption format
60
- - **Multiple Languages** - Multi-track support
61
- - **Caption Selector** - Easy track switching with CC button
62
- - **Caption Styling** - Dedicated styling menu (font, size, color, opacity)
63
- - **Chapter Navigation** - Jump to video chapters
64
- - **Interactive Transcripts** - Full-text searchable transcript panel
65
-
66
- ### Playback Features
67
- - **Adjustable Speed** - 0.25x to 2x playback
68
- - **Seek Controls** - Forward/backward navigation
69
- - **Volume Control** - 0-100% with mute
70
- - **Loop Playback** - Single or playlist loop
71
- - **Fullscreen Mode** - Native fullscreen API with smart playlist overlay
72
- - **Picture-in-Picture** - PiP support
73
-
74
- ### Internationalization
75
- Built-in support for 5 languages:
76
- - English (en)
77
- - Spanish (es) - Español
78
- - French (fr) - Français
79
- - German (de) - Deutsch
80
- - Japanese (ja) - 日本語
81
-
82
- All UI elements are fully translated, including:
83
- - Control buttons and menus
84
- - Time display and duration formatting
85
- - Keyboard shortcuts
86
- - Error messages and notifications
87
- - ARIA labels for screen readers
88
-
89
- **Custom Translations**: Easily add your own languages by loading JSON or YAML translation files via data attributes or JavaScript options. The player automatically detects the HTML `lang` attribute and loads matching translations.
90
-
91
- ## Installation
92
-
93
- ### Build from Source
94
-
95
- First, build the player:
96
-
97
- ```bash
98
- # Install dependencies
99
- npm install
100
-
101
- # Build production files
102
- npm run build
103
- ```
104
-
105
- This creates minified files in the `dist/` folder.
106
-
107
- ### Option 1: Using Built Files (Recommended for Production)
108
-
109
- ```html
110
- <!DOCTYPE html>
111
- <html>
112
- <head>
113
- <link rel="stylesheet" href="dist/vidply.min.css">
114
- </head>
115
- <body>
116
- <video data-vidply src="video.mp4" width="800" height="450">
117
- <track kind="subtitles" src="captions.vtt" srclang="en" label="English">
118
- </video>
119
-
120
- <script type="module">
121
- import Player from './dist/vidply.esm.min.js';
122
- // Auto-initialized via data-vidply attribute
123
- </script>
124
- </body>
125
- </html>
126
- ```
127
-
128
- ### Option 2: Traditional Script Tag (IIFE)
129
-
130
- ```html
131
- <link rel="stylesheet" href="dist/vidply.min.css">
132
- <script src="dist/vidply.min.js"></script>
133
-
134
- <video id="my-video" src="video.mp4"></video>
135
-
136
- <script>
137
- const player = new VidPly.Player('#my-video', {
138
- controls: true,
139
- autoplay: false,
140
- volume: 0.8,
141
- language: 'en'
142
- });
143
- </script>
144
- ```
145
-
146
- ### Option 3: Development (Source Files)
147
-
148
- ```javascript
149
- import Player from './src/index.js';
150
-
151
- const player = new Player('#my-video', {
152
- controls: true,
153
- autoplay: false,
154
- volume: 0.8,
155
- language: 'en'
156
- });
157
- ```
158
-
159
- ## Quick Start
160
-
161
- ### 1. Build the Player
162
-
163
- ```bash
164
- npm install
165
- npm run build
166
- ```
167
-
168
- ### 2. Add to Your Page
169
-
170
- ```html
171
- <link rel="stylesheet" href="dist/vidply.min.css">
172
- <script type="module">
173
- import Player from './dist/vidply.esm.min.js';
174
- </script>
175
- ```
176
-
177
- ### 3. Create a Video Player
178
-
179
- ```html
180
- <video data-vidply width="800" height="450">
181
- <source src="video.mp4" type="video/mp4">
182
- <track kind="subtitles" src="captions-en.vtt" srclang="en" label="English">
183
- <track kind="subtitles" src="captions-es.vtt" srclang="es" label="Español">
184
- </video>
185
- ```
186
-
187
- That's it! The player auto-initializes.
188
-
189
- ### YouTube Player
190
-
191
- ```html
192
- <video data-vidply src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
193
- ```
194
-
195
- ### Vimeo Player
196
-
197
- ```html
198
- <video data-vidply src="https://vimeo.com/VIDEO_ID"></video>
199
- ```
200
-
201
- ### Audio Player
202
-
203
- ```html
204
- <audio data-vidply>
205
- <source src="audio.mp3" type="audio/mpeg">
206
- </audio>
207
- ```
208
-
209
- ### HLS Streaming
210
-
211
- ```html
212
- <video data-vidply src="https://example.com/stream.m3u8"></video>
213
- ```
214
-
215
- ## Configuration Options
216
-
217
- ```javascript
218
- const player = new Player('#video', {
219
- // Display
220
- width: 800,
221
- height: 450,
222
- poster: 'poster.jpg',
223
- responsive: true,
224
-
225
- // Playback
226
- autoplay: false,
227
- loop: false,
228
- muted: false,
229
- volume: 0.8,
230
- playbackSpeed: 1.0,
231
- startTime: 0,
232
-
233
- // Controls
234
- controls: true,
235
- hideControlsDelay: 3000,
236
- playPauseButton: true,
237
- progressBar: true,
238
- volumeControl: true,
239
- chaptersButton: true,
240
- qualityButton: true,
241
- captionStyleButton: true,
242
- speedButton: true,
243
- captionsButton: true,
244
- transcriptButton: true,
245
- audioDescriptionButton: true,
246
- signLanguageButton: true,
247
- fullscreenButton: true,
248
- pipButton: true,
249
-
250
- // Captions
251
- captions: true,
252
- captionsDefault: false,
253
- captionsFontSize: '100%',
254
- captionsFontFamily: 'sans-serif',
255
- captionsColor: '#FFFFFF',
256
- captionsBackgroundColor: '#000000',
257
- captionsOpacity: 0.8,
258
-
259
- // Audio Description
260
- audioDescription: true,
261
- audioDescriptionSrc: null, // URL to audio-described version
262
- audioDescriptionButton: true,
263
-
264
- // Sign Language
265
- signLanguage: true,
266
- signLanguageSrc: null, // URL to sign language video
267
- signLanguageButton: true,
268
- signLanguagePosition: 'bottom-right', // 'bottom-right', 'bottom-left', 'top-right', 'top-left'
269
-
270
- // Transcripts
271
- transcript: false,
272
- transcriptButton: true,
273
- transcriptPosition: 'external',
274
- transcriptContainer: null,
275
-
276
- // Keyboard
277
- keyboard: true,
278
- keyboardShortcuts: {
279
- 'play-pause': [' ', 'p', 'k'],
280
- 'seek-forward': ['ArrowRight', 'l'],
281
- 'seek-backward': ['ArrowLeft', 'j'],
282
- 'volume-up': ['ArrowUp'],
283
- 'volume-down': ['ArrowDown'],
284
- 'mute': ['m'],
285
- 'fullscreen': ['f'],
286
- 'captions': ['c']
287
- },
288
-
289
- // Accessibility
290
- screenReaderAnnouncements: true,
291
- focusHighlight: true,
292
-
293
- // Internationalization
294
- language: 'en',
295
-
296
- // Callbacks
297
- onReady: () => console.log('Ready!'),
298
- onPlay: () => console.log('Playing!'),
299
- onPause: () => console.log('Paused!'),
300
- onEnded: () => console.log('Ended!'),
301
-
302
- // Advanced
303
- debug: false,
304
- pauseOthersOnPlay: true
305
- });
306
- ```
307
-
308
- ## Keyboard Shortcuts
309
-
310
- | Key | Action |
311
- |-----|--------|
312
- | <kbd>Space</kbd> / <kbd>P</kbd> / <kbd>K</kbd> | Play/Pause |
313
- | <kbd>F</kbd> | Toggle Fullscreen |
314
- | <kbd>M</kbd> | Mute/Unmute |
315
- | <kbd>↑</kbd> / <kbd>↓</kbd> | Volume Up/Down |
316
- | <kbd>←</kbd> / <kbd>→</kbd> | Seek -10s / +10s |
317
- | <kbd>C</kbd> | Toggle Captions (or open menu if multiple) |
318
- | <kbd>A</kbd> | Open Caption Style Menu |
319
- | <kbd><</kbd> / <kbd>></kbd> | Decrease/Increase Speed |
320
- | <kbd>S</kbd> | Open Speed Menu |
321
- | <kbd>Q</kbd> | Open Quality Menu |
322
- | <kbd>J</kbd> | Open Chapters Menu |
323
- | <kbd>T</kbd> | Toggle Transcript |
324
- | <kbd>D</kbd> | Toggle Drag Mode (Transcript/Sign Language) |
325
- | <kbd>R</kbd> | Toggle Resize Mode (Transcript/Sign Language) |
326
- | <kbd>Escape</kbd> | Exit Drag/Resize Mode or Close Menus |
327
- | <kbd>Home</kbd> | Reset Transcript/Sign Language Position |
328
-
329
- ## API Reference
330
-
331
- ### Playback Control
332
-
333
- ```javascript
334
- player.play() // Start playback
335
- player.pause() // Pause playback
336
- player.stop() // Stop and reset
337
- player.toggle() // Toggle play/pause
338
- player.seek(30) // Seek to 30 seconds
339
- player.seekForward(10) // Skip forward 10 seconds
340
- player.seekBackward(10) // Skip backward 10 seconds
341
- ```
342
-
343
- ### Volume Control
344
-
345
- ```javascript
346
- player.setVolume(0.5) // Set volume (0.0-1.0)
347
- player.getVolume() // Get current volume
348
- player.mute() // Mute audio
349
- player.unmute() // Unmute audio
350
- player.toggleMute() // Toggle mute state
351
- ```
352
-
353
- **Note on Mobile Devices:** On touch devices (iOS, Android, tablets), only a **mute/unmute button** is shown instead of the volume slider. Mobile browsers control HTML5 video volume through **hardware device volume buttons** - this is standard behavior that cannot be overridden by web apps for security reasons. The mute button provides quick silencing functionality while hardware buttons control actual volume levels.
354
-
355
- ### Playback Speed
356
-
357
- ```javascript
358
- player.setPlaybackSpeed(1.5) // Set speed (0.25-2.0)
359
- player.getPlaybackSpeed() // Get current speed
360
- ```
361
-
362
- ### Fullscreen
363
-
364
- ```javascript
365
- player.enterFullscreen() // Enter fullscreen
366
- player.exitFullscreen() // Exit fullscreen
367
- player.toggleFullscreen() // Toggle fullscreen
368
- ```
369
-
370
- **Note on iOS/Mobile Safari:** Since iOS doesn't support the Fullscreen API on container elements, VidPly automatically falls back to a "pseudo-fullscreen" mode that positions the player to fill the entire viewport using CSS. This provides a fullscreen-like experience on iOS devices while maintaining all player functionality.
371
-
372
- ### Captions
373
-
374
- ```javascript
375
- player.enableCaptions() // Enable captions
376
- player.disableCaptions() // Disable captions
377
- player.toggleCaptions() // Toggle captions
378
-
379
- // Switch between caption tracks
380
- player.captionManager.switchTrack(0) // Switch to first track
381
- player.captionManager.getAvailableTracks() // Get all tracks
382
- ```
383
-
384
- ### Transcript
385
-
386
- ```javascript
387
- // Show/Hide Transcript
388
- player.transcriptManager.showTranscript() // Show transcript window
389
- player.transcriptManager.hideTranscript() // Hide transcript window
390
- player.transcriptManager.toggleTranscript() // Toggle transcript visibility
391
-
392
- // Drag & Resize Modes (Desktop only, mobile breakpoint: 768px)
393
- player.transcriptManager.toggleKeyboardDragMode() // Toggle drag mode (D key)
394
- player.transcriptManager.togglePointerResizeMode() // Toggle resize mode (R key)
395
-
396
- // Settings Menu
397
- player.transcriptManager.showSettingsMenu() // Show settings dropdown
398
- player.transcriptManager.hideSettingsMenu() // Hide settings dropdown
399
-
400
- // Check State
401
- if (player.transcriptManager.isVisible) {
402
- console.log('Transcript is visible');
403
- }
404
- ```
405
-
406
- ### Audio Description
407
-
408
- ```javascript
409
- player.enableAudioDescription() // Switch to described version
410
- player.disableAudioDescription() // Switch back to original
411
- player.toggleAudioDescription() // Toggle audio description
412
- ```
413
-
414
- ### Sign Language
415
-
416
- ```javascript
417
- // Show/Hide Sign Language Video
418
- player.enableSignLanguage() // Show sign language overlay
419
- player.disableSignLanguage() // Hide sign language overlay
420
- player.toggleSignLanguage() // Toggle sign language
421
-
422
- // Multi-Language Support
423
- player.switchSignLanguage('de') // Switch to German sign language
424
-
425
- // Drag & Resize (available via settings menu or keyboard)
426
- // D key - Toggle drag mode with arrow keys
427
- // R key - Toggle resize mode (shows resize handles)
428
- // Home key - Reset position
429
- // Escape - Exit drag/resize mode
430
- ```
431
-
432
- ### Playlists
433
-
434
- ```javascript
435
- import { Player, PlaylistManager } from './dist/vidply.esm.js';
436
-
437
- // Create player
438
- const player = new Player('#my-player');
439
-
440
- // Create playlist manager
441
- const playlist = new PlaylistManager(player, {
442
- autoAdvance: true, // Auto-play next track
443
- loop: false, // Loop back to start
444
- showPanel: true // Show playlist UI
445
- });
446
-
447
- // Load tracks
448
- playlist.loadPlaylist([
449
- {
450
- src: 'track1.mp3',
451
- title: 'Track 1',
452
- artist: 'Artist Name',
453
- poster: 'thumb1.jpg'
454
- },
455
- {
456
- src: 'track2.mp3',
457
- title: 'Track 2',
458
- artist: 'Artist Name',
459
- tracks: [
460
- { src: 'captions.vtt', kind: 'captions', srclang: 'en' }
461
- ]
462
- }
463
- ]);
464
-
465
- // Control playlist
466
- playlist.next() // Go to next track
467
- playlist.previous() // Go to previous track
468
- playlist.goToTrack(2) // Jump to specific track
469
- playlist.hasNext() // Check if next track exists
470
- playlist.hasPrevious() // Check if previous track exists
471
-
472
- // Listen for track changes
473
- player.on('playlisttrackchange', (e) => {
474
- console.log('Now playing:', e.item.title);
475
- });
476
- ```
477
-
478
- ### Settings
479
-
480
- ```javascript
481
- player.showSettings() // Open settings dialog
482
- player.hideSettings() // Close settings dialog
483
- ```
484
-
485
- ### State Information
486
-
487
- ```javascript
488
- player.getCurrentTime() // Get current time
489
- player.getDuration() // Get duration
490
- player.isPlaying() // Check if playing
491
- player.isPaused() // Check if paused
492
- player.isEnded() // Check if ended
493
- player.isMuted() // Check if muted
494
- player.isFullscreen() // Check if fullscreen
495
- ```
496
-
497
- ### Event Listeners
498
-
499
- ```javascript
500
- player.on('ready', () => {})
501
- player.on('play', () => {})
502
- player.on('pause', () => {})
503
- player.on('ended', () => {})
504
- player.on('timeupdate', (time) => {})
505
- player.on('volumechange', (volume) => {})
506
- player.on('playbackspeedchange', (speed) => {})
507
- player.on('fullscreenchange', (isFullscreen) => {})
508
- player.on('captionsenabled', (track) => {})
509
- player.on('captionsdisabled', () => {})
510
- player.on('error', (error) => {})
511
- ```
512
-
513
- ### Cleanup
514
-
515
- ```javascript
516
- player.destroy() // Remove player and cleanup
517
- ```
518
-
519
- ## Customization
520
-
521
- ### Custom Styling
522
-
523
- VidPly provides extensive CSS variables for easy customization:
524
-
525
- ```css
526
- /* Override default colors and sizing */
527
- .vidply-player {
528
- /* Colors */
529
- --vidply-primary-color: #3b82f6;
530
- --vidply-background: rgba(0, 0, 0, 0.8);
531
- --vidply-text-color: #ffffff;
532
-
533
- /* Sizing */
534
- --vidply-button-size: 40px;
535
- --vidply-icon-size: 20px;
536
-
537
- /* Spacing */
538
- --vidply-gap-sm: 4px;
539
- --vidply-gap-md: 8px;
540
- --vidply-gap-lg: 12px;
541
-
542
- /* Border radius */
543
- --vidply-radius-sm: 4px;
544
- --vidply-radius-md: 8px;
545
- --vidply-radius-lg: 12px;
546
-
547
- /* Transitions */
548
- --vidply-transition-fast: 150ms;
549
- --vidply-transition-normal: 300ms;
550
- }
551
-
552
- /* Custom progress bar */
553
- .vidply-progress-played {
554
- background: linear-gradient(90deg, #667eea, #764ba2);
555
- }
556
-
557
- /* Custom buttons */
558
- .vidply-button:hover {
559
- background: rgba(59, 130, 246, 0.2);
560
- }
561
- ```
562
-
563
- ### Add Custom Language
564
-
565
- #### Option 1: Load from URL (Recommended)
566
-
567
- ```html
568
- <video
569
- data-vidply
570
- data-vidply-language-files='{"pt": "languages/pt.json", "it": "languages/it.json"}'
571
- src="video.mp4"
572
- ></video>
573
- ```
574
-
575
- #### Option 2: JavaScript API
576
-
577
- ```javascript
578
- import { i18n } from './src/i18n/i18n.js';
579
-
580
- // Load language file from URL
581
- await i18n.loadLanguageFromUrl('pt', 'languages/pt.json');
582
-
583
- // Or load multiple languages
584
- await i18n.loadLanguagesFromUrls({
585
- 'pt': 'languages/pt.json',
586
- 'it': 'languages/it.json'
587
- });
588
-
589
- // Set the language
590
- i18n.setLanguage('pt');
591
- ```
592
-
593
- #### Option 3: Add Translations Programmatically
594
-
595
- ```javascript
596
- import { i18n } from './src/i18n/i18n.js';
597
-
598
- i18n.addTranslation('pt', {
599
- player: {
600
- play: 'Reproduzir',
601
- pause: 'Pausar',
602
- mute: 'Silenciar',
603
- unmute: 'Ativar som'
604
- }
605
- });
606
-
607
- i18n.setLanguage('pt');
608
- ```
609
-
610
- #### Language File Format
611
-
612
- Create `languages/pt.json`:
613
-
614
- ```json
615
- {
616
- "player": {
617
- "play": "Reproduzir",
618
- "pause": "Pausar",
619
- "mute": "Silenciar",
620
- "unmute": "Ativar som",
621
- "fullscreen": "Tela cheia",
622
- "captions": "Legendas"
623
- },
624
- "time": {
625
- "currentTime": "Tempo atual",
626
- "duration": "Duração"
627
- }
628
- }
629
- ```
630
-
631
- The player supports both JSON and YAML formats for language files.
632
-
633
- ## Build Process
634
-
635
- VidPly uses a modern build system with esbuild for JavaScript and clean-css for CSS.
636
-
637
- ### Available Scripts
638
-
639
- ```bash
640
- npm run build # Build everything (JS + CSS)
641
- npm run build:js # Build JavaScript only
642
- npm run build:css # Build CSS only
643
- npm run watch # Watch mode for development
644
- npm run clean # Clean dist directory
645
- npm run dev # Start dev server
646
- ```
647
-
648
- ### Output Files
649
-
650
- - `dist/vidply.esm.js` - ES Module (development)
651
- - `dist/vidply.esm.min.js` - ES Module (production)
652
- - `dist/vidply.js` - IIFE (development)
653
- - `dist/vidply.min.js` - IIFE (production)
654
- - `dist/vidply.css` - Styles (unminified)
655
- - `dist/vidply.min.css` - Styles (minified)
656
-
657
- See [BUILD.md](docs/BUILD.md) for detailed build documentation.
658
-
659
- ## Browser Support
660
-
661
- - Chrome 90+
662
- - Firefox 88+
663
- - Safari 14+
664
- - Edge 90+
665
- - iOS Safari 14+
666
- - Android Chrome 90+
667
-
668
- ## License
669
-
670
- GNU General Public License v2.0 or later
671
-
672
- Copyright (C) 2025 Matthias Peltzer
673
-
674
- This program is free software; you can redistribute it and/or modify
675
- it under the terms of the GNU General Public License as published by
676
- the Free Software Foundation; either version 2 of the License, or
677
- (at your option) any later version.
678
-
679
- See [LICENSE](LICENSE) for full license text.
680
-
681
- ## Contributing
682
-
683
- Contributions are welcome! Please feel free to submit a Pull Request.
684
-
685
- ## Documentation
686
-
687
- ### Guides
688
- - **[User's Guide](docs/Users-Guide.md)** - Complete integration guide for web developers
689
- - **[Developer Quickstart](docs/Developers-Quickstart.md)** - Quick reference for contributors
690
-
691
- ### Reference
692
- - [Getting Started Guide](docs/GETTING_STARTED.md) - Basic setup and usage
693
- - [Usage Guide](docs/USAGE.md) - Detailed usage examples
694
- - [Playlist Guide](docs/PLAYLIST.md) - Audio/video playlists with fullscreen support
695
- - [Transcript Guide](docs/TRANSCRIPT.md) - Interactive transcripts
696
- - [Keyboard Shortcuts](docs/KEYBOARD.md) - Complete keyboard reference
697
- - [Build Guide](docs/BUILD.md) - Build system and development
698
- - [Changelog](docs/CHANGELOG.md) - Version history and updates
699
-
700
- ## Credits
701
-
702
- Inspired by:
703
- - [AblePlayer](https://github.com/ableplayer/ableplayer) - Accessibility features
704
- - [MediaElement.js](https://github.com/mediaelement/mediaelement) - Streaming support
705
-
706
- ---
707
-
708
- Made with Vanilla JavaScript by Matthias Peltzer
1
+ # <img src="favicon.svg" width="32" alt="VidPly" /> VidPly
2
+
3
+ **Universal, Accessible Video & Audio Player**
4
+
5
+ A modern, feature-rich media player built with vanilla ES6 JavaScript. Combines the best accessibility features from AblePlayer with the streaming capabilities of MediaElement.js. Fully internationalized with support for 5 languages and complete WCAG 2.1 AA compliance.
6
+
7
+ ![License](https://img.shields.io/badge/license-GPL--2.0--or--later-blue.svg)
8
+ ![ES6](https://img.shields.io/badge/ES6-Module-yellow.svg)
9
+ ![WCAG](https://img.shields.io/badge/WCAG-2.1%20AA-green.svg)
10
+ ![Version](https://img.shields.io/badge/version-1.0.18-brightgreen.svg)
11
+
12
+ ## Live Demos
13
+
14
+ Try VidPly in action:
15
+ - **[Main Demo](https://matthiaspeltzer.github.io/vidply/demo/demo.html)** - Full-featured video player showcase
16
+ - **[Audio Playlist](https://matthiaspeltzer.github.io/vidply/demo/playlist-audio.html)** - Audio player with playlist support
17
+ - **[Video Playlist](https://matthiaspeltzer.github.io/vidply/demo/playlist-video.html)** - Video playlist with thumbnails
18
+ - **[HLS Streaming](https://matthiaspeltzer.github.io/vidply/demo/hls-test.html)** - Adaptive bitrate streaming demo
19
+
20
+ ## Why VidPly?
21
+
22
+ - **Zero Dependencies** - Pure vanilla JavaScript, no frameworks required
23
+ - **Accessibility First** - WCAG 2.1 AA compliant with full keyboard and screen reader support
24
+ - **Multilingual** - Built-in translations for 5 languages with easy extensibility
25
+ - **Fully Customizable** - CSS variables and comprehensive API
26
+ - **Modern Build** - ES6 modules with tree-shaking support
27
+ - **Production Ready** - Thoroughly tested with real-world media content
28
+
29
+ ## Features
30
+
31
+ ### Core Media Support
32
+ - **Audio & Video Playback** - Native HTML5 support for both media types
33
+ - **Multiple Formats** - MP3, OGG, WAV (audio) / MP4, WebM (video)
34
+ - **YouTube Integration** - Embed YouTube videos with unified controls
35
+ - **Vimeo Integration** - Seamless Vimeo player integration
36
+ - **HLS Streaming** - Adaptive bitrate streaming with quality selection
37
+ - **Playlists** - Full playlist support with auto-advance and navigation
38
+ - Audio playlists with track info
39
+ - Video playlists with thumbnails
40
+ - Previous/Next controls
41
+ - Visual playlist panel
42
+ - **Fullscreen Mode**: YouTube-style horizontal carousel
43
+ - Auto-show/hide based on playback state
44
+ - Swipeable touch interface
45
+ - Responsive card layout
46
+
47
+ ### Accessibility Features (WCAG 2.1 AA Compliant)
48
+ - **Full Keyboard Navigation** - All features accessible via keyboard, custom shortcuts, menu navigation with Arrow keys
49
+ - **Screen Reader Support** - Complete ARIA labels (`aria-controls`, `aria-expanded`, `aria-haspopup`), live regions
50
+ - **Interactive Transcripts** - Click-to-seek, searchable, auto-scroll with proper semantic HTML
51
+ - **Sign Language Overlay** - Picture-in-picture with drag/resize, keyboard accessible
52
+ - **Audio Description** - Alternate audio track with visual content descriptions
53
+ - **Caption Styling** - Fully customizable (font, size, color, opacity, edge style)
54
+ - **High Contrast Mode** - Windows HCM support, color-independent design
55
+ - **Focus Management** - Logical focus order, programmatic focus handling, visible indicators
56
+ - **Touch Accessibility** - 44x44px minimum touch targets, swipeable interfaces
57
+
58
+ ### Captions & Subtitles
59
+ - **WebVTT Support** - Standard caption format
60
+ - **Multiple Languages** - Multi-track support
61
+ - **Caption Selector** - Easy track switching with CC button
62
+ - **Caption Styling** - Dedicated styling menu (font, size, color, opacity)
63
+ - **Chapter Navigation** - Jump to video chapters
64
+ - **Interactive Transcripts** - Full-text searchable transcript panel
65
+
66
+ ### Playback Features
67
+ - **Adjustable Speed** - 0.25x to 2x playback
68
+ - **Seek Controls** - Forward/backward navigation
69
+ - **Volume Control** - 0-100% with mute
70
+ - **Loop Playback** - Single or playlist loop
71
+ - **Fullscreen Mode** - Native fullscreen API with smart playlist overlay
72
+ - **Picture-in-Picture** - PiP support
73
+
74
+ ### Internationalization
75
+ Built-in support for 5 languages:
76
+ - English (en)
77
+ - Spanish (es) - Español
78
+ - French (fr) - Français
79
+ - German (de) - Deutsch
80
+ - Japanese (ja) - 日本語
81
+
82
+ All UI elements are fully translated, including:
83
+ - Control buttons and menus
84
+ - Time display and duration formatting
85
+ - Keyboard shortcuts
86
+ - Error messages and notifications
87
+ - ARIA labels for screen readers
88
+
89
+ **Custom Translations**: Easily add your own languages by loading JSON or YAML translation files via data attributes or JavaScript options. The player automatically detects the HTML `lang` attribute and loads matching translations.
90
+
91
+ ## Installation
92
+
93
+ ### Build from Source
94
+
95
+ First, build the player:
96
+
97
+ ```bash
98
+ # Install dependencies
99
+ npm install
100
+
101
+ # Build production files
102
+ npm run build
103
+ ```
104
+
105
+ This creates minified files in the `dist/` folder.
106
+
107
+ ### Option 1: Using Built Files (Recommended for Production)
108
+
109
+ ```html
110
+ <!DOCTYPE html>
111
+ <html>
112
+ <head>
113
+ <link rel="stylesheet" href="dist/vidply.min.css">
114
+ </head>
115
+ <body>
116
+ <video data-vidply src="video.mp4" width="800" height="450">
117
+ <track kind="subtitles" src="captions.vtt" srclang="en" label="English">
118
+ </video>
119
+
120
+ <script type="module">
121
+ import Player from './dist/vidply.esm.min.js';
122
+ // Auto-initialized via data-vidply attribute
123
+ </script>
124
+ </body>
125
+ </html>
126
+ ```
127
+
128
+ ### Option 2: Traditional Script Tag (IIFE)
129
+
130
+ ```html
131
+ <link rel="stylesheet" href="dist/vidply.min.css">
132
+ <script src="dist/vidply.min.js"></script>
133
+
134
+ <video id="my-video" src="video.mp4"></video>
135
+
136
+ <script>
137
+ const player = new VidPly.Player('#my-video', {
138
+ controls: true,
139
+ autoplay: false,
140
+ volume: 0.8,
141
+ language: 'en'
142
+ });
143
+ </script>
144
+ ```
145
+
146
+ ### Option 3: Development (Source Files)
147
+
148
+ ```javascript
149
+ import Player from './src/index.js';
150
+
151
+ const player = new Player('#my-video', {
152
+ controls: true,
153
+ autoplay: false,
154
+ volume: 0.8,
155
+ language: 'en'
156
+ });
157
+ ```
158
+
159
+ ## Quick Start
160
+
161
+ ### 1. Build the Player
162
+
163
+ ```bash
164
+ npm install
165
+ npm run build
166
+ ```
167
+
168
+ ### 2. Add to Your Page
169
+
170
+ ```html
171
+ <link rel="stylesheet" href="dist/vidply.min.css">
172
+ <script type="module">
173
+ import Player from './dist/vidply.esm.min.js';
174
+ </script>
175
+ ```
176
+
177
+ ### 3. Create a Video Player
178
+
179
+ ```html
180
+ <video data-vidply width="800" height="450">
181
+ <source src="video.mp4" type="video/mp4">
182
+ <track kind="subtitles" src="captions-en.vtt" srclang="en" label="English">
183
+ <track kind="subtitles" src="captions-es.vtt" srclang="es" label="Español">
184
+ </video>
185
+ ```
186
+
187
+ That's it! The player auto-initializes.
188
+
189
+ ### YouTube Player
190
+
191
+ ```html
192
+ <video data-vidply src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
193
+ ```
194
+
195
+ ### Vimeo Player
196
+
197
+ ```html
198
+ <video data-vidply src="https://vimeo.com/VIDEO_ID"></video>
199
+ ```
200
+
201
+ ### Audio Player
202
+
203
+ ```html
204
+ <audio data-vidply>
205
+ <source src="audio.mp3" type="audio/mpeg">
206
+ </audio>
207
+ ```
208
+
209
+ ### HLS Streaming
210
+
211
+ ```html
212
+ <video data-vidply src="https://example.com/stream.m3u8"></video>
213
+ ```
214
+
215
+ ## Configuration Options
216
+
217
+ ```javascript
218
+ const player = new Player('#video', {
219
+ // Display
220
+ width: 800,
221
+ height: 450,
222
+ poster: 'poster.jpg',
223
+ responsive: true,
224
+
225
+ // Playback
226
+ autoplay: false,
227
+ loop: false,
228
+ muted: false,
229
+ volume: 0.8,
230
+ playbackSpeed: 1.0,
231
+ startTime: 0,
232
+
233
+ // Controls
234
+ controls: true,
235
+ hideControlsDelay: 3000,
236
+ playPauseButton: true,
237
+ progressBar: true,
238
+ volumeControl: true,
239
+ chaptersButton: true,
240
+ qualityButton: true,
241
+ captionStyleButton: true,
242
+ speedButton: true,
243
+ captionsButton: true,
244
+ transcriptButton: true,
245
+ audioDescriptionButton: true,
246
+ signLanguageButton: true,
247
+ fullscreenButton: true,
248
+ pipButton: true,
249
+
250
+ // Captions
251
+ captions: true,
252
+ captionsDefault: false,
253
+ captionsFontSize: '100%',
254
+ captionsFontFamily: 'sans-serif',
255
+ captionsColor: '#FFFFFF',
256
+ captionsBackgroundColor: '#000000',
257
+ captionsOpacity: 0.8,
258
+
259
+ // Audio Description
260
+ audioDescription: true,
261
+ audioDescriptionSrc: null, // URL to audio-described version
262
+ audioDescriptionButton: true,
263
+
264
+ // Sign Language
265
+ signLanguage: true,
266
+ signLanguageSrc: null, // URL to sign language video
267
+ signLanguageButton: true,
268
+ signLanguagePosition: 'bottom-right', // 'bottom-right', 'bottom-left', 'top-right', 'top-left'
269
+
270
+ // Transcripts
271
+ transcript: false,
272
+ transcriptButton: true,
273
+ transcriptPosition: 'external',
274
+ transcriptContainer: null,
275
+
276
+ // Keyboard
277
+ keyboard: true,
278
+ keyboardShortcuts: {
279
+ 'play-pause': [' ', 'p', 'k'],
280
+ 'seek-forward': ['ArrowRight', 'l'],
281
+ 'seek-backward': ['ArrowLeft', 'j'],
282
+ 'volume-up': ['ArrowUp'],
283
+ 'volume-down': ['ArrowDown'],
284
+ 'mute': ['m'],
285
+ 'fullscreen': ['f'],
286
+ 'captions': ['c']
287
+ },
288
+
289
+ // Accessibility
290
+ screenReaderAnnouncements: true,
291
+ focusHighlight: true,
292
+
293
+ // Internationalization
294
+ language: 'en',
295
+
296
+ // Callbacks
297
+ onReady: () => console.log('Ready!'),
298
+ onPlay: () => console.log('Playing!'),
299
+ onPause: () => console.log('Paused!'),
300
+ onEnded: () => console.log('Ended!'),
301
+
302
+ // Advanced
303
+ debug: false,
304
+ pauseOthersOnPlay: true
305
+ });
306
+ ```
307
+
308
+ ## Keyboard Shortcuts
309
+
310
+ | Key | Action |
311
+ |-----|--------|
312
+ | <kbd>Space</kbd> / <kbd>P</kbd> / <kbd>K</kbd> | Play/Pause |
313
+ | <kbd>F</kbd> | Toggle Fullscreen |
314
+ | <kbd>M</kbd> | Mute/Unmute |
315
+ | <kbd>↑</kbd> / <kbd>↓</kbd> | Volume Up/Down |
316
+ | <kbd>←</kbd> / <kbd>→</kbd> | Seek -10s / +10s |
317
+ | <kbd>C</kbd> | Toggle Captions (or open menu if multiple) |
318
+ | <kbd>A</kbd> | Open Caption Style Menu |
319
+ | <kbd><</kbd> / <kbd>></kbd> | Decrease/Increase Speed |
320
+ | <kbd>S</kbd> | Open Speed Menu |
321
+ | <kbd>Q</kbd> | Open Quality Menu |
322
+ | <kbd>J</kbd> | Open Chapters Menu |
323
+ | <kbd>T</kbd> | Toggle Transcript |
324
+ | <kbd>D</kbd> | Toggle Drag Mode (Transcript/Sign Language) |
325
+ | <kbd>R</kbd> | Toggle Resize Mode (Transcript/Sign Language) |
326
+ | <kbd>Escape</kbd> | Exit Drag/Resize Mode or Close Menus |
327
+ | <kbd>Home</kbd> | Reset Transcript/Sign Language Position |
328
+
329
+ ## API Reference
330
+
331
+ ### Playback Control
332
+
333
+ ```javascript
334
+ player.play() // Start playback
335
+ player.pause() // Pause playback
336
+ player.stop() // Stop and reset
337
+ player.toggle() // Toggle play/pause
338
+ player.seek(30) // Seek to 30 seconds
339
+ player.seekForward(10) // Skip forward 10 seconds
340
+ player.seekBackward(10) // Skip backward 10 seconds
341
+ ```
342
+
343
+ ### Volume Control
344
+
345
+ ```javascript
346
+ player.setVolume(0.5) // Set volume (0.0-1.0)
347
+ player.getVolume() // Get current volume
348
+ player.mute() // Mute audio
349
+ player.unmute() // Unmute audio
350
+ player.toggleMute() // Toggle mute state
351
+ ```
352
+
353
+ **Note on Mobile Devices:** On touch devices (iOS, Android, tablets), only a **mute/unmute button** is shown instead of the volume slider. Mobile browsers control HTML5 video volume through **hardware device volume buttons** - this is standard behavior that cannot be overridden by web apps for security reasons. The mute button provides quick silencing functionality while hardware buttons control actual volume levels.
354
+
355
+ ### Playback Speed
356
+
357
+ ```javascript
358
+ player.setPlaybackSpeed(1.5) // Set speed (0.25-2.0)
359
+ player.getPlaybackSpeed() // Get current speed
360
+ ```
361
+
362
+ ### Fullscreen
363
+
364
+ ```javascript
365
+ player.enterFullscreen() // Enter fullscreen
366
+ player.exitFullscreen() // Exit fullscreen
367
+ player.toggleFullscreen() // Toggle fullscreen
368
+ ```
369
+
370
+ **Note on iOS/Mobile Safari:** Since iOS doesn't support the Fullscreen API on container elements, VidPly automatically falls back to a "pseudo-fullscreen" mode that positions the player to fill the entire viewport using CSS. This provides a fullscreen-like experience on iOS devices while maintaining all player functionality.
371
+
372
+ ### Captions
373
+
374
+ ```javascript
375
+ player.enableCaptions() // Enable captions
376
+ player.disableCaptions() // Disable captions
377
+ player.toggleCaptions() // Toggle captions
378
+
379
+ // Switch between caption tracks
380
+ player.captionManager.switchTrack(0) // Switch to first track
381
+ player.captionManager.getAvailableTracks() // Get all tracks
382
+ ```
383
+
384
+ ### Transcript
385
+
386
+ ```javascript
387
+ // Show/Hide Transcript
388
+ player.transcriptManager.showTranscript() // Show transcript window
389
+ player.transcriptManager.hideTranscript() // Hide transcript window
390
+ player.transcriptManager.toggleTranscript() // Toggle transcript visibility
391
+
392
+ // Drag & Resize Modes (Desktop only, mobile breakpoint: 768px)
393
+ player.transcriptManager.toggleKeyboardDragMode() // Toggle drag mode (D key)
394
+ player.transcriptManager.togglePointerResizeMode() // Toggle resize mode (R key)
395
+
396
+ // Settings Menu
397
+ player.transcriptManager.showSettingsMenu() // Show settings dropdown
398
+ player.transcriptManager.hideSettingsMenu() // Hide settings dropdown
399
+
400
+ // Check State
401
+ if (player.transcriptManager.isVisible) {
402
+ console.log('Transcript is visible');
403
+ }
404
+ ```
405
+
406
+ ### Audio Description
407
+
408
+ ```javascript
409
+ player.enableAudioDescription() // Switch to described version
410
+ player.disableAudioDescription() // Switch back to original
411
+ player.toggleAudioDescription() // Toggle audio description
412
+ ```
413
+
414
+ ### Sign Language
415
+
416
+ ```javascript
417
+ // Show/Hide Sign Language Video
418
+ player.enableSignLanguage() // Show sign language overlay
419
+ player.disableSignLanguage() // Hide sign language overlay
420
+ player.toggleSignLanguage() // Toggle sign language
421
+
422
+ // Multi-Language Support
423
+ player.switchSignLanguage('de') // Switch to German sign language
424
+
425
+ // Drag & Resize (available via settings menu or keyboard)
426
+ // D key - Toggle drag mode with arrow keys
427
+ // R key - Toggle resize mode (shows resize handles)
428
+ // Home key - Reset position
429
+ // Escape - Exit drag/resize mode
430
+ ```
431
+
432
+ ### Playlists
433
+
434
+ ```javascript
435
+ import { Player, PlaylistManager } from './dist/vidply.esm.js';
436
+
437
+ // Create player
438
+ const player = new Player('#my-player');
439
+
440
+ // Create playlist manager
441
+ const playlist = new PlaylistManager(player, {
442
+ autoAdvance: true, // Auto-play next track
443
+ loop: false, // Loop back to start
444
+ showPanel: true // Show playlist UI
445
+ });
446
+
447
+ // Load tracks
448
+ playlist.loadPlaylist([
449
+ {
450
+ src: 'track1.mp3',
451
+ title: 'Track 1',
452
+ artist: 'Artist Name',
453
+ poster: 'thumb1.jpg'
454
+ },
455
+ {
456
+ src: 'track2.mp3',
457
+ title: 'Track 2',
458
+ artist: 'Artist Name',
459
+ tracks: [
460
+ { src: 'captions.vtt', kind: 'captions', srclang: 'en' }
461
+ ]
462
+ }
463
+ ]);
464
+
465
+ // Control playlist
466
+ playlist.next() // Go to next track
467
+ playlist.previous() // Go to previous track
468
+ playlist.goToTrack(2) // Jump to specific track
469
+ playlist.hasNext() // Check if next track exists
470
+ playlist.hasPrevious() // Check if previous track exists
471
+
472
+ // Listen for track changes
473
+ player.on('playlisttrackchange', (e) => {
474
+ console.log('Now playing:', e.item.title);
475
+ });
476
+ ```
477
+
478
+ ### Settings
479
+
480
+ ```javascript
481
+ player.showSettings() // Open settings dialog
482
+ player.hideSettings() // Close settings dialog
483
+ ```
484
+
485
+ ### State Information
486
+
487
+ ```javascript
488
+ player.getCurrentTime() // Get current time
489
+ player.getDuration() // Get duration
490
+ player.isPlaying() // Check if playing
491
+ player.isPaused() // Check if paused
492
+ player.isEnded() // Check if ended
493
+ player.isMuted() // Check if muted
494
+ player.isFullscreen() // Check if fullscreen
495
+ ```
496
+
497
+ ### Event Listeners
498
+
499
+ ```javascript
500
+ player.on('ready', () => {})
501
+ player.on('play', () => {})
502
+ player.on('pause', () => {})
503
+ player.on('ended', () => {})
504
+ player.on('timeupdate', (time) => {})
505
+ player.on('volumechange', (volume) => {})
506
+ player.on('playbackspeedchange', (speed) => {})
507
+ player.on('fullscreenchange', (isFullscreen) => {})
508
+ player.on('captionsenabled', (track) => {})
509
+ player.on('captionsdisabled', () => {})
510
+ player.on('error', (error) => {})
511
+ ```
512
+
513
+ ### Cleanup
514
+
515
+ ```javascript
516
+ player.destroy() // Remove player and cleanup
517
+ ```
518
+
519
+ ## Customization
520
+
521
+ ### Custom Styling
522
+
523
+ VidPly provides extensive CSS variables for easy customization:
524
+
525
+ ```css
526
+ /* Override default colors and sizing */
527
+ .vidply-player {
528
+ /* Colors */
529
+ --vidply-primary-color: #3b82f6;
530
+ --vidply-background: rgba(0, 0, 0, 0.8);
531
+ --vidply-text-color: #ffffff;
532
+
533
+ /* Sizing */
534
+ --vidply-button-size: 40px;
535
+ --vidply-icon-size: 20px;
536
+
537
+ /* Spacing */
538
+ --vidply-gap-sm: 4px;
539
+ --vidply-gap-md: 8px;
540
+ --vidply-gap-lg: 12px;
541
+
542
+ /* Border radius */
543
+ --vidply-radius-sm: 4px;
544
+ --vidply-radius-md: 8px;
545
+ --vidply-radius-lg: 12px;
546
+
547
+ /* Transitions */
548
+ --vidply-transition-fast: 150ms;
549
+ --vidply-transition-normal: 300ms;
550
+ }
551
+
552
+ /* Custom progress bar */
553
+ .vidply-progress-played {
554
+ background: linear-gradient(90deg, #667eea, #764ba2);
555
+ }
556
+
557
+ /* Custom buttons */
558
+ .vidply-button:hover {
559
+ background: rgba(59, 130, 246, 0.2);
560
+ }
561
+ ```
562
+
563
+ ### Add Custom Language
564
+
565
+ #### Option 1: Load from URL (Recommended)
566
+
567
+ ```html
568
+ <video
569
+ data-vidply
570
+ data-vidply-language-files='{"pt": "languages/pt.json", "it": "languages/it.json"}'
571
+ src="video.mp4"
572
+ ></video>
573
+ ```
574
+
575
+ #### Option 2: JavaScript API
576
+
577
+ ```javascript
578
+ import { i18n } from './src/i18n/i18n.js';
579
+
580
+ // Load language file from URL
581
+ await i18n.loadLanguageFromUrl('pt', 'languages/pt.json');
582
+
583
+ // Or load multiple languages
584
+ await i18n.loadLanguagesFromUrls({
585
+ 'pt': 'languages/pt.json',
586
+ 'it': 'languages/it.json'
587
+ });
588
+
589
+ // Set the language
590
+ i18n.setLanguage('pt');
591
+ ```
592
+
593
+ #### Option 3: Add Translations Programmatically
594
+
595
+ ```javascript
596
+ import { i18n } from './src/i18n/i18n.js';
597
+
598
+ i18n.addTranslation('pt', {
599
+ player: {
600
+ play: 'Reproduzir',
601
+ pause: 'Pausar',
602
+ mute: 'Silenciar',
603
+ unmute: 'Ativar som'
604
+ }
605
+ });
606
+
607
+ i18n.setLanguage('pt');
608
+ ```
609
+
610
+ #### Language File Format
611
+
612
+ Create `languages/pt.json`:
613
+
614
+ ```json
615
+ {
616
+ "player": {
617
+ "play": "Reproduzir",
618
+ "pause": "Pausar",
619
+ "mute": "Silenciar",
620
+ "unmute": "Ativar som",
621
+ "fullscreen": "Tela cheia",
622
+ "captions": "Legendas"
623
+ },
624
+ "time": {
625
+ "currentTime": "Tempo atual",
626
+ "duration": "Duração"
627
+ }
628
+ }
629
+ ```
630
+
631
+ The player supports both JSON and YAML formats for language files.
632
+
633
+ ## Build Process
634
+
635
+ VidPly uses a modern build system with esbuild for JavaScript and clean-css for CSS.
636
+
637
+ ### Available Scripts
638
+
639
+ ```bash
640
+ npm run build # Build everything (JS + CSS)
641
+ npm run build:js # Build JavaScript only
642
+ npm run build:css # Build CSS only
643
+ npm run watch # Watch mode for development
644
+ npm run clean # Clean dist directory
645
+ npm run dev # Start dev server
646
+ ```
647
+
648
+ ### Output Files
649
+
650
+ - `dist/vidply.esm.js` - ES Module (development)
651
+ - `dist/vidply.esm.min.js` - ES Module (production)
652
+ - `dist/vidply.js` - IIFE (development)
653
+ - `dist/vidply.min.js` - IIFE (production)
654
+ - `dist/vidply.css` - Styles (unminified)
655
+ - `dist/vidply.min.css` - Styles (minified)
656
+
657
+ See [BUILD.md](docs/BUILD.md) for detailed build documentation.
658
+
659
+ ## Browser Support
660
+
661
+ - Chrome 90+
662
+ - Firefox 88+
663
+ - Safari 14+
664
+ - Edge 90+
665
+ - iOS Safari 14+
666
+ - Android Chrome 90+
667
+
668
+ ## License
669
+
670
+ GNU General Public License v2.0 or later
671
+
672
+ Copyright (C) 2025 Matthias Peltzer
673
+
674
+ This program is free software; you can redistribute it and/or modify
675
+ it under the terms of the GNU General Public License as published by
676
+ the Free Software Foundation; either version 2 of the License, or
677
+ (at your option) any later version.
678
+
679
+ See [LICENSE](LICENSE) for full license text.
680
+
681
+ ## Contributing
682
+
683
+ Contributions are welcome! Please feel free to submit a Pull Request.
684
+
685
+ ## Documentation
686
+
687
+ ### Guides
688
+ - **[User's Guide](docs/Users-Guide.md)** - Complete integration guide for web developers
689
+ - **[Developer Quickstart](docs/Developers-Quickstart.md)** - Quick reference for contributors
690
+
691
+ ### Reference
692
+ - [Getting Started Guide](docs/GETTING_STARTED.md) - Basic setup and usage
693
+ - [Usage Guide](docs/USAGE.md) - Detailed usage examples
694
+ - [Playlist Guide](docs/PLAYLIST.md) - Audio/video playlists with fullscreen support
695
+ - [Transcript Guide](docs/TRANSCRIPT.md) - Interactive transcripts
696
+ - [Keyboard Shortcuts](docs/KEYBOARD.md) - Complete keyboard reference
697
+ - [Build Guide](docs/BUILD.md) - Build system and development
698
+ - [Changelog](docs/CHANGELOG.md) - Version history and updates
699
+
700
+ ## Credits
701
+
702
+ Inspired by:
703
+ - [AblePlayer](https://github.com/ableplayer/ableplayer) - Accessibility features
704
+ - [MediaElement.js](https://github.com/mediaelement/mediaelement) - Streaming support
705
+
706
+ ---
707
+
708
+ Made with Vanilla JavaScript by Matthias Peltzer