UNPKG

unified-video-framework

Version:

Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more

173 lines 6.3 kB
export class ChapterManager { constructor(config = {}) { this.chapters = []; this.segments = []; this.currentChapter = null; this.activeSegments = new Set(); this.lastProcessedTime = -1; this.eventHandlers = new Map(); this.config = { ...config }; this.chapters = config.chapters || []; this.segments = config.segments || []; this.eventHandlers.set('chapterchange', []); this.eventHandlers.set('segmententered', []); this.eventHandlers.set('segmentexited', []); this.eventHandlers.set('segmentskipped', []); } updateConfig(config) { this.config = { ...this.config, ...config }; this.chapters = config.chapters || this.chapters; this.segments = config.segments || this.segments; } async loadChapterData(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch chapter data: ${response.status}`); } const data = await response.json(); if (data.chapters) { this.chapters = data.chapters; } if (data.segments) { this.segments = data.segments; } } catch (error) { console.error('Error loading chapter data:', error); throw error; } } async initialize() { if (this.config.dataUrl) { await this.loadChapterData(this.config.dataUrl); } this.chapters.sort((a, b) => a.startTime - b.startTime); this.segments.sort((a, b) => a.startTime - b.startTime); } processTimeUpdate(currentTime) { if (Math.abs(currentTime - this.lastProcessedTime) < 0.1) { return; } this.lastProcessedTime = currentTime; this.processChapterChange(currentTime); this.processSegments(currentTime); } processChapterChange(currentTime) { const newChapter = this.getCurrentChapter(currentTime); if (newChapter !== this.currentChapter) { this.currentChapter = newChapter; this.emit('chapterchange', newChapter); if (this.config.onChapterChange) { this.config.onChapterChange(newChapter); } } } processSegments(currentTime) { const currentSegments = this.segments.filter(segment => currentTime >= segment.startTime && currentTime <= segment.endTime); for (const segment of currentSegments) { if (!this.activeSegments.has(segment.id)) { this.activeSegments.add(segment.id); this.emit('segmententered', segment); if (this.config.onSegmentEntered) { this.config.onSegmentEntered(segment); } if (this.config.autoSkip && segment.action === 'skip') { this.skipSegment(segment); } } } const currentSegmentIds = new Set(currentSegments.map(s => s.id)); for (const activeSegmentId of this.activeSegments) { if (!currentSegmentIds.has(activeSegmentId)) { const segment = this.segments.find(s => s.id === activeSegmentId); if (segment) { this.activeSegments.delete(activeSegmentId); this.emit('segmentexited', segment); if (this.config.onSegmentExited) { this.config.onSegmentExited(segment); } } } } } getCurrentChapter(currentTime) { return this.chapters.find(chapter => currentTime >= chapter.startTime && currentTime <= chapter.endTime) || null; } getChapters() { return [...this.chapters]; } getSegments() { return [...this.segments]; } getSegmentsAtTime(currentTime) { return this.segments.filter(segment => currentTime >= segment.startTime && currentTime <= segment.endTime); } skipSegment(segment) { this.emit('segmentskipped', segment); if (this.config.onSegmentSkipped) { this.config.onSegmentSkipped(segment); } } seekToChapter(chapterId) { const chapter = this.chapters.find(c => c.id === chapterId); if (chapter) { return chapter; } return null; } getNextChapter(currentTime) { return this.chapters.find(chapter => chapter.startTime > currentTime) || null; } getPreviousChapter(currentTime) { const previousChapters = this.chapters .filter(chapter => chapter.startTime < currentTime) .sort((a, b) => b.startTime - a.startTime); return previousChapters[0] || null; } on(event, handler) { const handlers = this.eventHandlers.get(event) || []; handlers.push(handler); this.eventHandlers.set(event, handlers); } off(event, handler) { const handlers = this.eventHandlers.get(event) || []; if (handler) { const index = handlers.indexOf(handler); if (index > -1) { handlers.splice(index, 1); } } else { handlers.length = 0; } this.eventHandlers.set(event, handlers); } emit(event, data) { const handlers = this.eventHandlers.get(event) || []; handlers.forEach(handler => { try { handler(data); } catch (error) { console.error(`Error in chapter manager event handler for ${event}:`, error); } }); } reset() { this.currentChapter = null; this.activeSegments.clear(); this.lastProcessedTime = -1; } destroy() { this.reset(); this.eventHandlers.clear(); } getCurrentChapterInfo() { return this.currentChapter; } isEnabled() { return this.config.enabled !== false; } } //# sourceMappingURL=chapter-manager.js.map