bep40 commited on
Commit
215fbb2
Β·
verified Β·
1 Parent(s): 90206e8

fix: simpler JS scroll for video cards - no escape issues

Browse files
Files changed (1) hide show
  1. app_wrapper.py +7 -15
app_wrapper.py CHANGED
@@ -4,16 +4,13 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
4
  from shorts_carousel import scrape_24h_news_shorts, render_shorts_carousel, SHORTS_CSS, _extract_24h_video_url
5
  import app
6
 
7
- # ══ Disable auto-refresh timer ══
8
  app.REFRESH_SECONDS = 9999
9
 
10
- # ══ CSS ══
11
  SHORTS_EXTRA_CSS = """
12
  .shorts-feed-mode .tiktok-video{object-fit:cover!important}
13
  .tiktok-fullscreen-container{width:100%!important;max-width:100%!important;border-radius:0!important;height:80vh!important;max-height:680px!important;min-height:400px!important}
14
  .tiktok-fullscreen-feed{height:100%!important}
15
  .tiktok-slide{height:80vh!important;max-height:680px!important;min-height:400px!important}
16
- /* Highlight video default 1:1 (square crop center) */
17
  .tiktok-fullscreen-container:not(.shorts-feed-mode) .tiktok-video{object-fit:cover!important}
18
  .tiktok-fullscreen-container.contain-mode .tiktok-video{object-fit:contain!important}
19
  .tiktok-fullheight-btn{position:absolute;bottom:70px;right:12px;background:rgba(255,255,255,.15);color:#fff;border:none;padding:6px 12px;border-radius:16px;font-size:11px;cursor:pointer;z-index:8;backdrop-filter:blur(6px)}
@@ -33,7 +30,6 @@ if "vslide-shorts-item" not in app.CSS: app.CSS += SHORTS_CSS
33
  if "shorts-feed-mode" not in app.CSS: app.CSS += SHORTS_EXTRA_CSS
34
  if "FULLWIDTH" not in app.CSS: app.CSS += FULLWIDTH_CSS
35
 
36
- # ══ Patches ══
37
  def _fixed_extract(url):
38
  vid=_extract_24h_video_url(url)
39
  if not vid:return []
@@ -63,7 +59,6 @@ app.render_homepage_html=_php
63
  _orig_vp=app.render_video_page_html
64
  def _pvp():
65
  html=_orig_vp()
66
- # Add contain toggle button (default is 1:1 cover, button switches to contain)
67
  btn='<button class="tiktok-fullheight-btn" onclick="event.stopPropagation();var c=this.closest(\'.tiktok-fullscreen-container\');c.classList.toggle(\'contain-mode\');var on=c.classList.contains(\'contain-mode\');c.querySelectorAll(\'.tiktok-fullheight-btn\').forEach(function(b){b.classList.toggle(\'active\',on);b.textContent=on?\'\\u2922 1:1\':\'\\u2B07 Contain\';});">\u2B07 Contain</button>'
68
  return html.replace('<div class="tiktok-unmute-hint"',btn+'<div class="tiktok-unmute-hint"')
69
  app.render_video_page_html=_pvp
@@ -84,9 +79,7 @@ def _pra(url):
84
  return [{"title":a["title"]+(f" (P{i+1})" if len(ps)>1 else ""),"link":a["link"],"img":a.get("img",""),"src":p,"poster":v["poster"],"vtype":"hls"} for i,p in enumerate(ps)]
85
  with ThreadPoolExecutor(8) as ex:
86
  results=list(ex.map(_f,arts))
87
- vids=[]
88
- for r in results:
89
- if r:vids.extend(r)
90
  if vids:
91
  ca=app.make_id(url);ordered=[v for v in vids if app.make_id(v["link"])==ca]+[v for v in vids if app.make_id(v["link"])!=ca]
92
  return _btk(ordered,"24h")
@@ -103,9 +96,7 @@ def _pra(url):
103
  return [{"title":a["title"],"link":a["link"],"img":a.get("img",""),"src":e["mp4"],"poster":e.get("poster",""),"vtype":"mp4"}]
104
  with ThreadPoolExecutor(6) as ex:
105
  results=list(ex.map(_fb,bl))
106
- vids=[]
107
- for r in results:
108
- if r:vids.extend(r)
109
  if vids:
110
  ca=app.make_id(url);ordered=[v for v in vids if app.make_id(v["link"])==ca]+[v for v in vids if app.make_id(v["link"])!=ca]
111
  return _btk(ordered,"BDP")
@@ -113,7 +104,7 @@ def _pra(url):
113
 
114
  def _btk(ordered,sl):
115
  badge="bdp-badge-24h" if sl=="24h" else "bdp-badge-bdp"
116
- is_shorts = sl=="24h"
117
  slides=[];cards=[]
118
  for vi,v in enumerate(ordered):
119
  po=app.safe_url(v.get("poster",""));pa=f' poster="{po}"' if po else ""
@@ -121,12 +112,13 @@ def _btk(ordered,sl):
121
  orig_url=app.esc(v["link"])
122
  sj=f"event.stopPropagation();window.bdpShareOriginal('{app.esc(v['title'])}','{orig_url}')"
123
  vt=f'<video class="tiktok-video" playsinline preload="metadata"{pa} data-hls-src="{vs}" muted loop></video>' if v.get("vtype")=="hls" else f'<video class="tiktok-video" playsinline preload="metadata"{pa} muted loop><source src="{app.safe_url(vs)}" type="video/mp4"></video>'
124
- # Contain toggle (default = 1:1 cover crop)
125
  cb='<button class="tiktok-fullheight-btn" onclick="event.stopPropagation();var c=this.closest(\'.tiktok-fullscreen-container\');c.classList.toggle(\'contain-mode\');var on=c.classList.contains(\'contain-mode\');c.querySelectorAll(\'.tiktok-fullheight-btn\').forEach(function(b){b.classList.toggle(\'active\',on);b.textContent=on?\'\\u2922 1:1\':\'\\u2B07 Contain\';});">\u2B07 Contain</button>'
126
  slides.append(f'<div class="tiktok-slide" data-index="{vi}" data-aid="{aid}">{vt}<div class="tiktok-pause-icon">\u25b6</div><div class="tiktok-seek-controls"><button class="tiktok-seek-btn" onclick="event.stopPropagation();window.bdpSeek(this,-10)">\u23ea 10s</button><button class="tiktok-seek-btn" onclick="event.stopPropagation();window.bdpSeek(this,10)">10s \u23e9</button></div><div class="tiktok-bottom"><span class="bdp-badge {badge}">{sl}</span><p class="tiktok-title">{v["title"]}</p><div class="tiktok-actions"><button class="tiktok-action-btn" onclick="{sj}">\U0001f4e4 Chia s\u1ebb</button></div></div>{cb}<div class="tiktok-unmute-hint" onclick="window.bdpTikTokUnmute(this)">\U0001f507 B\u1eadt ti\u1ebfng</div><span class="tiktok-counter">{vi+1}/{len(ordered)}</span></div>')
127
  img=app.safe_url(v.get("img")or v.get("poster",""))
128
- # Cards use JS scroll instead of bdpOpen (no page reload)
129
- cards.append(f'<div class="bdp-card" onclick="event.stopPropagation();var sl=document.querySelector(\'[data-index=\\\'{vi}\\\']\');if(sl){{sl.scrollIntoView({{behavior:\\\'smooth\\\'}});window.scrollTo(0,0);}}"><div class="bdp-card-img"><img src="{img}" alt="" class="bdp-lazy-img"><div class="bdp-play-overlay">\u25b6</div></div><div class="bdp-card-body"><span class="bdp-badge {badge}">{sl}</span><h3 class="bdp-card-title">{v["title"]}</h3></div></div>')
 
 
130
  grid=f'<div class="bdp-wrap"><div class="bdp-topbar"><span>\U0001f3ac Video</span><span>{len(ordered)} video</span></div><div class="bdp-grid">{"".join(cards)}</div></div>'
131
  mode_class="shorts-feed-mode" if is_shorts else ""
132
  return f'<div class="tiktok-fullscreen-container {mode_class}" id="tiktok-fullscreen-feed"><div class="tiktok-fullscreen-feed">{"".join(slides)}</div></div>{grid}'
 
4
  from shorts_carousel import scrape_24h_news_shorts, render_shorts_carousel, SHORTS_CSS, _extract_24h_video_url
5
  import app
6
 
 
7
  app.REFRESH_SECONDS = 9999
8
 
 
9
  SHORTS_EXTRA_CSS = """
