marqetive-lib 0.1.11__py3-none-any.whl → 0.1.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -52,7 +52,7 @@ MAX_VIDEO_SIZE = 512 * 1024 * 1024 # 512MB for videos
|
|
|
52
52
|
DEFAULT_REQUEST_TIMEOUT = 120.0 # 2 minutes
|
|
53
53
|
|
|
54
54
|
# Twitter API v2 media upload endpoints
|
|
55
|
-
MEDIA_UPLOAD_BASE_URL = "https://api.x.com/2/media"
|
|
55
|
+
MEDIA_UPLOAD_BASE_URL = "https://api.x.com/2/media/upload"
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class MediaCategory(str, Enum):
|
|
@@ -342,9 +342,9 @@ class TwitterMediaManager:
|
|
|
342
342
|
async with aiofiles.open(file_path, "rb") as f:
|
|
343
343
|
file_data = await f.read()
|
|
344
344
|
|
|
345
|
-
# Prepare form data
|
|
345
|
+
# Prepare multipart form data
|
|
346
346
|
files = {"media": (os.path.basename(file_path), file_data)}
|
|
347
|
-
data = {}
|
|
347
|
+
data: dict[str, str] = {}
|
|
348
348
|
|
|
349
349
|
if media_category:
|
|
350
350
|
data["media_category"] = media_category.value
|
|
@@ -362,22 +362,24 @@ class TwitterMediaManager:
|
|
|
362
362
|
total_bytes=file_size,
|
|
363
363
|
)
|
|
364
364
|
|
|
365
|
-
# Upload
|
|
365
|
+
# Upload - v2 API uses base URL directly
|
|
366
366
|
response = await self.client.post(
|
|
367
|
-
|
|
367
|
+
self.base_url,
|
|
368
368
|
files=files,
|
|
369
369
|
data=data,
|
|
370
370
|
)
|
|
371
371
|
response.raise_for_status()
|
|
372
372
|
result_data = response.json()
|
|
373
|
+
logger.debug(f"Simple upload response: {result_data}")
|
|
373
374
|
|
|
374
|
-
# Parse result
|
|
375
|
-
|
|
375
|
+
# Parse result - v2 API returns {"data": {"id": "..."}}
|
|
376
|
+
media_data = result_data["data"]
|
|
377
|
+
media_id = str(media_data["id"])
|
|
376
378
|
result = MediaUploadResult(
|
|
377
379
|
media_id=media_id,
|
|
378
|
-
media_key=
|
|
379
|
-
size=
|
|
380
|
-
expires_after_secs=
|
|
380
|
+
media_key=media_data.get("media_key"),
|
|
381
|
+
size=media_data.get("size"),
|
|
382
|
+
expires_after_secs=media_data.get("expires_after_secs"),
|
|
381
383
|
)
|
|
382
384
|
|
|
383
385
|
# Notify completion
|
|
@@ -544,23 +546,27 @@ class TwitterMediaManager:
|
|
|
544
546
|
|
|
545
547
|
@retry_async(config=STANDARD_BACKOFF)
|
|
546
548
|
async def _do_init() -> str:
|
|
547
|
-
|
|
548
|
-
|
|
549
|
+
# v2 API uses JSON body for INIT
|
|
550
|
+
json_data: dict[str, Any] = {
|
|
549
551
|
"total_bytes": total_bytes,
|
|
550
552
|
"media_type": media_type,
|
|
551
553
|
"media_category": media_category.value,
|
|
554
|
+
"shared": False,
|
|
552
555
|
}
|
|
553
556
|
|
|
554
557
|
if additional_owners:
|
|
555
|
-
|
|
558
|
+
json_data["additional_owners"] = ",".join(additional_owners)
|
|
556
559
|
|
|
560
|
+
logger.debug(f"INIT request: {json_data}")
|
|
557
561
|
response = await self.client.post(
|
|
558
|
-
f"{self.base_url}/
|
|
559
|
-
|
|
562
|
+
f"{self.base_url}/initialize",
|
|
563
|
+
json=json_data,
|
|
560
564
|
)
|
|
561
565
|
response.raise_for_status()
|
|
562
566
|
result = response.json()
|
|
563
|
-
|
|
567
|
+
logger.debug(f"INIT response: {result}")
|
|
568
|
+
# v2 API returns {"data": {"id": "..."}}
|
|
569
|
+
return str(result["data"]["id"])
|
|
564
570
|
|
|
565
571
|
return await _do_init()
|
|
566
572
|
|
|
@@ -582,19 +588,18 @@ class TwitterMediaManager:
|
|
|
582
588
|
|
|
583
589
|
@retry_async(config=STANDARD_BACKOFF)
|
|
584
590
|
async def _do_append() -> None:
|
|
591
|
+
# v2 API uses /{media_id}/append endpoint with form data
|
|
585
592
|
files = {"media": (filename, chunk_data)}
|
|
586
|
-
|
|
587
|
-
"command": "APPEND",
|
|
588
|
-
"media_id": media_id,
|
|
589
|
-
"segment_index": segment_index,
|
|
590
|
-
}
|
|
593
|
+
data = {"segment_index": str(segment_index)}
|
|
591
594
|
|
|
592
595
|
response = await self.client.post(
|
|
593
|
-
f"{self.base_url}/
|
|
594
|
-
params=params,
|
|
596
|
+
f"{self.base_url}/{media_id}/append",
|
|
595
597
|
files=files,
|
|
598
|
+
data=data,
|
|
596
599
|
)
|
|
600
|
+
logger.debug(f"APPEND response status: {response.status_code}")
|
|
597
601
|
response.raise_for_status()
|
|
602
|
+
# APPEND returns empty body on success
|
|
598
603
|
|
|
599
604
|
await _do_append()
|
|
600
605
|
|
|
@@ -610,24 +615,23 @@ class TwitterMediaManager:
|
|
|
610
615
|
|
|
611
616
|
@retry_async(config=STANDARD_BACKOFF)
|
|
612
617
|
async def _do_finalize() -> MediaUploadResult:
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
"media_id": media_id,
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
+
# v2 API uses /{media_id}/finalize endpoint
|
|
619
|
+
logger.debug(f"Finalizing chunked upload for media_id: {media_id}")
|
|
618
620
|
response = await self.client.post(
|
|
619
|
-
f"{self.base_url}/
|
|
620
|
-
params=params,
|
|
621
|
+
f"{self.base_url}/{media_id}/finalize",
|
|
621
622
|
)
|
|
622
623
|
response.raise_for_status()
|
|
623
624
|
result = response.json()
|
|
625
|
+
logger.debug(f"FINALIZE response: {result}")
|
|
624
626
|
|
|
627
|
+
# v2 API returns {"data": {...}}
|
|
628
|
+
media_data = result["data"]
|
|
625
629
|
return MediaUploadResult(
|
|
626
|
-
media_id=str(
|
|
627
|
-
media_key=
|
|
628
|
-
size=
|
|
629
|
-
expires_after_secs=
|
|
630
|
-
processing_info=
|
|
630
|
+
media_id=str(media_data["id"]),
|
|
631
|
+
media_key=media_data.get("media_key"),
|
|
632
|
+
size=media_data.get("size"),
|
|
633
|
+
expires_after_secs=media_data.get("expires_after_secs"),
|
|
634
|
+
processing_info=media_data.get("processing_info"),
|
|
631
635
|
)
|
|
632
636
|
|
|
633
637
|
return await _do_finalize()
|
|
@@ -644,24 +648,28 @@ class TwitterMediaManager:
|
|
|
644
648
|
|
|
645
649
|
@retry_async(config=STANDARD_BACKOFF)
|
|
646
650
|
async def _do_status() -> MediaUploadResult:
|
|
651
|
+
# v2 API uses GET with media_id and command params
|
|
647
652
|
params = {
|
|
648
|
-
"command": "STATUS",
|
|
649
653
|
"media_id": media_id,
|
|
654
|
+
"command": "STATUS",
|
|
650
655
|
}
|
|
651
656
|
|
|
652
657
|
response = await self.client.get(
|
|
653
|
-
|
|
658
|
+
self.base_url,
|
|
654
659
|
params=params,
|
|
655
660
|
)
|
|
656
661
|
response.raise_for_status()
|
|
657
662
|
result = response.json()
|
|
663
|
+
logger.debug(f"STATUS response: {result}")
|
|
658
664
|
|
|
665
|
+
# v2 API returns {"data": {...}}
|
|
666
|
+
media_data = result["data"]
|
|
659
667
|
return MediaUploadResult(
|
|
660
|
-
media_id=str(
|
|
661
|
-
media_key=
|
|
662
|
-
size=
|
|
663
|
-
expires_after_secs=
|
|
664
|
-
processing_info=
|
|
668
|
+
media_id=str(media_data["id"]),
|
|
669
|
+
media_key=media_data.get("media_key"),
|
|
670
|
+
size=media_data.get("size"),
|
|
671
|
+
expires_after_secs=media_data.get("expires_after_secs"),
|
|
672
|
+
processing_info=media_data.get("processing_info"),
|
|
665
673
|
)
|
|
666
674
|
|
|
667
675
|
return await _do_status()
|
|
@@ -24,7 +24,7 @@ marqetive/platforms/tiktok/models.py,sha256=WWdjuFqhTIR8SnHkz-8UaNc5Mm2PrGomwQ3W
|
|
|
24
24
|
marqetive/platforms/twitter/__init__.py,sha256=dvcgVT-v-JOtjSz-OUvxGrn_43OI6w_ep42Wx_nHTSM,217
|
|
25
25
|
marqetive/platforms/twitter/client.py,sha256=08jV2hQVmGOpnG3C05u7bCqL7KapWn7bSsG0wbN_t5M,23270
|
|
26
26
|
marqetive/platforms/twitter/exceptions.py,sha256=eZ-dJKOXH_-bAMg29zWKbEqMFud29piEJ5IWfC9wFts,8926
|
|
27
|
-
marqetive/platforms/twitter/media.py,sha256=
|
|
27
|
+
marqetive/platforms/twitter/media.py,sha256=KpPxnLCas8NhnsEvaXSJZ7To4wW4FY0YqQvUkJIIr7g,28010
|
|
28
28
|
marqetive/platforms/twitter/models.py,sha256=yPQlx40SlNmz7YGasXUqdx7rEDEgrQ64aYovlPKo6oc,2126
|
|
29
29
|
marqetive/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
marqetive/utils/__init__.py,sha256=bSrNajbxYBSKQayrPviLz8JeGjplnyK8y_NGDtgb7yQ,977
|
|
@@ -34,6 +34,6 @@ marqetive/utils/media.py,sha256=O1rISYdaP3CuuPxso7kqvxWXNfe2jjioNkaBc4cpwkY,1466
|
|
|
34
34
|
marqetive/utils/oauth.py,sha256=1SkYCE6dcyPvcDqbjRFSSBcKTwLJy8u3jAANPdftVmo,13108
|
|
35
35
|
marqetive/utils/retry.py,sha256=lAniJLMNWp9XsHrvU0XBNifpNEjfde4MGfd5hlFTPfA,7636
|
|
36
36
|
marqetive/utils/token_validator.py,sha256=dNvDeHs2Du5UyMMH2ZOW6ydR7OwOEKA4c9e-rG0f9-0,6698
|
|
37
|
-
marqetive_lib-0.1.
|
|
38
|
-
marqetive_lib-0.1.
|
|
39
|
-
marqetive_lib-0.1.
|
|
37
|
+
marqetive_lib-0.1.12.dist-info/METADATA,sha256=UfSKVNuQnGu17NTqgGUKv8ttCClMOCQMen3shK_GgxY,7876
|
|
38
|
+
marqetive_lib-0.1.12.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
39
|
+
marqetive_lib-0.1.12.dist-info/RECORD,,
|
|
File without changes
|