bep40 commited on
Commit
8a3fcaa
·
verified ·
1 Parent(s): ffe8cdb

Add all VNE categories + VnExpress video + DanTri tin nong slide

Browse files
Files changed (1) hide show
  1. main.py +70 -3
main.py CHANGED
@@ -24,6 +24,66 @@ def _cached(key, fn):
24
  def _get(url,headers=None):
25
  h=headers or HEADERS;r=requests.get(url,headers=h,timeout=15);r.encoding="utf-8"
26
  return BeautifulSoup(r.text,"lxml")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def scrape_vne(cat_url):
28
  try:
29
  soup=_get(cat_url);arts=[]
@@ -195,7 +255,10 @@ def extract_bdp_video(url):
195
  source=video.find("source")
196
  return{"src":source.get("src","") if source else "","poster":video.get("poster","")}
197
  except:return None
198
- VNE_CATS={"thoi-su":("https://vnexpress.net/thoi-su","Thời Sự"),"the-gioi":("https://vnexpress.net/the-gioi","Thế Giới"),"kinh-doanh":("https://vnexpress.net/kinh-doanh","Kinh Doanh"),"cong-nghe":("https://vnexpress.net/so-hoa","Công Nghệ"),"the-thao":("https://vnexpress.net/the-thao","Thể Thao"),"giai-tri":("https://vnexpress.net/giai-tri","Giải Trí"),"suc-khoe":("https://vnexpress.net/suc-khoe","Sức Khỏe")}
 
 
 
199
  @app.get("/api/homepage")
200
  def api_homepage():
201
  def _f():
@@ -225,6 +288,10 @@ def api_categories():
225
  def api_highlights():return JSONResponse(_cached("highlights",scrape_24h_highlights))
226
  @app.get("/api/shorts")
227
  def api_shorts():return JSONResponse(_cached("shorts",scrape_24h_shorts))
 
 
 
 
228
  @app.get("/api/bdp_videos")
229
  def api_bdp_videos():return JSONResponse(_cached("bdp_videos",scrape_bdp_videos))
230
  @app.get("/api/video_url")
