marqetive-lib 0.1.8__py3-none-any.whl → 0.1.9__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.
@@ -231,15 +231,26 @@ class TikTokClient(SocialMediaPlatform):
231
231
  wait_for_publish=True,
232
232
  )
233
233
 
234
- if not upload_result.video_id:
235
- raise PlatformError(
236
- "Video upload succeeded but no video ID returned. "
237
- "Video may still be processing.",
238
- platform=self.platform_name,
239
- )
234
+ # 4. Return post - either fetch full details or create minimal Post
235
+ if upload_result.video_id:
236
+ # Fetch the created post to return full Post object
237
+ return await self.get_post(upload_result.video_id)
240
238
 
241
- # 4. Fetch the created post to return full Post object
242
- return await self.get_post(upload_result.video_id)
239
+ # For private/SELF_ONLY posts, TikTok may not return video_id
240
+ # Return a minimal Post object with publish_id
241
+ return Post(
242
+ post_id=upload_result.publish_id,
243
+ platform=self.platform_name,
244
+ content=request.content,
245
+ status=PostStatus.PUBLISHED,
246
+ created_at=datetime.now(),
247
+ raw_data={
248
+ "publish_id": upload_result.publish_id,
249
+ "upload_status": upload_result.status,
250
+ "privacy_level": privacy_level.value,
251
+ "note": "Video published but video_id not returned (common for private posts)",
252
+ },
253
+ )
243
254
 
244
255
  async def get_post(self, post_id: str) -> Post:
245
256
  """Retrieve a TikTok video by its ID.
@@ -531,12 +531,22 @@ class TikTokMediaManager:
531
531
  result_data = data.get("data", {})
532
532
  status = result_data.get("status", PublishStatus.FAILED)
533
533
 
534
+ logger.debug(f"TikTok publish status response: {data}")
535
+
534
536
  video_id = None
535
537
  if status == PublishStatus.PUBLISH_COMPLETE:
536
- # Video IDs are in publicaly_available_post_id array
538
+ # Video IDs are in publicaly_available_post_id array (note TikTok's typo)
539
+ # For private/SELF_ONLY posts, this may be empty
537
540
  video_ids = result_data.get("publicaly_available_post_id", [])
538
541
  if video_ids:
539
542
  video_id = str(video_ids[0])
543
+ else:
544
+ # Try alternative field names that TikTok might use
545
+ video_id = result_data.get("video_id") or result_data.get("item_id")
546
+ logger.warning(
547
+ f"No video ID in publicaly_available_post_id, "
548
+ f"tried alternatives: video_id={video_id}"
549
+ )
540
550
 
541
551
  return MediaUploadResult(
542
552
  publish_id=publish_id,
@@ -713,6 +723,11 @@ class TikTokMediaManager:
713
723
  def _normalize_chunk_size(self, chunk_size: int, file_size: int) -> int:
714
724
  """Normalize chunk size to TikTok's requirements.
715
725
 
726
+ TikTok chunk requirements:
727
+ - Minimum chunk size: 5MB (except for files smaller than 5MB)
728
+ - Maximum chunk size: 64MB (final chunk can be up to 128MB)
729
+ - All non-final chunks must be at least MIN_CHUNK_SIZE
730
+
716
731
  Args:
717
732
  chunk_size: Requested chunk size.
718
733
  file_size: Total file size.
@@ -720,13 +735,27 @@ class TikTokMediaManager:
720
735
  Returns:
721
736
  Normalized chunk size within TikTok limits.
