diff --git a/desktop-client/yt-scraper.js b/desktop-client/yt-scraper.js new file mode 100644 index 0000000..4fa8a8c --- /dev/null +++ b/desktop-client/yt-scraper.js @@ -0,0 +1,61 @@ +const { ipcRenderer } = require('electron'); + +const POLL_INTERVAL_MS = 3000; +let lastSent = null; + +function scrapeNowPlaying() { + const titleEl = + document.querySelector('ytmusic-player-bar .title') || + document.querySelector('.ytmusic-player-bar .title'); + const title = titleEl ? titleEl.textContent.trim() : null; + + const bylineEl = + document.querySelector('ytmusic-player-bar .byline') || + document.querySelector('.ytmusic-player-bar .byline'); + const artist = bylineEl ? bylineEl.textContent.trim() : null; + + const artImg = + document.querySelector('ytmusic-player-bar .middle-controls .thumbnail-image-wrapper img') || + document.querySelector('ytmusic-player-bar .image img') || + document.querySelector('ytmusic-player-bar img.image'); + const albumArt = artImg ? artImg.src : null; + + // The play/pause button's title indicates state: when music is playing the + // button's action is "Pause", and vice versa. + const playPauseBtn = document.querySelector('#play-pause-button'); + let isPlaying = false; + if (playPauseBtn) { + const btnTitle = ( + playPauseBtn.getAttribute('title') || + playPauseBtn.getAttribute('aria-label') || + '' + ).toLowerCase(); + isPlaying = btnTitle.includes('pause'); + } + + if (!title) return null; + return { title, artist, albumArt, isPlaying }; +} + +function changed(a, b) { + if (a === null && b === null) return false; + if (a === null || b === null) return true; + return ( + a.title !== b.title || + a.artist !== b.artist || + a.albumArt !== b.albumArt || + a.isPlaying !== b.isPlaying + ); +} + +function poll() { + const data = scrapeNowPlaying(); + if (!changed(data, lastSent)) return; + lastSent = data; + ipcRenderer.send('wtm:state', data || { isPlaying: false }); +} + +setInterval(poll, POLL_INTERVAL_MS); +poll(); + +console.log('[wtm] yt-scraper preload loaded');