Update pipeline.py
Browse files- pipeline.py +23 -112
pipeline.py
CHANGED
|
@@ -601,15 +601,24 @@ async def _upload_one(app, entry, thumb, movie_name, upload_lock, status_prefix=
|
|
| 601 |
)
|
| 602 |
|
| 603 |
tg_send_status(f"{status_prefix}β« {label}: Uploading...")
|
|
|
|
| 604 |
async with upload_lock:
|
| 605 |
-
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 613 |
|
| 614 |
tg_link = generate_telegram_link(CHAT_ID, sent.id)
|
| 615 |
dl_link = generate_direct_link(tg_link)
|
|
@@ -659,12 +668,10 @@ def post_mega_link_payload(movie, abyss_link, abyss_iframe, collected):
|
|
| 659 |
website = movie.get("website","")
|
| 660 |
author = movie.get("author","")
|
| 661 |
|
| 662 |
-
with_sub
|
| 663 |
-
without_sub = {}
|
| 664 |
for e in collected:
|
| 665 |
q = str(e["quality"])
|
| 666 |
-
if e["is_burned"]: with_sub[q]
|
| 667 |
-
else: without_sub[q] = e
|
| 668 |
|
| 669 |
def _q(entry, with_iframe=False):
|
| 670 |
if not entry: return {}
|
|
@@ -688,11 +695,6 @@ def post_mega_link_payload(movie, abyss_link, abyss_iframe, collected):
|
|
| 688 |
"720p": _q(with_sub.get("720")),
|
| 689 |
"480p": _q(with_sub.get("480")),
|
| 690 |
},
|
| 691 |
-
"without_sinhala_subtitle": {
|
| 692 |
-
"1080p": _q(without_sub.get("1080")),
|
| 693 |
-
"720p": _q(without_sub.get("720")),
|
| 694 |
-
"480p": _q(without_sub.get("480")),
|
| 695 |
-
},
|
| 696 |
},
|
| 697 |
}
|
| 698 |
|
|
@@ -711,9 +713,9 @@ def post_mega_link_payload(movie, abyss_link, abyss_iframe, collected):
|
|
| 711 |
tg_log_error(f"Movie DB POST failed: {e}")
|
| 712 |
|
| 713 |
# Send the final formatted links as a NEW message
|
| 714 |
-
_send_links_message(movie, abyss_iframe, with_sub
|
| 715 |
|
| 716 |
-
def _send_links_message(movie, abyss_iframe, with_sub
|
| 717 |
"""Single new Telegram message with all final links β sent once at the very end."""
|
| 718 |
name = movie["name"]
|
| 719 |
year = movie.get("year","")
|
|
@@ -746,15 +748,6 @@ def _send_links_message(movie, abyss_iframe, with_sub, without_sub):
|
|
| 746 |
if e.get("bot_link"): lines.append(f" π€ {e['bot_link']}")
|
| 747 |
lines.append(f" π¦ {fmt_size(e['file_size'])}")
|
| 748 |
|
| 749 |
-
lines += ["","<b>Without Sinhala Subtitle</b>"]
|
| 750 |
-
for qk, ql in [("1080","1080p"),("720","720p"),("480","480p")]:
|
| 751 |
-
if qk in without_sub:
|
| 752 |
-
e=without_sub[qk]
|
| 753 |
-
lines.append(f" <b>{ql}</b>")
|
| 754 |
-
if e.get("direct_link"): lines.append(f" π₯ {e['direct_link']}")
|
| 755 |
-
if e.get("bot_link"): lines.append(f" π€ {e['bot_link']}")
|
| 756 |
-
lines.append(f" π¦ {fmt_size(e['file_size'])}")
|
| 757 |
-
|
| 758 |
tg_send_new("\n".join(lines))
|
| 759 |
|
| 760 |
def _trigger_uploaded_kv(imdb, movie_name, payload):
|
|
@@ -827,80 +820,7 @@ def run_burn_1080(movie, input_video, src_w, src_h, file_type):
|
|
| 827 |
# burned_path stays on disk for GH artifact upload
|
| 828 |
|
| 829 |
|
| 830 |
-
#
|
| 831 |
-
|
| 832 |
-
def run_plain_all(movie, input_video, src_w, src_h, file_type, all_qualities, thumb=None):
|
| 833 |
-
name = movie["name"]; year=movie.get("year","")
|
| 834 |
-
ft = file_type
|
| 835 |
-
prefix = f"π¬ <b>{name} {year}</b>\nEncode: <b>{ft} x264</b> | 1080p/720p/480p\n\n"
|
| 836 |
-
|
| 837 |
-
# Include ALL qualities (1080p included) β upload order: 1080 β 720 β 480
|
| 838 |
-
plain_qualities = sorted([q for q in all_qualities if q in (1080, 720, 480)], reverse=True)
|
| 839 |
-
tg_send_status(f"{prefix}π plain_all β encoding {plain_qualities}")
|
| 840 |
-
|
| 841 |
-
total_secs = get_duration(input_video)
|
| 842 |
-
src_bitrate = get_video_bitrate(input_video)
|
| 843 |
-
src_is_x265 = is_x265(input_video)
|
| 844 |
-
ref_pixels = src_w*src_h
|
| 845 |
-
q_icons = {2160:"π΄",1080:"π΅",720:"π’",480:"π‘"}
|
| 846 |
-
|
| 847 |
-
import nest_asyncio; nest_asyncio.apply()
|
| 848 |
-
|
| 849 |
-
async def _upload_one_plain(entry):
|
| 850 |
-
from pyrogram import Client
|
| 851 |
-
lock=asyncio.Lock()
|
| 852 |
-
async with Client("user_session",api_id=API_ID,api_hash=API_HASH,
|
| 853 |
-
session_string=SESSION_CODE) as app:
|
| 854 |
-
return await _upload_one(app, entry, thumb, name, lock, prefix)
|
| 855 |
-
|
| 856 |
-
# ββ Phase 1: Encode ALL qualities first ββββββββββββββββββββββββββββββββββ
|
| 857 |
-
encoded_entries = []
|
| 858 |
-
for q in plain_qualities:
|
| 859 |
-
w, h = get_res(q, src_w, src_h)
|
| 860 |
-
plain_path = os.path.join(WORK_DIR, make_filename(name, q, ft, burned=False))
|
| 861 |
-
|
| 862 |
-
# Only stream-copy if SAME resolution AND already x264 (no transcode needed)
|
| 863 |
-
is_same = (w == src_w and h == src_h)
|
| 864 |
-
if is_same and not src_is_x265:
|
| 865 |
-
cmd = ["ffmpeg", "-y", "-i", input_video, "-c", "copy",
|
| 866 |
-
"-progress", "pipe:1", "-nostats", plain_path]
|
| 867 |
-
else:
|
| 868 |
-
if src_bitrate:
|
| 869 |
-
tbv = max(int(src_bitrate * (w * h) / ref_pixels), 400_000)
|
| 870 |
-
ea = ["-c:v", "libx264", "-pix_fmt", "yuv420p",
|
| 871 |
-
"-b:v", str(tbv), "-maxrate", str(int(tbv * 1.1)),
|
| 872 |
-
"-bufsize", str(int(tbv * 2))]
|
| 873 |
-
else:
|
| 874 |
-
ea = ["-c:v", "libx264", "-pix_fmt", "yuv420p", "-crf", str(get_crf(q))]
|
| 875 |
-
# Use explicit w:h so ffmpeg never defaults to 16:9
|
| 876 |
-
cmd = (["ffmpeg", "-y", "-i", input_video, "-vf", f"scale={w}:{h}"]
|
| 877 |
-
+ ea + ["-c:a", "copy", "-progress", "pipe:1", "-nostats", plain_path])
|
| 878 |
-
|
| 879 |
-
ok = run_ffmpeg(cmd, total_secs, f"Plain {q}p ({w}x{h})", prefix)
|
| 880 |
-
if not ok:
|
| 881 |
-
tg_send_status(f"{prefix}β οΈ Plain {q}p failed β skipping"); continue
|
| 882 |
-
|
| 883 |
-
entry = {"file_path": plain_path, "quality": q, "is_burned": False,
|
| 884 |
-
"abyss_link": "", "icon": q_icons.get(q, "βͺ"), "label": f"{q}p | Plain"}
|
| 885 |
-
encoded_entries.append(entry)
|
| 886 |
-
|
| 887 |
-
# ββ Phase 2: Upload ONE AT A TIME in order 1080 β 720 β 480 βββββββββββββ
|
| 888 |
-
collected=[]
|
| 889 |
-
for entry in encoded_entries: # already sorted highestβlowest from plain_qualities
|
| 890 |
-
result=asyncio.run(_upload_one_plain(entry))
|
| 891 |
-
if result: collected.append(result)
|
| 892 |
-
try: os.remove(entry["file_path"])
|
| 893 |
-
except: pass
|
| 894 |
-
|
| 895 |
-
plain_links_path = os.path.join(WORK_DIR, "plain_links.json")
|
| 896 |
-
try:
|
| 897 |
-
with open(plain_links_path, "w", encoding="utf-8") as _f:
|
| 898 |
-
json.dump(collected, _f)
|
| 899 |
-
except Exception as _e:
|
| 900 |
-
tg_log_error(f"Failed to save plain_links.json: {_e}")
|
| 901 |
-
|
| 902 |
-
tg_send_status(f"{prefix}β
plain_all complete β {len(collected)} files uploaded")
|
| 903 |
-
return collected
|
| 904 |
|
| 905 |
|
| 906 |
# βββ Variant: downscale_upload ββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -968,15 +888,6 @@ def run_downscale_upload(movie, src_w, src_h, file_type, all_qualities, thumb):
|
|
| 968 |
import nest_asyncio; nest_asyncio.apply()
|
| 969 |
collected=asyncio.run(tg_upload_all(entries, thumb, name, prefix))
|
| 970 |
|
| 971 |
-
tg_send_status(f"{prefix}π‘ Posting to movie DB...")
|
| 972 |
-
plain_links_path = os.path.join(WORK_DIR, "plain_links.json")
|
| 973 |
-
if os.path.exists(plain_links_path):
|
| 974 |
-
try:
|
| 975 |
-
with open(plain_links_path, "r", encoding="utf-8") as _f:
|
| 976 |
-
plain_data = json.load(_f)
|
| 977 |
-
collected = collected + plain_data
|
| 978 |
-
except Exception as _e:
|
| 979 |
-
tg_log_error(f"Failed to load plain_links.json: {_e}")
|
| 980 |
post_mega_link_payload(movie, abyss_link, abyss_iframe, collected)
|
| 981 |
|
| 982 |
cleanup(list(burned_files.values())+([thumb] if thumb else []))
|
|
@@ -1070,4 +981,4 @@ def main():
|
|
| 1070 |
run_downscale_upload(movie, src_w, src_h, file_type, all_q, thumb)
|
| 1071 |
|
| 1072 |
if __name__=="__main__":
|
| 1073 |
-
main()
|
|
|
|
| 601 |
)
|
| 602 |
|
| 603 |
tg_send_status(f"{status_prefix}β« {label}: Uploading...")
|
| 604 |
+
sent = None
|
| 605 |
async with upload_lock:
|
| 606 |
+
for attempt in range(1, 4):
|
| 607 |
+
try:
|
| 608 |
+
if attempt > 1:
|
| 609 |
+
tg_send_status(f"{status_prefix}β« {label}: Retry {attempt}/3...")
|
| 610 |
+
await asyncio.sleep(10 * attempt)
|
| 611 |
+
us[0] = time.time() # reset speed timer on retry
|
| 612 |
+
sent = await app.send_video(
|
| 613 |
+
chat_id=CHAT_ID, video=file_path, file_name=fname,
|
| 614 |
+
caption=caption, duration=dur, width=w, height=h,
|
| 615 |
+
thumb=thumb_ok, supports_streaming=True, progress=_prog
|
| 616 |
+
)
|
| 617 |
+
break # success
|
| 618 |
+
except Exception as e:
|
| 619 |
+
tg_log_error(f"Upload failed ({label}) attempt {attempt}/3: {e}")
|
| 620 |
+
if attempt == 3:
|
| 621 |
+
return None
|
| 622 |
|
| 623 |
tg_link = generate_telegram_link(CHAT_ID, sent.id)
|
| 624 |
dl_link = generate_direct_link(tg_link)
|
|
|
|
| 668 |
website = movie.get("website","")
|
| 669 |
author = movie.get("author","")
|
| 670 |
|
| 671 |
+
with_sub = {}
|
|
|
|
| 672 |
for e in collected:
|
| 673 |
q = str(e["quality"])
|
| 674 |
+
if e["is_burned"]: with_sub[q] = e
|
|
|
|
| 675 |
|
| 676 |
def _q(entry, with_iframe=False):
|
| 677 |
if not entry: return {}
|
|
|
|
| 695 |
"720p": _q(with_sub.get("720")),
|
| 696 |
"480p": _q(with_sub.get("480")),
|
| 697 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 698 |
},
|
| 699 |
}
|
| 700 |
|
|
|
|
| 713 |
tg_log_error(f"Movie DB POST failed: {e}")
|
| 714 |
|
| 715 |
# Send the final formatted links as a NEW message
|
| 716 |
+
_send_links_message(movie, abyss_iframe, with_sub)
|
| 717 |
|
| 718 |
+
def _send_links_message(movie, abyss_iframe, with_sub):
|
| 719 |
"""Single new Telegram message with all final links β sent once at the very end."""
|
| 720 |
name = movie["name"]
|
| 721 |
year = movie.get("year","")
|
|
|
|
| 748 |
if e.get("bot_link"): lines.append(f" π€ {e['bot_link']}")
|
| 749 |
lines.append(f" π¦ {fmt_size(e['file_size'])}")
|
| 750 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 751 |
tg_send_new("\n".join(lines))
|
| 752 |
|
| 753 |
def _trigger_uploaded_kv(imdb, movie_name, payload):
|
|
|
|
| 820 |
# burned_path stays on disk for GH artifact upload
|
| 821 |
|
| 822 |
|
| 823 |
+
# plain_all removed β only burned (Sinhala subtitle) versions are produced
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 824 |
|
| 825 |
|
| 826 |
# βββ Variant: downscale_upload ββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 888 |
import nest_asyncio; nest_asyncio.apply()
|
| 889 |
collected=asyncio.run(tg_upload_all(entries, thumb, name, prefix))
|
| 890 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
post_mega_link_payload(movie, abyss_link, abyss_iframe, collected)
|
| 892 |
|
| 893 |
cleanup(list(burned_files.values())+([thumb] if thumb else []))
|
|
|
|
| 981 |
run_downscale_upload(movie, src_w, src_h, file_type, all_q, thumb)
|
| 982 |
|
| 983 |
if __name__=="__main__":
|
| 984 |
+
main()
|