models.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. from sqlalchemy import Column, String, Float, DateTime, Integer, Text, Boolean, ForeignKey
  2. from sqlalchemy.ext.declarative import declarative_base
  3. from sqlalchemy.orm import relationship
  4. from sqlalchemy.sql import func
  5. from datetime import datetime
  6. Base = declarative_base()
  7. class User(Base):
  8. """User account with Audiobookshelf credentials."""
  9. __tablename__ = "users"
  10. id = Column(Integer, primary_key=True, autoincrement=True)
  11. username = Column(String, unique=True, nullable=False, index=True)
  12. email = Column(String, unique=True, nullable=False, index=True)
  13. hashed_password = Column(String, nullable=False)
  14. # Per-user Audiobookshelf credentials
  15. abs_url = Column(String, nullable=False)
  16. abs_api_token = Column(String, nullable=False) # Encrypted with Fernet
  17. # Profile information
  18. display_name = Column(String)
  19. created_at = Column(DateTime, default=func.now())
  20. last_login = Column(DateTime)
  21. is_active = Column(Boolean, default=True)
  22. is_admin = Column(Boolean, default=False)
  23. # Relationships
  24. listening_sessions = relationship("ListeningSession", back_populates="user", cascade="all, delete-orphan")
  25. recommendations = relationship("Recommendation", back_populates="user", cascade="all, delete-orphan")
  26. class Book(Base):
  27. """Book information from Audiobookshelf."""
  28. __tablename__ = "books"
  29. id = Column(String, primary_key=True) # Audiobookshelf book ID
  30. title = Column(String, nullable=False)
  31. author = Column(String)
  32. narrator = Column(String)
  33. description = Column(Text)
  34. genres = Column(String) # JSON string of genres
  35. tags = Column(String) # JSON string of tags
  36. duration = Column(Float) # Duration in seconds
  37. cover_url = Column(String)
  38. created_at = Column(DateTime, default=func.now())
  39. updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
  40. class ListeningSession(Base):
  41. """User listening sessions and progress."""
  42. __tablename__ = "listening_sessions"
  43. id = Column(Integer, primary_key=True, autoincrement=True)
  44. user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
  45. book_id = Column(String, nullable=False)
  46. # Progress tracking
  47. progress = Column(Float, default=0.0) # 0.0 to 1.0
  48. current_time = Column(Float, default=0.0) # Current position in seconds
  49. is_finished = Column(Boolean, default=False)
  50. # Timestamps
  51. started_at = Column(DateTime)
  52. finished_at = Column(DateTime, nullable=True)
  53. last_update = Column(DateTime, default=func.now(), onupdate=func.now())
  54. # Ratings and preferences
  55. rating = Column(Integer, nullable=True) # 1-5 stars, optional
  56. # Relationships
  57. user = relationship("User", back_populates="listening_sessions")
  58. class Recommendation(Base):
  59. """AI-generated book recommendations."""
  60. __tablename__ = "recommendations"
  61. id = Column(Integer, primary_key=True, autoincrement=True)
  62. user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
  63. # Recommendation details
  64. title = Column(String, nullable=False)
  65. author = Column(String)
  66. description = Column(Text)
  67. reason = Column(Text) # Why this book was recommended
  68. # Metadata
  69. genres = Column(String) # JSON string
  70. created_at = Column(DateTime, default=func.now())
  71. dismissed = Column(Boolean, default=False)
  72. # Relationships
  73. user = relationship("User", back_populates="recommendations")
  74. class AppSettings(Base):
  75. """Application-wide settings."""
  76. __tablename__ = "app_settings"
  77. id = Column(Integer, primary_key=True, autoincrement=True)
  78. key = Column(String, unique=True, nullable=False, index=True)
  79. value = Column(String, nullable=False)
  80. updated_at = Column(DateTime, default=func.now(), onupdate=func.now())