Pythonを使ってTwitterに長い動画を簡単に投稿する方法

# Tweepyは開発版しか動画投稿がサポートされていない
- [これ](https://github.com/tweepy/tweepy/pull/1486)を使うと投稿できるらしいが、まだpipには無い。色々調べたら結果的に遠回りになったがTweepy以外のほうが楽そうだったので情報をまとめる。
  - python-twitterを使って投稿する方法(おすすめ)
  - Twitterのエンドポイントにライブラリを使わないでやる方法(ひたすらダルい)

## python-twitterを使う

- `api.PostUpdate(status=text, media=mediaId)`のmediaにmp4のアドレスを指定しても30秒までなら何故かいけた。
  - 30秒以上の動画は分割して圧縮しなきゃならないらしい(後述処理でまんまそれをやっている)、python-twitterだと内部処理で行ってくれているらしい、非常にありがたい。
    - 欲を言うならステータス確認的なコードが欲しかった。 


```python
import twitter
# 認証
api = twitter.Api(consumer_key=baka,
                  consumer_secret=aho,
                  access_token_key=manuke,
                  access_token_secret=darazu)
# アップロード
mediaId = api.UploadMediaChunked(
    media="./a.mp4", media_category="tweet_video")
# 仕様です https://github.com/bear/python-twitter/issues/654
time.sleep(10)
# ツイート
api.PostUpdate(status=text, media=mediaId)
```

- 地味にByteIO型も対応しているのでFaaSでも安心！

```python
from io import BytesIO
import requests

movieUrl = "http://~~~~~~.mp4"
ioimg = requests.get(movieUrl)
upimg = BytesIO(ioimg.content)
upimg.mode = 'rb'
upimg.name = 'mobie.mp4'
# 可能
mediaId = api.UploadMediaChunked(
    media=upimg, media_category="tweet_video")
```

## 素でエンドポイントにPostする
- [解説動画](https://www.youtube.com/watch?v=vokoaSeY1SA)はあったがコードが無かった。
- [別コード](https://wolf-code.com/how-to-tweet-movie-on-twitter-by-python/)もある。

```python
from requests_oauthlib import OAuth1Session
import os

# ツイート用エンドポイント
twUrl = "https://api.twitter.com/1.1/statuses/update.json"
# メディア用エンドポイント
upUrl = "https://upload.twitter.com/1.1/media/upload.json"

# 認証
twitter = OAuth1Session(consumer_key, consumer_secret, access_key, access_secret)
# サイズ指定が必要なので後で使う
totalBytes = os.path.getsize("./a.mp4")

# ID取得
initParams = {
    "command": "INIT",
    "media_type": "video/mp4",
    "total_bytes": totalBytes,
    "media_category": "tweet_video"
}
initResponse = twitter.post(url=upUrl, data=initParams)
mediaId = initResponse.json()['media_id']

# 分割アップロード処理
segmentId = 0
bytesSent = 0
with open("./a.mp4") as f: #ByteIO型はgetsize含めて別に作りこみが必要
    while bytesSent < totalBytes:
        chunk = f.read(1*1024*1024)

        addParams = {
            "command": "APPEND",
            "media_id": mediaId,
            "segment_index": segmentId
        }

        files = {
            "media": chunk
        }

        appendResponse = twitter.post(url=upUrl, data=addParams, files=files)
        print(appendResponse)

        segmentId = segmentId + 1
        bytesSent = f.tell() # バイナリモードの時にファイルの先頭からのバイト数を返却する
        print("%s of %s bytes uploaded" % (str(bytesSent), str(totalBytes)))

    print("upload complete")

    # ファイナライズ処理
    finalizeParams = {
        "command": "FINALIZE",
        "media_id": mediaId
    }

    finalizeResponse = twitter.post(url=upUrl, data=finalizeParams)

    statusParams = {
        "command": "STATUS",
        "media_id": mediaId
    }

    statusResponse = twitter.get(url=upUrl, params=statusParams)
    print(statusResponse)
    processingInfo = statusResponse.json().get("processing_info", None)

    while processingInfo['state'] == 'in_progress':
        time.sleep(1)
        statusResponse = twitter.get(url=upUrl, params=statusParams)
        processingInfo = statusResponse.json().get("processing_info", None)
        print(processingInfo)

    # ツイートする
    params = {
        "status": "動画ツイート",
        "media_ids": mediaId
    }

    twitter.post(url=twUrl, data=params)

```