upload-post 2.1.1__tar.gz → 2.2.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: upload-post
3
- Version: 2.1.1
3
+ Version: 2.2.2
4
4
  Summary: Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, and X (Twitter)
5
5
  Home-page: https://www.upload-post.com/
6
6
  Author: Upload-Post
@@ -210,6 +210,10 @@ jwt = client.generate_jwt(
210
210
  "my-profile",
211
211
  redirect_url="https://yourapp.com/callback",
212
212
  platforms=["tiktok", "instagram"],
213
+ # Optional: force the connection page language for this profile.
214
+ # Supported: "en", "es", "de", "fr", "pt". When omitted, the page
215
+ # auto-detects the visitor's browser language and falls back to English.
216
+ language="es",
213
217
  )
214
218
  ```
215
219
 
@@ -223,6 +227,23 @@ analytics = client.get_analytics(
223
227
  print(analytics)
224
228
  ```
225
229
 
230
+ ### Get Media
231
+
232
+ Retrieve recent posts from a connected social account. Supported platforms:
233
+ `instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
234
+ `pinterest`, `bluesky`, `reddit`.
235
+
236
+ ```python
237
+ # Personal LinkedIn profile (default for non-org accounts):
238
+ media = client.get_media("linkedin", "my-profile")
239
+
240
+ # Force the personal profile of an account connected as an org admin:
241
+ media = client.get_media("linkedin", "my-profile", page_urn="me")
242
+
243
+ # Target a specific LinkedIn organization page:
244
+ media = client.get_media("linkedin", "my-profile", page_urn="12345")
245
+ ```
246
+
226
247
  ### Helper Methods
227
248
 
228
249
  ```python
@@ -172,6 +172,10 @@ jwt = client.generate_jwt(
172
172
  "my-profile",
173
173
  redirect_url="https://yourapp.com/callback",
174
174
  platforms=["tiktok", "instagram"],
175
+ # Optional: force the connection page language for this profile.
176
+ # Supported: "en", "es", "de", "fr", "pt". When omitted, the page
177
+ # auto-detects the visitor's browser language and falls back to English.
178
+ language="es",
175
179
  )
176
180
  ```
177
181
 
@@ -185,6 +189,23 @@ analytics = client.get_analytics(
185
189
  print(analytics)
186
190
  ```
187
191
 
192
+ ### Get Media
193
+
194
+ Retrieve recent posts from a connected social account. Supported platforms:
195
+ `instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
196
+ `pinterest`, `bluesky`, `reddit`.
197
+
198
+ ```python
199
+ # Personal LinkedIn profile (default for non-org accounts):
200
+ media = client.get_media("linkedin", "my-profile")
201
+
202
+ # Force the personal profile of an account connected as an org admin:
203
+ media = client.get_media("linkedin", "my-profile", page_urn="me")
204
+
205
+ # Target a specific LinkedIn organization page:
206
+ media = client.get_media("linkedin", "my-profile", page_urn="12345")
207
+ ```
208
+
188
209
  ### Helper Methods
189
210
 
190
211
  ```python
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="upload-post",
8
- version="2.1.1",
8
+ version="2.2.2",
9
9
  author="Upload-Post",
10
10
  author_email="hi@img2html.com",
11
11
  description="Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, and X (Twitter)",
@@ -15,7 +15,7 @@ Example:
15
15
  ... )
