const axios = require('axios'); const sharp = require('sharp'); const rp = require('request-promise'); const fs = require('fs'); const { exec } = require('child_process'); const config = JSON.parse(fs.readFileSync("config.json")); const updateInterval = 5000; async function processAlbumCover(url) { try { console.log(`Processing album cover from URL: ${url}`); const response = await axios.get(url, { responseType: 'arraybuffer' }); const imageBuffer = Buffer.from(response.data, 'binary'); const imageSharp = sharp(imageBuffer); const metadata = await imageSharp.metadata(); const dominantColor = await getDominantColor(imageBuffer); const resizedBuffer = await imageSharp .resize({ width: 1920, height: 1080, fit: 'inside' }) .toBuffer(); const resizedMetadata = await sharp(resizedBuffer).metadata(); const extendByX = Math.round((1920 - resizedMetadata.width) / 2); const extendByY = Math.round((1080 - resizedMetadata.height) / 2); const outputBuffer = await sharp(resizedBuffer) .extend({ top: extendByY, bottom: extendByY, left: extendByX, right: extendByX, background: dominantColor }) .toBuffer(); console.log('Processed album cover successfully.'); return { outputBuffer, dominantColor }; } catch (error) { console.error(`Failed to process album cover from URL: ${url}`, error); throw error; } } async function getDominantColor(imageBuffer) { const imageSharp = sharp(imageBuffer); const { channels } = await imageSharp.stats(); const redAvg = channels[0].mean; const greenAvg = channels[1].mean; const blueAvg = channels[2].mean; console.log(`Determined dominant color: r=${Math.round(redAvg)}, g=${Math.round(greenAvg)}, b=${Math.round(blueAvg)}`); return { r: Math.round(redAvg), g: Math.round(greenAvg), b: Math.round(blueAvg) }; } async function setAsWallpaper(buffer, dominantColor) { try { await fs.promises.writeFile('/tmp/current_album_cover.png', buffer, 'binary'); const colorString = `#${dominantColor.r.toString(16).padStart(2, '0')}${dominantColor.g.toString(16).padStart(2, '0')}${dominantColor.b.toString(16).padStart(2, '0')}`; console.log(`Sending color string to Python script: ${colorString}`); const command = `python3 ./tap_in.py '${colorString}'`; console.log("Running command:", command); exec(command, (error, stdout, stderr) => { if (error) { console.error(`Error running the command: ${error}`); } console.log(`Python stdout: ${stdout}`); console.log(`Python stderr: ${stderr}`); }); exec('feh --bg-center /tmp/current_album_cover.png'); console.log('Wallpaper and Qtile colors successfully updated.'); } catch (error) { console.error("Failed to set wallpaper and update Qtile colors:", error); throw error; } } async function fetchCurrentScrobble(user) { try { console.log("Fetching current scrobble..."); const optionsGetTrack = { uri: `http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=${user}&api_key=${config.apiKey}&format=json&limit=1`, json: true }; const lastTrack = await rp(optionsGetTrack); const lastArtist = lastTrack.recenttracks.track[0].artist["#text"]; const lastTrackName = lastTrack.recenttracks.track[0].name; const images = lastTrack.recenttracks.track[0].image; let coverURL = null; for (const img of images) { if (img.size === 'extralarge' || img.size === 'mega') { coverURL = img["#text"].trim(); break; } } if (coverURL) { const { outputBuffer, dominantColor } = await processAlbumCover(coverURL); await setAsWallpaper(outputBuffer, dominantColor); console.log("Successfully fetched current scrobble."); return { outputBuffer, dominantColor }; } else { console.error(`Cover URL not found for track: ${lastTrackName}`); throw new Error('Cover URL not found'); } } catch (error) { console.error(`Failed to fetch current scrobble:`, error); throw error; } } function startFetching() { setInterval(async () => { try { console.log('Initiating fetch sequence.'); await fetchCurrentScrobble(config.username); console.log('Fetch sequence completed.'); } catch (error) { console.error(`Failed in startFetching:`, error); } }, updateInterval); } startFetching();