const uiLocale = chrome.i18n.getMessage('@@ui_locale') const defaultServerURL = chrome.i18n.getMessage('default_server_url') const getURL = () => { return new Promise(resolve => { chrome.storage.local.get([ 'server_url', ]).then((data) => { const serverURL = data.server_url || defaultServerURL const url = new URL(serverURL) url.pathname = '/ws/v1/server' resolve(url) }) }) } const mutationObserverConfig = { attributes: true, childList: false, characterData: false, } const connectWebSocket = async () => { const url = await getURL() const ws = new WebSocket(url) const progressElement = document.querySelector('#progress-bar') const mutationObserver = new MutationObserver(() => { const promise = new Promise(resolve => { const playerBarElement = document.querySelector('ytmusic-player-bar') const metadataElement = playerBarElement.querySelector('.middle-controls > .content-info-wrapper') const titleElement = metadataElement.querySelector(`yt-formatted-string.title`) const subtitleElement = metadataElement.querySelector('span.subtitle > yt-formatted-string.byline') const imageElement = playerBarElement.querySelector('img') if (titleElement.textContent === '' || subtitleElement.length === 0) return const data = { type: 'music', attributes: { locale: uiLocale, title: titleElement.textContent, artists: subtitleElement.title.split('•')[0].trim(), progress: progressElement.ariaValueNow / progressElement.ariaValueMax, image: imageElement.src, }, } ws.send(JSON.stringify(data)) resolve() }) promise.then() }) ws.onopen = () => mutationObserver.observe(progressElement, mutationObserverConfig) ws.onclose = () => { mutationObserver.disconnect() wsPromise = connectWebSocket() } return ws } chrome.storage.onChanged.addListener((changes) => { const settings = {} for (let [key, { oldValue, newValue }] of Object.entries(changes)) { settings[key] = newValue || oldValue } chrome.storage.local.set(settings).then(() => { wsPromise.then(ws => ws.close()) }) }) let wsPromise = connectWebSocket()