16
16
  """
17
17
 
18
- __version__ = "2.1.1"
18
+ __version__ = "2.2.2"
19
19
 
20
20
  from .api_client import UploadPostClient, UploadPostError
21
21
 
@@ -74,6 +74,8 @@ class UploadPostClient:
74
74
  response = self.session.delete(url, json=json_data)
75
75
  else:
76
76
  response = self.session.delete(url)
77
+ elif method == "PATCH":
78
+ response = self.session.patch(url, json=json_data)
77
79
  else:
78
80
  raise UploadPostError(f"Unsupported HTTP method: {method}")
79
81
 
@@ -212,7 +214,7 @@ class UploadPostClient:
212
214
  if kwargs.get("thumb_offset"):
213
215
  data.append(("thumb_offset", kwargs["thumb_offset"]))
214
216
 
215
- def _add_youtube_params(self, data: List[tuple], **kwargs):
217
+ def _add_youtube_params(self, data: List[tuple], files: List[tuple] = None, **kwargs):
216
218
  """Add YouTube-specific parameters."""
217
219
  if kwargs.get("tags"):
218
220
  tags = kwargs["tags"]
@@ -248,6 +250,21 @@ class UploadPostClient:
248
250
  data.append(("hasPaidProductPlacement", str(kwargs["hasPaidProductPlacement"]).lower()))
249
251
  if kwargs.get("recordingDate"):
250
252
  data.append(("recordingDate", kwargs["recordingDate"]))
253
+ if kwargs.get("subtitles"):
254
+ for idx, sub in enumerate(kwargs["subtitles"]):
255
+ if sub.get("language"):
256
+ data.append((f"youtube_subtitle_language_{idx}", sub["language"]))
257
+ if sub.get("name"):
258
+ data.append((f"youtube_subtitle_name_{idx}", sub["name"]))
259
+ if sub.get("file"):
260
+ sub_path = Path(sub["file"])
261
+ if sub_path.exists() and files is not None:
262
+ files.append((f"youtube_subtitle_file_{idx}", (sub_path.name, sub_path.open("rb"))))
263
+ else:
264
+ # Treat as URL string
265
+ data.append((f"youtube_subtitle_file_{idx}", str(sub["file"])))
266
+ elif sub.get("url"):
267
+ data.append((f"youtube_subtitle_file_{idx}", sub["url"]))
251
268
 
252
269
  def _add_linkedin_params(self, data: List[tuple], is_text: bool = False, **kwargs):
253
270
  """Add LinkedIn-specific parameters."""
@@ -429,7 +446,9 @@ class UploadPostClient:
429
446
  blockedCountries: Comma-separated country codes
430
447
  hasPaidProductPlacement: Paid placement flag
431
448
  recordingDate: Recording date (ISO 8601)
432
-
449
+ subtitles: List of subtitle dicts with keys: language (BCP-47),
450
+ name (display name), file (path to SRT/VTT file), url (subtitle URL)
451
+
433
452
  LinkedIn:
434
453
  visibility: PUBLIC, CONNECTIONS, LOGGED_IN, CONTAINER
435
454
  target_linkedin_page_id: Page ID for organization posts
@@ -489,7 +508,7 @@ class UploadPostClient:
489
508
  if "instagram" in platforms:
490
509
  self._add_instagram_params(data, is_video=True, files=files, **kwargs)
491
510
  if "youtube" in platforms:
492
- self._add_youtube_params(data, **kwargs)
511
+ self._add_youtube_params(data, files=files, **kwargs)
493
512
  if "linkedin" in platforms:
494
513
  self._add_linkedin_params(data, **kwargs)
495
514
  if "facebook" in platforms:
@@ -973,6 +992,30 @@ class UploadPostClient:
973
992
  """
974
993
  return self._request("/uploadposts/platform-metrics", "GET")
975
994
 
995
+ def get_media(
996
+ self,
997
+ platform: str,
998
+ user: str,
999
+ page_urn: Optional[str] = None,
1000
+ ) -> Dict:
1001
+ """
1002
+ Retrieve recent media from a connected social account.
1003
+
1004
+ Args:
1005
+ platform: instagram, tiktok, youtube, linkedin, facebook, x,
1006
+ threads, pinterest, bluesky, or reddit.
1007
+ user: Profile username.
1008
+ page_urn: LinkedIn only. Numeric org ID, full URN, or ``"me"`` to
1009
+ force the personal profile of an org-admin account.
1010
+
1011
+ Returns:
1012
+ ``{"success": True, "media": [...]}``.
1013
+ """
1014
+ params: Dict[str, str] = {"platform": platform, "user": user}
1015
+ if page_urn:
1016
+ params["page_urn"] = page_urn
1017
+ return self._request("/uploadposts/media", "GET", params=params)
1018
+
976
1019
  # ==================== Scheduled Posts ====================
