Popular tab now shows only flagged popular videos in rank order
Add channel_popular_videos table (channel_id, video_id, rank).
_fetch_popular_task clears and rewrites this table after each fetch.
GET /channels/{id}/videos?sort=popular now JOINs this table and orders
by rank instead of view_count, so the tab shows exactly the videos
YouTube returned in popularity order — nothing more.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -87,6 +87,14 @@ def on_startup():
|
|||||||
crawled_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
crawled_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)""",
|
)""",
|
||||||
"ALTER TABLE playlists ADD COLUMN video_ids TEXT",
|
"ALTER TABLE playlists ADD COLUMN video_ids TEXT",
|
||||||
|
"""CREATE TABLE IF NOT EXISTS channel_popular_videos (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
channel_id INTEGER NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
||||||
|
video_id INTEGER NOT NULL REFERENCES videos(id) ON DELETE CASCADE,
|
||||||
|
rank INTEGER NOT NULL,
|
||||||
|
fetched_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(channel_id, video_id)
|
||||||
|
)""",
|
||||||
"""CREATE TABLE IF NOT EXISTS search_history (
|
"""CREATE TABLE IF NOT EXISTS search_history (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
|||||||
@@ -612,18 +612,35 @@ def get_channel_videos(
|
|||||||
current_user: User = Depends(get_current_user),
|
current_user: User = Depends(get_current_user),
|
||||||
):
|
):
|
||||||
_get_channel_or_404(db, channel_id)
|
_get_channel_or_404(db, channel_id)
|
||||||
order = {
|
|
||||||
"newest": "v.published_at DESC NULLS LAST",
|
|
||||||
"oldest": "v.published_at ASC NULLS LAST",
|
|
||||||
"title": "v.title ASC",
|
|
||||||
"unwatched":"COALESCE(uv.watched, 0) ASC, v.published_at DESC NULLS LAST",
|
|
||||||
"popular": "v.view_count DESC NULLS LAST",
|
|
||||||
}.get(sort, "v.published_at DESC NULLS LAST")
|
|
||||||
params: dict = {"user_id": current_user.id, "channel_id": channel_id, "limit": limit, "offset": offset}
|
params: dict = {"user_id": current_user.id, "channel_id": channel_id, "limit": limit, "offset": offset}
|
||||||
q_clause = ""
|
q_clause = ""
|
||||||
if q.strip():
|
if q.strip():
|
||||||
q_clause = "AND (v.title LIKE :q OR v.description LIKE :q)"
|
q_clause = "AND (v.title LIKE :q OR v.description LIKE :q)"
|
||||||
params["q"] = f"%{q.strip()}%"
|
params["q"] = f"%{q.strip()}%"
|
||||||
|
|
||||||
|
if sort == "popular":
|
||||||
|
rows = db.execute(
|
||||||
|
text(f"""
|
||||||
|
SELECT v.id, v.youtube_video_id, v.title, v.thumbnail_url,
|
||||||
|
v.duration_seconds, v.published_at, v.view_count,
|
||||||
|
COALESCE(uv.downloaded, 0) AS is_downloaded,
|
||||||
|
COALESCE(uv.watched, 0) AS is_watched
|
||||||
|
FROM channel_popular_videos cpv
|
||||||
|
JOIN videos v ON cpv.video_id = v.id
|
||||||
|
LEFT JOIN user_videos uv ON v.id = uv.video_id AND uv.user_id = :user_id
|
||||||
|
WHERE cpv.channel_id = :channel_id {q_clause}
|
||||||
|
ORDER BY cpv.rank ASC
|
||||||
|
LIMIT :limit OFFSET :offset
|
||||||
|
"""),
|
||||||
|
params,
|
||||||
|
).mappings().all()
|
||||||
|
else:
|
||||||
|
order = {
|
||||||
|
"newest": "v.published_at DESC NULLS LAST",
|
||||||
|
"oldest": "v.published_at ASC NULLS LAST",
|
||||||
|
"title": "v.title ASC",
|
||||||
|
"unwatched":"COALESCE(uv.watched, 0) ASC, v.published_at DESC NULLS LAST",
|
||||||
|
}.get(sort, "v.published_at DESC NULLS LAST")
|
||||||
rows = db.execute(
|
rows = db.execute(
|
||||||
text(f"""
|
text(f"""
|
||||||
SELECT v.id, v.youtube_video_id, v.title, v.thumbnail_url,
|
SELECT v.id, v.youtube_video_id, v.title, v.thumbnail_url,
|
||||||
@@ -705,7 +722,12 @@ def _fetch_popular_task(channel_id: int, youtube_channel_id: str):
|
|||||||
channel = db.query(Channel).filter_by(id=channel_id).first()
|
channel = db.query(Channel).filter_by(id=channel_id).first()
|
||||||
if not channel:
|
if not channel:
|
||||||
return
|
return
|
||||||
for yt_id in video_ids:
|
|
||||||
|
# Clear previous popular list for this channel
|
||||||
|
db.execute(text("DELETE FROM channel_popular_videos WHERE channel_id = :cid"), {"cid": channel_id})
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
for rank, yt_id in enumerate(video_ids, start=1):
|
||||||
meta = results.get(yt_id)
|
meta = results.get(yt_id)
|
||||||
if not meta:
|
if not meta:
|
||||||
continue
|
continue
|
||||||
@@ -716,8 +738,9 @@ def _fetch_popular_task(channel_id: int, youtube_channel_id: str):
|
|||||||
existing.view_count = meta["view_count"]
|
existing.view_count = meta["view_count"]
|
||||||
if meta.get("published_at") and not existing.published_at:
|
if meta.get("published_at") and not existing.published_at:
|
||||||
existing.published_at = meta["published_at"]
|
existing.published_at = meta["published_at"]
|
||||||
|
video_id = existing.id
|
||||||
else:
|
else:
|
||||||
db.add(Video(
|
v = Video(
|
||||||
youtube_video_id=yt_id,
|
youtube_video_id=yt_id,
|
||||||
channel_id=channel.id,
|
channel_id=channel.id,
|
||||||
title=meta.get("title", ""),
|
title=meta.get("title", ""),
|
||||||
@@ -726,7 +749,18 @@ def _fetch_popular_task(channel_id: int, youtube_channel_id: str):
|
|||||||
published_at=meta.get("published_at"),
|
published_at=meta.get("published_at"),
|
||||||
tags=meta.get("tags") or "[]",
|
tags=meta.get("tags") or "[]",
|
||||||
view_count=meta.get("view_count"),
|
view_count=meta.get("view_count"),
|
||||||
))
|
)
|
||||||
|
db.add(v)
|
||||||
|
db.flush()
|
||||||
|
video_id = v.id
|
||||||
|
db.execute(
|
||||||
|
text("""
|
||||||
|
INSERT INTO channel_popular_videos (channel_id, video_id, rank)
|
||||||
|
VALUES (:cid, :vid, :rank)
|
||||||
|
ON CONFLICT(channel_id, video_id) DO UPDATE SET rank = :rank
|
||||||
|
"""),
|
||||||
|
{"cid": channel_id, "vid": video_id, "rank": rank},
|
||||||
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
except Exception:
|
except Exception:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
|
|||||||
Reference in New Issue
Block a user