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.
64 lines
2.5 KiB
Python
64 lines
2.5 KiB
Python
"""The scheduled RSS poll and recent backfill cover FOLLOWED channels only (owner decision, 2026-09-17).
|
|
|
|
A channel row also comes from a search result, a playlist item or a subscription somebody dropped,
|
|
and nothing deletes those rows. Polling all of them was 582 of 979 channels on prod with no follower,
|
|
three of them dead feeds answering 404 every 20 minutes. Followed = subscribed by someone, or explored
|
|
by someone. The admin card counting "channels to sync" must use the same selection, or it counts
|
|
channels the backfill will never touch. DB lane.
|
|
"""
|
|
|
|
from app.catalog.models import Channel, ExploredChannel, Subscription
|
|
from app.sync import runner
|
|
|
|
|
|
def _channels(db, make_user):
|
|
user = make_user()
|
|
for cid in ("UC_sub", "UC_explored", "UC_search", "UC_playlist"):
|
|
db.add(Channel(id=cid, title=cid, from_search=cid == "UC_search"))
|
|
db.flush()
|
|
db.add(Subscription(user_id=user.id, channel_id="UC_sub"))
|
|
db.add(ExploredChannel(user_id=user.id, channel_id="UC_explored"))
|
|
db.commit()
|
|
return user
|
|
|
|
|
|
def test_the_rss_poll_skips_channels_nobody_follows(db, make_user, monkeypatch):
|
|
_channels(db, make_user)
|
|
polled: list[str] = []
|
|
monkeypatch.setattr(runner, "fetch_channel_feed", lambda cid: polled.append(cid) or [])
|
|
monkeypatch.setattr(runner, "apply_rss_feed", lambda db, ch, entries: 0)
|
|
assert runner.run_rss_poll(db) == {"new": 0, "failed": 0, "fallback": 0}
|
|
assert sorted(polled) == ["UC_explored", "UC_sub"]
|
|
|
|
|
|
def test_the_recent_backfill_skips_channels_nobody_follows(db, make_user, monkeypatch):
|
|
user = _channels(db, make_user)
|
|
done: list[str] = []
|
|
|
|
class _Client:
|
|
def __init__(self, *a):
|
|
pass
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *a):
|
|
return False
|
|
|
|
monkeypatch.setattr(runner, "get_service_user", lambda db: user)
|
|
monkeypatch.setattr(runner, "YouTubeClient", _Client)
|
|
monkeypatch.setattr(runner.quota, "backfill_reserve_reached", lambda: False)
|
|
monkeypatch.setattr(
|
|
runner, "backfill_channel_recent", lambda db, yt, ch: done.append(ch.id) or 0
|
|
)
|
|
monkeypatch.setattr(runner, "reconcile_full_history", lambda db: 0)
|
|
runner.run_recent_backfill(db)
|
|
assert sorted(done) == ["UC_explored", "UC_sub"]
|
|
|
|
|
|
def test_the_dashboard_counts_the_channels_the_backfill_will_process(db, make_user, as_user):
|
|
_channels(db, make_user)
|
|
admin = make_user(role="admin")
|
|
queue = as_user(admin).get("/api/admin/scheduler").json()["queue"]
|
|
assert queue["channels_recent_pending"] == 2
|