diff --git a/content.js b/content.js index 29fbb97..2981f40 100644 --- a/content.js +++ b/content.js @@ -4,15 +4,23 @@ let artworkEndpoint = null; let token = null; let intervalId = null; let lastSentArtworkKey = null; +let placeholderArtwork = null; +let pausedTimeout = 300000; +let metadataFetchInterval = 1000; + + +// log credits to console +if (!window._nowPlayingExtensionLogged) { + console.log('Apple Music Now Playing Extension made by Sophia Atkinson with help from PreMiD contributors'); + window._nowPlayingExtensionLogged = true; +} -const defaultArtwork = "https://placehold.co/150/1E1F22/FFF?text=Nothing%20playing"; -const pausedTimeout = 300000; // 5 minutes -const metadataFetchInterval = 1000; // 1 second // Cache for artwork base64 by URL const artworkBase64Cache = { lastArtworkUrl: null, - lastArtworkBase64: null + lastArtworkBase64: null, + defaultArtworkBase64: null }; async function imageUrlToBase64(url) { @@ -44,8 +52,8 @@ async function getNowPlayingData() { const timestampInput = document.querySelector('amp-lcd.lcd.lcd__music')?.shadowRoot ?.querySelector('input#playback-progress[aria-valuenow][aria-valuemax]'); - if (!artworkBase64Cache.defaultArtworkBase64) { - artworkBase64Cache.defaultArtworkBase64 = await imageUrlToBase64(defaultArtwork); + if (!artworkBase64Cache.defaultArtworkBase64 && placeholderArtwork) { + artworkBase64Cache.defaultArtworkBase64 = await imageUrlToBase64(placeholderArtwork); } const defaultArtworkBase64 = artworkBase64Cache.defaultArtworkBase64; @@ -97,7 +105,7 @@ async function getNowPlayingData() { const currentTime = timestampInput ? Number(timestampInput.getAttribute('aria-valuenow')) : media.currentTime || 0; const duration = timestampInput ? Number(timestampInput.getAttribute('aria-valuemax')) : media.duration || 0; - const nowUnix = Math.floor(Date.now() / metadataFetchInterval); + const nowUnix = Math.floor(Date.now() / 1000); return { details: title, @@ -180,19 +188,18 @@ function startNowPlayingLoop() { intervalId = setInterval(() => safeCall(sendNowPlaying), metadataFetchInterval); } } - -if (!window._nowPlayingExtensionLogged) { - console.log('Apple Music Now Playing Extension made by Sophia Atkinson with help from PreMiD contributors'); - window._nowPlayingExtensionLogged = true; -} - if (chrome?.storage?.sync) { - chrome.storage.sync.get(['endpoint', 'artworkEndpoint', 'token'], result => { + chrome.storage.sync.get(['endpoint', 'artworkEndpoint', 'token', 'placeholderArtwork', 'pausedTimeout', 'metadataFetchInterval'], result => { if (chrome.runtime.lastError) { console.error("Failed to load settings:", chrome.runtime.lastError.message); return; } - ({ endpoint, artworkEndpoint, token } = result); + endpoint = result.endpoint; + artworkEndpoint = result.artworkEndpoint; + token = result.token; + placeholderArtwork = result.placeholderArtwork || 'https://placehold.co/150/1E1F22/FFF?text=Nothing%20playing'; + pausedTimeout = Number(result.pausedTimeout) || pausedTimeout; + metadataFetchInterval = Number(result.metadataFetchInterval) || metadataFetchInterval; if (!endpoint || !token) { console.error("No endpoint/token configured."); diff --git a/manifest.json b/manifest.json index 416995a..bdf9e94 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Apple Music Now Playing", - "version": "1.4.2", + "version": "1.4.3", "description": "Easily display your currently playing Apple Music track on your website with this extension.", "permissions": [ "storage", diff --git a/options.html b/options.html index 4217449..dfe82ed 100644 --- a/options.html +++ b/options.html @@ -14,6 +14,8 @@ --button-bg: var(--accent); --button-hover: #d67b8a; --shadow: rgba(245, 169, 184, 0.3); + --details-bg: #18181a; + --details-border: #2a2a2a; } body { margin: 0; @@ -83,18 +85,93 @@ background-color: var(--button-hover); outline: none; } + details { + margin-top: 2rem; + background: var(--details-bg); + border: 1.5px solid var(--details-border); + border-radius: 10px; + padding: 0.5rem 1rem; + max-width: 100%; + } + details summary { + cursor: pointer; + font-weight: 700; + color: var(--accent); + font-size: 1.05rem; + outline: none; + padding: 0.5rem 0; + user-select: none; + transition: color 0.2s; + } + details summary:hover, + details summary:focus { + color: #fff; + } + details > div { + margin-top: 1rem; + padding-bottom: 0.5rem; + border-top: 1px solid var(--details-border); + padding-top: 1rem; + overflow-x: hidden; + } + details label { + margin-top: 0; + font-size: 0.98rem; + font-weight: 500; + color: #ccc; + } + details input[type="text"] { + margin-top: 0.3rem; + font-size: 0.98rem; + background: #232326; + border-color: #333; + width: 100%; + box-sizing: border-box; + } + .help { + cursor: help; + color: var(--accent); + transition: color 0.2s ease; + } + label[for="endpoint"]:before, + label[for="artworkEndpoint"]:before, + label[for="token"]:before { + content: "* "; + color: red; + font-weight: bold; + } + #version { + margin-top: 1.5rem; + font-size: 0.9rem; + color: #aaa; + text-align: center; + }
-

