understanding commited on
Commit
5dbdb1f
·
verified ·
1 Parent(s): 9660ed3

Update bot/youtube/uploader.py

Browse files
Files changed (1) hide show
  1. bot/youtube/uploader.py +74 -16
bot/youtube/uploader.py CHANGED
@@ -1,34 +1,92 @@
1
- # PATH: bot/youtube/uploader.py
2
- from typing import Callable, Awaitable
3
- from bot.youtube.resume import start_resumable_session, upload_resumable
 
 
 
 
 
4
  from bot.youtube.metadata import build_metadata
 
5
 
6
  ProgressCB = Callable[[int, int], Awaitable[None]]
7
 
8
 
 
 
 
 
 
9
  async def upload_video(
 
10
  access_token: str,
11
  file_path: str,
12
  title: str,
13
  description: str,
14
  privacy: str = "private",
15
- progress_cb: ProgressCB | None = None,
16
- ) -> str:
17
- """
18
- Returns youtube video URL.
 
 
 
19
  """
20
- meta = build_metadata(title=title, description=description, privacy=privacy)
21
- upload_url = await start_resumable_session(access_token, meta)
22
 
23
- # pass ALL as keywords so progress_cb can’t be duplicated
24
- resp = await upload_resumable(
25
- upload_url=upload_url,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  file_path=file_path,
27
  access_token=access_token,
 
28
  progress_cb=progress_cb,
29
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- vid = resp.get("id")
32
- if not vid:
33
- raise RuntimeError("upload_ok_but_no_video_id")
34
- return f"https://youtu.be/{vid}"
 
 
 
1
+ # FILE: bot/youtube/uploader.py
2
+ # NOTE: Updated so upload_video returns a dict (ok/url/err), matching handlers.py.
3
+
4
+ from __future__ import annotations
5
+
6
+ import os
7
+ from typing import Any, Awaitable, Callable, Dict, Optional
8
+
9
  from bot.youtube.metadata import build_metadata
10
+ from bot.youtube.resume import start_resumable_session, upload_resumable
11
 
12
  ProgressCB = Callable[[int, int], Awaitable[None]]
13
 
14
 
15
+ def _watch_url(video_id: str) -> str:
16
+ vid = (video_id or "").strip()
17
+ return f"https://youtu.be/{vid}" if vid else ""
18
+
19
+
20
  async def upload_video(
21
+ *,
22
  access_token: str,
23
  file_path: str,
24
  title: str,
25
  description: str,
26
  privacy: str = "private",
27
+ progress_cb: Optional[ProgressCB] = None,
28
+ ) -> Dict[str, Any]:
29
+ """Upload a video to YouTube via resumable upload.
30
+
31
+ Returns:
32
+ {"ok": True, "video_id": "...", "url": "...", "response": {...}}
33
+ {"ok": False, "err": "...", "detail": "..."}
34
  """
 
 
35
 
36
+ if not access_token:
37
+ return {"ok": False, "err": "missing_access_token"}
38
+ if not file_path or not os.path.exists(file_path):
39
+ return {"ok": False, "err": "file_not_found"}
40
+
41
+ try:
42
+ total_bytes = int(os.path.getsize(file_path))
43
+ except Exception:
44
+ total_bytes = 0
45
+
46
+ metadata = build_metadata(title=title, description=description, privacy=privacy)
47
+
48
+ # 1) Start session
49
+ start = await start_resumable_session(
50
+ access_token=access_token,
51
+ metadata=metadata,
52
+ total_bytes=total_bytes,
53
+ )
54
+ if not (isinstance(start, dict) and start.get("ok") and start.get("session_url")):
55
+ err = start.get("err", "start_failed") if isinstance(start, dict) else "start_failed"
56
+ detail = start.get("detail") if isinstance(start, dict) else None
57
+ out = {"ok": False, "err": err}
58
+ if detail:
59
+ out["detail"] = str(detail)[:500]
60
+ return out
61
+
62
+ session_url = str(start["session_url"])
63
+
64
+ # 2) Upload chunks
65
+ up = await upload_resumable(
66
+ session_url=session_url,
67
  file_path=file_path,
68
  access_token=access_token,
69
+ total_bytes=total_bytes,
70
  progress_cb=progress_cb,
71
  )
72
+ if not (isinstance(up, dict) and up.get("ok")):
73
+ err = up.get("err", "upload_failed") if isinstance(up, dict) else "upload_failed"
74
+ detail = up.get("detail") if isinstance(up, dict) else None
75
+ out = {"ok": False, "err": err}
76
+ if detail:
77
+ out["detail"] = str(detail)[:800]
78
+ return out
79
+
80
+ resp = up.get("response") if isinstance(up, dict) else None
81
+ if not isinstance(resp, dict):
82
+ resp = {}
83
+
84
+ video_id = str(resp.get("id") or resp.get("videoId") or "").strip()
85
+ url = _watch_url(video_id)
86
 
87
+ return {
88
+ "ok": True,
89
+ "video_id": video_id,
90
+ "url": url,
91
+ "response": resp,
92
+ }