diff --git a/api/video/youtube.py b/api/video/youtube.py
index 29b3509f..5155c09c 100644
--- a/api/video/youtube.py
+++ b/api/video/youtube.py
@@ -147,6 +147,12 @@ def register_routes(bp):
return jsonify({"success": False, "error": "Channel not found"}), 404
cid = channel["youtube_id"]
following = bool(db.channel_watch_state([cid]))
+ # backfill the real avatar onto wished rows (flat listing often omits it)
+ if channel.get("avatar_url"):
+ try:
+ db.set_wishlist_channel_poster(cid, channel["avatar_url"])
+ except Exception:
+ pass
wished = db.youtube_video_wish_state([v.get("youtube_id") for v in channel.get("videos") or []])
for v in channel.get("videos") or []:
v["wished"] = v.get("youtube_id") in wished
diff --git a/database/video_database.py b/database/video_database.py
index 3e95b2ce..2224cb53 100644
--- a/database/video_database.py
+++ b/database/video_database.py
@@ -1975,6 +1975,22 @@ class VideoDatabase:
finally:
conn.close()
+ def set_wishlist_channel_poster(self, channel_id, poster_url) -> int:
+ """Refresh the channel avatar on all of a channel's wished video rows — used
+ to backfill avatars that flat listing didn't surface (channel page resolves
+ the real avatar). Returns rows updated."""
+ if not poster_url or not channel_id:
+ return 0
+ conn = self._get_connection()
+ try:
+ cur = conn.execute(
+ "UPDATE video_wishlist SET poster_url=? WHERE kind='video' AND parent_source_id=?",
+ (poster_url, str(channel_id)))
+ conn.commit()
+ return cur.rowcount
+ finally:
+ conn.close()
+
def youtube_wishlist_counts(self) -> dict:
"""{'channel': n distinct channels, 'video': n videos} in the wishlist."""
conn = self._get_connection()
diff --git a/tests/test_video_database.py b/tests/test_video_database.py
index 12892e8b..82133d15 100644
--- a/tests/test_video_database.py
+++ b/tests/test_video_database.py
@@ -1144,3 +1144,16 @@ def test_upgrade_from_pre_source_schema(tmp_path):
assert db.add_videos_to_wishlist({"youtube_id": "UCx", "title": "Chan"},
[{"youtube_id": "x1", "title": "X1"}]) == 1
assert db.youtube_wishlist_counts() == {"channel": 1, "video": 1}
+
+
+def test_set_wishlist_channel_poster_backfills_avatar(db):
+ # videos added without an avatar (flat listing omitted it) → poster_url null
+ db.add_videos_to_wishlist({"youtube_id": "UCx", "title": "X"},
+ [{"youtube_id": "a", "title": "A", "published_at": "2024-01-01"},
+ {"youtube_id": "b", "title": "B", "published_at": "2024-02-01"}])
+ grp = db.query_youtube_wishlist()["items"][0]
+ assert not grp["poster_url"]
+ # backfilling the resolved avatar fills every row → the orb gets its poster
+ assert db.set_wishlist_channel_poster("UCx", "http://yt/avatar.jpg") == 2
+ grp = db.query_youtube_wishlist()["items"][0]
+ assert grp["poster_url"] == "http://yt/avatar.jpg"
diff --git a/webui/static/video/video-wishlist.js b/webui/static/video/video-wishlist.js
index dfcdcc44..89efad89 100644
--- a/webui/static/video/video-wishlist.js
+++ b/webui/static/video/video-wishlist.js
@@ -82,8 +82,11 @@
: 'data-vwsh-open-show data-vwsh-src="' + src + '" data-vwsh-id="' + esc(openId) + '"';
var hue = hueOf(sh.title);
var total = sh.wanted || 0;
- var img = sh.poster_url
- ? '' + esc(initials(sh.title)) + '\'">'
: '