|
| 1 | +import { BTR_BASE, getToken, connect, verify, disconnect } from './bittorrented.js'; |
| 2 | + |
| 3 | +const $ = (id) => document.getElementById(id); |
| 4 | +const el = (t, c, x) => { const e = document.createElement(t); if (c) e.className = c; if (x != null) e.textContent = x; return e; }; |
| 5 | + |
| 6 | +let activeTab = 'favorites'; |
| 7 | + |
| 8 | +function setStatus(text, kind) { const s = $('status'); s.textContent = text; s.className = 'status ' + (kind || ''); } |
| 9 | + |
| 10 | +function showConnected(email) { |
| 11 | + $('connect').classList.remove('active'); |
| 12 | + $('content').classList.add('active'); |
| 13 | + $('acct').textContent = email || 'connected'; |
| 14 | + $('disc').classList.remove('hidden'); |
| 15 | + loadTab(activeTab); |
| 16 | +} |
| 17 | + |
| 18 | +function showDisconnected() { |
| 19 | + $('content').classList.remove('active'); |
| 20 | + $('connect').classList.add('active'); |
| 21 | + $('acct').textContent = ''; |
| 22 | + $('disc').classList.add('hidden'); |
| 23 | +} |
| 24 | + |
| 25 | +// bittorrented item shapes vary by section — render defensively from common fields. |
| 26 | +function fieldOf(o, keys) { for (const k of keys) if (o && o[k] != null && o[k] !== '') return o[k]; return ''; } |
| 27 | + |
| 28 | +function renderItems(items) { |
| 29 | + const list = $('list'); list.innerHTML = ''; |
| 30 | + if (!Array.isArray(items) || items.length === 0) { list.appendChild(el('div', 'muted', 'Nothing here yet.')); return; } |
| 31 | + for (const it of items) { |
| 32 | + const title = fieldOf(it, ['title', 'name', 'label']) || '(untitled)'; |
| 33 | + const url = fieldOf(it, ['url', 'stream', 'streamUrl', 'link', 'magnet', 'href']); |
| 34 | + const sub = fieldOf(it, ['group', 'category', 'genre', 'author', 'description']); |
| 35 | + const row = el('div', 'msg'); |
| 36 | + const n = el('span', 'n', '▶'); |
| 37 | + const a = url ? el('a', null, title) : el('span', null, title); |
| 38 | + if (url) { a.href = url; a.target = '_blank'; a.rel = 'noreferrer'; } |
| 39 | + row.append(n, a); |
| 40 | + if (sub) { const s = el('span', 't', ' ' + sub); row.append(s); } |
| 41 | + list.appendChild(row); |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +async function loadTab(tab) { |
| 46 | + activeTab = tab; |
| 47 | + document.querySelectorAll('#media-tabs .tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab)); |
| 48 | + const list = $('list'); list.innerHTML = ''; list.appendChild(el('div', 'muted', 'Loading…')); |
| 49 | + const token = await getToken(); |
| 50 | + // Map UI tabs → bittorrented.com /api/v1 endpoints. |
| 51 | + const path = { favorites: 'favorites', livetv: 'livetv', radio: 'radio', podcasts: 'podcasts' }[tab] || 'favorites'; |
| 52 | + try { |
| 53 | + const r = await fetch(`${BTR_BASE}/api/v1/${path}`, { headers: { authorization: `Bearer ${token}` } }); |
| 54 | + if (r.status === 401) { showDisconnected(); setStatus('Session expired — connect again.', 'err'); return; } |
| 55 | + const data = await r.json().catch(() => ([])); |
| 56 | + renderItems(Array.isArray(data) ? data : (data.items || data.results || data[path] || [])); |
| 57 | + } catch (e) { |
| 58 | + list.innerHTML = ''; |
| 59 | + list.appendChild(el('div', 'muted', 'Could not load ' + path + '. ' + ((e && e.message) || ''))); |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +document.querySelectorAll('#media-tabs .tab').forEach((b) => b.addEventListener('click', () => loadTab(b.dataset.tab))); |
| 64 | + |
| 65 | +$('go').addEventListener('click', async () => { |
| 66 | + setStatus('Opening bittorrented.com… finish signing in & approving in the new tab.'); |
| 67 | + try { |
| 68 | + const res = await connect(); |
| 69 | + if (res.connected) { setStatus('Connected ✓', 'ok'); showConnected(res.email); } |
| 70 | + else setStatus('Connection not completed.', 'err'); |
| 71 | + } catch (e) { setStatus((e && e.message) || 'connect failed', 'err'); } |
| 72 | +}); |
| 73 | + |
| 74 | +$('disc').addEventListener('click', async () => { await disconnect(); showDisconnected(); }); |
| 75 | + |
| 76 | +// On load: if already connected, jump straight to content. |
| 77 | +(async () => { |
| 78 | + const res = await verify(); |
| 79 | + if (res.connected) showConnected(res.email); |
| 80 | +})(); |
0 commit comments