@@ -266,9 +266,8 @@ def _upload_youtube(
266266 },
267267 method = "POST" ,
268268 )
269- resp = urllib .request .urlopen (req , timeout = 30 )
270- upload_url = resp .headers .get ("Location" )
271- resp .close ()
269+ with urllib .request .urlopen (req , timeout = 30 ) as resp :
270+ upload_url = resp .headers .get ("Location" )
272271
273272 if not upload_url :
274273 return UploadResult (platform = "youtube" , success = False , error = "Failed to get upload URL" )
@@ -296,9 +295,8 @@ def _upload_youtube(
296295 }
297296 req = urllib .request .Request (upload_url , data = chunk , headers = headers , method = "PUT" )
298297 try :
299- resp = urllib .request .urlopen (req , timeout = 300 )
300- body = resp .read ()
301- resp .close ()
298+ with urllib .request .urlopen (req , timeout = 300 ) as resp :
299+ body = resp .read ()
302300 except urllib .error .HTTPError as e :
303301 if e .code == 308 :
304302 # Resume incomplete — read and discard response
@@ -364,11 +362,14 @@ def _refresh_youtube_token(auth: PlatformAuth) -> Optional[PlatformAuth]:
364362 data = data ,
365363 headers = {"Content-Type" : "application/x-www-form-urlencoded" },
366364 )
367- resp = urllib .request .urlopen (req , timeout = 10 )
368- result = json .loads (resp .read ())
369- resp .close ()
365+ with urllib .request .urlopen (req , timeout = 10 ) as resp :
366+ result = json .loads (resp .read ())
370367
371- auth .access_token = result ["access_token" ]
368+ new_token = result .get ("access_token" )
369+ if not new_token :
370+ logger .error ("YouTube token refresh response missing access_token" )
371+ return None
372+ auth .access_token = new_token
372373 auth .expires_at = time .time () + result .get ("expires_in" , 3600 )
373374
374375 creds = _load_credentials ()
@@ -439,9 +440,8 @@ def _upload_tiktok(
439440 "Content-Type" : "application/json; charset=UTF-8" ,
440441 },
441442 )
442- resp = urllib .request .urlopen (req , timeout = 30 )
443- init_result = json .loads (resp .read ())
444- resp .close ()
443+ with urllib .request .urlopen (req , timeout = 30 ) as resp :
444+ init_result = json .loads (resp .read ())
445445
446446 publish_id = init_result .get ("data" , {}).get ("publish_id" , "" )
447447 upload_url = init_result .get ("data" , {}).get ("upload_url" , "" )
@@ -452,22 +452,33 @@ def _upload_tiktok(
452452 if on_progress :
453453 on_progress (15 , "Uploading to TikTok..." )
454454
455- # Step 2: Upload file
455+ # Step 2: Upload file in 10MB chunks
456+ chunk_size = 10 * 1024 * 1024
457+ uploaded = 0
458+
456459 with open (filepath , "rb" ) as f :
457- video_data = f .read ()
460+ while uploaded < file_size :
461+ chunk = f .read (chunk_size )
462+ if not chunk :
463+ break
464+ end = min (uploaded + len (chunk ), file_size )
465+ req = urllib .request .Request (
466+ upload_url ,
467+ data = chunk ,
468+ headers = {
469+ "Content-Type" : "video/mp4" ,
470+ "Content-Length" : str (len (chunk )),
471+ "Content-Range" : f"bytes { uploaded } -{ end - 1 } /{ file_size } " ,
472+ },
473+ method = "PUT" ,
474+ )
475+ with urllib .request .urlopen (req , timeout = 300 ) as resp :
476+ resp .read ()
458477
459- req = urllib .request .Request (
460- upload_url ,
461- data = video_data ,
462- headers = {
463- "Content-Type" : "video/mp4" ,
464- "Content-Length" : str (len (video_data )),
465- "Content-Range" : f"bytes 0-{ len (video_data ) - 1 } /{ len (video_data )} " ,
466- },
467- method = "PUT" ,
468- )
469- resp = urllib .request .urlopen (req , timeout = 600 )
470- resp .close ()
478+ uploaded += len (chunk )
479+ if on_progress :
480+ pct = 15 + int (uploaded / file_size * 70 )
481+ on_progress (pct , f"Uploading... { uploaded / (1024 * 1024 ):.0f} MB / { file_size / (1024 * 1024 ):.0f} MB" )
471482
472483 if on_progress :
473484 on_progress (90 , "Finalizing..." )
@@ -482,9 +493,8 @@ def _upload_tiktok(
482493 "Content-Type" : "application/json" ,
483494 },
484495 )
485- resp = urllib .request .urlopen (req , timeout = 30 )
486- resp .read () # Consume response body
487- resp .close ()
496+ with urllib .request .urlopen (req , timeout = 30 ) as resp :
497+ resp .read () # Consume response body
488498
489499 if on_progress :
490500 on_progress (100 , "Upload complete!" )
@@ -561,9 +571,8 @@ def _upload_instagram(
561571 "Content-Type" : "application/json" ,
562572 },
563573 )
564- resp = urllib .request .urlopen (req , timeout = 30 )
565- create_result = json .loads (resp .read ())
566- resp .close ()
574+ with urllib .request .urlopen (req , timeout = 30 ) as resp :
575+ create_result = json .loads (resp .read ())
567576
568577 container_id = create_result .get ("id" , "" )
569578 if not container_id :
@@ -580,9 +589,8 @@ def _upload_instagram(
580589 f"https://graph.facebook.com/v19.0/{ container_id } ?fields=status_code" ,
581590 headers = {"Authorization" : f"Bearer { auth .access_token } " },
582591 )
583- resp = urllib .request .urlopen (req , timeout = 10 )
584- status = json .loads (resp .read ())
585- resp .close ()
592+ with urllib .request .urlopen (req , timeout = 10 ) as resp :
593+ status = json .loads (resp .read ())
586594
587595 code = status .get ("status_code" , "" )
588596 if code == "FINISHED" :
@@ -610,9 +618,8 @@ def _upload_instagram(
610618 "Content-Type" : "application/json" ,
611619 },
612620 )
613- resp = urllib .request .urlopen (req , timeout = 30 )
614- pub_result = json .loads (resp .read ())
615- resp .close ()
621+ with urllib .request .urlopen (req , timeout = 30 ) as resp :
622+ pub_result = json .loads (resp .read ())
616623
617624 media_id = pub_result .get ("id" , "" )
618625
0 commit comments