"""Startup: patches app.py to add 24h news shorts (9:16 vertical) carousel, then runs it.""" import os, sys APP_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app.py") def patch(): with open(APP_PATH, "r", encoding="utf-8") as f: code = f.read() if "vslide-shorts-item" in code: return # Already fully patched # 1. Add import if "from shorts_scraper import scrape_24h_news_shorts" not in code: code = code.replace( "from concurrent.futures import ThreadPoolExecutor, as_completed", "from concurrent.futures import ThreadPoolExecutor, as_completed\nfrom shorts_scraper import scrape_24h_news_shorts", 1 ) # 2. Add shorts fetch to fetch_homepage if "h24_shorts" not in code: code = code.replace(" h24_videos=[]", " h24_videos=[]\n h24_shorts=[]", 1) # Add _fetch_shorts function old_fetch24h = " def _fetch_24h():\n nonlocal h24_videos\n try: h24_videos=scrape_24h_video_list()[:15]\n except: pass" new_fetch24h = old_fetch24h + "\n def _fetch_shorts():\n nonlocal h24_shorts\n try: h24_shorts=scrape_24h_news_shorts()[:15]\n except: pass" code = code.replace(old_fetch24h, new_fetch24h, 1) # Submit _fetch_shorts code = code.replace(" ex.submit(_fetch_24h)\n futures=", " ex.submit(_fetch_24h)\n ex.submit(_fetch_shorts)\n futures=", 1) # Return shorts code = code.replace(" return all_articles, h24_videos", " return all_articles, h24_videos, h24_shorts", 1) # 3. Update fetch_news_list unpacking if "h24_shorts = fetch_homepage" not in code: code = code.replace( " articles, h24_videos = fetch_homepage()\n return render_homepage_html(articles, h24_videos)", " articles, h24_videos, h24_shorts = fetch_homepage()\n return render_homepage_html(articles, h24_videos, h24_shorts)", 1 ) # 4. Add render_shorts_carousel_html if "render_shorts_carousel_html" not in code: fn = [ 'def render_shorts_carousel_html(shorts):', ' """9:16 vertical shorts carousel from 24h video-tin-tuc."""', ' vids = [v for v in shorts if v.get("img")]', ' if not vids: return ""', ' items = []', ' for v in vids[:15]:', ' img = safe_url(v.get("img",""))', ' link = v.get("link","#")', ' title = v.get("title","")', ' aid = make_id(link)', " cjs = \"window.bdpOpenTikTok('\"+esc(link)+\"','\"+aid+\"')\"", ' items.append(\'
\')', ' h = \'\'', ' return h', '', ] fn_code = '\n'.join(fn) + '\n' code = code.replace( "def render_video_carousel_html(videos):", fn_code + "def render_video_carousel_html(videos):", 1 ) # 5. Update render_homepage_html if "h24_shorts=None" not in code: code = code.replace( "def render_homepage_html(articles, h24_videos=None):", "def render_homepage_html(articles, h24_videos=None, h24_shorts=None):", 1 ) if "shorts_carousel" not in code: code = code.replace( " video_carousel = render_video_carousel_html(h24_videos or [])", " shorts_carousel = render_shorts_carousel_html(h24_shorts or [])\n video_carousel = render_video_carousel_html(h24_videos or [])", 1 ) code = code.replace( "{video_carousel}{news_carousel}", "{shorts_carousel}{video_carousel}{news_carousel}", 1 ) # 6. Add CSS for 9:16 shorts if "vslide-shorts-item" not in code: shorts_css = ( '\n/* Shorts 9:16 Slider */\n' '.vslide-shorts-item{flex:0 0 110px;scroll-snap-align:start;cursor:pointer;transition:transform .15s}\n' '.vslide-shorts-item:hover{transform:scale(1.04)}\n' '@media(min-width:768px){.vslide-shorts-item{flex:0 0 130px}}\n' '.vslide-shorts-thumb{position:relative;width:100%;aspect-ratio:9/16;border-radius:12px;overflow:hidden;background:#222}\n' '.vslide-shorts-thumb img{width:100%;height:100%;object-fit:cover}\n' '.vslide-shorts-title{color:#ccc;font-size:10.5px;margin:5px 0 0;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n' ) code = code.replace( ".vslide-badge-24h{background:#e67e22;color:#fff}", ".vslide-badge-24h{background:#e67e22;color:#fff}" + shorts_css, 1 ) with open(APP_PATH, "w", encoding="utf-8") as f: f.write(code) print("[startup.py] Patched app.py with 9:16 shorts carousel") # Run patch then execute app patch() # Execute patched app.py with open(APP_PATH, encoding="utf-8") as f: exec(compile(f.read(), APP_PATH, "exec"), {"__name__": "__main__", "__file__": APP_PATH})