refactor(catalog): the unit's tables move into catalog/models

Channel, Subscription, Video, SearchFind, ExploredChannel and BlockedChannel (and LIVE_OR_UPCOMING)
leave app/models.py for app/catalog/models.py; app.tables registers them. The User↔Subscription
relationship names its other side as a type only. No schema change.
This commit is contained in:
2026-10-19 02:03:14 +02:00
parent a35eece652
commit 238e6f8a61
55 changed files with 353 additions and 308 deletions
+2 -1
View File
@@ -9,7 +9,8 @@ from datetime import datetime, timedelta, timezone
from app.auth import admin_user
from app.main import app
from app.models import AuditLog, Channel, JobRun, LogEvent, QuotaEvent
from app.models import AuditLog, JobRun, LogEvent, QuotaEvent
from app.catalog.models import Channel
from tests.test_body_limit import _route_objects
T0 = datetime(2026, 10, 1, 12, 0, tzinfo=timezone.utc)
+1 -1
View File
@@ -7,7 +7,7 @@ drops an unknown id, so the view silently showed the whole feed under its old na
from sqlalchemy import select
from app.models import Channel
from app.catalog.models import Channel
from app.reader.models import ChannelTag, SavedView, Tag
from app.reader import service as reader_service
+2 -1
View File
@@ -12,7 +12,8 @@ import app.state as state
from app.auth import current_user
from app.db import get_db
from app.main import app
from app.models import Channel, Subscription, User, Video
from app.models import User
from app.catalog.models import Channel, Subscription, Video
from app.sync import runner, videos
_PUB = datetime(2020, 1, 1, tzinfo=timezone.utc)
@@ -10,7 +10,7 @@ from datetime import datetime, timedelta, timezone
import pytest
from app.models import Channel, Subscription
from app.catalog.models import Channel, Subscription
from app.routes import channels
from app.sync import subscriptions
from app.sync.subscriptions import DETAILS_MAX_AGE, import_subscriptions
@@ -14,7 +14,7 @@ from sqlalchemy import text
from sqlalchemy.dialects import postgresql
from app.feedquery import filtered_query
from app.models import Video
from app.catalog.models import Video
from app.routes.channels import channel_aggregates
INDEX = "ix_videos_channel_pub_cover"
@@ -9,7 +9,7 @@ import pytest
from fastapi import HTTPException
from sqlalchemy import select
from app.models import Channel, Subscription
from app.catalog.models import Channel, Subscription
from app.routes import channels
from app.youtube.client import YouTubeError
+2 -1
View File
@@ -14,7 +14,8 @@ import app.state as state
from app.auth import current_user
from app.db import get_db
from app.main import app
from app.models import Channel, User
from app.models import User
from app.catalog.models import Channel
from app.reader.models import ChannelTag, Tag
+2 -1
View File
@@ -18,7 +18,8 @@ from app.downloads import errors as dlerrors
from app.downloads import formats, pipeline, quota, runner, service
from app.downloads import probe as probemod
from app.downloads.edit import INPUT_GUARD
from app.models import Channel, PlexItem, PlexLibrary, PlexShow, Video
from app.models import PlexItem, PlexLibrary, PlexShow
from app.catalog.models import Channel, Video
from app.downloads.models import DownloadJob, MediaAsset
from app.plex import paths as plex_paths
+3 -2
View File
@@ -9,7 +9,8 @@ from app.auth import current_user
from app.collation import sorted_words
from app.db import get_db
from app.main import app
from app.models import Channel, PlexCollection, PlexItem, PlexLibrary, Subscription, User, Video
from app.models import PlexCollection, PlexItem, PlexLibrary, User
from app.catalog.models import Channel, Subscription, Video
from app.reader.models import Playlist, PlaylistItem
from datetime import datetime, timezone
@@ -222,7 +223,7 @@ def test_the_share_recipients_are_in_the_readers_alphabet(db, monkeypatch, overr
def test_the_blocked_channels_are_in_the_readers_alphabet(db, monkeypatch, override_dep):
from app.models import BlockedChannel
from app.catalog.models import BlockedChannel
user = _user(db, "hu")
db.add_all(Channel(id=f"UC{i}", title=w) for i, w in enumerate(WORDS))
+2 -11
View File
@@ -17,17 +17,8 @@ from app.discover import hero, pins, queries, rails
from app.discover.budget import BANDS, fits, remaining_seconds
from app.plex import rollup
from app.plex.cards import leaf_card
from app.models import (
BlockedChannel,
Channel,
PlexItem,
PlexLibrary,
PlexShow,
PlexState,
Subscription,
User,
Video,
)
from app.models import PlexItem, PlexLibrary, PlexShow, PlexState, User
from app.catalog.models import BlockedChannel, Channel, Subscription, Video
from app.reader.models import ComfortPin, Playlist, PlaylistItem, VideoState
NOW = datetime(2026, 6, 1, tzinfo=timezone.utc)
+2 -1
View File
@@ -12,7 +12,8 @@ contradicts the remote's own count is not believed either.
import pytest
from sqlalchemy import select
from app.models import Channel, PlexCollection, PlexItem, PlexLibrary, Video
from app.models import PlexCollection, PlexItem, PlexLibrary
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
from app.plex import sync as plex_sync
from app.sync import playlists as plsync
+1 -1
View File
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta, timezone
import pytest
from app import sysconfig
from app.models import Channel, Video
from app.catalog.models import Channel, Video
from app.sync import runner
from app.youtube.client import YouTubeError
+2 -1
View File
@@ -16,7 +16,8 @@ from datetime import datetime, timezone
import pytest
from app.models import Channel, Subscription, User, Video
from app.models import User
from app.catalog.models import Channel, Subscription, Video
# Every sort feedquery.sort_keys defines except "relevance" (which needs a search query to rank).
_SORTS = [
+2 -1
View File
@@ -12,7 +12,8 @@ from datetime import datetime, timezone
import pytest
from app import feedquery
from app.models import Channel, Subscription, User, Video
from app.models import User
from app.catalog.models import Channel, Subscription, Video
def _video(vid: str, day: int, title: str) -> Video:
+1 -1
View File
@@ -17,7 +17,7 @@ from sqlalchemy.dialects import postgresql
from app import collation
from app.db import engine
from app.feedquery import order_by, sort_keys
from app.models import Video
from app.catalog.models import Video
VIDEO_SORTS = [
"newest",
+1 -1
View File
@@ -14,7 +14,7 @@ import pytest
from app import feedquery
from app.models import Channel, Subscription, Video
from app.catalog.models import Channel, Subscription, Video
from app.reader.models import ChannelTag, Tag, VideoState
+1 -1
View File
@@ -7,7 +7,7 @@ by someone. The admin card counting "channels to sync" must use the same selecti
channels the backfill will never touch. DB lane.
"""
from app.models import Channel, ExploredChannel, Subscription
from app.catalog.models import Channel, ExploredChannel, Subscription
from app.sync import runner
+1 -1
View File
@@ -9,7 +9,7 @@ from datetime import datetime, timezone
from sqlalchemy import select
from app.models import Channel, Subscription, Video
from app.catalog.models import Channel, Subscription, Video
from app.routes.search import _fold_term
+2 -1
View File
@@ -12,7 +12,8 @@ from datetime import datetime, timedelta, timezone
import pytest
from sqlalchemy import select
from app.models import Channel, Notification, Video
from app.models import Notification
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
from app.sync import maintenance
+1 -1
View File
@@ -3,7 +3,7 @@ ones this user asked full history for. The numerator used to count every subscri
back-catalog was complete (another user had asked, or the channel was short), so the page read
"342/329". "Channels without full history yet" still counts every subscribed channel. Needs the DB."""
from app.models import Channel, Subscription
from app.catalog.models import Channel, Subscription
def test_full_history_ratio_counts_only_the_requested_channels(db, make_user, as_user):
+1 -1
View File
@@ -8,7 +8,7 @@ the position is an index over the ORDERED rows, and the list is renumbered aroun
from datetime import datetime, timezone
from app.models import Channel, Video
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
+1 -1
View File
@@ -10,7 +10,7 @@ from datetime import datetime, timezone
import pytest
from app.models import Channel, Video
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
from app.sync import playlists as pl_mod
from app.sync.playlist_merge import merge_plan
+1 -1
View File
@@ -16,7 +16,7 @@ from datetime import datetime, timedelta, timezone
import pytest
from sqlalchemy.exc import OperationalError
from app.models import Channel, Video
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
+2 -1
View File
@@ -19,7 +19,8 @@ from datetime import datetime, timezone
import pytest
from sqlalchemy import event
from app.models import Channel, PlexItem, PlexLibrary, PlexPlaylist, PlexPlaylistItem, Video
from app.models import PlexItem, PlexLibrary, PlexPlaylist, PlexPlaylistItem
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
@@ -18,7 +18,7 @@ import pytest
from sqlalchemy import delete, event, text
from app.db import SessionLocal
from app.models import Channel, Video
from app.catalog.models import Channel, Video
from app.reader.models import Playlist, PlaylistItem
from app.sync import playlists as pl_mod
+1 -1
View File
@@ -14,7 +14,7 @@ from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from app.discover import pins
from app.models import Channel, Video
from app.catalog.models import Channel, Video
from app.reader import queries, service
from app.reader.models import ChannelTag, ComfortPin, Playlist, PlaylistItem, Tag, VideoState
+2 -1
View File
@@ -13,7 +13,8 @@ import pytest
from sqlalchemy import select
from app import jobruns, logs, logsink, quota, scheduler, state, sysconfig
from app.models import AuditLog, Channel, JobRun, Notification, QuotaEvent
from app.models import AuditLog, JobRun, Notification, QuotaEvent
from app.catalog.models import Channel
from app.routes import scheduler as scheduler_routes
from app.runstatus import RunStatus, RunTrigger
+2 -1
View File
@@ -14,7 +14,8 @@ a placeholder never becomes the video's permanent date.
from datetime import datetime, timezone
from app import sysconfig
from app.models import User, Video
from app.models import User
from app.catalog.models import Video
from app.routes.search import _ingest_candidates
+2 -1
View File
@@ -11,7 +11,8 @@ network, pure DB state.
Uses the DB lane (`db` fixture) — skipped when no Postgres is reachable.
"""
from app.models import Channel, Subscription, User
from app.models import User
from app.catalog.models import Channel, Subscription
from app.reader.models import ChannelTag, Tag
from app.sync.tagsuggest import (
AUTOAPPLY_THRESHOLD,
+2 -1
View File
@@ -8,7 +8,8 @@ import httpx
import pytest
from app.auth import has_read_scope
from app.models import Channel, OAuthToken
from app.models import OAuthToken
from app.catalog.models import Channel
from app.sync.explore import explore_ingest_page
from app.sync.videos import backfill_channel_deep, backfill_channel_recent
from app.youtube import client as yt