upload-post 2.1.0__tar.gz → 2.2.0__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.
- {upload_post-2.1.0 → upload_post-2.2.0}/PKG-INFO +18 -1
- {upload_post-2.1.0 → upload_post-2.2.0}/README.md +17 -0
- {upload_post-2.1.0 → upload_post-2.2.0}/setup.py +1 -1
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post/__init__.py +1 -1
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post/api_client.py +212 -8
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post.egg-info/PKG-INFO +18 -1
- {upload_post-2.1.0 → upload_post-2.2.0}/setup.cfg +0 -0
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post/cli.py +0 -0
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post.egg-info/SOURCES.txt +0 -0
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post.egg-info/dependency_links.txt +0 -0
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post.egg-info/requires.txt +0 -0
- {upload_post-2.1.0 → upload_post-2.2.0}/upload_post.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: upload-post
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
@@ -223,6 +223,23 @@ analytics = client.get_analytics(
|
|
|
223
223
|
print(analytics)
|
|
224
224
|
```
|
|
225
225
|
|
|
226
|
+
### Get Media
|
|
227
|
+
|
|
228
|
+
Retrieve recent posts from a connected social account. Supported platforms:
|
|
229
|
+
`instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
|
|
230
|
+
`pinterest`, `bluesky`, `reddit`.
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# Personal LinkedIn profile (default for non-org accounts):
|
|
234
|
+
media = client.get_media("linkedin", "my-profile")
|
|
235
|
+
|
|
236
|
+
# Force the personal profile of an account connected as an org admin:
|
|
237
|
+
media = client.get_media("linkedin", "my-profile", page_urn="me")
|
|
238
|
+
|
|
239
|
+
# Target a specific LinkedIn organization page:
|
|
240
|
+
media = client.get_media("linkedin", "my-profile", page_urn="12345")
|
|
241
|
+
```
|
|
242
|
+
|
|
226
243
|
### Helper Methods
|
|
227
244
|
|
|
228
245
|
```python
|
|
@@ -185,6 +185,23 @@ analytics = client.get_analytics(
|
|
|
185
185
|
print(analytics)
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
+
### Get Media
|
|
189
|
+
|
|
190
|
+
Retrieve recent posts from a connected social account. Supported platforms:
|
|
191
|
+
`instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
|
|
192
|
+
`pinterest`, `bluesky`, `reddit`.
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
# Personal LinkedIn profile (default for non-org accounts):
|
|
196
|
+
media = client.get_media("linkedin", "my-profile")
|
|
197
|
+
|
|
198
|
+
# Force the personal profile of an account connected as an org admin:
|
|
199
|
+
media = client.get_media("linkedin", "my-profile", page_urn="me")
|
|
200
|
+
|
|
201
|
+
# Target a specific LinkedIn organization page:
|
|
202
|
+
media = client.get_media("linkedin", "my-profile", page_urn="12345")
|
|
203
|
+
```
|
|
204
|
+
|
|
188
205
|
### Helper Methods
|
|
189
206
|
|
|
190
207
|
```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.
|
|
8
|
+
version="2.2.0",
|
|
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)",
|
|
@@ -183,7 +183,7 @@ class UploadPostClient:
|
|
|
183
183
|
if kwargs.get("photo_cover_index") is not None:
|
|
184
184
|
data.append(("photo_cover_index", str(kwargs["photo_cover_index"])))
|
|
185
185
|
|
|
186
|
-
def _add_instagram_params(self, data: List[tuple], is_video: bool = True, **kwargs):
|
|
186
|
+
def _add_instagram_params(self, data: List[tuple], is_video: bool = True, files: List[tuple] | None = None, **kwargs):
|
|
187
187
|
"""Add Instagram-specific parameters."""
|
|
188
188
|
if kwargs.get("media_type"):
|
|
189
189
|
data.append(("media_type", kwargs["media_type"]))
|
|
@@ -193,18 +193,26 @@ class UploadPostClient:
|
|
|
193
193
|
data.append(("user_tags", kwargs["user_tags"]))
|
|
194
194
|
if kwargs.get("location_id"):
|
|
195
195
|
data.append(("location_id", kwargs["location_id"]))
|
|
196
|
-
|
|
196
|
+
|
|
197
197
|
if is_video:
|
|
198
198
|
if kwargs.get("share_to_feed") is not None:
|
|
199
199
|
data.append(("share_to_feed", str(kwargs["share_to_feed"]).lower()))
|
|
200
200
|
if kwargs.get("cover_url"):
|
|
201
|
-
|
|
201
|
+
cover_val = str(kwargs["cover_url"])
|
|
202
|
+
if cover_val.lower().startswith(("http://", "https://")):
|
|
203
|
+
data.append(("cover_url", cover_val))
|
|
204
|
+
elif files is not None:
|
|
205
|
+
cover_path = Path(cover_val)
|
|
206
|
+
if cover_path.exists():
|
|
207
|
+
files.append(("cover_image", (cover_path.name, cover_path.open("rb"))))
|
|
208
|
+
else:
|
|
209
|
+
data.append(("cover_url", cover_val))
|
|
202
210
|
if kwargs.get("audio_name"):
|
|
203
211
|
data.append(("audio_name", kwargs["audio_name"]))
|
|
204
212
|
if kwargs.get("thumb_offset"):
|
|
205
213
|
data.append(("thumb_offset", kwargs["thumb_offset"]))
|
|
206
214
|
|
|
207
|
-
def _add_youtube_params(self, data: List[tuple], **kwargs):
|
|
215
|
+
def _add_youtube_params(self, data: List[tuple], files: List[tuple] = None, **kwargs):
|
|
208
216
|
"""Add YouTube-specific parameters."""
|
|
209
217
|
if kwargs.get("tags"):
|
|
210
218
|
tags = kwargs["tags"]
|
|
@@ -240,6 +248,21 @@ class UploadPostClient:
|
|
|
240
248
|
data.append(("hasPaidProductPlacement", str(kwargs["hasPaidProductPlacement"]).lower()))
|
|
241
249
|
if kwargs.get("recordingDate"):
|
|
242
250
|
data.append(("recordingDate", kwargs["recordingDate"]))
|
|
251
|
+
if kwargs.get("subtitles"):
|
|
252
|
+
for idx, sub in enumerate(kwargs["subtitles"]):
|
|
253
|
+
if sub.get("language"):
|
|
254
|
+
data.append((f"youtube_subtitle_language_{idx}", sub["language"]))
|
|
255
|
+
if sub.get("name"):
|
|
256
|
+
data.append((f"youtube_subtitle_name_{idx}", sub["name"]))
|
|
257
|
+
if sub.get("file"):
|
|
258
|
+
sub_path = Path(sub["file"])
|
|
259
|
+
if sub_path.exists() and files is not None:
|
|
260
|
+
files.append((f"youtube_subtitle_file_{idx}", (sub_path.name, sub_path.open("rb"))))
|
|
261
|
+
else:
|
|
262
|
+
# Treat as URL string
|
|
263
|
+
data.append((f"youtube_subtitle_file_{idx}", str(sub["file"])))
|
|
264
|
+
elif sub.get("url"):
|
|
265
|
+
data.append((f"youtube_subtitle_file_{idx}", sub["url"]))
|
|
243
266
|
|
|
244
267
|
def _add_linkedin_params(self, data: List[tuple], is_text: bool = False, **kwargs):
|
|
245
268
|
"""Add LinkedIn-specific parameters."""
|
|
@@ -399,7 +422,7 @@ class UploadPostClient:
|
|
|
399
422
|
media_type: REELS or STORIES
|
|
400
423
|
share_to_feed: Share to feed
|
|
401
424
|
collaborators: Comma-separated collaborator usernames
|
|
402
|
-
cover_url: Custom cover URL
|
|
425
|
+
cover_url: Custom cover URL or file path. URLs are sent directly; file paths are uploaded as binary.
|
|
403
426
|
audio_name: Audio track name
|
|
404
427
|
user_tags: Comma-separated user tags
|
|
405
428
|
location_id: Location ID
|
|
@@ -421,7 +444,9 @@ class UploadPostClient:
|
|
|
421
444
|
blockedCountries: Comma-separated country codes
|
|
422
445
|
hasPaidProductPlacement: Paid placement flag
|
|
423
446
|
recordingDate: Recording date (ISO 8601)
|
|
424
|
-
|
|
447
|
+
subtitles: List of subtitle dicts with keys: language (BCP-47),
|
|
448
|
+
name (display name), file (path to SRT/VTT file), url (subtitle URL)
|
|
449
|
+
|
|
425
450
|
LinkedIn:
|
|
426
451
|
visibility: PUBLIC, CONNECTIONS, LOGGED_IN, CONTAINER
|
|
427
452
|
target_linkedin_page_id: Page ID for organization posts
|
|
@@ -479,9 +504,9 @@ class UploadPostClient:
|
|
|
479
504
|
if "tiktok" in platforms:
|
|
480
505
|
self._add_tiktok_params(data, is_video=True, **kwargs)
|
|
481
506
|
if "instagram" in platforms:
|
|
482
|
-
self._add_instagram_params(data, is_video=True, **kwargs)
|
|
507
|
+
self._add_instagram_params(data, is_video=True, files=files, **kwargs)
|
|
483
508
|
if "youtube" in platforms:
|
|
484
|
-
self._add_youtube_params(data, **kwargs)
|
|
509
|
+
self._add_youtube_params(data, files=files, **kwargs)
|
|
485
510
|
if "linkedin" in platforms:
|
|
486
511
|
self._add_linkedin_params(data, **kwargs)
|
|
487
512
|
if "facebook" in platforms:
|
|
@@ -937,6 +962,25 @@ class UploadPostClient:
|
|
|
937
962
|
"""
|
|
938
963
|
return self._request(f"/uploadposts/post-analytics/{request_id}", "GET")
|
|
939
964
|
|
|
965
|
+
def get_post_analytics_by_platform_id(self, platform_post_id: str, platform: str, user: str) -> Dict:
|
|
966
|
+
"""
|
|
967
|
+
Get analytics for any post (including organic posts) using its native platform ID.
|
|
968
|
+
|
|
969
|
+
Args:
|
|
970
|
+
platform_post_id: The native post ID on the platform (e.g., Instagram media ID).
|
|
971
|
+
platform: The platform to query (instagram, youtube, tiktok, facebook, linkedin, x, threads, pinterest, reddit).
|
|
972
|
+
user: The profile_username that owns the social account.
|
|
973
|
+
|
|
974
|
+
Returns:
|
|
975
|
+
Post analytics with live per-post metrics from the platform API.
|
|
976
|
+
"""
|
|
977
|
+
params = {
|
|
978
|
+
"platform_post_id": platform_post_id,
|
|
979
|
+
"platform": platform,
|
|
980
|
+
"user": user,
|
|
981
|
+
}
|
|
982
|
+
return self._request("/uploadposts/post-analytics", "GET", params=params)
|
|
983
|
+
|
|
940
984
|
def get_platform_metrics(self) -> Dict:
|
|
941
985
|
"""
|
|
942
986
|
Get available metrics configuration for all supported platforms.
|
|
@@ -946,6 +990,30 @@ class UploadPostClient:
|
|
|
946
990
|
"""
|
|
947
991
|
return self._request("/uploadposts/platform-metrics", "GET")
|
|
948
992
|
|
|
993
|
+
def get_media(
|
|
994
|
+
self,
|
|
995
|
+
platform: str,
|
|
996
|
+
user: str,
|
|
997
|
+
page_urn: Optional[str] = None,
|
|
998
|
+
) -> Dict:
|
|
999
|
+
"""
|
|
1000
|
+
Retrieve recent media from a connected social account.
|
|
1001
|
+
|
|
1002
|
+
Args:
|
|
1003
|
+
platform: instagram, tiktok, youtube, linkedin, facebook, x,
|
|
1004
|
+
threads, pinterest, bluesky, or reddit.
|
|
1005
|
+
user: Profile username.
|
|
1006
|
+
page_urn: LinkedIn only. Numeric org ID, full URN, or ``"me"`` to
|
|
1007
|
+
force the personal profile of an org-admin account.
|
|
1008
|
+
|
|
1009
|
+
Returns:
|
|
1010
|
+
``{"success": True, "media": [...]}``.
|
|
1011
|
+
"""
|
|
1012
|
+
params: Dict[str, str] = {"platform": platform, "user": user}
|
|
1013
|
+
if page_urn:
|
|
1014
|
+
params["page_urn"] = page_urn
|
|
1015
|
+
return self._request("/uploadposts/media", "GET", params=params)
|
|
1016
|
+
|
|
949
1017
|
# ==================== Scheduled Posts ====================
|
|
950
1018
|
|
|
951
1019
|
def list_scheduled(self) -> Dict:
|
|
@@ -1089,6 +1157,66 @@ class UploadPostClient:
|
|
|
1089
1157
|
"""
|
|
1090
1158
|
return self._request("/uploadposts/users/validate-jwt", "POST", json_data={"jwt": jwt})
|
|
1091
1159
|
|
|
1160
|
+
def get_user_preferences(self) -> Dict:
|
|
1161
|
+
"""
|
|
1162
|
+
Get user preferences (including calendar settings).
|
|
1163
|
+
|
|
1164
|
+
Returns:
|
|
1165
|
+
User preferences including week_start_day.
|
|
1166
|
+
"""
|
|
1167
|
+
return self._request("/uploadposts/users/preferences", "GET")
|
|
1168
|
+
|
|
1169
|
+
def update_user_preferences(
|
|
1170
|
+
self,
|
|
1171
|
+
week_start_day: Optional[int] = None
|
|
1172
|
+
) -> Dict:
|
|
1173
|
+
"""
|
|
1174
|
+
Update user preferences (including calendar settings).
|
|
1175
|
+
|
|
1176
|
+
Args:
|
|
1177
|
+
week_start_day: Week start day (0=Sunday, 1=Monday).
|
|
1178
|
+
|
|
1179
|
+
Returns:
|
|
1180
|
+
Updated preferences.
|
|
1181
|
+
"""
|
|
1182
|
+
body: Dict[str, Any] = {}
|
|
1183
|
+
if week_start_day is not None:
|
|
1184
|
+
body["week_start_day"] = week_start_day
|
|
1185
|
+
return self._request("/uploadposts/users/preferences", "POST", json_data=body)
|
|
1186
|
+
|
|
1187
|
+
def get_notification_config(self) -> Dict:
|
|
1188
|
+
"""
|
|
1189
|
+
Get notification configuration (including webhook settings).
|
|
1190
|
+
|
|
1191
|
+
Returns:
|
|
1192
|
+
Notification config including webhook_events and webhook_url.
|
|
1193
|
+
"""
|
|
1194
|
+
return self._request("/uploadposts/notification-config", "GET")
|
|
1195
|
+
|
|
1196
|
+
def update_notification_config(
|
|
1197
|
+
self,
|
|
1198
|
+
webhook_events: Optional[List[str]] = None,
|
|
1199
|
+
webhook_url: Optional[str] = None
|
|
1200
|
+
) -> Dict:
|
|
1201
|
+
"""
|
|
1202
|
+
Update notification configuration (including webhook settings).
|
|
1203
|
+
|
|
1204
|
+
Args:
|
|
1205
|
+
webhook_events: Webhook event types to subscribe to
|
|
1206
|
+
(upload_completed, social_account_connected,
|
|
1207
|
+
social_account_disconnected, social_account_reauth_required).
|
|
1208
|
+
webhook_url: Webhook URL for notifications.
|
|
1209
|
+
|
|
1210
|
+
Returns:
|
|
1211
|
+
Updated notification config.
|
|
1212
|
+
"""
|
|
1213
|
+
body: Dict[str, Any] = {}
|
|
1214
|
+
if webhook_events:
|
|
1215
|
+
body["webhook_events"] = webhook_events
|
|
1216
|
+
if webhook_url:
|
|
1217
|
+
body["webhook_url"] = webhook_url
|
|
1218
|
+
return self._request("/uploadposts/notification-config", "POST", json_data=body)
|
|
1219
|
+
|
|
1092
1220
|
# ==================== Helper Endpoints ====================
|
|
1093
1221
|
|
|
1094
1222
|
def get_facebook_pages(self, profile: Optional[str] = None) -> Dict:
|
|
@@ -1130,6 +1258,82 @@ class UploadPostClient:
|
|
|
1130
1258
|
params = {"profile": profile} if profile else None
|
|
1131
1259
|
return self._request("/uploadposts/pinterest/boards", "GET", params=params)
|
|
1132
1260
|
|
|
1261
|
+
# ==================== Instagram Comments ====================
|
|
1262
|
+
|
|
1263
|
+
def get_post_comments(
|
|
1264
|
+
self,
|
|
1265
|
+
user: str,
|
|
1266
|
+
post_id: Optional[str] = None,
|
|
1267
|
+
post_url: Optional[str] = None
|
|
1268
|
+
) -> Dict:
|
|
1269
|
+
"""
|
|
1270
|
+
Get comments on an Instagram post.
|
|
1271
|
+
|
|
1272
|
+
Args:
|
|
1273
|
+
user: Profile username.
|
|
1274
|
+
post_id: Numeric media ID (provide post_id or post_url).
|
|
1275
|
+
post_url: Full Instagram post URL (provide post_id or post_url).
|
|
1276
|
+
|
|
1277
|
+
Returns:
|
|
1278
|
+
Comments data including comment IDs, text, timestamps, and user info.
|
|
1279
|
+
"""
|
|
1280
|
+
params = {"platform": "instagram", "user": user}
|
|
1281
|
+
if post_id:
|
|
1282
|
+
params["post_id"] = post_id
|
|
1283
|
+
if post_url:
|
|
1284
|
+
params["post_url"] = post_url
|
|
1285
|
+
return self._request("/uploadposts/comments", "GET", params=params)
|
|
1286
|
+
|
|
1287
|
+
def reply_to_comment(
|
|
1288
|
+
self,
|
|
1289
|
+
user: str,
|
|
1290
|
+
comment_id: str,
|
|
1291
|
+
message: str
|
|
1292
|
+
) -> Dict:
|
|
1293
|
+
"""
|
|
1294
|
+
Send a private reply (DM) to the author of an Instagram comment.
|
|
1295
|
+
|
|
1296
|
+
Args:
|
|
1297
|
+
user: Profile username.
|
|
1298
|
+
comment_id: Comment ID from get_post_comments.
|
|
1299
|
+
message: Reply message text.
|
|
1300
|
+
|
|
1301
|
+
Returns:
|
|
1302
|
+
Reply result with recipient_id and message_id.
|
|
1303
|
+
"""
|
|
1304
|
+
return self._request("/uploadposts/comments/reply", "POST", json_data={
|
|
1305
|
+
"platform": "instagram",
|
|
1306
|
+
"user": user,
|
|
1307
|
+
"comment_id": comment_id,
|
|
1308
|
+
"message": message
|
|
1309
|
+
})
|
|
1310
|
+
|
|
1311
|
+
def public_reply_to_comment(
|
|
1312
|
+
self,
|
|
1313
|
+
user: str,
|
|
1314
|
+
comment_id: str,
|
|
1315
|
+
message: str
|
|
1316
|
+
) -> Dict:
|
|
1317
|
+
"""
|
|
1318
|
+
Post a public reply to an Instagram comment (visible under the original comment).
|
|
1319
|
+
|
|
1320
|
+
Args:
|
|
1321
|
+
user: Profile username.
|
|
1322
|
+
comment_id: Comment ID from get_post_comments.
|
|
1323
|
+
message: Reply message text.
|
|
1324
|
+
|
|
1325
|
+
Returns:
|
|
1326
|
+
Reply result with the new comment ID.
|
|
1327
|
+
"""
|
|
1328
|
+
return self._request("/uploadposts/comments/public-reply", "POST", json_data={
|
|
1329
|
+
"platform": "instagram",
|
|
1330
|
+
"user": user,
|
|
1331
|
+
"comment_id": comment_id,
|
|
1332
|
+
"message": message
|
|
1333
|
+
})
|
|
1334
|
+
|
|
1335
|
+
# ==================== Google Business ====================
|
|
1336
|
+
|
|
1133
1337
|
def get_google_business_locations(self, profile: Optional[str] = None) -> Dict:
|
|
1134
1338
|
"""
|
|
1135
1339
|
Get Google Business Profile locations for a connected account.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: upload-post
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
@@ -223,6 +223,23 @@ analytics = client.get_analytics(
|
|
|
223
223
|
print(analytics)
|
|
224
224
|
```
|
|
225
225
|
|
|
226
|
+
### Get Media
|
|
227
|
+
|
|
228
|
+
Retrieve recent posts from a connected social account. Supported platforms:
|
|
229
|
+
`instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
|
|
230
|
+
`pinterest`, `bluesky`, `reddit`.
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# Personal LinkedIn profile (default for non-org accounts):
|
|
234
|
+
media = client.get_media("linkedin", "my-profile")
|
|
235
|
+
|
|
236
|
+
# Force the personal profile of an account connected as an org admin:
|
|
237
|
+
media = client.get_media("linkedin", "my-profile", page_urn="me")
|
|
238
|
+
|
|
239
|
+
# Target a specific LinkedIn organization page:
|
|
240
|
+
media = client.get_media("linkedin", "my-profile", page_urn="12345")
|
|
241
|
+
```
|
|
242
|
+
|
|
226
243
|
### Helper Methods
|
|
227
244
|
|
|
228
245
|
```python
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|