lastfm-qtiles-background/main.js

168 lines
5.5 KiB
JavaScript
Raw Normal View History

2023-10-16 16:32:57 -04:00
const axios = require('axios');
const sharp = require('sharp');
const rp = require('request-promise');
2023-10-16 16:32:57 -04:00
const fs = require('fs');
const { exec } = require('child_process');
const crypto = require('crypto');
2023-10-16 16:32:57 -04:00
const config = JSON.parse(fs.readFileSync("config.json"));
const updateInterval = 5000;
2023-10-16 16:32:57 -04:00
let previousHash = null;
2023-10-16 16:32:57 -04:00
async function processAlbumCover(url) {
try {
console.log(`Processing album cover from URL: ${url}`);
2023-10-16 16:32:57 -04:00
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();
2023-10-16 16:32:57 -04:00
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 };
2023-10-16 16:32:57 -04:00
} catch (error) {
console.error(`Failed to process album cover from URL: ${url}`, error);
throw error;
2023-10-16 16:32:57 -04:00
}
}
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)}`);
2023-10-16 16:32:57 -04:00
return {
r: Math.round(redAvg),
g: Math.round(greenAvg),
b: Math.round(blueAvg)
};
}
async function setAsWallpaper(buffer, dominantColor) {
2023-10-16 16:32:57 -04:00
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.');
2023-10-16 16:32:57 -04:00
} catch (error) {
console.error("Failed to set wallpaper and update Qtile colors:", error);
throw error;
2023-10-16 16:32:57 -04:00
}
}
async function fetchCurrentScrobble(user) {
try {
console.log("Fetching current scrobble...");
2023-10-16 16:32:57 -04:00
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;
2023-10-16 16:32:57 -04:00
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 && coverURL.includes('300x300')) {
coverURL = coverURL.replace('300x300', '1000x1000');
}
2023-10-16 23:29:01 -04:00
const ignoreURL = "https://lastfm.freetls.fastly.net/i/u/1000x1000/2a96cbd8b46e442fc41c2b86b821562f.png";
if (coverURL === ignoreURL) {
console.log("Ignored URL detected. Skipping update.");
return;
}
2023-10-16 16:32:57 -04:00
if (coverURL) {
const { outputBuffer, dominantColor } = await processAlbumCover(coverURL);
const hash = crypto.createHash('sha256').update(outputBuffer).digest('hex');
if (hash === previousHash) {
console.log("Image is the same as before. Skipping updates.");
return;
}
previousHash = hash;
await setAsWallpaper(outputBuffer, dominantColor);
console.log("Successfully fetched current scrobble.");
return { outputBuffer, dominantColor };
2023-10-16 16:32:57 -04:00
} else {
console.error(`Cover URL not found for track: ${lastTrackName}`);
throw new Error('Cover URL not found');
2023-10-16 16:32:57 -04:00
}
} catch (error) {
console.error(`Failed to fetch current scrobble:`, error);
throw error;
2023-10-16 16:32:57 -04:00
}
}
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);
}
2023-10-16 16:32:57 -04:00
}, updateInterval);
}
startFetching();