Execute the following Homey script after change of artist or track and save the song text in a Homey flow variable:
// 1. Configuratie & Hardware
const SONOS_ID = 'ce48fa04-xxxx-xxxx-xxxxxxxxxxxxxxxxx';
const LRCLIB_ENDPOINT = 'https://lrclib.net/api/get';
const DEFAULT_TEXT = "Geen songtext gevonden"; // Centraal ingesteld
// 2. Data ophalen
const sonos = await Homey.devices.getDevice({ id: SONOS_ID });
const {
speaker_artist,
speaker_track,
speaker_playing,
speaker_duration
} = sonos.capabilitiesObj;
const artist = speaker_artist?.value;
const track = speaker_track?.value;
const isPlaying = speaker_playing?.value;
const duration = speaker_duration?.value;
// 3. Validatie
if (!artist || !track || !isPlaying) return false;
// 4. Voorbereiding resultaat
let resultaat = DEFAULT_TEXT;
// 5. API Request
const query = new URLSearchParams({
artist_name: artist,
track_name: track,
duration: duration
});
try {
const response = await fetch(LRCLIB_ENDPOINT + '?' + query.toString());
if (response.ok) {
const data = await response.json();
const syncedLyrics = data.syncedLyrics;
// 6. Verwerking van Lyrics (indien aanwezig)
if (syncedLyrics && syncedLyrics.trim() !== "") {
const verwerkteTekst = syncedLyrics
.split('\n')
.filter(line => line.trim() !== "")
.map(line => {
const timestamp = line.substring(1, 6); // mm:ss
let text = line.substring(10).trim();
if (!text) {
text = "[instrumentaal]";
}
return timestamp + " - " + text;
})
.join('\n');
if (verwerkteTekst.length > 0) {
resultaat = verwerkteTekst;
}
}
}
} catch (error) {
console.log("Fout bij ophalen lyrics: " + error.message);
}
// 7. Opslaan in Homey Logic variabelen
const allVars = await Homey.logic.getVariables();
const myVar = Object.values(allVars).find(v => v.name === 'DSSongtext');
const myVarNL = Object.values(allVars).find(v => v.name === 'DSSongtextNL');
// Altijd DSSongtextNL leegmaken bij een nieuwe actie
if (myVarNL) {
await Homey.logic.updateVariable({ id: myVarNL.id, variable: { value: "" } });
}
if (myVar) {
await Homey.logic.updateVariable({ id: myVar.id, variable: { value: resultaat } });
console.log("Status opgeslagen in DSSongtext. DSSongtextNL is leeggemaakt.");
return true;
} else {
console.log("Variabele 'DSSongtext' niet gevonden in Homey Logic.");
return false;
}
Match the song text with the actual play time of the current song. There is even a song text translation option in the code, which needs a separate script (not included here).
// 1. Configuratie & Performance Caching
const SONOS_ID = 'ce48fa04-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
const CORRECTIE_ID = '88ba3497-xxxx-xxxx-xxxx-xxxxxxxxxxxx'';
const OFFSET_MS = 1000;
const MELDING = "Geen songtext gevonden";
global.myDevices = global.myDevices || {};
if (!global.myDevices.sonos) {
global.myDevices.sonos = await Homey.devices.getDevice({ id: SONOS_ID });
}
if (!global.myDevices.correction) {
global.myDevices.correction = await Homey.devices.getDevice({ id: CORRECTIE_ID });
}
const sonos = global.myDevices.sonos;
const correctionDevice = global.myDevices.correction;
// 2. Haal de Sonos data op
let posObj = sonos.capabilitiesObj.speaker_position || { value: 0, lastUpdated: new Date().toISOString() };
const durObj = sonos.capabilitiesObj.speaker_duration;
let manualCorrectionSeconds = 0;
if (correctionDevice?.capabilitiesObj.target_temperature) {
manualCorrectionSeconds = correctionDevice.capabilitiesObj.target_temperature.value || 0;
}
// 3. De EXACTE berekening
const lastUpdatedUnix = new Date(posObj.lastUpdated).getTime();
const driftSeconds = (Date.now() - lastUpdatedUnix) / 1000;
const exactTimeSeconds = posObj.value + driftSeconds + (OFFSET_MS / 1000) + manualCorrectionSeconds;
// 4. Helper functie
const formatTime = (totalSeconds) => {
if (isNaN(totalSeconds) || totalSeconds < 0) return "0:00";
const minutes = Math.floor(totalSeconds / 60);
const seconds = Math.floor(totalSeconds % 60);
return minutes + ":" + seconds.toString().padStart(2, '0');
};
// 5. Haal songtekst variabelen op
const allVars = await Homey.logic.getVariables();
const vertaalNaarNL = Object.values(allVars).find(v => v.name === "DSVertaalNaarNL")?.value || false;
const targetVarName = vertaalNaarNL ? "DSSongtextNL" : "DSSongtext";
const songtextVar = Object.values(allVars).find(v => v.name === targetVarName);
if (!songtextVar || !songtextVar.value) {
return JSON.stringify({ error: "Variabele '" + targetVarName + "' is leeg" });
}
// 6. Bepaal de tekstinhoud (Efficiënte toewijzing)
let lyrics = { vorige_regel: "", huidige_regel: "[instrumentaal]", volgende_regel: "" };
if (songtextVar.value.trim() === MELDING) {
// Specifieke afhandeling voor "Geen songtext gevonden"
lyrics = { vorige_regel: "", huidige_regel: MELDING, volgende_regel: "" };
} else {
// Verwerk tekst naar array en zoek huidige index
const lines = songtextVar.value.split('\n')
.filter(l => l.includes(' - '))
.map(line => {
const [timeStr, ...textParts] = line.split(' - ');
const [min, sec] = timeStr.split(':').map(Number);
return { totalSeconds: (min * 60) + sec, text: textParts.join(' - ') };
});
let currentIndex = -1;
for (let i = 0; i < lines.length; i++) {
if (exactTimeSeconds >= lines[i].totalSeconds) currentIndex = i;
else break;
}
if (currentIndex !== -1) {
lyrics = {
vorige_regel: lines[currentIndex - 1]?.text || "",
huidige_regel: lines[currentIndex].text,
volgende_regel: lines[currentIndex + 1]?.text || ""
};
} else if (lines.length > 0) {
lyrics.volgende_regel = lines[0].text;
}
}
// 7. Eén centrale return voor alle data
return JSON.stringify({
...lyrics,
actuele_speeltijd: formatTime(exactTimeSeconds),
actuele_speeltijd_sec: Math.round(exactTimeSeconds),
totale_duur: formatTime(durObj?.value || 0)
});
The Homey script “card” is the script above.
