211 const API_NEWS_BY_BATCH = '/api/news/batch/';
212
213 async function init() {
214 await lucide.createIcons();
215
251 }
252
253 function setupEventListeners() {
254 prevBtn.addEventListener('click', goToPrevious);
255 nextBtn.addEventListener('click', goToNext);
282 }
283
284 function handleAudioEnded() {
285 audioEnded = true;
286 console.log("Audio ended");
297
298
299 function speakNewsItem() {
300 audioEnded = false;
301 ttsAbortController.abort();
424
425
426 function stopSpeaking() {
427 ttsAbortController.abort();
428 ttsAudio.pause();
437
438
439 function userActive() {
440 carouselContainer.classList.remove('user-inactive');
441 carouselContainer.classList.add('user-active');
450 }
451
452 function startUserActivityMonitor() {
453 userActive();
454 }
455
456 function updateHeadline() {
457 if (newsItems.length === 0) {
458 headline.textContent = 'No news available.';
463 }
464
465 function updateFullContent() {
466 if (newsItems.length === 0) return;
467
489 }
490
491 async function goToNext() {
492 if (isTransitioning) return;
493 isTransitioning = true;
497 }
498
499 async function goToPrevious() {
500 if (isTransitioning) return;
501 isTransitioning = true;
505 }
506
507 function updateCarousel() {
508 updateHeadline();
509 updateFullContent();
515
516
517 async function restartVideo() {
518 stopSpeaking();
519 audioEnded = false;
535 }
536
537 function togglePlayPause() {
538 isPlaying = !isPlaying;
539
559
560
561 function updatePlayPauseIcon() {
562 const btn = document.getElementById('play-pause-btn');
563 btn.innerHTML = `<i data-lucide="${isPlaying ? 'pause' : 'play'}"></i>`;
565 }
566
567 function startAutoAdvance() {
568 stopAutoAdvance();
569 if (isPlaying) {
576 }
577
578 function stopAutoAdvance() {
579 if (autoAdvanceInterval) {
580 clearInterval(autoAdvanceInterval);
583 }
584
585 function toggleMute() {
586 if (video.volume > 0) {
587 lastVolume = video.volume;
597 userActive();
598 }
599 function updateVolume() {
600 const volume = parseFloat(volumeSlider.value);
601 video.volume = volume;
610 }
611 }
612 function updateVolumeIcon(volume) {
613 const btn = document.getElementById('mute-btn');
614 let iconName = 'volume-x';
620 }
621
622 function updateProgressBar() {
623 if (video.duration) {
624 const progress = (video.currentTime / video.duration) * 100;
628 }
629
630 function seekVideo(e) {
631 const rect = progressContainer.getBoundingClientRect();
632 const percent = (e.clientX - rect.left) / rect.width;
637 }
638
639 function updateTimeDisplay() {
640 if (video.duration) {
641 const currentTime = formatTime(video.currentTime);
645 }
646
647 function updateVideoDurationDisplay() {
648 if (video.duration) {
649 timeDisplay.textContent = `0:00 / ${formatTime(video.duration)}`;
653 }
654
655 function formatTime(seconds) {
656 if (!seconds || isNaN(seconds)) return '0:00';
657
661 }
662
663 function handleVideoEnded() {
664 // Let the audio ended event handle navigation
665 }
666
667 function showContentPanel() {
668 contentVisible = true;
669 newsContent.classList.add('active');
676 }
677
678 function hideContentPanel() {
679 contentVisible = false;
680 newsContent.classList.remove('active');
682 }
683
684 async function openHistoryPanel() {
685 loadingOverlay.style.display = 'flex';
686 loadingOverlay.querySelector('.loading-text').textContent = 'Loading news history...';
707 }
708
709 function populateHistoryPanel() {
710 historyList.innerHTML = '';
711
741 }
742
743 async function loadNewsBatch(batchId) {
744 loadingOverlay.style.display = 'flex';
745 loadingOverlay.querySelector('.loading-text').textContent = 'Loading news batch...';
777 }
778
779 function closeHistoryPanel() {
780 historyPanel.classList.remove('active');
781 userActive();
782 }
783
784 function toggleFullscreen() {
785 if (!document.fullscreenElement) {
786 document.querySelector('.carousel-container').requestFullscreen().catch(err => {
793 }
794
795 function updateFullscreenIcon() {
796 const icon = document.fullscreenElement ? 'minimize' : 'maximize';
797 fullscreenBtn.innerHTML = `<i data-lucide="${icon}"></i>`;
799 }
800
801 function handleMediaError(e) {
802 console.error('Media error:', e);
803 const mediaElement = e.target;
813 }
814
815 function showError(message) {
816 errorMessage.textContent = message;
817 errorMessage.classList.add('active');
822 }
823
824 function handleKeyboardShortcuts(e) {
825 if (e.code === 'Space') {
826 e.preventDefault();