upload-post 2.13.0__tar.gz → 2.14.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.13.0 → upload_post-2.14.0}/PKG-INFO +16 -1
- {upload_post-2.13.0 → upload_post-2.14.0}/README.md +15 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/setup.py +1 -1
- upload_post-2.14.0/tests/test_edit_scheduled.py +68 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/tests/test_parity_fields.py +0 -1
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post/__init__.py +1 -1
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post/api_client.py +60 -6
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post.egg-info/PKG-INFO +16 -1
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post.egg-info/SOURCES.txt +1 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/setup.cfg +0 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/tests/test_comments_audience.py +0 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post/cli.py +0 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post.egg-info/dependency_links.txt +0 -0
- {upload_post-2.13.0 → upload_post-2.14.0}/upload_post.egg-info/requires.txt +0 -0
- {upload_post-2.13.0 → upload_post-2.14.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.14.0
|
|
4
4
|
Summary: Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, Discord, Telegram, and X (Twitter)
|
|
5
5
|
Home-page: https://www.upload-post.com/
|
|
6
6
|
Author: Upload-Post
|
|
@@ -191,6 +191,21 @@ client.edit_scheduled(
|
|
|
191
191
|
timezone="America/New_York",
|
|
192
192
|
)
|
|
193
193
|
|
|
194
|
+
# Fix the text in place (only the platforms listed change)
|
|
195
|
+
client.edit_scheduled(
|
|
196
|
+
"job-id",
|
|
197
|
+
platform_content={"instagram": {"caption": "New Instagram caption"}},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Change any other option by its API form name (None removes it), schedule the
|
|
201
|
+
# video natively on YouTube, or replace the Reels cover
|
|
202
|
+
client.edit_scheduled(
|
|
203
|
+
"job-id",
|
|
204
|
+
fields={"privacyStatus": "unlisted", "disable_comment": True},
|
|
205
|
+
youtube_publish_at="2026-11-01T09:00:00Z",
|
|
206
|
+
cover_image_base64="data:image/jpeg;base64,...", # or remove_cover=True
|
|
207
|
+
)
|
|
208
|
+
|
|
194
209
|
# Cancel a scheduled post
|
|
195
210
|
client.cancel_scheduled("job-id")
|
|
196
211
|
```
|
|
@@ -153,6 +153,21 @@ client.edit_scheduled(
|
|
|
153
153
|
timezone="America/New_York",
|
|
154
154
|
)
|
|
155
155
|
|
|
156
|
+
# Fix the text in place (only the platforms listed change)
|
|
157
|
+
client.edit_scheduled(
|
|
158
|
+
"job-id",
|
|
159
|
+
platform_content={"instagram": {"caption": "New Instagram caption"}},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Change any other option by its API form name (None removes it), schedule the
|
|
163
|
+
# video natively on YouTube, or replace the Reels cover
|
|
164
|
+
client.edit_scheduled(
|
|
165
|
+
"job-id",
|
|
166
|
+
fields={"privacyStatus": "unlisted", "disable_comment": True},
|
|
167
|
+
youtube_publish_at="2026-11-01T09:00:00Z",
|
|
168
|
+
cover_image_base64="data:image/jpeg;base64,...", # or remove_cover=True
|
|
169
|
+
)
|
|
170
|
+
|
|
156
171
|
# Cancel a scheduled post
|
|
157
172
|
client.cancel_scheduled("job-id")
|
|
158
173
|
```
|
|
@@ -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.14.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, Discord, Telegram, and X (Twitter)",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""edit_scheduled must forward every editable part of the PATCH body.
|
|
2
|
+
|
|
3
|
+
The SDK builds the body from fixed arguments, so anything it does not map is
|
|
4
|
+
unreachable. No network: the session's PATCH is patched.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest
|
|
8
|
+
from unittest.mock import MagicMock, patch
|
|
9
|
+
|
|
10
|
+
from upload_post import UploadPostClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestEditScheduled(unittest.TestCase):
|
|
14
|
+
def setUp(self):
|
|
15
|
+
self.client = UploadPostClient("k")
|
|
16
|
+
response = MagicMock()
|
|
17
|
+
response.status_code = 200
|
|
18
|
+
response.json.return_value = {"success": True}
|
|
19
|
+
response.raise_for_status.return_value = None
|
|
20
|
+
self.patch = patch.object(self.client.session, "patch", return_value=response).start()
|
|
21
|
+
self.addCleanup(patch.stopall)
|
|
22
|
+
|
|
23
|
+
def body(self):
|
|
24
|
+
return self.patch.call_args.kwargs["json"]
|
|
25
|
+
|
|
26
|
+
def test_positional_date_and_timezone_still_work(self):
|
|
27
|
+
self.client.edit_scheduled("job1", "2026-11-01T09:00:00Z", "Europe/Madrid")
|
|
28
|
+
self.assertTrue(self.patch.call_args.args[0].endswith("/uploadposts/schedule/job1"))
|
|
29
|
+
self.assertEqual(self.body(), {"scheduled_date": "2026-11-01T09:00:00Z", "timezone": "Europe/Madrid"})
|
|
30
|
+
|
|
31
|
+
def test_text_and_platform_content(self):
|
|
32
|
+
pc = {"instagram": {"caption": "ig"}, "youtube": {"title": "yt"}}
|
|
33
|
+
self.client.edit_scheduled("job1", title="T", caption="C", platform_content=pc)
|
|
34
|
+
self.assertEqual(self.body(), {"title": "T", "caption": "C", "platform_content": pc})
|
|
35
|
+
|
|
36
|
+
def test_description_is_alias_and_caption_wins(self):
|
|
37
|
+
self.client.edit_scheduled("job1", description="D")
|
|
38
|
+
self.assertEqual(self.body(), {"description": "D"})
|
|
39
|
+
self.client.edit_scheduled("job1", caption="C", description="D")
|
|
40
|
+
self.assertEqual(self.body(), {"caption": "C"})
|
|
41
|
+
|
|
42
|
+
def test_fields_and_youtube_publish_at(self):
|
|
43
|
+
self.client.edit_scheduled(
|
|
44
|
+
"job1",
|
|
45
|
+
fields={"privacyStatus": "unlisted", "disable_comment": True, "cover_url": None,
|
|
46
|
+
"youtube_publish_at": "old"},
|
|
47
|
+
youtube_publish_at="2026-11-01T09:00:00Z",
|
|
48
|
+
)
|
|
49
|
+
self.assertEqual(self.body(), {"fields": {
|
|
50
|
+
"privacyStatus": "unlisted", "disable_comment": True, "cover_url": None,
|
|
51
|
+
"youtube_publish_at": "2026-11-01T09:00:00Z",
|
|
52
|
+
}})
|
|
53
|
+
|
|
54
|
+
def test_cover_and_its_removal(self):
|
|
55
|
+
self.client.edit_scheduled("job1", cover_image_base64="AAAA", cover_filename="c.png",
|
|
56
|
+
cover_content_type="image/png")
|
|
57
|
+
self.assertEqual(self.body(), {"cover_image_base64": "AAAA", "cover_filename": "c.png",
|
|
58
|
+
"cover_content_type": "image/png"})
|
|
59
|
+
self.client.edit_scheduled("job1", remove_cover=True, cover_image_base64="AAAA")
|
|
60
|
+
self.assertEqual(self.body(), {"remove_cover": True})
|
|
61
|
+
|
|
62
|
+
def test_empty_fields_are_not_sent(self):
|
|
63
|
+
self.client.edit_scheduled("job1", "2026-11-01T09:00:00Z", fields={})
|
|
64
|
+
self.assertEqual(self.body(), {"scheduled_date": "2026-11-01T09:00:00Z"})
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
unittest.main()
|
|
@@ -38,7 +38,6 @@ class TestVersions(unittest.TestCase):
|
|
|
38
38
|
match = re.search(r'version="([^"]*)"', text)
|
|
39
39
|
self.assertIsNotNone(match)
|
|
40
40
|
self.assertEqual(match.group(1), __version__)
|
|
41
|
-
self.assertEqual(__version__, "2.13.0")
|
|
42
41
|
|
|
43
42
|
|
|
44
43
|
class TestTikTokDraftAliases(unittest.TestCase):
|
|
@@ -1843,24 +1843,78 @@ class UploadPostClient:
|
|
|
1843
1843
|
self,
|
|
1844
1844
|
job_id: str,
|
|
1845
1845
|
scheduled_date: Optional[str] = None,
|
|
1846
|
-
timezone: Optional[str] = None
|
|
1846
|
+
timezone: Optional[str] = None,
|
|
1847
|
+
*,
|
|
1848
|
+
title: Optional[str] = None,
|
|
1849
|
+
caption: Optional[str] = None,
|
|
1850
|
+
description: Optional[str] = None,
|
|
1851
|
+
platform_content: Optional[Dict[str, Dict[str, str]]] = None,
|
|
1852
|
+
fields: Optional[Dict[str, Any]] = None,
|
|
1853
|
+
youtube_publish_at: Optional[str] = None,
|
|
1854
|
+
cover_image_base64: Optional[str] = None,
|
|
1855
|
+
cover_filename: Optional[str] = None,
|
|
1856
|
+
cover_content_type: Optional[str] = None,
|
|
1857
|
+
remove_cover: bool = False,
|
|
1847
1858
|
) -> Dict:
|
|
1848
1859
|
"""
|
|
1849
|
-
Edit a scheduled post.
|
|
1860
|
+
Edit a scheduled post (``PATCH /api/uploadposts/schedule/<job_id>``).
|
|
1861
|
+
|
|
1862
|
+
Every argument is optional; only what you pass is changed. The media,
|
|
1863
|
+
profile and platforms of a scheduled post cannot be edited.
|
|
1850
1864
|
|
|
1851
1865
|
Args:
|
|
1852
1866
|
job_id: Scheduled job ID.
|
|
1853
|
-
scheduled_date: New scheduled date (ISO 8601).
|
|
1854
|
-
timezone:
|
|
1867
|
+
scheduled_date: New scheduled date (ISO 8601), future and within 1 year.
|
|
1868
|
+
timezone: IANA timezone ``scheduled_date`` is read in (default UTC).
|
|
1869
|
+
title: New title for every platform of the post.
|
|
1870
|
+
caption: New caption/description for every platform of the post.
|
|
1871
|
+
description: Alias of ``caption`` (``caption`` wins if both are given).
|
|
1872
|
+
platform_content: Per-platform text, e.g.
|
|
1873
|
+
``{"instagram": {"caption": "..."}, "youtube": {"title": "..."}}``.
|
|
1874
|
+
Only the platforms listed are touched.
|
|
1875
|
+
fields: Any other editable upload option, keyed by its API form name
|
|
1876
|
+
(``privacyStatus``, ``tags``, ``disable_comment``,
|
|
1877
|
+
``instagram_first_comment``, ``gbp_cta_url``...). ``None`` as a
|
|
1878
|
+
value removes that option; unknown or internal keys are ignored.
|
|
1879
|
+
youtube_publish_at: Native YouTube scheduling (RFC3339), sent as
|
|
1880
|
+
``fields["youtube_publish_at"]``; wins over the same key in
|
|
1881
|
+
``fields``. To remove it pass ``fields={"youtube_publish_at": None}``.
|
|
1882
|
+
cover_image_base64: New cover image (Instagram / Facebook Reels) as
|
|
1883
|
+
base64 or a data URL.
|
|
1884
|
+
cover_filename: File name of the new cover (default ``cover.jpg``).
|
|
1885
|
+
cover_content_type: MIME type of the new cover (default ``image/jpeg``).
|
|
1886
|
+
remove_cover: Remove the custom cover (ignores ``cover_image_base64``).
|
|
1855
1887
|
|
|
1856
1888
|
Returns:
|
|
1857
|
-
Edit result
|
|
1889
|
+
Edit result (``success``, ``job_id``, and the new ``scheduled_date``,
|
|
1890
|
+
``title``, ``caption``, ``platform_content`` when they changed).
|
|
1858
1891
|
"""
|
|
1859
|
-
body = {}
|
|
1892
|
+
body: Dict[str, Any] = {}
|
|
1860
1893
|
if scheduled_date:
|
|
1861
1894
|
body["scheduled_date"] = scheduled_date
|
|
1862
1895
|
if timezone:
|
|
1863
1896
|
body["timezone"] = timezone
|
|
1897
|
+
if title is not None:
|
|
1898
|
+
body["title"] = title
|
|
1899
|
+
if caption is not None:
|
|
1900
|
+
body["caption"] = caption
|
|
1901
|
+
elif description is not None:
|
|
1902
|
+
body["description"] = description
|
|
1903
|
+
if platform_content:
|
|
1904
|
+
body["platform_content"] = platform_content
|
|
1905
|
+
edited_fields = dict(fields or {})
|
|
1906
|
+
if youtube_publish_at is not None:
|
|
1907
|
+
edited_fields["youtube_publish_at"] = youtube_publish_at
|
|
1908
|
+
if edited_fields:
|
|
1909
|
+
body["fields"] = edited_fields
|
|
1910
|
+
if remove_cover:
|
|
1911
|
+
body["remove_cover"] = True
|
|
1912
|
+
elif cover_image_base64:
|
|
1913
|
+
body["cover_image_base64"] = cover_image_base64
|
|
1914
|
+
if cover_filename:
|
|
1915
|
+
body["cover_filename"] = cover_filename
|
|
1916
|
+
if cover_content_type:
|
|
1917
|
+
body["cover_content_type"] = cover_content_type
|
|
1864
1918
|
return self._request(f"/uploadposts/schedule/{job_id}", "PATCH", json_data=body)
|
|
1865
1919
|
|
|
1866
1920
|
# ==================== User Management ====================
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: upload-post
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.14.0
|
|
4
4
|
Summary: Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, Discord, Telegram, and X (Twitter)
|
|
5
5
|
Home-page: https://www.upload-post.com/
|
|
6
6
|
Author: Upload-Post
|
|
@@ -191,6 +191,21 @@ client.edit_scheduled(
|
|
|
191
191
|
timezone="America/New_York",
|
|
192
192
|
)
|
|
193
193
|
|
|
194
|
+
# Fix the text in place (only the platforms listed change)
|
|
195
|
+
client.edit_scheduled(
|
|
196
|
+
"job-id",
|
|
197
|
+
platform_content={"instagram": {"caption": "New Instagram caption"}},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Change any other option by its API form name (None removes it), schedule the
|
|
201
|
+
# video natively on YouTube, or replace the Reels cover
|
|
202
|
+
client.edit_scheduled(
|
|
203
|
+
"job-id",
|
|
204
|
+
fields={"privacyStatus": "unlisted", "disable_comment": True},
|
|
205
|
+
youtube_publish_at="2026-11-01T09:00:00Z",
|
|
206
|
+
cover_image_base64="data:image/jpeg;base64,...", # or remove_cover=True
|
|
207
|
+
)
|
|
208
|
+
|
|
194
209
|
# Cancel a scheduled post
|
|
195
210
|
client.cancel_scheduled("job-id")
|
|
196
211
|
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|