# 🎬 @alper/video-player - Tam Dökümantasyon **Modern, zengin özellikli ve hafif React video oynatıcı kütüphanesi** [](https://www.npmjs.com/package/@alper/video-player) [](https://bundlephobia.com/package/@alper/video-player) [](https://www.typescriptlang.org/) [](https://opensource.org/licenses/MIT) --- ## 📑 İçindekiler - [Genel Bakış](#-genel-bakış) - [Kurulum](#-kurulum) - [NPM/PNPM ile Kurulum](#1-npmpnpm-ile-kurulum) - [.npmrc Yapılandırması](#2-npmrc-yapılandırması) - [Kütüphaneyi Yükleme](#3-kütüphaneyi-yükleme) - [Hızlı Başlangıç](#-hızlı-başlangıç) - [Mimari ve Yapı](#-mimari-ve-yapı) - [Özellikler](#-özellikler) - [Video Format Desteği](#video-format-desteği) - [Altyazı Sistemi](#altyazı-sistemi) - [Ses Parça Yönetimi](#ses-parça-yönetimi) - [Kalite Seviyesi Kontrolü](#kalite-seviyesi-kontrolü) - [Klavye Kısayolları](#klavye-kısayolları) - [Dokunmatik Jestler](#dokunmatik-jestler) - [API Referansı](#-api-referansı) - [VideoPlayer Props](#videoplayer-props) - [Exported Components](#exported-components) - [Exported Hooks](#exported-hooks) - [Exported Utilities](#exported-utilities) - [Type Definitions](#type-definitions) - [Kullanım Örnekleri](#-kullanım-örnekleri) - [Gelişmiş Kullanım](#-gelişmiş-kullanım) - [State Yönetimi](#-state-yönetimi) - [Tema ve Özelleştirme](#-tema-ve-özelleştirme) - [Uluslararasılaştırma (i18n)](#-uluslararasılaştırma-i18n) - [Performans](#-performans) - [Tarayıcı Uyumluluğu](#-tarayıcı-uyumluluğu) - [Hata Yönetimi](#-hata-yönetimi) - [Geliştirme](#-geliştirme) - [Katkıda Bulunma](#-katkıda-bulunma) - [Lisans](#-lisans) --- ## 🌟 Genel Bakış `@alper/video-player`, React uygulamaları için özel olarak tasarlanmış, modern bir video oynatıcı kütüphanesidir. HLS streaming, RTMP/FLV desteği, çoklu altyazı ve ses parçaları, kalite değiştirme ve daha fazlası gibi gelişmiş özellikleri içerir. ### Neden @alper/video-player? | Özellik | @alper/video-player | video.js | react-player | plyr | |---------|---------------------|----------|--------------|------| | **Paket Boyutu (gzipped)** | **~15KB** ✅ | ~500KB ❌ | ~50KB ⚠️ | ~30KB ⚠️ | | **Runtime Bağımlılıkları** | **0** ✅ | Çok ❌ | Az ⚠️ | Az ⚠️ | | **React Native** | **Evet** ✅ | Wrapper ⚠️ | **Evet** ✅ | Wrapper ⚠️ | | **TypeScript Native** | **Evet** ✅ | Types ⚠️ | Kısmi ⚠️ | Types ⚠️ | | **HLS Desteği** | **Evet** ✅ | Evet ✅ | Evet ✅ | Hayır ❌ | | **RTMP/FLV Desteği** | **Evet** ✅ | Hayır ❌ | Hayır ❌ | Hayır ❌ | | **Kalite Değiştirme** | **Evet** ✅ | Evet ✅ | Sınırlı ⚠️ | Hayır ❌ | | **Dokunmatik Jestler** | **15+** ✅ | Sınırlı ⚠️ | Hayır ❌ | Sınırlı ⚠️ | | **Klavye Kısayolları** | **15+** ✅ | ~8 ⚠️ | Temel ⚠️ | ~10 ⚠️ | | **i18n Desteği** | **Evet** ✅ | Evet ✅ | Hayır ❌ | Evet ✅ | ### Ana Avantajlar - 📦 **%97 daha küçük** - video.js'e göre sadece 15KB (500KB yerine) - ⚡ **Çok hızlı** - Sıfır runtime bağımlılık, daha hızlı yükleme - 🎯 **React-first** - React için özel yapılmış, wrapper değil - 🔧 **Tam TypeScript** - Box'tan çıktığı gibi tam tip güvenliği - 🎨 **Kolay özelleştirme** - CSS değişkenleri ile tema desteği - 📱 **Mobil hazır** - Kapsamlı dokunmatik jest desteği - 🌍 **Uluslararasılaştırılmış** - İngilizce ve Türkçe yerleşik i18n - ♿ **Erişilebilir** - ARIA etiketleri ve klavye navigasyonu - 🎬 **Çoklu format** - MP4, WebM, HLS (.m3u8), RTMP/FLV desteği - 🔒 **Güvenli** - CORS hatası tespiti ve yardımcı hata mesajları --- ## 📦 Kurulum Bu kütüphane, Gitea üzerinde barındırılan özel bir npm registry'de yayınlanmaktadır. Kurulum için aşağıdaki adımları takip edin. ### 1. NPM/PNPM ile Kurulum Öncelikle projenizde npm veya pnpm kurulu olduğundan emin olun: ```bash # npm kurulu mu kontrol et npm --version # pnpm kurulu mu kontrol et (opsiyonel, hızlı alternatif) pnpm --version # pnpm kurulu değilse npm install -g pnpm ``` ### 2. .npmrc Yapılandırması `@alper` scope'lu paketlerin Gitea registry'den çekilmesi için projenizin kök dizininde bir `.npmrc` dosyası oluşturmanız gerekir. #### Adım 2.1: .npmrc Dosyası Oluşturma Projenizin **kök dizininde** (package.json dosyasının bulunduğu yerde) `.npmrc` adlı bir dosya oluşturun: ```bash # Linux/Mac touch .npmrc # Windows (PowerShell) New-Item -Path .npmrc -ItemType File ``` #### Adım 2.2: .npmrc İçeriği `.npmrc` dosyasını aşağıdaki içerikle doldurun: ```ini # @alper scope'u için Gitea registry'yi kullan @alper:registry=https://gitea.hibna.com.tr/api/packages/hibna/npm/ # Authentication token # Token'ınızı almak için: https://gitea.hibna.com.tr/user/settings/applications # "Generate New Token" butonuna tıklayın ve "read:package" yetkisini seçin //gitea.hibna.com.tr/api/packages/hibna/npm/:_authToken=YOUR_TOKEN_HERE ``` **ÖNEMLİ:** `YOUR_TOKEN_HERE` kısmını kendi Gitea access token'ınız ile değiştirin! #### Adım 2.3: Gitea Access Token Alma 1. Gitea hesabınıza giriş yapın: https://gitea.hibna.com.tr 2. Sağ üst köşeden profil ikonuna tıklayın → **Settings** 3. Sol menüden **Applications** seçeneğine tıklayın 4. **Manage Access Tokens** bölümünde **Generate New Token** butonuna tıklayın 5. Token için bir isim verin (örn: "video-player-npm") 6. **Select permissions** bölümünde şu yetkileri seçin: - `read:package` - Paketleri okuma yetkisi - (Yayınlayacaksanız) `write:package` - Paket yayınlama yetkisi 7. **Generate Token** butonuna tıklayın 8. Oluşturulan token'ı kopyalayın (bu token sadece bir kez gösterilir!) 9. Token'ı `.npmrc` dosyasındaki `YOUR_TOKEN_HERE` yerine yapıştırın #### Adım 2.4: .npmrc'yi .gitignore'a Ekleyin **ÇOK ÖNEMLİ:** Token'ınızı Git'e commit etmeyin! `.npmrc` dosyasını `.gitignore`'a ekleyin: ```bash # .gitignore dosyasına ekleyin echo ".npmrc" >> .gitignore ``` `.gitignore` dosyanız şöyle görünmeli: ``` node_modules/ dist/ .npmrc # ← Bu satırı ekleyin .env ``` #### Alternatif: Environment Variable Kullanımı (Önerilen - Daha Güvenli) Daha güvenli bir yöntem için token'ı environment variable olarak saklayabilirsiniz: **.npmrc dosyası:** ```ini @alper:registry=https://gitea.hibna.com.tr/api/packages/hibna/npm/ //gitea.hibna.com.tr/api/packages/hibna/npm/:_authToken=${GITEA_TOKEN} ``` **Environment variable ayarlama:** ```bash # Linux/Mac (.bashrc veya .zshrc dosyasına ekleyin) export GITEA_TOKEN=your-actual-token-here # Windows (PowerShell) $env:GITEA_TOKEN="your-actual-token-here" # Windows (Kalıcı - Sistem Environment Variables) # Sistem Özellikler → Gelişmiş → Ortam Değişkenleri → Yeni # Değişken adı: GITEA_TOKEN # Değişken değeri: your-actual-token-here ``` **CI/CD için (GitHub Actions, GitLab CI, vb.):** Repository settings → Secrets → `GITEA_TOKEN` adında bir secret oluşturun. ### 3. Kütüphaneyi Yükleme `.npmrc` dosyası yapılandırıldıktan sonra, kütüphaneyi yükleyebilirsiniz: ```bash # npm ile npm install @alper/video-player # veya pnpm ile (önerilen - daha hızlı) pnpm add @alper/video-player # veya yarn ile yarn add @alper/video-player ``` ### 4. Peer Dependencies Kütüphane, React 18+ gerektirir. Eğer projenizde yoksa: ```bash npm install react@^18.0.0 react-dom@^18.0.0 # veya pnpm add react@^18.0.0 react-dom@^18.0.0 ``` ### 5. Optional Dependencies (Otomatik) HLS ve RTMP/FLV desteği için gerekli kütüphaneler, ihtiyaç duyulduğunda **otomatik olarak lazy-load** edilir: - `hls.js` - HLS streaming için (.m3u8 dosyaları) - `flv.js` - RTMP/FLV streaming için Bu kütüphaneler manuel kuruluma gerek yoktur. Ancak bundle size'ı azaltmak için isterseniz kurabilirsiniz: ```bash npm install --save-optional hls.js flv.js ``` ### Kurulum Doğrulama Kurulumun başarılı olduğunu doğrulamak için: ```bash npm list @alper/video-player # veya pnpm list @alper/video-player ``` Çıktı şöyle olmalı: ``` your-project@1.0.0 └─┬ @alper/video-player@0.1.5 ``` ### Sorun Giderme **Problem: "401 Unauthorized" hatası** - `.npmrc` dosyasındaki token'ın doğru olduğundan emin olun - Token'ın `read:package` yetkisine sahip olduğundan emin olun - Token'ın süresi dolmamış olduğundan emin olun **Problem: "404 Not Found" hatası** - Registry URL'inin doğru olduğundan emin olun - `@alper:registry=https://gitea.hibna.com.tr/api/packages/hibna/npm/` - İnternet bağlantınızı kontrol edin - Gitea sunucusunun erişilebilir olduğundan emin olun **Problem: "Cannot find module '@alper/video-player'"** - `node_modules` klasörünü silin ve yeniden yükleyin: ```bash rm -rf node_modules package-lock.json npm install ``` --- ## 🚀 Hızlı Başlangıç ### Temel Kullanım ```tsx import { VideoPlayer } from '@alper/video-player' import '@alper/video-player/styles.css' function App() { return ( ) } ``` ### HLS Streaming ile Kullanım ```tsx ``` ### Event Handler'lar ile Kullanım ```tsx console.log('Video oynatılmaya başladı')} onPause={() => console.log('Video durakladı')} onEnded={() => console.log('Video bitti')} onTimeUpdate={(time) => console.log('Geçerli zaman:', time)} onError={(error) => console.error('Video hatası:', error)} /> ``` ### Tema Özelleştirmesi ```tsx ``` --- ## 🏗️ Mimari ve Yapı ### Proje Yapısı ``` video-player/ ├── src/ │ ├── components/ # React UI bileşenleri │ │ ├── controls/ # Kontrol butonları (Play, Pause, vb.) │ │ │ ├── PlayPauseButton.tsx │ │ │ ├── ProgressBar.tsx │ │ │ ├── VolumeControl.tsx │ │ │ ├── TimeDisplay.tsx │ │ │ ├── FullscreenButton.tsx │ │ │ ├── PIPButton.tsx │ │ │ ├── SettingsButton.tsx │ │ │ └── CenterPlayButton.tsx │ │ ├── menus/ # Ayar menüleri │ │ │ └── SettingsMenu.tsx │ │ ├── overlays/ # Overlay bileşenleri │ │ │ └── LoadingSpinner.tsx │ │ ├── VideoPlayer.tsx # Ana wrapper bileşen │ │ ├── VideoElement.tsx # Video element handler │ │ └── ControlsLayer.tsx # Kontrol katmanı │ ├── contexts/ # React Context │ │ └── PlayerContext.tsx │ ├── hooks/ # Custom React hooks │ │ ├── useKeyboardShortcuts.ts │ │ └── useTouchGestures.ts │ ├── utils/ # Utility fonksiyonlar │ │ ├── hlsSetup.ts # HLS.js setup │ │ ├── hlsLoader.ts # HLS.js lazy loading │ │ ├── hlsControl.ts # HLS kalite/ses kontrolü │ │ ├── rtmpSetup.ts # FLV.js setup │ │ ├── rtmpLoader.ts # FLV.js lazy loading │ │ ├── videoProtocol.ts # Protokol tespiti │ │ ├── m3u8Parser.ts # M3U8 manifest parsing │ │ ├── subtitles.ts # SRT/VTT altyazı işleme │ │ ├── corsHelper.ts # CORS doğrulama │ │ ├── time.ts # Zaman formatlama │ │ └── polyfills.ts # Tarayıcı uyumluluk │ ├── icons/ # SVG icon bileşenleri │ │ └── index.tsx │ ├── styles/ # CSS değişkenleri │ │ └── variables.css │ ├── i18n/ # Uluslararasılaştırma │ │ └── index.ts # İngilizce & Türkçe │ ├── types/ # TypeScript tanımları │ │ └── index.ts │ └── index.ts # Ana export dosyası ├── examples/ # Demo uygulaması │ ├── App.tsx │ └── main.tsx ├── dist/ # Build çıktısı ├── package.json ├── vite.config.ts # Geliştirme config ├── vite.config.lib.ts # Kütüphane build config └── tsconfig.json ``` ### Bileşen Hiyerarşisi ``` VideoPlayer (Main) ├── PlayerProvider (Context) │ ├── VideoElement (Video handler) │ │ └── element │ ├── ControlsLayer (Controls container) │ │ ├── CenterPlayButton (Overlay) │ │ ├── PlayPauseButton │ │ ├── ProgressBar │ │ ├── VolumeControl │ │ ├── TimeDisplay │ │ ├── SettingsButton │ │ ├── FullscreenButton │ │ ├── PIPButton │ │ └── SettingsMenu (Lazy-loaded) │ │ ├── Main Menu │ │ ├── Speed Menu │ │ ├── Quality Menu │ │ ├── Subtitle Menu │ │ └── Audio Track Menu │ └── LoadingSpinner (Overlay) ``` ### State Management Kütüphane, **React Context API** kullanarak merkezi state yönetimi sağlar: - **VideoState**: Video durumu (playing, currentTime, duration, vb.) - **UIState**: UI durumu (controls visibility, menu states, vb.) - **PlayerSettings**: Player ayarları (quality, subtitle, audioTrack, vb.) Context yapısı, tüm child bileşenlerin state'e erişmesini ve güncellemesini sağlar. --- ## ✨ Özellikler ### Video Format Desteği #### 1. Native HTML5 Video (MP4, WebM, OGG) **Desteklenen Formatlar:** - MP4 (H.264/H.265 codec) - WebM (VP8/VP9 codec) - OGG (Theora codec) **Nasıl Çalışır:** - Doğrudan `` elementi ile `src` attribute kullanılır - HTTP Range Request desteği ile progressive download - Harici kütüphane gerektirmez - Tüm modern tarayıcılarda native destek **Kullanım:** ```tsx ``` #### 2. HLS Streaming (.m3u8) **Özellikler:** - Adaptive bitrate streaming (ABR) - Çoklu kalite seviyeleri - Çoklu ses parçaları - Altyazı parça çıkarma - Otomatik kalite seçimi - Live stream desteği **Kütüphane:** hls.js (opsiyonel, lazy-loaded) **Safari Desteği:** Safari'de native HLS desteği var, kütüphane yüklenmez **Loading Stratejisi:** 1. HLS source tespit edilir (.m3u8 uzantısı) 2. Safari ise → Native HLS kullanılır 3. Diğer tarayıcılarda: - Önce NPM package'dan hls.js yüklenir - Başarısız olursa CDN'den fallback (jsdelivr) - MSE desteği kontrol edilir **CDN Fallback:** ``` https://cdn.jsdelivr.net/npm/hls.js@1.5.13 ``` **Kullanım:** ```tsx ``` **Manifest Örneği:** ```m3u8 #EXTM3U #EXT-X-VERSION:3 # Kalite seviyeleri #EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1920x1080 1080p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=1280x720 720p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=500000,RESOLUTION=854x480 480p.m3u8 # Ses parçaları #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English",LANGUAGE="en",URI="audio_en.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="Turkish",LANGUAGE="tr",URI="audio_tr.m3u8" ``` **Hata Yönetimi:** - Network hataları → Otomatik yeniden bağlanma - Media hataları → HLS instance yeniden başlatma - Fatal hataları → Error state'e düşme #### 3. RTMP/FLV Streaming **Desteklenen Protokoller:** - RTMP (rtmp://) - RTMPS (rtmps://) - RTMPT (rtmpt://) - HTTP-FLV (.flv veya flv? query) **Kütüphane:** flv.js (opsiyonel, lazy-loaded) **Özellikler:** - Live stream desteği - Hata recovery - İstatistik takibi - Low latency **Loading Stratejisi:** 1. RTMP/FLV source tespit edilir 2. Önce NPM package'dan flv.js yüklenir 3. Başarısız olursa CDN'den fallback 4. MSE desteği kontrol edilir **CDN Fallback:** ``` https://cdn.jsdelivr.net/npm/flv.js@1.6.2 ``` **ÖNEMLİ NOT:** Doğrudan RTMP URL'leri tarayıcıda çalışmaz. HTTP-FLV proxy gerektirir. **Kullanım:** ```tsx // HTTP-FLV // RTMP (HTTP-FLV proxy gerektirir) ``` #### 4. IPTV (MPEG-TS) Streaming **Desteklenen Format:** - MPEG-TS (.ts) - Direct transport stream files **Kütüphane:** Yok (Native HTML5 video element) **Özellikler:** - Doğrudan HTTP üzerinden TS stream oynatma - Canlı IPTV kanalları için ideal - Ek kütüphane gerekmez **Tarayıcı Desteği:** - ⚠️ **Sınırlı destek**: Tüm tarayıcılar MPEG-TS formatını desteklemez - ✅ **Chrome/Edge**: Genellikle destekler - ⚠️ **Firefox**: Sınırlı destek - ⚠️ **Safari**: Sınırlı destek - ℹ️ **Alternatif**: M3U8 playlist üzerinden IPTV kullanımı önerilir **Kullanım:** ```tsx // IPTV (MPEG-TS) - Direct stream { console.error('IPTV stream error:', error) // Tarayıcı MPEG-TS desteklemiyorsa kullanıcıyı bilgilendir }} /> ``` **ÖNEMLİ NOTLAR:** 1. **Tarayıcı Uyumluluğu**: Tüm tarayıcılar `.ts` dosyalarını doğrudan oynatamaz 2. **Alternatif Çözüm**: Mümkünse IPTV sağlayıcınızdan `.m3u8` (HLS) link isteyin 3. **CORS**: IPTV sunucusu CORS ayarlarını doğru yapılandırmalıdır 4. **Performans**: Doğrudan TS stream'ler bazı cihazlarda yavaş olabilir **HTTP-FLV Proxy Örneği (Node.js):** ```javascript // RTMP stream'i HTTP-FLV'ye dönüştüren proxy const ffmpeg = require('fluent-ffmpeg'); ffmpeg('rtmp://source.com/live/stream') .outputOptions([ '-c copy', '-f flv' ]) .pipe(res); ``` #### 5. DASH Support (Planlanıyor) **Durum:** Protokol tespit ediliyor ancak henüz implement edilmemiş **.mpd URL'leri tespit edilir ve hata mesajı döner:** ``` DASH streaming is detected but not yet supported ``` **Gelecek implementasyon** dash.js kütüphanesi ile planlanıyor. ### Protocol Detection System **Dosya:** `src/utils/videoProtocol.ts` Video URL'inden otomatik protokol tespiti: ```typescript function detectVideoProtocol(url: string): { protocol: VideoProtocol isLive: boolean needsSpecialPlayer: boolean } ``` **Tespit Mantığı:** 1. **HLS:** `.m3u8` uzantısı 2. **RTMP:** `rtmp://`, `rtmps://`, `rtmpt://`, `rtmpe://` protokolleri 3. **FLV:** `.flv` uzantısı veya URL'de `flv?` var 4. **DASH:** `.mpd` uzantısı 5. **Native:** Diğer her şey (MP4, WebM, vb.) **Live Stream Tespiti:** - RTMP/FLV → Her zaman live - HLS → Manifest'te `#EXT-X-PLAYLIST-TYPE:VOD` yoksa live - Diğerleri → VOD **Kullanım:** ```typescript import { detectVideoProtocol } from '@alper/video-player' const info = detectVideoProtocol('https://example.com/stream.m3u8') console.log(info.protocol) // 'hls' console.log(info.isLive) // true/false console.log(info.needsSpecialPlayer) // true ``` ### Altyazı Sistemi **Dosyalar:** - `src/utils/subtitles.ts` - Altyazı işleme - `src/components/VideoElement.tsx` - Altyazı entegrasyonu #### Desteklenen Formatlar **1. WebVTT (.vtt):** - Native tarayıcı desteği - Doğrudan `` elementi ile kullanılır **2. SRT (.srt):** - WebVTT'ye otomatik dönüştürme - Blob URL ile tarayıcıya verilir #### Özellikler - ✅ Çoklu altyazı parçaları - ✅ Dil seçimi - ✅ Varsayılan altyazı desteği - ✅ Yüklendiğinde otomatik etkinleştirme - ✅ SRT → VTT dönüşümü - ✅ HLS manifest'ten altyazı çıkarma - ✅ Manuel ve HLS altyazı birleştirme #### SRT → VTT Dönüşümü **SRT Format:** ```srt 1 00:00:01,000 --> 00:00:04,000 Merhaba dünya 2 00:00:05,000 --> 00:00:08,000 İkinci altyazı ``` **WebVTT Format (dönüştürülmüş):** ```vtt WEBVTT 00:00:01.000 --> 00:00:04.000 Merhaba dünya 00:00:05.000 --> 00:00:08.000 İkinci altyazı ``` **Dönüşüm Fonksiyonu:** ```typescript import { parseSRT, createSubtitleBlobURL } from '@alper/video-player' const srtContent = '...' // SRT içeriği const vttContent = parseSRT(srtContent) const blobUrl = createSubtitleBlobURL(vttContent) // blobUrl → blob:http://localhost:5173/abc123... ``` #### Implementation Akışı 1. Altyazı dosyaları fetch edilir 2. SRT ise WebVTT'ye dönüştürülür 3. Blob URL'leri oluşturulur 4. `` elementleri dinamik olarak eklenir 5. Track mode Settings context üzerinden kontrol edilir 6. Component unmount'ta blob URL'leri temizlenir #### Kullanım **Temel Kullanım:** ```tsx ``` **HLS ile Otomatik Altyazı (manifest'ten):** ```tsx // HLS manifest'te altyazılar varsa otomatik ekler ``` **Programmatic Control:** ```tsx import { usePlayerContext } from '@alper/video-player' function CustomSubtitleToggle() { const { settings, setSubtitle } = usePlayerContext() return ( setSubtitle(settings.subtitle ? null : mySubtitle)}> {settings.subtitle ? 'Altyazıyı Kapat' : 'Altyazıyı Aç'} ) } ``` ### Ses Parça Yönetimi **Dosyalar:** - `src/utils/hlsLoader.ts` - HLS ses parçası çıkarma - `src/utils/hlsControl.ts` - Ses parçası kontrolü #### Özellikler - ✅ HLS manifest'ten ses parçası çıkarma - ✅ Oynatma sırasında değiştirme - ✅ Dil tespiti - ✅ Varsayılan parça seçimi - ✅ Otomatik seçim desteği #### HLS Manifest'ten Çıkarma **Manifest Örneği:** ```m3u8 #EXTM3U #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en",URI="audio_en.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="Turkish",LANGUAGE="tr",URI="audio_tr.m3u8" ``` **Çıkarılan AudioTrack:** ```typescript { name: "English", language: "en", url: "audio_en.m3u8", groupId: "audio", default: true, autoselect: true } ``` #### Kullanım **Programmatic Control:** ```tsx import { usePlayerContext } from '@alper/video-player' function AudioTrackSelector() { const { settings, setAudioTrack } = usePlayerContext() const [tracks] = useState([...]) // HLS'den alınan parçalar return ( { const track = tracks.find(t => t.name === e.target.value) setAudioTrack(track || null) }} > {tracks.map(track => ( {track.label} ({track.language}) ))} ) } ``` ### Kalite Seviyesi Kontrolü **Dosyalar:** - `src/utils/hlsLoader.ts` - Kalite çıkarma - `src/utils/hlsControl.ts` - Kalite kontrolü #### Özellikler - ✅ HLS'den çoklu kalite seviyeleri - ✅ Manuel kalite seçimi - ✅ Otomatik kalite (adaptive bitrate) - ✅ Çözünürlük bazlı etiketleme (1080p, 720p, vb.) - ✅ Bitrate bilgisi gösterimi - ✅ Seçilen kalitenin kalıcılığı #### Kalite Tespiti **HLS Manifest:** ```m3u8 #EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080 1080p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720 720p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=854x480 480p.m3u8 ``` **Çıkarılan VideoQuality:** ```typescript [ { label: "1080p", height: 1080, width: 1920, bitrate: 5000000, levelIndex: 0, url: "1080p.m3u8" }, { label: "720p", height: 720, width: 1280, bitrate: 2500000, levelIndex: 1, url: "720p.m3u8" }, // ... ] ``` #### Kalite Değiştirme **Otomatik Kalite (Adaptive Bitrate):** ```typescript import { setHlsQualityLevel } from '@alper/video-player' setHlsQualityLevel(hlsInstance, null) // Auto ``` **Manuel Kalite:** ```typescript setHlsQualityLevel(hlsInstance, { label: "1080p", levelIndex: 0, // ... }) ``` #### Kullanım **Settings Menu'den:** Kullanıcı Settings → Quality menüsünden kalite seçer. **Programmatic Control:** ```tsx import { usePlayerContext } from '@alper/video-player' function QualitySelector() { const { settings, setQuality } = usePlayerContext() const [qualities] = useState([...]) // HLS'den alınan return ( { if (e.target.value === 'auto') { setQuality(null) // Auto } else { const quality = qualities.find(q => q.label === e.target.value) setQuality(quality || null) } }} > Auto {qualities.map(q => ( {q.label} ({(q.bitrate! / 1000000).toFixed(1)} Mbps) ))} ) } ``` ### Klavye Kısayolları **Dosya:** `src/hooks/useKeyboardShortcuts.ts` #### Tüm Kısayollar | Tuş | Aksiyon | Açıklama | |-----|---------|----------| | `Space` | Oynat/Duraklat | Videoyu oynatır veya duraklatır | | `K` | Oynat/Duraklat | Space ile aynı | | `←` (Sol Ok) | -5 saniye | 5 saniye geri sar | | `→` (Sağ Ok) | +5 saniye | 5 saniye ileri sar | | `J` | -10 saniye | 10 saniye geri sar | | `L` | +10 saniye | 10 saniye ileri sar | | `↑` (Yukarı Ok) | Ses +10% | Sesi %10 artır | | `↓` (Aşağı Ok) | Ses -10% | Sesi %10 azalt | | `M` | Sessiz/Sesli | Sesi aç/kapat | | `F` | Tam ekran | Tam ekran moduna geç/çık | | `P` | PIP | Picture-in-Picture aç/kapat | | `0` | 0% | Videonun başına git | | `1` | 10% | Videonun %10'una git | | `2` | 20% | Videonun %20'sine git | | `3` | 30% | Videonun %30'una git | | `4` | 40% | Videonun %40'ına git | | `5` | 50% | Videonun ortasına git | | `6` | 60% | Videonun %60'ına git | | `7` | 70% | Videonun %70'ine git | | `8` | 80% | Videonun %80'ine git | | `9` | 90% | Videonun %90'ına git | | `Home` | Başa git | Videonun en başına git | | `End` | Sona git | Videonun en sonuna git | #### Özellikler - ✅ Input/textarea alanlarında devre dışı - ✅ Default tarayıcı davranışını önler - ✅ Enable/disable ile açılıp kapatılabilir - ✅ Fullscreen'de de çalışır #### Kullanım **Otomatik (default):** ```tsx // Klavye kısayolları otomatik aktif ``` **Manuel kontrol:** ```tsx ``` **Custom hook ile:** ```tsx import { useKeyboardShortcuts } from '@alper/video-player' function MyComponent() { const { videoRef, containerRef } = usePlayerContext() useKeyboardShortcuts({ videoRef, containerRef, enabled: true }) // ... } ``` ### Dokunmatik Jestler **Dosya:** `src/hooks/useTouchGestures.ts` #### Tüm Jestler | Jest | Aksiyon | Açıklama | |------|---------|----------| | Tek dokunuş (tap) | Oynat/Duraklat | Videoyu oynatır/duraklatır | | Çift dokunuş sol | -10 saniye | 10 saniye geri sar | | Çift dokunuş sağ | +10 saniye | 10 saniye ileri sar | | Yatay kaydırma (swipe) | Seek | Videoyu ileri/geri sar (max 30s) | | Dikey kaydırma (swipe) | Ses | Sesi artır/azalt | #### Özellikler - ✅ Tap tespiti (timeout ile) - ✅ Double-tap tespit (pozisyon bazlı - sol/sağ) - ✅ Görsel geri bildirim animasyonları - ✅ Swipe mesafesi hesaplama - ✅ Threshold değerleri (minimum hareket mesafesi) - ✅ Mobil ve tablet uyumlu #### Parametreler **Tap Timeout:** 300ms (çift dokunuş için bekleme süresi) **Swipe Threshold:** 50px (minimum swipe mesafesi) **Double Tap Zone:** Ekran genişliğinin 1/3'ü (sol/sağ bölge) #### Görsel Geri Bildirim **Double Tap Animasyonu:** - Sol tarafa çift dokunuş → "« 10s" animasyonu - Sağ tarafa çift dokunuş → "10s »" animasyonu - 500ms sonra kaybolur **Seek Feedback:** - Swipe sırasında progress bar güncellemesi - Seek edilen zamanın gösterimi #### Kullanım **Otomatik (mobil cihazlarda):** ```tsx // Touch jestleri otomatik aktif (touch destekli cihazlarda) ``` **Custom hook ile:** ```tsx import { useTouchGestures } from '@alper/video-player' function MyComponent() { const { videoRef, containerRef } = usePlayerContext() useTouchGestures({ videoRef, containerRef, onGesture: (event) => { console.log('Jest:', event.type, event.direction) } }) // ... } ``` --- ## 📚 API Referansı ### VideoPlayer Props ```typescript interface VideoPlayerProps { // Video kaynağı (zorunlu) src: string // Poster/thumbnail resmi poster?: string // Otomatik oynat autoplay?: boolean // Döngü loop?: boolean // Başlangıçta sessiz muted?: boolean // Kontrolleri göster (default: true) controls?: boolean // Altyazı parçaları subtitles?: SubtitleTrack[] // Tema özelleştirme theme?: PlayerTheme // Dil (i18n için) language?: string // Klavye kısayolları (default: true) keyboardShortcuts?: boolean // Picture-in-Picture butonu (default: true) pictureInPicture?: boolean // CSS class className?: string // Inline styles style?: CSSProperties // Event handlers onPlay?: () => void onPause?: () => void onEnded?: () => void onTimeUpdate?: (currentTime: number) => void onVolumeChange?: (volume: number) => void onError?: (error: Error) => void onLoadedMetadata?: () => void onSeeking?: () => void onSeeked?: () => void } ``` #### Prop Detayları **src** (zorunlu) - Tip: `string` - Video dosyasının URL'i - Desteklenen formatlar: - MP4: `https://example.com/video.mp4` - WebM: `https://example.com/video.webm` - HLS: `https://example.com/stream.m3u8` - RTMP: `rtmp://example.com/live/stream` - FLV: `https://example.com/stream.flv` **poster** - Tip: `string | undefined` - Video yüklenmeden önce gösterilecek resim - Önerilen format: JPG, PNG, WebP - Önerilen boyut: Video ile aynı aspect ratio **autoplay** - Tip: `boolean | undefined` - Default: `false` - NOT: Çoğu tarayıcı, `muted: true` olmadan autoplay'e izin vermez **loop** - Tip: `boolean | undefined` - Default: `false` - Video bittiğinde başa döner **muted** - Tip: `boolean | undefined` - Default: `false` - Başlangıçta sessiz moda alır **controls** - Tip: `boolean | undefined` - Default: `true` - `false` yaparsanız tüm kontroller gizlenir **subtitles** - Tip: `SubtitleTrack[] | undefined` - Altyazı parçaları dizisi - WebVTT (.vtt) ve SRT (.srt) desteklenir **theme** - Tip: `PlayerTheme | undefined` - CSS variable'ları override eder - Tüm alanlar opsiyonel **language** - Tip: `string | undefined` - Default: Tarayıcı dili - Desteklenen: `'en'`, `'tr'` **keyboardShortcuts** - Tip: `boolean | undefined` - Default: `true` - Klavye kısayollarını aktif/deaktif eder **pictureInPicture** - Tip: `boolean | undefined` - Default: `true` - PIP butonunu gösterir/gizler - Tarayıcı desteği yoksa otomatik gizlenir **onTimeUpdate** - Tip: `(currentTime: number) => void | undefined` - Video oynarken sürekli çağrılır (~250ms aralıklarla) - Analytics ve progress tracking için kullanışlı **onError** - Tip: `(error: Error) => void | undefined` - Video yükleme veya oynatma hatalarında çağrılır - CORS hataları için `isCORSError(error)` kullanabilirsiniz ### Type Definitions #### SubtitleTrack ```typescript interface SubtitleTrack { // Altyazı dosyasının URL'i (.vtt veya .srt) src: string // Dil kodu (ISO 639-1) lang: string // Kullanıcıya gösterilecek etiket label: string // Varsayılan altyazı olarak işaretle default?: boolean } ``` **Örnek:** ```typescript const subtitles: SubtitleTrack[] = [ { src: '/subtitles/english.vtt', lang: 'en', label: 'English', default: true }, { src: '/subtitles/turkish.srt', lang: 'tr', label: 'Türkçe' } ] ``` #### AudioTrack ```typescript interface AudioTrack { // Ses parçasının adı name: string // Dil kodu language: string // HLS manifest'teki URL url: string // Group ID (HLS) groupId: string // Varsayılan parça mı default?: boolean // Otomatik seçilsin mi autoselect?: boolean } ``` **Örnek:** ```typescript const audioTrack: AudioTrack = { name: "English Stereo", language: "en", url: "audio_en.m3u8", groupId: "audio", default: true, autoselect: true } ``` #### VideoQuality ```typescript interface VideoQuality { // Yükseklik (piksel) height?: number // Kullanıcıya gösterilecek etiket (örn: "1080p") label: string // Kalite stream URL'i (HLS) url?: string // Genişlik (piksel) width?: number // Bitrate (bits/second) bitrate?: number // HLS.js level index levelIndex?: number } ``` **Örnek:** ```typescript const quality: VideoQuality = { label: "1080p", height: 1080, width: 1920, bitrate: 5000000, levelIndex: 0, url: "1080p.m3u8" } ``` #### PlayerTheme ```typescript interface PlayerTheme { // Ana renk (progress bar, butonlar) primaryColor?: string // Vurgu rengi (hover states) accentColor?: string // Arka plan rengi backgroundColor?: string // Metin rengi textColor?: string } ``` **Örnek:** ```typescript const theme: PlayerTheme = { primaryColor: '#ef4444', // Kırmızı accentColor: '#dc2626', // Koyu kırmızı backgroundColor: '#000000', // Siyah textColor: '#ffffff' // Beyaz } ``` #### VideoState ```typescript interface VideoState { playing: boolean // Oynatılıyor mu currentTime: number // Geçerli zaman (saniye) duration: number // Toplam süre (saniye) buffered: number // Buffered zaman (saniye) volume: number // Ses seviyesi (0-1) muted: boolean // Sessiz mi playbackRate: number // Oynatma hızı (0.25-2) fullscreen: boolean // Tam ekran mı pictureInPicture: boolean // PIP modunda mı loading: boolean // Yükleniyor mu error: Error | null // Hata varsa seeking: boolean // Seek ediliyor mu } ``` #### UIState ```typescript interface UIState { controlsVisible: boolean // Kontroller görünür mü settingsOpen: boolean // Ayarlar menüsü açık mı volumeControlOpen: boolean // Ses kontrolü açık mı qualityMenuOpen: boolean // Kalite menüsü açık mı subtitleMenuOpen: boolean // Altyazı menüsü açık mı } ``` #### PlayerSettings ```typescript interface PlayerSettings { quality: VideoQuality | null // Seçili kalite (null = auto) subtitle: SubtitleTrack | null // Seçili altyazı (null = off) audioTrack: AudioTrack | null // Seçili ses parçası playbackRate: number // Oynatma hızı } ``` #### PlayerContextValue ```typescript interface PlayerContextValue { // State videoState: VideoState uiState: UIState settings: PlayerSettings // Refs videoRef: MutableRefObject containerRef: MutableRefObject // Video kontrol fonksiyonları play: () => void pause: () => void togglePlay: () => void seek: (time: number) => void setVolume: (volume: number) => void toggleMute: () => void setPlaybackRate: (rate: number) => void // Fullscreen & PIP toggleFullscreen: () => void togglePictureInPicture: () => void // UI kontrolleri showControls: () => void hideControls: () => void toggleSettings: () => void // Ayarlar setQuality: (quality: VideoQuality | null) => void setSubtitle: (subtitle: SubtitleTrack | null) => void setAudioTrack: (audioTrack: AudioTrack | null) => void } ``` ### Exported Components ```typescript // Ana bileşen import { VideoPlayer } from '@alper/video-player' ``` ### Exported Hooks ```typescript // Player context hook import { usePlayerContext } from '@alper/video-player' // Klavye kısayolları hook'u import { useKeyboardShortcuts } from '@alper/video-player' // Dokunmatik jest hook'u import { useTouchGestures } from '@alper/video-player' ``` **usePlayerContext Kullanımı:** ```tsx function CustomControl() { const { videoState, play, pause, seek, setVolume } = usePlayerContext() return ( Oynat Duraklat seek(30)}>30s İleri {videoState.currentTime}s / {videoState.duration}s ) } // PlayerProvider içinde kullanılmalı ``` ### Exported Utilities ```typescript // Zaman formatlama import { formatTime, parseTime } from '@alper/video-player' formatTime(125) // "2:05" formatTime(3665) // "1:01:05" parseTime("2:05") // 125 parseTime("1:01:05") // 3665 // Altyazı utilities import { parseSRT, createSubtitleBlobURL, fetchSubtitle } from '@alper/video-player' const srtContent = "1\n00:00:01,000 --> 00:00:04,000\nMerhaba" const vttContent = parseSRT(srtContent) const blobUrl = createSubtitleBlobURL(vttContent) const subtitle = await fetchSubtitle('/subtitle.srt') // CORS helpers import { validateVideoURL, getCORSErrorMessage, isCORSError, checkVideoCORS } from '@alper/video-player' const validation = validateVideoURL(url) if (!validation.valid) { console.error(validation.error) } const corsCheck = await checkVideoCORS(url) if (!corsCheck.supported) { console.error(corsCheck.error) } if (isCORSError(error)) { const message = getCORSErrorMessage(error, videoUrl) console.log(message) } // i18n import { getTranslations, detectBrowserLanguage, translations } from '@alper/video-player' const lang = detectBrowserLanguage() // "tr", "en", vb. const t = getTranslations('tr') console.log(t.subtitles) // "Altyazı" console.log(translations.tr.quality) // "Kalite" ``` --- ## 💡 Kullanım Örnekleri ### Temel MP4 Oynatma ```tsx import { VideoPlayer } from '@alper/video-player' import '@alper/video-player/styles.css' function App() { return ( ) } ``` ### HLS Streaming ile Altyazı ```tsx ``` ### Event Tracking ```tsx function VideoWithAnalytics() { const handlePlay = () => { // Analytics gönder analytics.track('video_play') } const handleTimeUpdate = (time: number) => { // Her 30 saniyede milestone kaydet if (time % 30 === 0) { analytics.track('video_progress', { seconds: time }) } } const handleEnded = () => { analytics.track('video_completed') } return ( ) } ``` ### RTMP Live Stream ```tsx // HTTP-FLV proxy üzerinden RTMP stream ``` ### Custom Kontroller ```tsx import { VideoPlayer, usePlayerContext } from '@alper/video-player' function CustomControls() { const { videoState, play, pause, seek, setPlaybackRate } = usePlayerContext() return ( {videoState.playing ? ( ⏸️ Duraklat ) : ( ▶️ Oynat )} seek(videoState.currentTime - 10)}> ⏪ 10s Geri seek(videoState.currentTime + 10)}> ⏩ 10s İleri setPlaybackRate(Number(e.target.value))} > 0.5x Normal 1.5x 2x {formatTime(videoState.currentTime)} / {formatTime(videoState.duration)} ) } function App() { return ( ) } ``` ### Çoklu Video Playlist ```tsx import { useState } from 'react' import { VideoPlayer } from '@alper/video-player' const videos = [ { id: 1, src: 'video1.mp4', title: 'Video 1' }, { id: 2, src: 'video2.mp4', title: 'Video 2' }, { id: 3, src: 'video3.mp4', title: 'Video 3' }, ] function Playlist() { const [currentIndex, setCurrentIndex] = useState(0) const currentVideo = videos[currentIndex] const handleEnded = () => { // Sonraki videoya geç if (currentIndex < videos.length - 1) { setCurrentIndex(currentIndex + 1) } } return ( {videos.map((video, index) => ( setCurrentIndex(index)} className={index === currentIndex ? 'active' : ''} > {video.title} ))} ) } ``` ### CORS Hata Yönetimi ```tsx import { VideoPlayer, isCORSError, getCORSErrorMessage } from '@alper/video-player' import { useState } from 'react' function VideoWithCORSHandling() { const [error, setError] = useState(null) const videoUrl = 'https://example.com/video.mp4' const handleError = (err: Error) => { if (isCORSError(err)) { const message = getCORSErrorMessage(err, videoUrl) setError(message) console.error('CORS Hatası:', message) } else { setError(err.message) } } return ( {error && ( Video Yükleme Hatası {error} Çözüm: Video sunucunuzda CORS headers ekleyin: Access-Control-Allow-Origin: *{'\n'} Access-Control-Allow-Methods: GET, HEAD{'\n'} Access-Control-Allow-Headers: Range )} ) } ``` --- ## 🔧 Gelişmiş Kullanım ### Feature Detection ```typescript import { hasNativeHLS, hasMSE, hasPIP, hasFullscreen, hasTouch, isIOSSafari, hasVolumeControl } from '@alper/video-player' // Safari'de native HLS var mı kontrol et if (hasNativeHLS()) { console.log('Native HLS destekleniyor') } // MSE desteği kontrol et (HLS.js için gerekli) if (hasMSE()) { console.log('HLS.js kullanılabilir') } // PIP desteği kontrol et if (hasPIP()) { console.log('Picture-in-Picture kullanılabilir') } // iOS Safari kontrolü if (isIOSSafari()) { console.log('iOS Safari - volume control yok') } // Ses kontrolü desteği if (hasVolumeControl()) { // Volume slider göster } else { // Volume slider gizle (iOS) } ``` ### Manual HLS.js Setup ```typescript import { loadHls, setupHls } from '@alper/video-player' async function customHlsSetup() { const videoElement = document.querySelector('video') const Hls = await loadHls() if (Hls) { const { instance, cleanup } = setupHls( Hls, videoElement, 'https://example.com/stream.m3u8', { onManifestParsed: (qualities, audioTracks, subtitles) => { console.log('Qualities:', qualities) console.log('Audio tracks:', audioTracks) console.log('Subtitles:', subtitles) }, onError: (error) => { console.error('HLS error:', error) } } ) // instance → hls.js instance // cleanup → cleanup function (unmount'ta çağır) return { instance, cleanup } } } ``` ### Custom Subtitle Processing ```typescript import { parseSRT, createSubtitleBlobURL, fetchSubtitle } from '@alper/video-player' async function loadCustomSubtitle(url: string) { // SRT dosyasını fetch et const srtContent = await fetchSubtitle(url) // VTT'ye dönüştür const vttContent = parseSRT(srtContent) // Blob URL oluştur const blobUrl = createSubtitleBlobURL(vttContent) // Video elementine ekle const track = document.createElement('track') track.kind = 'subtitles' track.label = 'Custom' track.srclang = 'en' track.src = blobUrl videoElement.appendChild(track) // Cleanup return () => URL.revokeObjectURL(blobUrl) } ``` ### Progressive Download Monitoring ```tsx function VideoWithProgress() { const [buffered, setBuffered] = useState(0) const { videoRef } = usePlayerContext() useEffect(() => { const video = videoRef.current if (!video) return const updateBuffer = () => { if (video.buffered.length > 0) { const bufferedEnd = video.buffered.end(video.buffered.length - 1) setBuffered((bufferedEnd / video.duration) * 100) } } video.addEventListener('progress', updateBuffer) return () => video.removeEventListener('progress', updateBuffer) }, [videoRef]) return ( Buffer: {buffered.toFixed(0)}% ) } ``` --- ## 🎨 Tema ve Özelleştirme ### CSS Variables Tüm tema CSS değişkenleri ile özelleştirilebilir: ```css :root { /* Ana renkler */ --player-primary: #ef4444; --player-primary-hover: #dc2626; --player-bg: #000000; --player-text: #ffffff; /* Spacing */ --player-spacing-xs: 4px; --player-spacing-sm: 8px; --player-spacing-md: 12px; --player-spacing-lg: 16px; /* Border radius */ --player-radius: 14px; --player-radius-sm: 8px; /* Transitions */ --player-transition-fast: 120ms; --player-transition-normal: 200ms; --player-transition-slow: 300ms; /* Z-index layers */ --player-z-video: 1; --player-z-overlay: 10; --player-z-controls: 20; --player-z-menu: 30; --player-z-loading: 40; } ``` ### Custom Theme Örneği **Mavi Tema:** ```tsx ``` **Yeşil Tema:** ```tsx ``` **Dark Theme:** ```tsx ``` ### CSS Override ile Özelleştirme ```css /* Progress bar yüksekliğini artır */ .video-player .progress-bar { height: 8px !important; } /* Kontrol butonlarını büyüt */ .video-player .control-button { width: 48px !important; height: 48px !important; } /* Loading spinner rengini değiştir */ .video-player .loading-spinner { border-color: #10b981 transparent transparent transparent !important; } /* Settings menü arka planı */ .video-player .settings-menu { background: rgba(30, 41, 59, 0.95) !important; backdrop-filter: blur(10px) !important; } ``` ### Responsive Design ```css /* Mobil cihazlar için özelleştirme */ @media (max-width: 768px) { .video-player { --player-spacing-md: 8px; --player-radius: 8px; } .video-player .control-button { width: 40px; height: 40px; } .video-player .time-display { font-size: 12px; } } /* Tablet için */ @media (min-width: 769px) and (max-width: 1024px) { .video-player { --player-spacing-md: 10px; } } /* Desktop için */ @media (min-width: 1025px) { .video-player { --player-spacing-md: 12px; } } ``` --- ## 🌍 Uluslararasılaştırma (i18n) ### Desteklenen Diller - **English (en)** - Varsayılan - **Turkish (tr)** - Türkçe ### Otomatik Dil Tespiti ```tsx // Tarayıcı dilini otomatik tespit eder ``` ### Manuel Dil Seçimi ```tsx // Türkçe zorla // İngilizce zorla ``` ### Translation Keys ```typescript interface Translations { noSubtitlesAvailable: string // "No subtitles available" / "Altyazı mevcut değil" subtitles: string // "Subtitles" / "Altyazı" off: string // "Off" / "Kapalı" auto: string // "Auto" / "Otomatik" quality: string // "Quality" / "Kalite" speed: string // "Speed" / "Hız" normal: string // "Normal" / "Normal" default: string // "Default" / "Varsayılan" audioTrack: string // "Audio Track" / "Ses" settings: string // "Settings" / "Ayarlar" level: string // "Level" / "Seviye" } ``` ### Programmatic Access ```typescript import { getTranslations, detectBrowserLanguage } from '@alper/video-player' // Tarayıcı dilini tespit et const browserLang = detectBrowserLanguage() // "tr", "en-US", vb. // Translation'ları al const t = getTranslations('tr') console.log(t.subtitles) // "Altyazı" console.log(t.quality) // "Kalite" // Fallback ile const t2 = getTranslations('fr') // Fransızca yok console.log(t2.subtitles) // "Subtitles" (İngilizce fallback) ``` ### Yeni Dil Ekleme `src/i18n/index.ts` dosyasını düzenleyin: ```typescript export const translations: Record = { en: { /* ... */ }, tr: { /* ... */ }, // Yeni dil ekle es: { noSubtitlesAvailable: 'No hay subtítulos disponibles', subtitles: 'Subtítulos', off: 'Desactivado', auto: 'Automático', quality: 'Calidad', speed: 'Velocidad', normal: 'Normal', default: 'Predeterminado', audioTrack: 'Pista de audio', settings: 'Configuración', level: 'Nivel', } } ``` --- ## ⚡ Performans ### Bundle Size | Component | Size (gzipped) | |-----------|----------------| | Core library | ~8KB | | CSS | ~7KB | | **Total** | **~15KB** | | HLS.js (lazy) | ~200KB | | FLV.js (lazy) | ~150KB | ### Optimizasyon Teknikleri 1. **Lazy Loading** - HLS.js ve FLV.js sadece ihtiyaç duyulduğunda yüklenir - Settings menü lazy-loaded - CDN fallback ile yükleme garantisi 2. **Tree Shaking** - ES Module format - Kullanılmayan kod elimine edilir - Named exports ile selective import 3. **Code Splitting** - Async component loading - Dynamic imports - Route-based splitting için hazır 4. **CSS Optimization** - CSS minification - Tek dosyada bundle - CSS-only animasyonlar (JS yok) - Critical CSS inline (opsiyonel) 5. **React Optimization** - React.memo kullanımı - useCallback/useMemo - Gereksiz re-render önleme - Event delegation 6. **Memory Management** - Proper cleanup (useEffect return) - Blob URL revocation - HLS/FLV instance destroy - Event listener removal ### Performance Monitoring ```tsx import { useEffect } from 'react' import { VideoPlayer } from '@alper/video-player' function MonitoredVideo() { useEffect(() => { // Bundle size monitoring console.log('Initial bundle loaded') // Measure loading time const start = performance.now() return () => { const end = performance.now() console.log(`Player active for ${end - start}ms`) } }, []) return ( { console.log('Video metadata loaded') }} /> ) } ``` ### Loading Strategy ```tsx // Lazy load player component import { lazy, Suspense } from 'react' const VideoPlayer = lazy(() => import('@alper/video-player').then(module => ({ default: module.VideoPlayer })) ) function App() { return ( Loading player...}> ) } ``` --- ## 🌐 Tarayıcı Uyumluluğu ### Desteklenen Tarayıcılar | Tarayıcı | Versiyon | MP4 | HLS | RTMP/FLV | PIP | Fullscreen | |----------|----------|-----|-----|----------|-----|------------| | Chrome | 90+ | ✅ | ✅ | ✅ | ✅ | ✅ | | Edge | 90+ | ✅ | ✅ | ✅ | ✅ | ✅ | | Firefox | 88+ | ✅ | ✅ | ✅ | ❌ | ✅ | | Safari | 14+ | ✅ | ✅ (native) | ❌ | ✅ | ✅ | | iOS Safari | 14+ | ✅ | ✅ (native) | ❌ | ✅ | ✅ | | Chrome Mobile | 90+ | ✅ | ✅ | ✅ | ✅ | ✅ | ### Feature Support Matrix | Özellik | Desktop | Mobile | Safari | iOS | |---------|---------|--------|--------|-----| | MP4/WebM | ✅ | ✅ | ✅ | ✅ | | HLS (native) | ❌ | ❌ | ✅ | ✅ | | HLS (hls.js) | ✅ | ✅ | ❌ | ❌ | | RTMP/FLV | ✅ | ✅ | ❌ | ❌ | | Subtitles | ✅ | ✅ | ✅ | ✅ | | Quality switching | ✅ | ✅ | ✅ | ✅ | | Audio tracks | ✅ | ✅ | ✅ | ✅ | | Keyboard shortcuts | ✅ | ❌ | ✅ | ❌ | | Touch gestures | ❌ | ✅ | ❌ | ✅ | | Picture-in-Picture | ✅ | ✅ | ✅ | ✅ | | Fullscreen | ✅ | ✅ | ✅ | ✅ | | Volume control | ✅ | ✅ | ✅ | ❌* | *iOS Safari'de programmatic volume control yok (donanım butonları) ### Polyfills Kütüphane, eski tarayıcılar için otomatik polyfill içerir: ```typescript // src/utils/polyfills.ts // Fullscreen API polyfill (vendor prefixes) - requestFullscreen - exitFullscreen - fullscreenElement - fullscreenchange event // Picture-in-Picture polyfill - requestPictureInPicture - exitPictureInPicture - pictureInPictureElement ``` ### Known Issues **Safari:** - HLS.js kullanılmaz (native HLS var) - FLV.js MSE desteği sınırlı **iOS Safari:** - Volume control programmatic olarak değiştirilemez - Autoplay sadece `muted: true` ile çalışır - Fullscreen API sınırlı (video element fullscreen olur, container değil) **Firefox:** - Picture-in-Picture API henüz desteklenmiyor (planned) **Eski Tarayıcılar (IE11, Edge <90):** - Desteklenmez - MSE/EME yok → HLS/FLV çalışmaz - ES6 features gerektirir --- ## 🚨 Hata Yönetimi ### CORS Errors **Problem:** Video farklı origin'den geliyorsa CORS hatası **Tespit:** ```typescript import { isCORSError, getCORSErrorMessage } from '@alper/video-player' const handleError = (error: Error) => { if (isCORSError(error)) { const message = getCORSErrorMessage(error, videoUrl) console.error(message) } } ``` **Çözüm:** Video sunucunuzda CORS headers ekleyin: ``` Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, HEAD, OPTIONS Access-Control-Allow-Headers: Range, Content-Type Access-Control-Expose-Headers: Content-Length, Content-Range ``` **Nginx Örneği:** ```nginx location /videos/ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS'; add_header Access-Control-Allow-Headers 'Range'; add_header Access-Control-Expose-Headers 'Content-Length, Content-Range'; if ($request_method = OPTIONS) { return 204; } } ``` **Apache Örneği:** ```apache Header set Access-Control-Allow-Origin "*" Header set Access-Control-Allow-Methods "GET, HEAD, OPTIONS" Header set Access-Control-Allow-Headers "Range" Header set Access-Control-Expose-Headers "Content-Length, Content-Range" ``` ### HLS Errors **Manifest Parse Error:** ```typescript // HLS manifest yüklenemedi veya parse edilemedi // Çözüm: .m3u8 URL'inin doğru olduğundan emin olun ``` **Network Error:** ```typescript // HLS segment indirilemiyor // Otomatik recovery: 3 kez retry ``` **Media Error:** ```typescript // Video decode hatası // Otomatik recovery: HLS instance restart ``` **Fatal Error:** ```typescript // Kurtarılamaz hata // Error state'e düşer, onError callback çağrılır ``` ### RTMP/FLV Errors **Network Exception:** ```typescript // FLV stream bağlantı hatası // Otomatik retry ``` **Media Error:** ```typescript // FLV decode hatası // Error callback çağrılır ``` ### Error Handling Best Practices ```tsx function RobustVideoPlayer() { const [error, setError] = useState(null) const [retryCount, setRetryCount] = useState(0) const maxRetries = 3 const handleError = (err: Error) => { console.error('Video error:', err) if (isCORSError(err)) { setError('CORS hatası: Video sunucusu CORS headers eklemeli') } else if (retryCount < maxRetries) { // Retry setRetryCount(retryCount + 1) setTimeout(() => { window.location.reload() }, 2000) } else { setError(`Video yüklenemedi: ${err.message}`) } } if (error) { return ( Video Hatası {error} window.location.reload()}> Yeniden Dene ) } return ( ) } ``` --- ## 🛠️ Geliştirme ### Kurulum ```bash # Repository'yi klonlayın git clone https://gitea.hibna.com.tr/hibna/video-player.git cd video-player # Bağımlılıkları yükleyin npm install # veya pnpm install ``` ### Development Server ```bash # Dev server'ı başlat (examples/ klasörü) npm run dev # Tarayıcıda açın: http://localhost:5173 ``` ### Build ```bash # Kütüphane build npm run build:lib # Development build (examples) npm run build # Çıktı: dist/ klasörü ``` ### Testing ```bash # Unit testleri çalıştır npm run test # Test UI npm run test:ui # Coverage raporu npm run test:coverage ``` ### Linting ```bash # ESLint kontrolü npm run lint ``` ### Type Checking ```bash # TypeScript kontrolü npx tsc --noEmit ``` ### Package Yayınlama ```bash # 1. Version bump npm version patch # 0.1.5 -> 0.1.6 npm version minor # 0.1.5 -> 0.2.0 npm version major # 0.1.5 -> 1.0.0 # 2. Build npm run build:lib # 3. Gitea'ya push git push origin main --tags # 4. NPM'e yayınla (Gitea registry) npm publish # NOT: .npmrc dosyasında authentication token olmalı ``` ### Project Scripts ```json { "scripts": { "dev": "vite", // Dev server "build": "tsc && vite build", // Build examples "build:lib": "vite build --config vite.config.lib.ts", // Build library "preview": "vite preview", // Preview build "lint": "eslint . --max-warnings 0", // ESLint "test": "vitest", // Run tests "test:ui": "vitest --ui", // Test UI "test:coverage": "vitest --coverage" // Coverage } } ``` --- ## 🤝 Katkıda Bulunma Katkılarınızı bekliyoruz! Lütfen şu adımları takip edin: ### 1. Fork & Clone ```bash # Repository'yi fork edin (Gitea UI'dan) # Fork'unuzu klonlayın git clone https://gitea.hibna.com.tr/YOUR_USERNAME/video-player.git cd video-player ``` ### 2. Branch Oluşturun ```bash git checkout -b feature/amazing-feature ``` ### 3. Değişiklik Yapın ```bash # Kodunuzu yazın # Testlerinizi ekleyin # Linting'i kontrol edin npm run lint npm run test ``` ### 4. Commit & Push ```bash git add . git commit -m "feat: Add amazing feature" git push origin feature/amazing-feature ``` ### 5. Pull Request Gitea'da Pull Request oluşturun. ### Commit Conventions ``` feat: Yeni özellik fix: Bug fix docs: Dökümantasyon style: Kod formatı refactor: Refactoring test: Test ekleme chore: Build/config değişikliği ``` ### Code Style - TypeScript strict mode - ESLint rules - Prettier formatting (opsiyonel) - Component/function comment'leri --- ## 📝 Lisans MIT License Copyright (c) 2024 Alper Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --- ## 📞 İletişim - **Repository:** https://gitea.hibna.com.tr/hibna/video-player - **NPM Registry:** https://gitea.hibna.com.tr/api/packages/hibna/npm/ - **Issues:** https://gitea.hibna.com.tr/hibna/video-player/issues - **Author:** Alper --- ## 🎉 Teşekkürler Bu proje, aşağıdaki açık kaynak kütüphanelerden ilham almıştır: - [hls.js](https://github.com/video-dev/hls.js) - HLS streaming - [flv.js](https://github.com/bilibili/flv.js) - FLV streaming - [React](https://react.dev/) - UI framework - [Vite](https://vitejs.dev/) - Build tool - [TypeScript](https://www.typescriptlang.org/) - Type safety --- **Built with ❤️ using React, TypeScript, and Vite** *Son güncelleme: 2024*
{error}
Çözüm: Video sunucunuzda CORS headers ekleyin:
Access-Control-Allow-Origin: *{'\n'} Access-Control-Allow-Methods: GET, HEAD{'\n'} Access-Control-Allow-Headers: Range