
🚀 Einrichtung
# Clone repository
git clone github.com/MatthiasPeltzer/vidply.git
cd vidply
# Install dependencies
npm install
# Build production files
npm run build
# Start dev server
npm run dev
Der Entwicklungsserver läuft unter localhost
📁 Verzeichnisstruktur
vidply/
├── build/ # Build scripts
│ ├── build.js # TypeScript bundling (esbuild → ESM + IIFE)
│ ├── build-css.js # CSS build (clean-css)
│ ├── watch.js # Watch mode
│ └── clean.js # Clean dist
├── demo/ # Demo pages
│ ├── demo.html # Main demo
│ ├── playlist-audio.html # Audio playlist demo
│ ├── playlist-video.html # Video playlist demo
│ ├── hls-test.html # HLS streaming demo
│ ├── dash-test.html # DASH streaming demo
│ └── single-player-dash.html # Single DASH player demo
├── dist/ # Built files (generated)
│ ├── prod/vidply.esm.min.js # ES Module (production)
│ ├── legacy/vidply.min.js # IIFE (production)
│ ├── types/index.d.ts # TypeScript declarations
│ └── vidply.min.css # Styles (production)
├── docs/ # Documentation
├── src/ # Source code (strict TypeScript)
│ ├── core/
│ │ └── Player.ts # Main Player class
│ ├── controls/
│ │ ├── ControlBar.ts # Control bar UI (incl. download button, buffering spinner)
│ │ ├── CaptionManager.ts # Caption handling
│ │ ├── KeyboardManager.ts # Keyboard shortcuts
│ │ ├── SettingsDialog.ts # Settings menu
│ │ └── TranscriptManager.ts
│ ├── features/
│ │ └── PlaylistManager.ts # Playlist support
│ ├── i18n/
│ │ ├── i18n.ts # i18n system
│ │ ├── translations.ts # Translation loader
│ │ └── languages/ # Built-in languages
│ │ ├── en.ts
│ │ ├── de.ts
│ │ ├── es.ts
│ │ ├── fr.ts
│ │ └── ja.ts
│ ├── icons/
│ │ └── Icons.ts # SVG icon definitions
│ ├── renderers/
│ │ ├── HTML5Renderer.ts # Native HTML5 video/audio
│ │ ├── YouTubeRenderer.ts # YouTube iframe API
│ │ ├── VimeoRenderer.ts # Vimeo Player API
│ │ ├── SoundCloudRenderer.ts# SoundCloud Widget API
│ │ ├── HLSRenderer.ts # hls.js integration + native iOS bridge
│ │ └── DASHRenderer.ts # dash.js integration
│ ├── styles/
│ │ └── vidply.css # Main stylesheet
│ ├── types/ # Shared TypeScript types
│ │ ├── options.ts # PlayerOptions
│ │ └── globals.d.ts # Ambient declarations (Hls, dashjs, …)
│ ├── utils/
│ │ ├── DOMUtils.ts # DOM helpers
│ │ ├── EventEmitter.ts # Event system
│ │ ├── TimeUtils.ts # Time formatting
│ │ ├── FocusUtils.ts # Focus management
│ │ ├── MenuUtils.ts # Menu helpers
│ │ ├── StorageManager.ts # localStorage wrapper
│ │ └── ...
│ └── index.ts # Main entry point
├── index.html # Development page
├── tsconfig.json # Strict TypeScript config
├── package.json
└── server.js # Dev server
⚡ NPM-Skripte
| Skript | Beschreibung |
|---|---|
npm run build | Alles erstellen (TypeScript-Bundles + Typen + CSS) |
npm run build:js | TypeScript mit esbuild bündeln (ESM + IIFE) |
npm run build:types | Typdeklarationen .d.ts Typdeklarationen in dist/types/ |
npm run build:css | Nur CSS erstellen |
npm run typecheck | tsc --noEmit Strenge Typprüfung im src/ |
npm run watch | Watch-Modus (automatischer Neuaufbau) |
npm run dev | Entwicklungsserver starten |
npm run clean | Verzeichnis „dist“ bereinigen |
npm run start | Erstellen + Entwicklungsserver starten |
npm run test | Vitest-Unit-Tests |
npm run test:e2e | Playwright-End-to-End-Tests |
🏗️ Build-System
TypeScript-Bundles (esbuild)
build/build.js verwendet die TypeScript-Quelldateien direkt (esbuild übernimmt die Transpilation) und erzeugt:
| Datei | Format | Verwendung |
|---|---|---|
dev/vidply.esm.js | ES-Modul | Entwicklung |
prod/vidply.esm.min.js | ES-Modul | Produktion |
legacy/vidply.js | IIFE | Entwicklung |
legacy/vidply.min.js | IIFE | Produktion |
Funktionen:
- Code-Splitting (Renderer werden bei Bedarf geladen)
- Tree Shaking
- Source Maps (Entwicklung)
- Minifizierung (Produktionsumgebung)
Typdeklarationen (tsc)
npm run build:types Läufe tsc --emitDeclarationOnly gegen tsconfig.build.json und gibt Folgendes aus:
| Datei | Verwenden |
|---|---|
dist/types/index.d.ts | Öffentlichen Typ-Eintrag, auf den verwiesen wird von package.json#types |
dist/types/**/*.d.ts | Modulbezogene Deklarationen für „Tree-Shake“-fähige benannte Importe |
CSS (clean-css)
build/build-css.js erzeugt:
| Datei | Verwendung |
|---|---|
vidply.css | Entwicklung |
vidply.min.css | Produktion |
🎯 Architektur
Kernkomponenten
Player
├── ControlBar # UI controls
│ ├── PlayButton
│ ├── ProgressBar
│ ├── VolumeControl
│ ├── DownloadButton # opt-in via downloadButton/downloadUrl
│ ├── PipButton # native PiP, or pin/unpin custom floating player when floating: true
│ ├── SettingsButton
│ └── FullscreenButton
├── BufferingOverlay # Centered loading spinner (.vidply-loading)
├── CaptionManager # Captions/subtitles
├── KeyboardManager # Keyboard shortcuts
├── TranscriptManager # Interactive transcript
├── FloatingPlayerManager # Custom in-page miniplayer ("own PiP"), opt-in via floating: true
├── Renderer # Media playback
│ ├── HTML5Renderer
│ ├── YouTubeRenderer
│ ├── VimeoRenderer
│ ├── SoundCloudRenderer
│ ├── HLSRenderer # hls.js + native iOS TextTrack bridge
│ └── DASHRenderer
└── PlaylistManager # Playlist handling
Ereignisablauf
User Action → KeyboardManager/ControlBar → Player → Renderer → DOM
↓
EventEmitter → External Listeners
Auswahl des Renderers
// src/core/Player.ts
selectRenderer(src: string): RendererCtor {
if (isYouTubeUrl(src)) return YouTubeRenderer;
if (isVimeoUrl(src)) return VimeoRenderer;
if (src.includes('soundcloud.com')) return SoundCloudRenderer;
if (isHLSUrl(src)) return HLSRenderer; // hls.js (or native HLS on iOS/iPadOS)
if (isDASHUrl(src)) return DASHRenderer;
return HTML5Renderer;
}
Der HLS-Renderer entscheidet selbst, ob er
hls.js(Chrome / Firefox / Edge / Desktop-Safari) oder die native<video>HLS-Unterstützung (iOS / iPadOS, wo MSE nicht verfügbar ist). Beim nativen Pfad wird dieTextTrackin die Benutzeroberfläche von VidPly für Untertitel, Transkripte und Qualität ein, sodass die Funktionsparität gewahrt bleibt.
📝 Funktionen hinzufügen
Neue Schaltfläche
- Zur Steuerleiste hinzufügen (
src/controls/ControlBar.ts):
createMyButton(): HTMLButtonElement {
const button = document.createElement('button');
button.className = 'vidply-button vidply-my-button';
button.setAttribute('aria-label', i18n.t('player.myButton'));
button.innerHTML = Icons.myIcon;
button.addEventListener('click', () => this.player.myAction());
return button;
}
- Symbol „Hinzufügen“ (
src/icons/Icons.ts):
export const Icons = {
// ...existing icons
myIcon: `<svg>...</svg>`,
} as const;
- Übersetzung hinzufügen (
src/i18n/languages/en.ts):
export default {
player: {
// ...existing
myButton: 'My Button',
}
};
- Zur Player-API hinzufügen (
src/core/Player.ts):
myAction(): void {
this.emit('myaction');
}
Neuer Renderer
- Renderer erstellen (
src/renderers/MyRenderer.ts):
import type { Player } from '../core/Player';
export class MyRenderer {
constructor(public player: Player) {}
async init(): Promise<void> { /* ... */ }
async load(src: string): Promise<void> { /* ... */ }
play(): void { /* ... */ }
pause(): void { /* ... */ }
seek(time: number): void { /* ... */ }
setVolume(vol: number): void { /* ... */ }
getCurrentTime(): number { /* ... */ }
getDuration(): number { /* ... */ }
destroy(): void { /* ... */ }
}
- Im Player registrieren:
import { MyRenderer } from '../renderers/MyRenderer';
// In selectRenderer()
if (isMyServiceUrl(src)) return MyRenderer;
Neue Sprache
- Sprachdatei erstellen (
src/i18n/languages/pt.ts):
export default {
player: {
play: 'Reproduzir',
pause: 'Pausar',
// ... all translations
}
};
- Registrieren (
src/i18n/translations.ts):
import pt from './languages/pt';
export const translations = {
en, de, es, fr, ja,
pt,
};
🎨 CSS-Architektur
Variablen
:root {
/* Colors */
--vidply-primary-color: #3b82f6;
--vidply-background: rgba(0, 0, 0, 0.8);
--vidply-text-color: #ffffff;
/* Sizing */
--vidply-button-size: 40px;
--vidply-icon-size: 20px;
/* Spacing */
--vidply-gap-sm: 4px;
--vidply-gap-md: 8px;
--vidply-gap-lg: 12px;
}
BEM-Namenskonvention
.vidply-player { } /* Block */
.vidply-player--fullscreen { } /* Modifier */
.vidply-controls { } /* Block */
.vidply-controls__left { } /* Element */
.vidply-button { } /* Block */
.vidply-button--active { } /* Modifier */
Barrierefreiheit
/* High contrast mode */
@media (forced-colors: active) {
.vidply-button {
border: 1px solid currentColor;
}
}
/* Focus visible */
.vidply-button:focus-visible {
outline: 2px solid var(--vidply-primary-color);
outline-offset: 2px;
}
/* Touch targets */
.vidply-button {
min-width: 44px;
min-height: 44px;
}
🧪 Testen
Manuelles Testen
- Öffnen
localhostnachnpm run dev - Test-Demos:
demo/demo.html- Alle Funktionendemo/playlist-audio.html- Audio-Wiedergabelistendemo/playlist-video.html- Video-Playlistsdemo/hls-test.html- HLS-Streamingdemo/dash-test.html- DASH-Streaming
Barrierefreiheitstests
- Tastatur: Navigation ausschließlich über die Tastatur
- Bildschirmleseprogramm: Testen mit NVDA/VoiceOver
- Hoher Kontrast: Windows-Hochkontrastmodus aktivieren
- Mobilgeräte: Touch-Interaktionen testen
Browsertests
| Browser | Priorität |
|---|---|
| Chrome | Hoch |
| Firefox | Hoch |
| Safari | Hoch |
| Edge | Mittel |
| iOS Safari | Hoch |
| Android Chrome | Mittel |
🔌 Plugin-System
EventEmitter
// Player extends EventEmitter
player.on('play', () => console.log('Playing'));
player.on('pause', () => console.log('Paused'));
player.on('timeupdate', (time) => console.log(time));
// Custom events
player.emit('mycustomevent', { data: 'value' });
Verfügbare Ereignisse
| Ereignis | Daten | Beschreibung |
|---|---|---|
ready | - | Player initialisiert |
play | - | Wiedergabe gestartet |
pause | - | Wiedergabe angehalten |
ended | - | Wiedergabe beendet |
timeupdate | Zeit | Aktuelle Zeit geändert |
volumechange | Lautstärke | Lautstärke geändert |
playbackspeedchange | Geschwindigkeit | Geschwindigkeit geändert |
fullscreenchange | istVollbild | Vollbild umgeschaltet |
hlsmanifestparsed | Daten | HLS-Manifest analysiert |
dashqualitychanged | Daten | DASH-Qualität geändert |
textcuesupdate | - | Neue Text-Cues verfügbar (HLS/DASH) |
captionsenabled | Spur | Untertitel aktiviert |
captionsdisabled | - | Untertitel deaktiviert |
playlisttrackchange | Element | Titel in der Wiedergabeliste geändert |
error | Fehler | Es ist ein Fehler aufgetreten |
🐛 Debugging
Debug-Modus aktivieren
const player = new Player('#video', { debug: true });
Konsolenprotokollierung
if (this.options.debug) {
console.log('[VidPly]', message, data);
}
Häufige Probleme
| Problem | Schritte zur Fehlerbehebung |
|---|---|
| Der Player wird nicht initialisiert | Überprüfen Sie das data-vidply Attribut; Konsolenfehler prüfen |
| Renderer wird nicht geladen | Überprüfen Sie das Format der Quell-URL; überprüfen Sie die Netzwerkanfragen |
| Untertitel werden nicht angezeigt | VTT-Syntax überprüfen; CORS überprüfen |
| Tastatur funktioniert nicht | Überprüfen Sie keyboard: true; Fokus überprüfen |
📚 Dokumentationsdateien
| Datei | Inhalt |
|---|---|
| Erste Schritte mit VidPly | Grundlegende Einrichtung |
| Bedienungsanleitung | Detaillierte API-Verwendung |
| Playlist-Funktion | Funktionen der Wiedergabeliste |
| Interaktive Transkriptfunktion | Transkriptionssystem |
| Tastaturkürzel | Tastaturkürzel |
| Build-Anleitung | Details zum Build-System |
| Änderungsprotokoll | Versionshistorie |
| Benutzerhandbuch: VidPly Player | Integrationshandbuch |
🔗 Kurzreferenz
Wichtige Dateien
| Was | Wo |
|---|---|
| Einstiegspunkt | src/index.ts |
| Player-Klasse | src/core/Player.ts |
| Typ der Spieleroptionen | src/types/options.ts |
| Steuerleiste | src/controls/ControlBar.ts |
| Untertitel | src/controls/CaptionManager.ts |
| Tastatur | src/controls/KeyboardManager.ts |
| i18n | src/i18n/i18n.ts |
| Stile | src/styles/vidply.css |
| Symbole | src/icons/Icons.ts |
| TypeScript-Konfiguration | tsconfig.json |
Build-Ausgabe
| Datei | Format | Größe |
|---|---|---|
vidply.esm.min.js | ESM | ~45 KB |
vidply.min.js | IIFE | ~50 KB |
vidply.min.css | CSS | ~15 KB |
Externe Abhängigkeiten
| Abhängigkeit | Festgelegte Version | Zweck | Geladen |
|---|---|---|---|
| hls.js | 1.6.16 | HLS-Streaming (Chrome / Firefox / Edge / Safari auf dem Desktop) | On-Demand (CDN-Fallback) |
| dash.js | 5.2.0 (modernes UMD) | DASH-Streaming | On-Demand (CDN-Fallback) |
| YouTube-IFrame-API | — | YouTube-Wiedergabe | Auf Abruf |
| Vimeo-Player-API | — | Vimeo-Wiedergabe | Auf Abruf |
| SoundCloud-Widget-API | — | SoundCloud-Wiedergabe | Auf Abruf |
Standard-CDN-Fallback-URLs (Überschreiben über hlsScriptUrl / dashScriptUrl):
🤝 Mitwirken
- Repository forken
- Feature-Branch erstellen:
git checkout -b feature/my-feature - Änderungen vornehmen
- Gründlich testen
- Erstellen:
npm run build - Commit:
git commit -m 'Add my feature' - Push:
git push origin feature/my-feature - Pull-Anfrage öffnen
Code-Stil
- Strict TypeScript (
strict: true,noImplicitAny,strictNullChecks) - BEM-CSS-Namenskonvention
- Aussagekräftige Variablennamen
- Kommentiere nicht offensichtliche Absichten (nicht das, was der Code tut)
- Füge ARIA-Attribute zu jedem interaktiven Element hinzu
- Ausführen
npm run typecheckundnpm run testvor dem Commit
Version: 1.1.7 | Lizenz: GPL-2.0-oder-später