From 1ac096ca524b1c1fdc48b3f10e427d2b13cbe629 Mon Sep 17 00:00:00 2001 From: Sophia Atkinson Date: Fri, 27 Jun 2025 12:00:56 -0700 Subject: [PATCH] Made it so you can configure everything You can configure the following settings: - Placeholder artwork URL - Paused timeout (in seconds, minutes, or hours) - Metadata fetch interval (in seconds, minutes, or hours) I also added helping notes to the title of the inputs to make it clearer what each setting does. Also meow meow meow meow meow meow meow meow meow meow meow meow meow meow --- content.js | 37 +++++++++++++--------- manifest.json | 2 +- options.html | 85 ++++++++++++++++++++++++++++++++++++++++++++++--- options.js | 88 ++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 180 insertions(+), 32 deletions(-) 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 +
+ + + + + + +
+
+ +
You are running version: (unavailable)
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