import json import os from pathlib import Path from datetime import datetime from sqlmodel import Session, select from sqlalchemy.exc import IntegrityError import sys # Add the root directory to sys.path to import app modules sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from app.database import engine, create_db_and_tables from app.models.auth import UserTable from app.models.watchlist import WatchlistItemTable, WatchlistSettingsTable, WatchlistStatus, QualityPreference from app.models.favorites import FavoriteTable from app.models.sonarr import SonarrMappingTable, SonarrConfigTable def migrate_users(session: Session): path = Path("config/users.json") if not path.exists(): print("No users.json found.") return with open(path, "r", encoding="utf-8") as f: data = json.load(f) users_data = data.get("users", {}) count = 0 for user_id, user_info in users_data.items(): existing = session.get(UserTable, user_id) if existing: continue # Parse dates created_at = datetime.now() if "created_at" in user_info: try: created_at = datetime.fromisoformat(user_info["created_at"]) except ValueError: pass last_login = None if "last_login" in user_info and user_info["last_login"]: try: last_login = datetime.fromisoformat(user_info["last_login"]) except ValueError: pass user = UserTable( id=user_id, username=user_info.get("username", "unknown"), email=user_info.get("email"), hashed_password=user_info.get("hashed_password", ""), is_active=user_info.get("is_active", True), created_at=created_at, last_login=last_login ) session.add(user) count += 1 session.commit() print(f"Migrated {count} users.") def migrate_watchlist(session: Session): path = Path("config/watchlist.json") if not path.exists(): print("No watchlist.json found.") return with open(path, "r", encoding="utf-8") as f: data = json.load(f) count = 0 for user_id, items in data.items(): for item in items: existing = session.get(WatchlistItemTable, item.get("id")) if existing: continue last_checked = None if "last_checked" in item and item["last_checked"]: try: last_checked = datetime.fromisoformat(item["last_checked"]) except ValueError: pass added_at = datetime.now() if "added_at" in item: try: added_at = datetime.fromisoformat(item["added_at"]) except ValueError: pass updated_at = datetime.now() if "updated_at" in item: try: updated_at = datetime.fromisoformat(item["updated_at"]) except ValueError: pass wl_item = WatchlistItemTable( id=item["id"], user_id=user_id, anime_title=item["anime_title"], anime_url=item["anime_url"], provider_id=item["provider_id"], lang=item.get("lang", "vostfr"), last_checked=last_checked, last_episode_downloaded=item.get("last_episode_downloaded", 0), total_episodes=item.get("total_episodes"), auto_download=item.get("auto_download", True), quality_preference=item.get("quality_preference", QualityPreference.AUTO), status=item.get("status", WatchlistStatus.ACTIVE), poster_image=item.get("poster_image"), cover_image=item.get("cover_image"), synopsis=item.get("synopsis"), genres=item.get("genres", []), added_at=added_at, updated_at=updated_at ) session.add(wl_item) count += 1 session.commit() print(f"Migrated {count} watchlist items.") def migrate_watchlist_settings(session: Session): path = Path("config/watchlist_settings.json") if not path.exists(): print("No watchlist_settings.json found.") return with open(path, "r", encoding="utf-8") as f: settings = json.load(f) count = 0 # Treat as global settings for "default" user user_id = "default" existing = session.exec(select(WatchlistSettingsTable).where(WatchlistSettingsTable.user_id == user_id)).first() if not existing: setting_row = WatchlistSettingsTable( user_id=user_id, check_interval_hours=settings.get("check_interval_hours", 6), auto_download_enabled=settings.get("auto_download_enabled", True), max_concurrent_auto_downloads=settings.get("max_concurrent_auto_downloads", 2), notify_on_new_episodes=settings.get("notify_on_new_episodes", False), include_completed_anime=settings.get("include_completed_anime", False) ) session.add(setting_row) count += 1 session.commit() print(f"Migrated {count} watchlist settings.") def migrate_favorites(session: Session): path = Path("data/favorites.json") if not path.exists(): print("No favorites.json found.") return with open(path, "r", encoding="utf-8") as f: try: data = json.load(f) except json.JSONDecodeError: print("Invalid favorites.json.") return count = 0 for fav_id, fav in data.items(): existing = session.exec(select(FavoriteTable).where(FavoriteTable.anime_id == fav_id)).first() if existing: continue created_at = datetime.now() if "created_at" in fav: try: created_at = datetime.fromisoformat(fav["created_at"]) except ValueError: pass updated_at = datetime.now() if "updated_at" in fav: try: updated_at = datetime.fromisoformat(fav["updated_at"]) except ValueError: pass fav_row = FavoriteTable( anime_id=fav_id, user_id="default", # Favorites were global title=fav.get("title", ""), url=fav.get("url", ""), provider=fav.get("provider", ""), poster_url=fav.get("poster_url"), anime_metadata=fav.get("metadata", {}), created_at=created_at, updated_at=updated_at ) session.add(fav_row) count += 1 session.commit() print(f"Migrated {count} favorites.") def migrate_sonarr(session: Session): # Config path_config = Path("config/sonarr.json") if path_config.exists(): with open(path_config, "r", encoding="utf-8") as f: data = json.load(f) existing = session.exec(select(SonarrConfigTable)).first() if not existing: conf = SonarrConfigTable( webhook_enabled=data.get("webhook_enabled", False), webhook_secret=data.get("webhook_secret"), auto_download_enabled=data.get("auto_download_enabled", True), default_language=data.get("default_language", "vostfr"), default_quality=data.get("default_quality"), default_provider=data.get("default_provider", "anime-sama"), verify_hmac=data.get("verify_hmac", False), log_webhooks=data.get("log_webhooks", True) ) session.add(conf) session.commit() print("Migrated Sonarr config.") # Mappings path_maps = Path("config/sonarr_mappings.json") if path_maps.exists(): with open(path_maps, "r", encoding="utf-8") as f: data = json.load(f) count = 0 for map_id, mapping in data.items(): existing = session.exec(select(SonarrMappingTable).where(SonarrMappingTable.sonarr_series_id == int(map_id))).first() if existing: continue created_at = datetime.now() if "created_at" in mapping: try: created_at = datetime.fromisoformat(mapping["created_at"]) except ValueError: pass updated_at = datetime.now() if "updated_at" in mapping: try: updated_at = datetime.fromisoformat(mapping["updated_at"]) except ValueError: pass map_row = SonarrMappingTable( user_id="default", sonarr_series_id=mapping.get("sonarr_series_id", int(map_id)), sonarr_title=mapping.get("sonarr_title", ""), anime_provider=mapping.get("anime_provider", ""), anime_url=mapping.get("anime_url", ""), anime_title=mapping.get("anime_title", ""), lang=mapping.get("lang", "vostfr"), quality_preference=mapping.get("quality_preference"), auto_download=mapping.get("auto_download", True), created_at=created_at, updated_at=updated_at ) session.add(map_row) count += 1 session.commit() print(f"Migrated {count} Sonarr mappings.") if __name__ == "__main__": create_db_and_tables() with Session(engine) as session: migrate_users(session) migrate_watchlist(session) migrate_watchlist_settings(session) migrate_favorites(session) migrate_sonarr(session) print("Data migration complete.")