A Chrome extension that scrobbles NTS Radio tracks to teal.fm
at main 4.3 kB view raw
1// Popup script 2 3document.addEventListener('DOMContentLoaded', async () => { 4 const loginForm = document.getElementById('login-form'); 5 const loggedInSection = document.getElementById('logged-in'); 6 const loginBtn = document.getElementById('login-btn'); 7 const logoutBtn = document.getElementById('logout-btn'); 8 const pdsUrlInput = document.getElementById('pds-url'); 9 const identifierInput = document.getElementById('identifier'); 10 const passwordInput = document.getElementById('password'); 11 const errorMsg = document.getElementById('error-msg'); 12 const autoScrobbleCheckbox = document.getElementById('auto-scrobble'); 13 14 // Check auth status 15 const response = await chrome.runtime.sendMessage({ type: 'GET_AUTH_STATUS' }); 16 17 if (response.authenticated) { 18 showLoggedIn(); 19 } else { 20 showLogin(); 21 } 22 23 // Load settings 24 const settings = await chrome.storage.local.get(['autoScrobble', 'pdsUrl']); 25 if (settings.autoScrobble !== undefined) { 26 autoScrobbleCheckbox.checked = settings.autoScrobble; 27 } 28 if (settings.pdsUrl) { 29 pdsUrlInput.value = settings.pdsUrl; 30 } 31 32 // Get current track and recent scrobbles 33 updateCurrentTrack(); 34 updateRecentScrobbles(); 35 36 // Listen for track updates 37 chrome.runtime.onMessage.addListener((message) => { 38 if (message.type === 'TRACK_UPDATE') { 39 updateCurrentTrack(); 40 } else if (message.type === 'SCROBBLE_SUCCESS') { 41 updateRecentScrobbles(); 42 } 43 }); 44 45 // Login handler 46 loginBtn.addEventListener('click', async () => { 47 const identifier = identifierInput.value.trim(); 48 const password = passwordInput.value; 49 let pdsUrl = pdsUrlInput.value.trim(); 50 51 if (!pdsUrl) { 52 pdsUrl = 'https://bsky.social'; 53 } 54 55 if (!identifier || !password) { 56 errorMsg.textContent = 'Please enter both handle/email and password'; 57 return; 58 } 59 60 loginBtn.disabled = true; 61 loginBtn.textContent = 'Logging in...'; 62 errorMsg.textContent = ''; 63 64 // Save PDS URL 65 await chrome.storage.local.set({ pdsUrl }); 66 67 const result = await chrome.runtime.sendMessage({ 68 type: 'LOGIN', 69 data: { identifier, password, pdsUrl } 70 }); 71 72 if (result.success) { 73 showLoggedIn(); 74 passwordInput.value = ''; 75 } else { 76 errorMsg.textContent = result.error || 'Login failed'; 77 } 78 79 loginBtn.disabled = false; 80 loginBtn.textContent = 'Login'; 81 }); 82 83 // Logout handler 84 logoutBtn.addEventListener('click', async () => { 85 await chrome.runtime.sendMessage({ type: 'LOGOUT' }); 86 showLogin(); 87 }); 88 89 // Auto-scrobble setting 90 autoScrobbleCheckbox.addEventListener('change', async (e) => { 91 await chrome.storage.local.set({ autoScrobble: e.target.checked }); 92 }); 93 94 function showLogin() { 95 loginForm.style.display = 'block'; 96 loggedInSection.style.display = 'none'; 97 } 98 99 function showLoggedIn() { 100 loginForm.style.display = 'none'; 101 loggedInSection.style.display = 'block'; 102 } 103 104 async function updateCurrentTrack() { 105 const response = await chrome.runtime.sendMessage({ type: 'GET_CURRENT_TRACK' }); 106 const currentTrackDiv = document.getElementById('current-track'); 107 108 if (response && response.track) { 109 const track = response.track; 110 currentTrackDiv.innerHTML = ` 111 <div class="track-info"> 112 <div class="track-title">${track.track}</div> 113 <div class="track-artist">${track.artist}</div> 114 </div> 115 `; 116 } else { 117 currentTrackDiv.innerHTML = '<p class="info">No track detected</p>'; 118 } 119 } 120 121 async function updateRecentScrobbles() { 122 const response = await chrome.runtime.sendMessage({ type: 'GET_RECENT_TRACKS' }); 123 const recentTracksList = document.getElementById('recent-tracks-list'); 124 125 if (response && response.tracks && response.tracks.length > 0) { 126 // Show only the latest 3 scrobbles 127 const latestTracks = response.tracks.slice(0, 3); 128 recentTracksList.innerHTML = latestTracks.map(track => ` 129 <div class="recent-track"> 130 <span class="recent-track-title">${track.track}</span> 131 <span class="recent-track-artist">${track.artist}</span> 132 </div> 133 `).join(''); 134 } else { 135 recentTracksList.innerHTML = '<p class="info small">No recent scrobbles</p>'; 136 } 137 } 138});