296 lines
9.9 KiB
Python
296 lines
9.9 KiB
Python
"""
|
|
Comprehensive El Goose Data Importer
|
|
Fetches ALL Goose data from El Goose API and populates demo database
|
|
"""
|
|
import requests
|
|
import time
|
|
from datetime import datetime
|
|
from sqlmodel import Session, select
|
|
from database import engine
|
|
from models import (
|
|
Vertical, Venue, Tour, Show, Song, Performance, Artist,
|
|
User, UserPreferences
|
|
)
|
|
from passlib.context import CryptContext
|
|
|
|
BASE_URL = "https://elgoose.net/api/v2"
|
|
ARTIST_ID = 1 # Goose
|
|
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
|
|
|
|
# User personas for demo
|
|
DEMO_USERS = [
|
|
{"email": "archivist@demo.com", "username": "TheArchivist", "role": "user", "wiki_mode": True},
|
|
{"email": "statnerd@demo.com", "username": "StatNerd420", "role": "user", "wiki_mode": False},
|
|
{"email": "reviewer@demo.com", "username": "CriticalListener", "role": "user", "wiki_mode": False},
|
|
{"email": "casual@demo.com", "username": "CasualFan", "role": "user", "wiki_mode": False},
|
|
{"email": "groupleader@demo.com", "username": "NortheastHonkers", "role": "user", "wiki_mode": False},
|
|
{"email": "mod@demo.com", "username": "ModGoose", "role": "moderator", "wiki_mode": False},
|
|
{"email": "admin@demo.com", "username": "AdminBird", "role": "admin", "wiki_mode": False},
|
|
{"email": "newbie@demo.com", "username": "NewToGoose", "role": "user", "wiki_mode": False},
|
|
{"email": "taper@demo.com", "username": "TaperTom", "role": "user", "wiki_mode": False},
|
|
{"email": "tourfollower@demo.com", "username": "RoadWarrior", "role": "user", "wiki_mode": False},
|
|
{"email": "lurker@demo.com", "username": "SilentHonker", "role": "user", "wiki_mode": True},
|
|
{"email": "hype@demo.com", "username": "HypeGoose", "role": "user", "wiki_mode": False},
|
|
]
|
|
|
|
def fetch_json(endpoint, params=None):
|
|
"""Fetch JSON from El Goose API with error handling"""
|
|
url = f"{BASE_URL}/{endpoint}.json"
|
|
try:
|
|
response = requests.get(url, params=params)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
if data.get('error') == 1:
|
|
print(f"❌ API Error: {data.get('error_message')}")
|
|
return None
|
|
|
|
return data.get('data', [])
|
|
except Exception as e:
|
|
print(f"❌ Failed to fetch {endpoint}: {e}")
|
|
return None
|
|
|
|
def create_users(session):
|
|
"""Create demo user personas"""
|
|
print("\n📝 Creating user personas...")
|
|
users = []
|
|
for user_data in DEMO_USERS:
|
|
user = User(
|
|
email=user_data["email"],
|
|
hashed_password=pwd_context.hash("demo123"),
|
|
is_active=True,
|
|
is_superuser=(user_data["role"] == "admin"),
|
|
role=user_data["role"]
|
|
)
|
|
session.add(user)
|
|
session.commit()
|
|
session.refresh(user)
|
|
|
|
prefs = UserPreferences(
|
|
user_id=user.id,
|
|
wiki_mode=user_data["wiki_mode"],
|
|
show_ratings=not user_data["wiki_mode"],
|
|
show_comments=not user_data["wiki_mode"]
|
|
)
|
|
session.add(prefs)
|
|
users.append(user)
|
|
|
|
session.commit()
|
|
print(f"✓ Created {len(users)} users")
|
|
return users
|
|
|
|
def import_venues(session):
|
|
"""Import all venues"""
|
|
print("\n🏛️ Importing venues...")
|
|
venues_data = fetch_json("venues")
|
|
if not venues_data:
|
|
return {}
|
|
|
|
venue_map = {}
|
|
for v in venues_data:
|
|
existing = session.exec(
|
|
select(Venue).where(Venue.name == v['venuename'])
|
|
).first()
|
|
|
|
if existing:
|
|
venue_map[v['venue_id']] = existing.id
|
|
else:
|
|
venue = Venue(
|
|
name=v['venuename'],
|
|
city=v.get('city'),
|
|
state=v.get('state'),
|
|
country=v.get('country'),
|
|
capacity=v.get('capacity')
|
|
)
|
|
session.add(venue)
|
|
session.commit()
|
|
session.refresh(venue)
|
|
venue_map[v['venue_id']] = venue.id
|
|
|
|
print(f"✓ Imported {len(venue_map)} venues")
|
|
return venue_map
|
|
|
|
def import_songs(session, vertical_id):
|
|
"""Import all songs"""
|
|
print("\n🎵 Importing songs...")
|
|
songs_data = fetch_json("songs")
|
|
if not songs_data:
|
|
return {}
|
|
|
|
song_map = {}
|
|
for s in songs_data:
|
|
# Check if song exists
|
|
existing = session.exec(
|
|
select(Song).where(
|
|
Song.title == s['name'],
|
|
Song.vertical_id == vertical_id
|
|
)
|
|
).first()
|
|
|
|
if existing:
|
|
song_map[s['id']] = existing.id # API uses 'id' not 'song_id'
|
|
else:
|
|
song = Song(
|
|
title=s['name'],
|
|
original_artist=s.get('original_artist'),
|
|
vertical_id=vertical_id
|
|
# API doesn't include debut_date or times_played in base response
|
|
)
|
|
session.add(song)
|
|
session.commit()
|
|
session.refresh(song)
|
|
song_map[s['id']] = song.id # API uses 'id' not 'song_id'
|
|
|
|
print(f"✓ Imported {len(song_map)} songs")
|
|
return song_map
|
|
|
|
def import_shows(session, vertical_id, venue_map):
|
|
"""Import all Goose shows"""
|
|
print("\n🎤 Importing shows...")
|
|
params = {"artist": ARTIST_ID}
|
|
shows_data = fetch_json("shows", params)
|
|
|
|
if not shows_data:
|
|
# Fallback: fetch all shows and filter
|
|
print(" Fetching all shows and filtering for Goose...")
|
|
shows_data = fetch_json("shows")
|
|
shows_data = [s for s in (shows_data or []) if s.get('artist_id') == ARTIST_ID]
|
|
|
|
if not shows_data:
|
|
print("❌ No shows found")
|
|
return {}, {}
|
|
|
|
show_map = {}
|
|
tour_map = {}
|
|
|
|
for s in shows_data:
|
|
# Handle tours
|
|
tour_id = None
|
|
if s.get('tour_id') and s['tour_id'] != 1: # 1 = "Not Part of a Tour"
|
|
if s['tour_id'] not in tour_map:
|
|
# Check if tour exists
|
|
existing_tour = session.exec(
|
|
select(Tour).where(Tour.name == s['tourname'])
|
|
).first()
|
|
|
|
if existing_tour:
|
|
tour_map[s['tour_id']] = existing_tour.id
|
|
else:
|
|
tour = Tour(name=s['tourname'])
|
|
session.add(tour)
|
|
session.commit()
|
|
session.refresh(tour)
|
|
tour_map[s['tour_id']] = tour.id
|
|
|
|
tour_id = tour_map[s['tour_id']]
|
|
|
|
# Create show
|
|
show_date = datetime.strptime(s['showdate'], '%Y-%m-%d')
|
|
show = Show(
|
|
date=show_date,
|
|
vertical_id=vertical_id,
|
|
venue_id=venue_map.get(s['venue_id']),
|
|
tour_id=tour_id,
|
|
notes=s.get('showtitle')
|
|
)
|
|
session.add(show)
|
|
session.commit()
|
|
session.refresh(show)
|
|
show_map[s['show_id']] = show.id
|
|
|
|
if len(show_map) % 50 == 0:
|
|
print(f" Progress: {len(show_map)} shows...")
|
|
|
|
print(f"✓ Imported {len(show_map)} shows and {len(tour_map)} tours")
|
|
return show_map, tour_map
|
|
|
|
def import_setlists(session, show_map, song_map):
|
|
"""Import setlists for all shows"""
|
|
print("\n📋 Importing setlists...")
|
|
|
|
# Fetch all setlists (this gets all performances across all shows)
|
|
setlists_data = fetch_json("setlists")
|
|
if not setlists_data:
|
|
print("❌ No setlist data found")
|
|
return
|
|
|
|
# Filter for Goose shows
|
|
goose_setlists = [
|
|
s for s in setlists_data
|
|
if s.get('show_id') in show_map
|
|
]
|
|
|
|
performance_count = 0
|
|
for perf_data in goose_setlists:
|
|
# Map to our show and song IDs
|
|
our_show_id = show_map.get(perf_data['show_id'])
|
|
our_song_id = song_map.get(perf_data['song_id'])
|
|
|
|
if not our_show_id or not our_song_id:
|
|
continue
|
|
|
|
perf = Performance(
|
|
show_id=our_show_id,
|
|
song_id=our_song_id,
|
|
position=perf_data.get('position', 0),
|
|
set_name=perf_data.get('set'),
|
|
segue=bool(perf_data.get('segue', 0)),
|
|
notes=perf_data.get('notes')
|
|
)
|
|
session.add(perf)
|
|
performance_count += 1
|
|
|
|
if performance_count % 100 == 0:
|
|
session.commit()
|
|
print(f" Progress: {performance_count} performances...")
|
|
|
|
session.commit()
|
|
print(f"✓ Imported {performance_count} performances")
|
|
|
|
def main():
|
|
print("="*60)
|
|
print("EL GOOSE DATA IMPORTER")
|
|
print("="*60)
|
|
|
|
with Session(engine) as session:
|
|
# 1. Create vertical
|
|
print("\n🦆 Creating Goose vertical...")
|
|
vertical = Vertical(
|
|
name="Goose",
|
|
slug="goose",
|
|
description="Goose is a jam band from Connecticut"
|
|
)
|
|
session.add(vertical)
|
|
session.commit()
|
|
session.refresh(vertical)
|
|
print(f"✓ Created vertical (ID: {vertical.id})")
|
|
|
|
# 2. Create users
|
|
users = create_users(session)
|
|
|
|
# 3. Import base data
|
|
venue_map = import_venues(session)
|
|
song_map = import_songs(session, vertical.id)
|
|
|
|
# 4. Import shows
|
|
show_map, tour_map = import_shows(session, vertical.id, venue_map)
|
|
|
|
# 5. Import setlists
|
|
import_setlists(session, show_map, song_map)
|
|
|
|
print("\n" + "="*60)
|
|
print("✓ IMPORT COMPLETE!")
|
|
print("="*60)
|
|
print(f"\nImported:")
|
|
print(f" • {len(venue_map)} venues")
|
|
print(f" • {len(tour_map)} tours")
|
|
print(f" • {len(song_map)} songs")
|
|
print(f" • {len(show_map)} shows")
|
|
print(f" • {len(users)} demo users")
|
|
print(f"\nAll passwords: demo123")
|
|
print(f"\nStart demo servers:")
|
|
print(f" Backend: DATABASE_URL='sqlite:///./elmeg-demo.db' uvicorn main:app --reload --port 8001")
|
|
print(f" Frontend: NEXT_PUBLIC_API_URL=http://localhost:8001 npm run dev -- -p 3001")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|