722
737
  """
723
- # Files smaller than MIN_CHUNK_SIZE must be uploaded as single chunk
724
- if file_size < MIN_CHUNK_SIZE:
738
+ # Files smaller than MAX_CHUNK_SIZE (64MB) should be uploaded as single chunk
739
+ # This avoids issues with the final chunk being smaller than MIN_CHUNK_SIZE
740
+ if file_size <= MAX_CHUNK_SIZE:
725
741
  return file_size
726
742
 
727
- # Ensure within limits
743
+ # For larger files, ensure chunk size is within limits
728
744
  chunk_size = max(MIN_CHUNK_SIZE, min(chunk_size, MAX_CHUNK_SIZE))
729
745
 
746
+ # Ensure the last chunk won't be smaller than MIN_CHUNK_SIZE
747
+ # If it would be, increase chunk size to make fewer, larger chunks
748
+ total_chunks = math.ceil(file_size / chunk_size)
749
+ last_chunk_size = file_size - (chunk_size * (total_chunks - 1))
750
+
751
+ if last_chunk_size < MIN_CHUNK_SIZE and total_chunks > 1:
752
+ # Recalculate to have fewer chunks with larger size
753
+ # Use ceiling division to ensure last chunk is large enough
754
+ total_chunks = math.ceil(file_size / MAX_CHUNK_SIZE)
755
+ chunk_size = math.ceil(file_size / total_chunks)
756
+ # Ensure still within limits
757
+ chunk_size = max(MIN_CHUNK_SIZE, min(chunk_size, MAX_CHUNK_SIZE))
758
+
730
759
  return chunk_size
731
760
 
732
761
  def _validate_media(self, mime_type: str, file_size: int) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marqetive-lib
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: Modern Python utilities for web APIs
5
5
  Keywords: api,utilities,web,http,marqetive
6
6
  Requires-Python: >=3.12
@@ -17,9 +17,9 @@ marqetive/platforms/linkedin/exceptions.py,sha256=i5fARUkZik46bS3htZBwUInVzetsZx
17
17
  marqetive/platforms/linkedin/media.py,sha256=iWXUfqDYGsrTqeM6CGZ7a8xjpbdJ5qESolQL8Fv2PIg,20341
18
18
  marqetive/platforms/linkedin/models.py,sha256=n7DqwVxYSbGYBmeEJ1woCZ6XhUIHcLx8Gpm8uCBACzI,12620
19
19
  marqetive/platforms/tiktok/__init__.py,sha256=BqjkXTZDyBlcY3lvREy13yP9h3RcDga8E6Rl6f5KPp8,238
20
- marqetive/platforms/tiktok/client.py,sha256=wCCCFQ4mGiZrrGYjRUCUngz6_eqf4G6BUxYxw8szpig,17178
20
+ marqetive/platforms/tiktok/client.py,sha256=ErhJOskyWVJP1nfLeJl09fGEyVh3QEhjYCgRlVLV-JY,17704
21
21
  marqetive/platforms/tiktok/exceptions.py,sha256=vxwyAKujMGZJh0LetG1QsLF95QfUs_kR6ujsWSHGqL0,10124
22
- marqetive/platforms/tiktok/media.py,sha256=bPQmyVL8egb4teXQDzxQvWLwg2EnBh4Ik6lz20ReFvg,27008
22
+ marqetive/platforms/tiktok/media.py,sha256=aa47EDRA7woKGqKZkl_5XWu7kcRp2nT93Ol2skEQJpY,28592
23
23
  marqetive/platforms/tiktok/models.py,sha256=WWdjuFqhTIR8SnHkz-8UaNc5Mm2PrGomwQ3W7pJcQFg,2962
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
@@ -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.8.dist-info/METADATA,sha256=q99TsfInwfKVr_zoFnkvM3Wvb5cGZ7Nj6qQikle5EG4,7875
38
- marqetive_lib-0.1.8.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
39
- marqetive_lib-0.1.8.dist-info/RECORD,,
37
+ marqetive_lib-0.1.9.dist-info/METADATA,sha256=jdnVbFyp8VBoa2wtc3OMObF0RUDNucFAm6IeezeGYG8,7875
38
+ marqetive_lib-0.1.9.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
39
+ marqetive_lib-0.1.9.dist-info/RECORD,,