AmNP Settings (Beta)

+

AmNP Settings (Beta)

- + - + - + + +
+ Extra Configurations +
+ + + + + + +
+
+ +
diff --git a/options.js b/options.js index b8cc77e..7aec754 100644 --- a/options.js +++ b/options.js @@ -1,17 +1,81 @@ /* global chrome */ document.addEventListener('DOMContentLoaded', () => { - chrome.storage.sync.get(['endpoint', 'token', 'artworkEndpoint'], (data) => { - document.getElementById('endpoint').value = data.endpoint || ''; - document.getElementById('token').value = data.token || ''; - document.getElementById('artworkEndpoint').value = data.artworkEndpoint || ''; - }); + const keys = [ + 'endpoint', + 'token', + 'artworkEndpoint', + 'placeholderArtwork', + 'pausedTimeout', + 'metadataFetchInterval' + ]; + function parseTimeToMs(input) { + if (!input) return 0; + const str = input.trim().toLowerCase(); + const match = str.match(/^(\d+(\.\d+)?)(\s*(ms|milliseconds?|s|sec|seconds?|m|min|minutes?|h|hr|hrs|hour|hours?))?$/); + if (!match) return Number(str) || 0; + const value = parseFloat(match[1]); + const unit = match[4] || ''; + switch (unit) { + case 'ms': + case 'millisecond': + case 'milliseconds': + return value; + case 's': + case 'sec': + case 'second': + case 'seconds': + return value * 1000; + case 'm': + case 'min': + case 'minute': + case 'minutes': + return value * 60 * 1000; + case 'h': + case 'hr': + case 'hrs': + case 'hour': + case 'hours': + return value * 60 * 60 * 1000; + default: + return value; + } + } - document.getElementById('save').addEventListener('click', () => { - const endpoint = document.getElementById('endpoint').value; - const token = document.getElementById('token').value; - const artworkEndpoint = document.getElementById('artworkEndpoint').value; - chrome.storage.sync.set({ endpoint, token, artworkEndpoint }, () => { - alert('Settings saved.'); - }); + chrome.storage.sync.get(keys, (data) => { + for (const key of keys) { + const elem = document.getElementById(key); + if (elem) { + elem.value = data[key] != null ? String(data[key]) : ''; + } else { + console.warn(`Element with id "${key}" not found in DOM`); + } + } + const saveBtn = document.getElementById('save'); + if (saveBtn) { + saveBtn.addEventListener('click', () => { + const valuesToSave = {}; + + for (const key of keys) { + const elem = document.getElementById(key); + let value = elem ? elem.value.trim() : ''; + // Parse time fields to ms + if (key === 'pausedTimeout' || key === 'metadataFetchInterval') { + value = parseTimeToMs(value); + } + valuesToSave[key] = value; + } + + chrome.storage.sync.set(valuesToSave, () => { + alert('Settings saved.'); + }); + }); + } else { + console.error('Save button not found in DOM'); + } }); }); + if (typeof chrome !== "undefined" && chrome.runtime && chrome.runtime.getManifest) { + document.getElementById('version').textContent = 'You are running Version: ' + chrome.runtime.getManifest().version; + } else { + document.getElementById('version').textContent = 'You are running Version: (unavailable)'; + } \ No newline at end of file