Skip to content

Commit 7e3964f

Browse files
authored
Merge pull request #176 from MerleLiuKun/feat-media-upload
Feat media upload v2
2 parents 189a163 + 5ba120b commit 7e3964f

File tree

15 files changed

+584
-39
lines changed

15 files changed

+584
-39
lines changed

.github/workflows/docs.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ jobs:
77
deploy:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@v2
11-
- uses: actions/setup-python@v2
10+
- uses: actions/checkout@v4
11+
- uses: actions/setup-python@v5
1212
with:
13-
python-version: 3.8
13+
python-version: 3.12
1414
- run: pip install mkdocs-material
1515
- run: mkdocs gh-deploy -f docs/mkdocs.yml --force

.github/workflows/release.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ jobs:
77
build:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@v2
10+
- uses: actions/checkout@v4
1111
- name: Build and publish to pypi
12-
uses: JRubics/poetry-publish@v1.17
12+
uses: JRubics/poetry-publish@v2.1
1313
with:
1414
pypi_token: ${{ secrets.PYPI_TOKEN }}
1515

@@ -19,7 +19,7 @@ jobs:
1919
.github/hack/changelog.sh $VERSION > NEW-VERSION-CHANGELOG.md
2020
2121
- name: Publish
22-
uses: softprops/action-gh-release@v1
22+
uses: softprops/action-gh-release@v2
2323
with:
2424
body_path: NEW-VERSION-CHANGELOG.md
2525
files: 'python-twitter-*'

.github/workflows/test.yaml

+10-10
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
14+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
1515
include:
16-
- python-version: '3.10'
16+
- python-version: '3.12'
1717
update-coverage: true
1818

1919
steps:
20-
- uses: actions/checkout@v3
20+
- uses: actions/checkout@v4
2121
- name: Set up Python ${{ matrix.python-version }}
22-
uses: actions/setup-python@v4
22+
uses: actions/setup-python@v5
2323
with:
2424
python-version: ${{ matrix.python-version }}
2525
- name: Cache pip
26-
uses: actions/cache@v2
26+
uses: actions/cache@v4
2727
with:
2828
path: ~/.cache/pip
2929
key: ${{ matrix.python-version }}-poetry-${{ hashFiles('pyproject.toml') }}
@@ -48,15 +48,15 @@ jobs:
4848
runs-on: ubuntu-latest
4949

