diff --git a/Dockerfile b/Dockerfile index 93ae667..0a68b75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,9 +22,13 @@ RUN apk add --no-cache \ # Download and extract Weatherscan music RUN mkdir -p /music && \ + echo "Downloading Weatherscan music..." && \ wget -O /tmp/weatherscan.zip "https://archive.org/compress/weatherscancompletecollection/formats=OGG%20VORBIS&file=/weatherscancompletecollection.zip" && \ + echo "Extracting OGG files..." && \ unzip -j /tmp/weatherscan.zip "*.ogg" -d /music && \ - rm /tmp/weatherscan.zip + echo "Music files extracted: $(ls -1 /music/*.ogg | wc -l) files" && \ + rm /tmp/weatherscan.zip && \ + echo "Weatherscan music setup complete!" # Set Puppeteer to use installed Chromium ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ diff --git a/index.js b/index.js index 247efe8..3347241 100644 --- a/index.js +++ b/index.js @@ -124,19 +124,24 @@ async function streamHandler(req, res, useMusic = false, lateGeocodePromise = nu if (useMusic) { // Get all music files and shuffle them const allMusicFiles = getAllMusicFiles(); - if (allMusicFiles.length > 0 && allMusicFiles.length > 0) { + console.log(`Found ${allMusicFiles.length} music files in ${MUSIC_PATH}`); + if (allMusicFiles.length > 0) { // Create a temporary concat playlist file playlistFile = path.join('/tmp', `playlist-${Date.now()}.txt`); - // Build playlist content - repeat the list 3 times to reduce loop edge case issues + // Build playlist content - repeat enough times for ~24 hours of playback + // Assuming avg 3 min per track, repeat enough to cover a full day const currentShuffle = shuffleArray([...allMusicFiles]); + const repetitions = Math.max(20, Math.ceil(480 / allMusicFiles.length)); // At least 480 tracks (~24hrs) const playlistLines = []; - for (let i = 0; i < 3; i++) { - currentShuffle.forEach(f => playlistLines.push(`file '${f}'`)); + for (let i = 0; i < repetitions; i++) { + // Re-shuffle each repetition for more variety + const shuffled = shuffleArray([...allMusicFiles]); + shuffled.forEach(f => playlistLines.push(`file '${f}'`)); } fs.writeFileSync(playlistFile, playlistLines.join('\n')); - // console.log(`Created shuffled playlist with ${allMusicFiles.length} tracks x3 repetitions (infinite loop)`); + // console.log(`Created playlist with ${allMusicFiles.length} tracks x${repetitions} repetitions (~${playlistLines.length} total tracks)`); // Input 0: video frames ffmpegArgs.push( @@ -149,7 +154,6 @@ async function streamHandler(req, res, useMusic = false, lateGeocodePromise = nu ffmpegArgs.push( '-f', 'concat', '-safe', '0', - '-stream_loop', '-1', // Loop playlist infinitely '-i', playlistFile ); // Encoding with audio filtering for smooth transitions @@ -314,7 +318,7 @@ async function streamHandler(req, res, useMusic = false, lateGeocodePromise = nu console.log('Page network idle, waiting for content to render...'); // Additional wait for dynamic content to fully render (weather data, radar, etc.) - await page.waitForTimeout(3000); + await new Promise(resolve => setTimeout(resolve, 3000)); // Verify content is actually visible before switching const hasVisibleContent = await page.evaluate(() => { @@ -332,7 +336,7 @@ async function streamHandler(req, res, useMusic = false, lateGeocodePromise = nu if (!hasVisibleContent) { console.log('Content not fully visible yet, waiting additional time...'); - await page.waitForTimeout(2000); + await new Promise(resolve => setTimeout(resolve, 2000)); } console.log('Page fully loaded with all resources, switching to live frames'); @@ -378,12 +382,15 @@ async function streamHandler(req, res, useMusic = false, lateGeocodePromise = nu if (!isCleaningUp && page && !page.isClosed() && updatedUrl && updatedUrl !== url) { try { console.log('Updating to correct location...'); + // Ensure black frames continue during navigation + sendBlackFrames = true; + // Wait for networkidle2 to ensure all resources load await page.goto(updatedUrl, { waitUntil: 'networkidle2', timeout: 45000 }); console.log('Correct location network idle, waiting for content...'); // Additional wait for dynamic content - await page.waitForTimeout(3000); + await new Promise(resolve => setTimeout(resolve, 3000)); // Verify content is visible const hasVisibleContent = await page.evaluate(() => { @@ -398,7 +405,7 @@ async function streamHandler(req, res, useMusic = false, lateGeocodePromise = nu if (!hasVisibleContent) { console.log('Content not fully visible yet, waiting additional time...'); - await page.waitForTimeout(2000); + await new Promise(resolve => setTimeout(resolve, 2000)); } console.log('Correct location fully loaded, switching to live frames');