diff --git a/journeyfm/web_service.py b/journeyfm/web_service.py index 81a4e04..9ee482e 100644 --- a/journeyfm/web_service.py +++ b/journeyfm/web_service.py @@ -6,7 +6,9 @@ import webbrowser from http.server import BaseHTTPRequestHandler, HTTPServer from pathlib import Path +from journeyfm.config_store import load_runtime_config from journeyfm.paths import data_path +from journeyfm.update_service import run_update_job from journeyfm.config_store import load_runtime_config from journeyfm.update_service import run_update_job @@ -81,6 +83,56 @@ def load_recent_stats(db_path=None): return stats +def load_history_entries(db_path=None, limit=100): + db_path = db_path or data_path("playlist_history.db") + rows = [] + if not Path(db_path).exists(): + return rows + conn = sqlite3.connect(db_path) + try: + c = conn.cursor() + c.execute( + "SELECT id, date, status, scraped_count, matched_count, added_count, missing_count, duplicate_count, skipped_count, station_breakdown FROM history ORDER BY date DESC LIMIT ?", + (limit,) + ) + result = c.fetchall() + for r in result: + rows.append({ + "id": r[0], + "date": r[1], + "status": r[2], + "scraped_count": r[3], + "matched_count": r[4], + "added_count": r[5], + "missing_count": r[6], + "duplicate_count": r[7], + "skipped_count": r[8], + "station_breakdown": json.loads(r[9] or '[]'), + }) + except Exception: + return [] + finally: + conn.close() + return rows + + +def load_buy_list(buy_list_path=None): + buy_list_path = buy_list_path or data_path("amazon_buy_list.txt") + if not Path(buy_list_path).exists(): + return [] + entries = [] + try: + with open(buy_list_path, 'r', encoding='utf-8') as f: + lines = [ln.strip() for ln in f if ln.strip()] + for ln in lines: + if ln.startswith('http'): + continue + entries.append(ln) + except Exception: + return [] + return entries + + def render_dashboard_html(stats): title = "Journey FM Song Count Command Center" station_rows = "".join( @@ -137,6 +189,9 @@ def render_dashboard_html(stats): + + + @@ -171,6 +226,30 @@ def render_dashboard_html(stats): +
| Date | Status | Scraped | Matched | Added | Missing | Duplicates | Skipped |
|---|
Loading…@@ -236,6 +315,7 @@ def render_dashboard_html(stats): }) .then(function(data) { status.textContent = data.status === 'ok' ? 'Refresh complete' : 'Refresh failed'; + document.getElementById('app-result').textContent = JSON.stringify(data.result || data, null, 2); setTimeout(function() { status.textContent = ''; }, 4500); setTimeout(function() { location.reload(); }, 1000); }) @@ -244,6 +324,65 @@ def render_dashboard_html(stats): setTimeout(function() { status.textContent = ''; }, 6500); }); } + + function previewStats() { + var status = document.getElementById('refresh-status'); + status.textContent = 'Previewing ...'; + fetch('/api/preview') + .then(function(response) { return response.json(); }) + .then(function(data) { + status.textContent = 'Preview complete'; + document.getElementById('app-result').textContent = JSON.stringify(data, null, 2); + setTimeout(function() { status.textContent = ''; }, 4500); + }) + .catch(function(err) { + status.textContent = 'Error: ' + err; + setTimeout(function() { status.textContent = ''; }, 6500); + }); + } + + function fetchBuyList() { + fetch('/api/buy-list') + .then(function(response) { return response.json(); }) + .then(function(data) { + var container = document.getElementById('buy-list-items'); + container.innerHTML = ''; + data.forEach(function(item) { + var li = document.createElement('li'); + li.textContent = item; + container.appendChild(li); + }); + document.getElementById('app-result').textContent = 'Loaded buy list (' + data.length + ' items).'; + }) + .catch(function(err) { + document.getElementById('app-result').textContent = 'Error loading buy list: ' + err; + }); + } + + function fetchHistory() { + fetch('/api/history') + .then(function(response) { return response.json(); }) + .then(function(data) { + var rows = document.getElementById('history-rows'); + rows.innerHTML = ''; + data.forEach(function(item) { + var tr = document.createElement('tr'); + tr.innerHTML = '