977
1020
 
978
1021
  def list_scheduled(self) -> Dict:
@@ -1018,7 +1061,7 @@ class UploadPostClient:
1018
1061
  body["scheduled_date"] = scheduled_date
1019
1062
  if timezone:
1020
1063
  body["timezone"] = timezone
1021
- return self._request(f"/uploadposts/schedule/{job_id}", "POST", json_data=body)
1064
+ return self._request(f"/uploadposts/schedule/{job_id}", "PATCH", json_data=body)
1022
1065
 
1023
1066
  # ==================== User Management ====================
1024
1067
 
@@ -1065,7 +1108,8 @@ class UploadPostClient:
1065
1108
  show_calendar: Optional[bool] = None,
1066
1109
  readonly_calendar: Optional[bool] = None,
1067
1110
  connect_title: Optional[str] = None,
1068
- connect_description: Optional[str] = None
1111
+ connect_description: Optional[str] = None,
1112
+ language: Optional[str] = None
1069
1113
  ) -> Dict:
1070
1114
  """
1071
1115
  Generate a JWT for platform integration.
@@ -1081,6 +1125,9 @@ class UploadPostClient:
1081
1125
  readonly_calendar: Show only a read-only calendar (no editing, no account connection).
1082
1126
  connect_title: Custom title for the connection page.
1083
1127
  connect_description: Custom description for the connection page.
1128
+ language: Force the connection page language for this profile.
1129
+ Supported: 'en', 'es', 'de', 'fr', 'pt'. When omitted, the page
1130
+ auto-detects the visitor's browser language and falls back to English.
1084
1131
 
1085
1132
  Returns:
1086
1133
  JWT and connection URL.
@@ -1102,6 +1149,8 @@ class UploadPostClient:
1102
1149
  body["connect_title"] = connect_title
1103
1150
  if connect_description:
1104
1151
  body["connect_description"] = connect_description
1152
+ if language:
1153
+ body["language"] = language
1105
1154
  return self._request("/uploadposts/users/generate-jwt", "POST", json_data=body)
1106
1155
 
1107
1156
  def validate_jwt(self, jwt: str) -> Dict:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: upload-post
3
- Version: 2.1.1
3
+ Version: 2.2.2
4
4
  Summary: Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, and X (Twitter)
5
5
  Home-page: https://www.upload-post.com/
6
6
  Author: Upload-Post
@@ -210,6 +210,10 @@ jwt = client.generate_jwt(
210
210
  "my-profile",
211
211
  redirect_url="https://yourapp.com/callback",
212
212
  platforms=["tiktok", "instagram"],
213
+ # Optional: force the connection page language for this profile.
214
+ # Supported: "en", "es", "de", "fr", "pt". When omitted, the page
215
+ # auto-detects the visitor's browser language and falls back to English.
216
+ language="es",
213
217
  )
214
218
  ```
215
219
 
@@ -223,6 +227,23 @@ analytics = client.get_analytics(
223
227
  print(analytics)
224
228
  ```
225
229
 
230
+ ### Get Media
231
+
232
+ Retrieve recent posts from a connected social account. Supported platforms:
233
+ `instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
234
+ `pinterest`, `bluesky`, `reddit`.
235
+
236
+ ```python
237
+ # Personal LinkedIn profile (default for non-org accounts):
238
+ media = client.get_media("linkedin", "my-profile")
239
+
240
+ # Force the personal profile of an account connected as an org admin:
241
+ media = client.get_media("linkedin", "my-profile", page_urn="me")
242
+
243
+ # Target a specific LinkedIn organization page:
244
+ media = client.get_media("linkedin", "my-profile", page_urn="12345")
245
+ ```
246
+
226
247
  ### Helper Methods
227
248
 
228
249
  ```python
File without changes