Search avatars: proxy with a UA + graceful initials fallback
Screenshot showed channel results with empty circles, not the initials chip — i.e. an avatar URL was present but the image was failing to load. Two causes addressed: - The image proxy fetched googleusercontent/yt3 with NO User-Agent, which the CDN 403s for some avatars → blank. Now sends a browser UA + Accept header. - A failed avatar now swaps to the initials chip (onerror → outerHTML) instead of hiding the img and leaving an empty circle. Also proxy protocol-relative + deeper-subdomain YouTube image hosts. img-proxy tests green.
This commit is contained in:
parent
0ff0d07c22
commit
3d67f51c29
2 changed files with 14 additions and 5 deletions
|
|
@ -133,7 +133,13 @@ def register_routes(bp):
|
|||
abort(404)
|
||||
try:
|
||||
import requests
|
||||
upstream = requests.get(url, timeout=15, stream=True)
|
||||
# A browser UA — Google's image CDN (yt3/googleusercontent) 403s some
|
||||
# avatars when fetched with no User-Agent, which blanked search results.
|
||||
upstream = requests.get(url, timeout=15, stream=True, headers={
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
"Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
|
||||
})
|
||||
if upstream.status_code != 200:
|
||||
abort(404)
|
||||
resp = Response(upstream.iter_content(8192),
|
||||
|
|
|
|||
|
|
@ -37,18 +37,21 @@
|
|||
// policy can't blank them out. Non-YouTube / already-proxied urls pass through.
|
||||
function img(url) {
|
||||
if (!url) return url;
|
||||
if (/^https:\/\/([\w-]+\.)?(ytimg\.com|ggpht\.com|googleusercontent\.com)\//i.test(url))
|
||||
if (url.indexOf('//') === 0) url = 'https:' + url; // protocol-relative
|
||||
if (/^https:\/\/([\w-]+\.)*(ytimg\.com|ggpht\.com|googleusercontent\.com)\//i.test(url))
|
||||
return '/api/video/img?u=' + encodeURIComponent(url);
|
||||
return url;
|
||||
}
|
||||
|
||||
function avatar(ch, cls) {
|
||||
var url = ch && (ch.poster_url || ch.avatar_url);
|
||||
var ini = esc(initials(ch && ch.title));
|
||||
if (url) {
|
||||
return '<img class="' + cls + '" src="' + esc(img(url)) +
|
||||
'" alt="" loading="lazy" onerror="this.style.display=\'none\'">';
|
||||
// If the image can't load, swap to the initials chip (never an empty circle).
|
||||
return '<img class="' + cls + '" src="' + esc(img(url)) + '" alt="" loading="lazy" ' +
|
||||
'onerror="this.outerHTML=\'<span class="' + cls + ' vyt-avatar--ph">' + ini + '</span>\'">';
|
||||
}
|
||||
return '<span class="' + cls + ' vyt-avatar--ph">' + esc(initials(ch && ch.title)) + '</span>';
|
||||
return '<span class="' + cls + ' vyt-avatar--ph">' + ini + '</span>';
|
||||
}
|
||||
|
||||
// A single wished video tile (thumbnail, title, date, remove).
|
||||
|
|
|
|||
Loading…
Reference in a new issue