fediversion/backend/import_per_show.py
fullsizemalt b4cddf41ea feat: Initialize Fediversion multi-band platform
- Fork elmeg-demo codebase for multi-band support
- Add data importer infrastructure with base class
- Create band-specific importers:
  - phish.py: Phish.net API v5
  - grateful_dead.py: Grateful Stats API
  - setlistfm.py: Dead & Company, Billy Strings (Setlist.fm)
- Add spec-kit configuration for Gemini
- Update README with supported bands and architecture
2025-12-28 12:39:28 -08:00

161 lines
5.5 KiB
Python

"""
Per-Show Setlist Importer
Fetches setlist for each show individually
"""
import requests
from sqlmodel import Session, select
from database import engine
from models import Show, Song, Performance
BASE_URL = "https://elgoose.net/api/v2"
def fetch_show_setlist(api_show_id):
"""Fetch setlist for a specific show"""
url = f"{BASE_URL}/setlists/showid/{api_show_id}.json"
try:
response = requests.get(url, timeout=30)
response.raise_for_status()
data = response.json()
if data.get('error') == 1:
return None
return data.get('data', [])
except Exception as e:
return None
def main():
print("PER-SHOW SETLIST IMPORTER")
print("=" * 40)
with Session(engine) as session:
# Get all shows
shows = session.exec(select(Show)).all()
print(f"Found {len(shows)} shows in database")
# Build song map by title
songs = session.exec(select(Song)).all()
song_map = {s.title.lower(): s.id for s in songs}
print(f"Mapped {len(song_map)} songs")
# Get existing performances
print("Loading existing performances...")
existing_map = {} # (show_id, song_id, position) -> Performance Object
perfs = session.exec(select(Performance)).all()
for p in perfs:
existing_map[(p.show_id, p.song_id, p.position)] = p
print(f"Found {len(existing_map)} existing performances")
# We need API show IDs. The ElGoose API shows endpoint returns show_id.
# Let's fetch and correlate by date
print("Fetching API shows to get API IDs...")
api_shows = {} # date_str -> api_show_id
page = 1
seen_ids = set()
while True:
url = f"{BASE_URL}/shows.json"
try:
resp = requests.get(url, params={"page": page}, timeout=30)
data = resp.json().get('data', [])
if not data:
break
# Loop detection
first_id = data[0].get('show_id') if data else None
if first_id in seen_ids:
print(f" Loop detected at page {page}")
break
if first_id:
seen_ids.add(first_id)
for s in data:
# CRITICAL: Only include Goose shows
if s.get('artist') != 'Goose':
continue
date_str = s['showdate']
api_shows[date_str] = s['show_id']
page += 1
except Exception as e:
print(f" Error on page {page}: {e}")
break
print(f"Got {len(api_shows)} API show IDs")
# Now import setlists for each show
total_added = 0
total_updated = 0
processed = 0
for show in shows:
date_str = show.date.strftime('%Y-%m-%d')
api_show_id = api_shows.get(date_str)
if not api_show_id:
continue
# REMOVED: Skipping logic. We verify everything.
# existing_for_show = ...
# Fetch setlist
setlist = fetch_show_setlist(api_show_id)
if not setlist:
continue
added = 0
updated = 0
for item in setlist:
song_title = item.get('songname', '').lower()
song_id = song_map.get(song_title)
if not song_id:
continue
position = item.get('position', 0)
key = (show.id, song_id, position)
# Resolve set name
set_val = str(item.get('setnumber', '1'))
if set_val.isdigit():
set_name = f"Set {set_val}"
elif set_val.lower() == 'e':
set_name = "Encore"
elif set_val.lower() == 'e2':
set_name = "Encore 2"
elif set_val.lower() == 's':
set_name = "Soundcheck"
else:
set_name = f"Set {set_val}"
if key in existing_map:
# Update Check
perf = existing_map[key]
if not perf.set_name or perf.set_name != set_name:
perf.set_name = set_name
session.add(perf)
updated += 1
total_updated += 1
continue
# Create New
perf = Performance(
show_id=show.id,
song_id=song_id,
position=position,
set_name=set_name,
segue=bool(item.get('segue', 0)),
notes=item.get('footnote')
)
session.add(perf)
existing_map[key] = perf # Add to map to prevent dupes in same run
added += 1
total_added += 1
if added > 0 or updated > 0:
session.commit()
processed += 1
print(f"Show {date_str}: +{added} new, ~{updated} updated")
print(f"\nImport Complete! Added: {total_added}, Updated: {total_updated}")
if __name__ == "__main__":
main()