5050
steps:
51-
- uses: actions/checkout@v3
52-
- uses: actions/setup-python@v4
51+
- uses: actions/checkout@v4
52+
- uses: actions/setup-python@v5
5353
with:
54-
python-version: '3.10'
54+
python-version: '3.8'
5555
- name: Cache pip
56-
uses: actions/cache@v2
56+
uses: actions/cache@v4
5757
with:
5858
path: ~/.cache/pip
59-
key: lintenv-v2
59+
key: lintenv-v2-38
6060
- name: Install dependencies
6161
run: python -m pip install --upgrade pip black
6262
- name: Black test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
This guide will help you make your first requests to upload media using the X API v2 media upload endpoint(s).
2+
3+
You can get more information for this at [docs](https://docs.x.com/x-api/media/quickstart/media-upload-chunked)
4+
5+
For video or chunked uploads, you must:
6+
7+
1. Initialize the upload using the `INIT` command
8+
2. Upload each chunk of bytes using the `APPEND` command
9+
3. Complete the upload using the `FINALIZE` command
10+
11+
let's do it, Now we need to upload a big video with a filename `/path/to/video.mp4`
12+
13+
### Step 1: Initialize the upload
14+
15+
As first step, you need to initialize the upload.
16+
17+
```python
18+
19+
import os
20+
21+
filename = "/path/to/video.mp4"
22+
23+
init_resp = myapi.upload_media_chunked_init_v2(
24+
total_bytes=os.path.getsize(filename),
25+
media_type="video/mp4",
26+
media_category="tweet_video",
27+
)
28+
print(init_resp)
29+
# Response(data=MediaUpload(id='1912334964932374529', media_key='7_1912334964932374529', processing_info=None, image=None, video=None))
30+
```
31+
32+
### Step 2: Append the file by chunks
33+
34+
Once we have the media identifiers `id` from the `init_resp`, we can start uploading the file by chunks.
35+
36+
```python
37+
38+
media_id = init_resp.data.id
39+
40+
chunk_size = 2 * 1024 * 1024
41+
segment_index = 0
42+
with open(filename, "rb") as f:
43+
while True:
44+
chunk = f.read(chunk_size)
45+
if not chunk:
46+
break
47+
48+
chunk_resp = myapi.upload_media_chunked_append_v2(
49+
media_id=media_id,
50+
media=chunk,
51+
segment_index=segment_index,
52+
)
53+
print(chunk_resp)
54+
segment_index += 1
55+
56+
# True
57+
```
58+
59+
### Step 3: Finalize the upload
60+
61+
Everything is ok, we need finalize the upload.
62+
63+
```python
64+
finalize_resp = myapi.upload_media_chunked_finalize_v2(media_id=media_id)
65+
print(finalize_resp)
66+
# Response(data=MediaUpload(id='1912090619981471744', media_key='7_1912090619981471744', processing_info=MediaUploadResponseProcessingInfo(state='succeeded', check_after_secs=None, progress_percent=None, error=None), image=None, video=None))
67+
```
68+
69+
### Step 4 (Optional): Check the processing status
70+
71+
Once you have finalized the upload, you can check the processing status.
72+
73+
```python
74+
status_resp = myapi.upload_media_chunked_status_v2(media_id=media_id)
75+
print(status_resp)
76+
# Response(data=MediaUpload(id='1912090619981471744', media_key='7_1912090619981471744', processing_info=MediaUploadResponseProcessingInfo(state='succeeded', check_after_secs=None, progress_percent=100, error=None), image=None, video=None))
77+
```
78+
79+
### Step 5: Create tweet with media
80+
81+
Congratulations, you have uploaded a video using the X API v2 media upload endpoint(s).
82+
83+
Now we can create a tweet with this video.
84+
85+
```python
86+
tweet_resp = myapi.create_tweet(text="My first tweet with a video", media_media_ids=[media_id])
87+
88+
# Tweet(id=1912338879258194343, text=My first tweet with a video...)
89+
```
90+
91+
Enjoy it!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
You can use media upload endpoint to upload simple media, images(gifs).
2+
3+
You can get more information for this at [docs](https://docs.x.com/x-api/media/media-upload)
4+
5+
## upload simple
6+
7+
```python
8+
9+
with open("path/to/image", "rb") as media:
10+
resp = my_api.upload_media_simple_v2(media=media)
11+
print(resp)
12+
```
13+

docs/mkdocs.yml

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ nav:
3737
- Media Upload:
3838
- Simple Upload: usage/media-upload/simple-upload.md
3939
- Chunked Upload: usage/media-upload/chunked-upload.md
40+
41+
- Media Upload V2:
42+
- Simple Upload: usage/media-upload-v2/simple-upload.md
43+
- Chunked Upload: usage/media-upload-v2/chunked-upload.md
4044
- Tweets:
4145
- Tweet Lookup: usage/tweets/tweet-lookup.md
4246
- Manage Tweets: usage/tweets/tweet-manage.md

examples/media_upload_v2.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Upload a video with media upload v2
3+
"""
4+
5+
import os
6+
7+
from pytwitter import Api
8+
9+
consumer_key = "your app consumer key"
10+
consumer_secret = "your app consumer secret"
11+
access_token = "your access token"
12+
access_secret = "your access token secret"
13+
14+
# init api with OAuth1.0
15+
api = Api(
16+
consumer_key=consumer_key,
17+
consumer_secret=consumer_secret,
18+
access_token=access_token,
19+
access_secret=access_secret,
20+
)
21+
22+
video_path = "path/to/video.mp4"
23+
24+
# init media upload
25+
26+
init_resp = api.upload_media_chunked_init_v2(
27+
total_bytes=os.path.getsize(video_path),
28+
media_type="video/mp4",
29+
media_category="tweet_video",
30+
)
31+
32+
print(f"Init response: {init_resp}")
33+
34+
# upload by chunk
35+
chunk_size = 1024 * 1024 * 1
36+
segment_index = 0
37+
38+
with open(video_path, "rb") as f:
39+
while True:
40+
chunk = f.read(chunk_size)
41+
if not chunk:
42+
break
43+
44+
chunk_resp = api.upload_media_chunked_append_v2(
45+
media_id=init_resp.data.id,
46+
segment_index=segment_index,
47+
media=chunk,
48+
)
49+
print(f"Chunk response: {chunk_resp}")
50+
51+
print("Finished chunk upload")
52+
53+
# finalize upload
54+
finalize_resp = api.upload_media_chunked_finalize_v2(
55+
media_id=init_resp.data.id,
56+
)
57+
print(f"Finalize response: {finalize_resp}")
58+
59+
# Now you can use the media to create tweet
60+
tweet_resp = api.create_tweet(
61+
text="Tweet with video", media_media_ids=[init_resp.data.id]
62+
)
63+
64+
print(f"Tweet response: {tweet_resp}")

0 commit comments

Comments
 (0)