@@ -244,13 +311,13 @@ async def video_share(url:str=Query(default=""),title:str=Query(default="VNEWS V
244
  og_image=unquote(img) if img else "https://s1.vnecdn.net/vnexpress/restruct/i/v9505/logo_default.jpg"
245
  decoded_url=unquote(url);decoded_title=unquote(title)
246
  redirect_script=f'<script>localStorage.setItem("pending_video",JSON.stringify({{"url":"{decoded_url}","type":"{type}"}}));location.href="{SPACE_URL}";</script>' if decoded_url else f'<script>location.href="{SPACE_URL}";</script>'
247
- return HTMLResponse(f'''<!DOCTYPE html><html><head><meta charset="utf-8"><title>{decoded_title} - VNEWS</title><meta property="og:title" content="{decoded_title}"><meta property="og:image" content="{og_image}"><meta property="og:type" content="video.other"><meta property="og:site_name" content="VNEWS"><meta property="og:description" content="🎬 {decoded_title} - Xem trên VNEWS"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="{decoded_title}"><meta name="twitter:image" content="{og_image}"></head><body style="background:#111;color:#fff;font-family:sans-serif;text-align:center;padding:40px"><p>⏳ Đang mở video...</p>{redirect_script}</body></html>''')
248
  @app.get("/s")
249
  async def share_redirect(url:str=Query(default=""),title:str=Query(default="VNEWS"),img:str=Query(default="")):
250
  og_image=unquote(img) if img else "https://s1.vnecdn.net/vnexpress/restruct/i/v9505/logo_default.jpg"
251
  decoded_url=unquote(url)
252
  redirect_script=f'<script>localStorage.setItem("pending_article","{decoded_url}");location.href="{SPACE_URL}";</script>' if decoded_url else f'<script>location.href="{SPACE_URL}";</script>'
253
- return HTMLResponse(f'''<!DOCTYPE html><html><head><meta charset="utf-8"><title>{unquote(title)}</title><meta property="og:title" content="{unquote(title)}"><meta property="og:image" content="{og_image}"><meta property="og:url" content="{SPACE_URL}/s?url={url}&title={title}&img={img}"><meta property="og:type" content="article"><meta property="og:site_name" content="VNEWS"><meta property="og:description" content="{unquote(title)} - Đọc trên VNEWS"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="{unquote(title)}"><meta name="twitter:image" content="{og_image}"></head><body>{redirect_script}</body></html>''')
254
  @app.get("/")
255
  async def index():
256
  with open("/app/static/index.html","r",encoding="utf-8") as f:return HTMLResponse(content=f.read())
 
24
  def _get(url,headers=None):
25
  h=headers or HEADERS;r=requests.get(url,headers=h,timeout=15);r.encoding="utf-8"
26
  return BeautifulSoup(r.text,"lxml")
27
+
28
+ # ===== DANTRI TIN NONG =====
29
+ def scrape_dantri_hot():
30
+ """Scrape tin nóng from dantri.com.vn"""
31
+ try:
32
+ soup=_get("https://dantri.com.vn/tin-nong.htm")
33
+ arts=[];seen=set()
34
+ for a in soup.find_all("a",href=True):
35
+ href=a.get("href","");title=a.get("title","") or a.get_text(strip=True)
36
+ if not title or len(title)<15 or"javascript:" in href:continue
37
+ if not href.startswith("http"):href="https://dantri.com.vn"+href
38
+ if href in seen or not href.endswith(".htm"):continue
39
+ if href=="https://dantri.com.vn/tin-nong.htm":continue
40
+ seen.add(href)
41
+ img=a.find("img")
42
+ if not img and a.parent:img=a.parent.find("img")
43
+ img_src=""
44
+ if img:img_src=img.get("data-src") or img.get("src","")
45
+ if img_src and("base64" in img_src or len(img_src)<10):img_src=""
46
+ arts.append({"title":title,"link":href,"img":img_src,"source":"dantri"})
47
+ if len(arts)>=15:break
48
+ # OG images for missing
49
+ def _og(art):
50
+ if art["img"]:return
51
+ try:
52
+ r2=requests.get(art["link"],headers=HEADERS,timeout=8);r2.encoding="utf-8"
53
+ og=BeautifulSoup(r2.text,"lxml").find("meta",property="og:image")
54
+ art["img"]=og.get("content","") if og else ""
55
+ except:pass
56
+ need=[a for a in arts if not a["img"]][:5]
57
+ if need:
58
+ with ThreadPoolExecutor(3) as ex:list(ex.map(_og,need))
59
+ return arts[:12]
60
+ except:return[]
61
+
62
+ # ===== VNEXPRESS VIDEO (VnEgo) =====
63
+ def scrape_vne_video():
64
+ """Scrape VnExpress video section."""
65
+ try:
66
+ soup=_get("https://vnexpress.net/video")
67
+ arts=[];seen=set()
68
+ for a in soup.find_all("a",href=True):
69
+ href=a.get("href","");title=a.get("title","") or a.get_text(strip=True)
70
+ if not title or len(title)<10 or"javascript:" in href:continue
71
+ if"/video/" not in href:continue
72
+ if href in seen:continue
73
+ seen.add(href)
74
+ img=a.find("img")
75
+ if not img and a.parent:img=a.parent.find("img")
76
+ img_src=""
77
+ if img:img_src=img.get("data-src") or img.get("src","")
78
+ if img_src and("blank" in img_src or"base64" in img_src):
79
+ source=a.find("source") or (a.parent.find("source") if a.parent else None)
80
+ if source:img_src=source.get("srcset","").split(",")[0].strip().split(" ")[0]
81
+ if not img_src or len(img_src)<10:img_src=""
82
+ arts.append({"title":title,"link":href,"img":img_src,"source":"vne-video"})
83
+ if len(arts)>=15:break
84
+ return arts[:12]
85
+ except:return[]
86
+
87
  def scrape_vne(cat_url):
88
  try:
89
  soup=_get(cat_url);arts=[]
 
255
  source=video.find("source")
256
  return{"src":source.get("src","") if source else "","poster":video.get("poster","")}
257
  except:return None
258
+
259
+ # All VnExpress categories
260
+ VNE_CATS={"thoi-su":("https://vnexpress.net/thoi-su","Thời Sự"),"the-gioi":("https://vnexpress.net/the-gioi","Thế Giới"),"kinh-doanh":("https://vnexpress.net/kinh-doanh","Kinh Doanh"),"cong-nghe":("https://vnexpress.net/so-hoa","Công Nghệ"),"the-thao":("https://vnexpress.net/the-thao","Thể Thao"),"giai-tri":("https://vnexpress.net/giai-tri","Giải Trí"),"suc-khoe":("https://vnexpress.net/suc-khoe","Sức Khỏe"),"giao-duc":("https://vnexpress.net/giao-duc","Giáo Dục"),"phap-luat":("https://vnexpress.net/phap-luat","Pháp Luật"),"du-lich":("https://vnexpress.net/du-lich","Du Lịch"),"xe":("https://vnexpress.net/oto-xe-may","Xe"),"doi-song":("https://vnexpress.net/doi-song","Đời Sống")}
261
+
262
  @app.get("/api/homepage")
263
  def api_homepage():
264
  def _f():
 
288
  def api_highlights():return JSONResponse(_cached("highlights",scrape_24h_highlights))
289
  @app.get("/api/shorts")
290
  def api_shorts():return JSONResponse(_cached("shorts",scrape_24h_shorts))
291
+ @app.get("/api/vne_video")
292
+ def api_vne_video():return JSONResponse(_cached("vne_video",scrape_vne_video))
293
+ @app.get("/api/dantri_hot")
294
+ def api_dantri_hot():return JSONResponse(_cached("dantri_hot",scrape_dantri_hot))
295
  @app.get("/api/bdp_videos")
296
  def api_bdp_videos():return JSONResponse(_cached("bdp_videos",scrape_bdp_videos))
297
  @app.get("/api/video_url")
 
311
  og_image=unquote(img) if img else "https://s1.vnecdn.net/vnexpress/restruct/i/v9505/logo_default.jpg"
312
  decoded_url=unquote(url);decoded_title=unquote(title)
313
  redirect_script=f'<script>localStorage.setItem("pending_video",JSON.stringify({{"url":"{decoded_url}","type":"{type}"}}));location.href="{SPACE_URL}";</script>' if decoded_url else f'<script>location.href="{SPACE_URL}";</script>'
314
+ return HTMLResponse(f'''<!DOCTYPE html><html><head><meta charset="utf-8"><title>{decoded_title} - VNEWS</title><meta property="og:title" content="{decoded_title}"><meta property="og:image" content="{og_image}"><meta property="og:type" content="video.other"><meta property="og:site_name" content="VNEWS"></head><body style="background:#111;color:#fff;text-align:center;padding:40px"><p>⏳ Đang mở video...</p>{redirect_script}</body></html>''')
315
  @app.get("/s")
316
  async def share_redirect(url:str=Query(default=""),title:str=Query(default="VNEWS"),img:str=Query(default="")):
317
  og_image=unquote(img) if img else "https://s1.vnecdn.net/vnexpress/restruct/i/v9505/logo_default.jpg"
318
  decoded_url=unquote(url)
319
  redirect_script=f'<script>localStorage.setItem("pending_article","{decoded_url}");location.href="{SPACE_URL}";</script>' if decoded_url else f'<script>location.href="{SPACE_URL}";</script>'
320
+ return HTMLResponse(f'''<!DOCTYPE html><html><head><meta charset="utf-8"><title>{unquote(title)}</title><meta property="og:title" content="{unquote(title)}"><meta property="og:image" content="{og_image}"><meta property="og:type" content="article"><meta property="og:site_name" content="VNEWS"></head><body>{redirect_script}</body></html>''')
321
  @app.get("/")
322
  async def index():
323
  with open("/app/static/index.html","r",encoding="utf-8") as f:return HTMLResponse(content=f.read())