Files
Senko-san 78007461e1
Docker Build & Publish / build (push) Successful in 2m39s
Docker Build & Publish / push (push) Failing after 36s
Docker Build & Publish / Prune old image versions (push) Has been skipped
feat(sources): YouTube Music search + download pipeline (§1C/§1E)
Pluggable fetch source: ytmusicapi search + yt-dlp download (cookies-file guard), DownloadJob entity/repo + DownloadService, download_task worker with exponential-backoff retries, and wired /search, /sources/{source}/search, and /downloads endpoints. Adds youtube_enabled/cookies config, yt-dlp+ytmusicapi deps, and the download_jobs.track_id migration. Snapshot also bundles in-progress storage/tracks/acoustid edits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 14:04:33 +03:00

44 lines
1.6 KiB
Python

"""ORM model for download jobs (plan §6.1).
Tracks a queued download through its lifecycle. ``retry_count`` supports the
exponential-backoff retries that yt-dlp needs; ``progress`` drives the UI
download manager.
"""
import uuid
from sqlalchemy import Float, ForeignKey, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from app.infrastructure.db.base import Base
from app.infrastructure.db.models.enums import DownloadStatus
from app.infrastructure.db.models.mixins import TimestampMixin, UUIDPrimaryKeyMixin
class DownloadJobModel(UUIDPrimaryKeyMixin, TimestampMixin, Base):
__tablename__ = "download_jobs"
source: Mapped[str] = mapped_column(String(32), nullable=False)
source_id: Mapped[str | None] = mapped_column(String(512), nullable=True)
query: Mapped[str | None] = mapped_column(String(1024), nullable=True)
requested_by: Mapped[uuid.UUID | None] = mapped_column(
ForeignKey("users.id", ondelete="SET NULL"),
index=True,
nullable=True,
)
status: Mapped[str] = mapped_column(
String(16),
index=True,
nullable=False,
default=DownloadStatus.QUEUED.value,
)
progress: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
retry_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
# Set once the download finishes and the track is imported — lets the UI
# link a completed job to its library track.
track_id: Mapped[uuid.UUID | None] = mapped_column(
ForeignKey("tracks.id", ondelete="SET NULL"),
nullable=True,
)