From e8b1f765c81cc3a03e6b72de527051a83bc94e3f Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 20 Oct 2026 16:47:31 +0200 Subject: [PATCH] =?UTF-8?q?Secci=C3=B3n=20"Lo=20m=C3=A1s=20visto":=20v?= =?UTF-8?q?=C3=ADdeos=20y=20Shorts=20populares=20con=20contador=20de=20vis?= =?UTF-8?q?tas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01TSyR5Zw5eGj6oPTRVjvP1b --- build.py | 41 +++++++++++++++++++++++++++++++----- public/index.html | 53 +++++++++++++++++++++++++++++++++++++++++++++++ public/styles.css | 4 ++++ 3 files changed, 93 insertions(+), 5 deletions(-) diff --git a/build.py b/build.py index c515a40..17c5b3b 100644 --- a/build.py +++ b/build.py @@ -14,6 +14,10 @@ CHANNEL = 'UC8gVtzB3Lqm7nnfMhMvXGxQ' # YouTube separa cada tipo en su propia lista: UULF = solo vídeos, UUSH = solo Shorts FEED_VIDEOS = os.environ.get('FEED_VIDEOS_URL', f'https://www.youtube.com/feeds/videos.xml?playlist_id=UULF{CHANNEL[2:]}') FEED_SHORTS = os.environ.get('FEED_SHORTS_URL', f'https://www.youtube.com/feeds/videos.xml?playlist_id=UUSH{CHANNEL[2:]}') +FEED_POP_VIDEOS = os.environ.get('FEED_POP_VIDEOS_URL', f'https://www.youtube.com/feeds/videos.xml?playlist_id=UULP{CHANNEL[2:]}') +FEED_POP_SHORTS = os.environ.get('FEED_POP_SHORTS_URL', f'https://www.youtube.com/feeds/videos.xml?playlist_id=UUPS{CHANNEL[2:]}') +POP_VIDEOS_SHOWN = 4 +POP_SHORTS_SHOWN = 6 VIDEOS_SHOWN = 8 # además del destacado SHORTS_SHOWN = 12 NS = {'a': 'http://www.w3.org/2005/Atom', 'y': 'http://www.youtube.com/xml/schemas/2015', @@ -40,16 +44,22 @@ def read_feed(url): 'title': e.find('a:title', NS).text, 'date': f'{int(d[2])} {MESES[int(d[1]) - 1]} {d[0]}', 'desc': e.find('m:group/m:description', NS).text or '', + 'views': int((e.find('m:group/m:community/m:statistics', NS).attrib.get('views') or 0) + if e.find('m:group/m:community/m:statistics', NS) is not None else 0), }) return out try: videos, shorts = read_feed(FEED_VIDEOS), read_feed(FEED_SHORTS) + pop_videos, pop_shorts = read_feed(FEED_POP_VIDEOS), read_feed(FEED_POP_SHORTS) except Exception as exc: # sin red o feed caído: se conserva la web anterior print('feed no disponible, se mantiene index.html:', exc, file=sys.stderr) sys.exit(0) videos, shorts = videos[:VIDEOS_SHOWN + 1], shorts[:SHORTS_SHOWN] +# la lista de populares de YouTube no viene ordenada por vistas: se ordena aquí +pop_videos = sorted(pop_videos, key=lambda v: -v['views'])[:POP_VIDEOS_SHOWN] +pop_shorts = sorted(pop_shorts, key=lambda v: -v['views'])[:POP_SHORTS_SHOWN] def sync_thumbs(vids): @@ -73,10 +83,12 @@ def sync_thumbs(vids): return ok -ok = sync_thumbs(videos + shorts) +ok = sync_thumbs(videos + shorts + pop_videos + pop_shorts) okids = {v['id'] for v in ok} videos = [v for v in videos if v['id'] in okids] shorts = [v for v in shorts if v['id'] in okids] +pop_videos = [v for v in pop_videos if v['id'] in okids] +pop_shorts = [v for v in pop_shorts if v['id'] in okids] if not videos: sys.exit(0) @@ -128,24 +140,30 @@ def url(v): return f"https://www.youtube.com/watch?v={v['id']}" -def card(v, n): +def vistas(v): + return f"{v['views']:,}".replace(',', '.') + ' vistas' if v['views'] else '' + + +def card(v, n, show_views=False): return f''' - {esc(v['title'])} + {esc(v['title'])} ''' -def short_card(v, n): +def short_card(v, n, show_views=False): return f''' - {esc(v['title'])} + {esc(v['title'])}{'' if show_views and v['views'] else ''} ''' cards = ''.join(card(v, i) for i, v in enumerate(rest)) scards = ''.join(short_card(v, i) for i, v in enumerate(shorts)) +pcards = ''.join(card(v, i, True) for i, v in enumerate(pop_videos)) +pscards = ''.join(short_card(v, i, True) for i, v in enumerate(pop_shorts)) page = f''' @@ -223,6 +241,19 @@ page = f''' +
+
+

Lo más visto

+ Ver populares en YouTube → +
+

Vídeos

+
{pcards} +
+

Shorts

+
{pscards} +
+
+

De qué va

Un programa de noche, con tertulia y sin prisa. Cada semana entra gente distinta, con su oficio y su manía, y se habla de lo que sale: de cómo se educa a un adolescente, de la vida en las calles de El Cairo, de si el árabe es tan antiguo como dicen, de qué tienen en común las religiones o de cómo se hace un truco de cartas.

diff --git a/public/index.html b/public/index.html index 3783565..08563df 100644 --- a/public/index.html +++ b/public/index.html @@ -154,6 +154,59 @@
+
+
+

Lo más visto

+ Ver populares en YouTube → +
+

Vídeos

+ +

Shorts

+ +
+

De qué va

Un programa de noche, con tertulia y sin prisa. Cada semana entra gente distinta, con su oficio y su manía, y se habla de lo que sale: de cómo se educa a un adolescente, de la vida en las calles de El Cairo, de si el árabe es tan antiguo como dicen, de qué tienen en común las religiones o de cómo se hace un truco de cartas.

diff --git a/public/styles.css b/public/styles.css index 24679bb..cd8442a 100644 --- a/public/styles.css +++ b/public/styles.css @@ -222,3 +222,7 @@ footer { margin-top: 40px; border-top: 1px solid var(--line); background: var(-- .scard:hover img { transform: scale(1.06); } .scard:hover .play { opacity: 1; } .scard .play::after { width: 44px; height: 44px; } + +/* lo más visto */ +.sub { margin: 26px 0 14px; font-size: .8rem; letter-spacing: .22em; text-transform: uppercase; color: var(--amber); font-weight: 700; } +.scard .meta time { color: var(--muted); font-size: .8rem; }