10
  .shorts-feed-mode .tiktok-video{object-fit:cover!important}
11
  .tiktok-fullscreen-container{width:100%!important;max-width:100%!important;border-radius:0!important;height:80vh!important;max-height:680px!important;min-height:400px!important}
12
  .tiktok-fullscreen-feed{height:100%!important}
13
  .tiktok-slide{height:80vh!important;max-height:680px!important;min-height:400px!important}
 
14
  .tiktok-fullscreen-container:not(.shorts-feed-mode) .tiktok-video{object-fit:cover!important}
15
  .tiktok-fullscreen-container.contain-mode .tiktok-video{object-fit:contain!important}
16
  .tiktok-fullheight-btn{position:absolute;bottom:70px;right:12px;background:rgba(255,255,255,.15);color:#fff;border:none;padding:6px 12px;border-radius:16px;font-size:11px;cursor:pointer;z-index:8;backdrop-filter:blur(6px)}
 
30
  if "shorts-feed-mode" not in app.CSS: app.CSS += SHORTS_EXTRA_CSS
31
  if "FULLWIDTH" not in app.CSS: app.CSS += FULLWIDTH_CSS
32
 
 
33
  def _fixed_extract(url):
34
  vid=_extract_24h_video_url(url)
35
  if not vid:return []
 
59
  _orig_vp=app.render_video_page_html
60
  def _pvp():
61
  html=_orig_vp()
 
62
  btn='<button class="tiktok-fullheight-btn" onclick="event.stopPropagation();var c=this.closest(\'.tiktok-fullscreen-container\');c.classList.toggle(\'contain-mode\');var on=c.classList.contains(\'contain-mode\');c.querySelectorAll(\'.tiktok-fullheight-btn\').forEach(function(b){b.classList.toggle(\'active\',on);b.textContent=on?\'\\u2922 1:1\':\'\\u2B07 Contain\';});">\u2B07 Contain</button>'
63
  return html.replace('<div class="tiktok-unmute-hint"',btn+'<div class="tiktok-unmute-hint"')
64
  app.render_video_page_html=_pvp
 
79
  return [{"title":a["title"]+(f" (P{i+1})" if len(ps)>1 else ""),"link":a["link"],"img":a.get("img",""),"src":p,"poster":v["poster"],"vtype":"hls"} for i,p in enumerate(ps)]
80
  with ThreadPoolExecutor(8) as ex:
81
  results=list(ex.map(_f,arts))
82
+ vids=[item for r in results if r for item in r]
 
 
83
  if vids:
84
  ca=app.make_id(url);ordered=[v for v in vids if app.make_id(v["link"])==ca]+[v for v in vids if app.make_id(v["link"])!=ca]
85
  return _btk(ordered,"24h")
 
96
  return [{"title":a["title"],"link":a["link"],"img":a.get("img",""),"src":e["mp4"],"poster":e.get("poster",""),"vtype":"mp4"}]
97
  with ThreadPoolExecutor(6) as ex:
98
  results=list(ex.map(_fb,bl))
99
+ vids=[item for r in results if r for item in r]
 
 
100
  if vids:
101
  ca=app.make_id(url);ordered=[v for v in vids if app.make_id(v["link"])==ca]+[v for v in vids if app.make_id(v["link"])!=ca]
102
  return _btk(ordered,"BDP")
 
104
 
105
  def _btk(ordered,sl):
106
  badge="bdp-badge-24h" if sl=="24h" else "bdp-badge-bdp"
107
+ is_shorts=sl=="24h"
108
  slides=[];cards=[]
109
  for vi,v in enumerate(ordered):
110
  po=app.safe_url(v.get("poster",""));pa=f' poster="{po}"' if po else ""
 
112
  orig_url=app.esc(v["link"])
113
  sj=f"event.stopPropagation();window.bdpShareOriginal('{app.esc(v['title'])}','{orig_url}')"
114
  vt=f'<video class="tiktok-video" playsinline preload="metadata"{pa} data-hls-src="{vs}" muted loop></video>' if v.get("vtype")=="hls" else f'<video class="tiktok-video" playsinline preload="metadata"{pa} muted loop><source src="{app.safe_url(vs)}" type="video/mp4"></video>'
 
115
  cb='<button class="tiktok-fullheight-btn" onclick="event.stopPropagation();var c=this.closest(\'.tiktok-fullscreen-container\');c.classList.toggle(\'contain-mode\');var on=c.classList.contains(\'contain-mode\');c.querySelectorAll(\'.tiktok-fullheight-btn\').forEach(function(b){b.classList.toggle(\'active\',on);b.textContent=on?\'\\u2922 1:1\':\'\\u2B07 Contain\';});">\u2B07 Contain</button>'
116
  slides.append(f'<div class="tiktok-slide" data-index="{vi}" data-aid="{aid}">{vt}<div class="tiktok-pause-icon">\u25b6</div><div class="tiktok-seek-controls"><button class="tiktok-seek-btn" onclick="event.stopPropagation();window.bdpSeek(this,-10)">\u23ea 10s</button><button class="tiktok-seek-btn" onclick="event.stopPropagation();window.bdpSeek(this,10)">10s \u23e9</button></div><div class="tiktok-bottom"><span class="bdp-badge {badge}">{sl}</span><p class="tiktok-title">{v["title"]}</p><div class="tiktok-actions"><button class="tiktok-action-btn" onclick="{sj}">\U0001f4e4 Chia s\u1ebb</button></div></div>{cb}<div class="tiktok-unmute-hint" onclick="window.bdpTikTokUnmute(this)">\U0001f507 B\u1eadt ti\u1ebfng</div><span class="tiktok-counter">{vi+1}/{len(ordered)}</span></div>')
117
  img=app.safe_url(v.get("img")or v.get("poster",""))
118
+ # Click card scrolls to that slide index in the feed (no server reload)
119
+ cards.append(f'<div class="bdp-card" data-goto="{vi}" onclick="var f=document.querySelector(\'.tiktok-fullscreen-feed\');if(f){{var t=f.querySelectorAll(\'.tiktok-slide\')[{vi}];if(t){{t.scrollIntoView();window.scrollTo(0,0);}}}}">'
120
+ f'<div class="bdp-card-img"><img src="{img}" alt="" class="bdp-lazy-img"><div class="bdp-play-overlay">\u25b6</div></div>'
121
+ f'<div class="bdp-card-body"><span class="bdp-badge {badge}">{sl}</span><h3 class="bdp-card-title">{v["title"]}</h3></div></div>')
122
  grid=f'<div class="bdp-wrap"><div class="bdp-topbar"><span>\U0001f3ac Video</span><span>{len(ordered)} video</span></div><div class="bdp-grid">{"".join(cards)}</div></div>'
123
  mode_class="shorts-feed-mode" if is_shorts else ""
124
  return f'<div class="tiktok-fullscreen-container {mode_class}" id="tiktok-fullscreen-feed"><div class="tiktok-fullscreen-feed">{"".join(slides)}</div></div>{grid}'