PythonエアプがTwitterアイコンにナイトモードを実装した話

#経緯
最近なんかUIでダークモードが流行ってますね！集中できるとか出来ないとか~~(僕はマジで集中出来ない)~~
最新のiOSやMacOS、Twitterアプリ等では自動でダークモードに切り替えてくれる機能もついていて~~こっちはちゃんと~~重宝してます
![スクリーンショット 2019-11-05 21.10.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292807/7da707b2-136f-727d-7b19-bb3803879ac9.png)

ところがダークモードに切り替えるとアイコンが真っ白でなんか浮いてしまっています！！！これはちょっと気になる...折角ならテーマと合わせて暗くしたい...
でも自動変更ごとにちまちまアップロードするのも手間だし...どうすれば...

#概要
茶番はこの辺で、大昔に取得したAPIキーを長らく放置しており折角なのでプロフィールアイコンを自動で変更してくれるプログラムを書いてみました。
当方クリエイターでPython自体がエアプなので至らぬ点が死ぬほどあるかと思いますが暖かい目で読んでいただけると幸いです。

#環境
- Mac OS 10.15 Catalina (Public Beta 9)
- Python 3.6.6

#事前準備
Twitter APIの申請を通している前提で続けます。[こちら](https://qiita.com/kngsym2018/items/2524d21455aac111cdee)など参照してください。

###画像の用意
通常モードとナイトモード用のプロフィールをそれぞれ用意しました。色調反転くらいならPythonでも出来そうな気がしなくもないですがそれは別の時にやってみます。
![day.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292807/91337936-48a4-7b53-5b88-d59c410ed389.jpeg)　![night.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292807/39dbc98f-1abb-468a-b10d-80a5d72f0ae7.jpeg)

###パッケージの導入
pipを用いてパッケージをインストールします。

```
% pip install requests requests-oauthlib
```

###APIトークンの記載
`config.py`を用意し、[Twitter Developers/App](https://developer.twitter.com/en/apps)`Details→keys and tokens`の各トークンを記載します。

```python:config.py
CONSUMER_KEY = "xxxxx" #API key
CONSUMER_SECRET = "xxxxx" #API secret key
ACCESS_TOKEN = "xxxxx" #access token
ACCESS_TOKEN_SECRET = "xxxxx" #access token secret
```

#コード

```python:main.py
#パッケージのインポート
import json, config, sys, os, datetime
from requests_oauthlib import OAuth1Session

#トークン
CK = config.CONSUMER_KEY
CS = config.CONSUMER_SECRET
AT = config.ACCESS_TOKEN
ATS = config.ACCESS_TOKEN_SECRET

twitter = OAuth1Session(CK, CS, AT, ATS)
#プロフィール画像の変更用のエンドポイント
url = "https://api.twitter.com/1.1/account/update_profile_image.json"
#現在時間の取得
ctime = datetime.datetime.now()

#現在時間が朝7時の場合の命令
if ctime.hour == 22:
    files = {"image": open("day.jpg", 'rb')}
    update_profile = twitter.post(url, files = files)
    print("change to day mode")
    if update_profile.status_code != 200:
        print("FAILED... :( ")
#現在時間が17時の場合の命令(ダークモードへ変更)
elif ctime.hour == 8:
    files = {"image": open("night.jpg", 'rb')}
    update_profile = twitter.post(url, files = files)
    print("changed to night mode")
    if update_profile.status_code != 200:
        print("FAILED... :( ")

#それ以外の場合(多分なくて大丈夫)
else:
    print("good night :)")
    sys.exit()
```

##プチ解説
cronでぶん回す前提で実行時点での時間をもとにifで命令を分けるプログラムとなっております。CircleCI(後述)のcronがUTCらしいので注意です。
GitHubのプライベートリポジトリを使わないとトークンが丸見えになるので環境変数を使ってあげた方がいいかもしれません。

#CircleCIにデプロイ
自分がCircleCIのシステムをほぼ全く理解していなかったためこの辺でずっとハマってました。

##各ファイルの準備

###パッケージの指定 → requirements.txt
使用したパッケージ名を記述するとCircleCI側にもインストールしてくれます。

```requirements.txt
requests
requests_oauthlib
```

###コマンドなどの宣言 → ~/.circleci/config.yml
これは何
現在進行形で記法を理解していないので深い解説はできません。友人に手伝ってもらいました。いじめないで下さい...
これはマジで何...

```yml:config.yml
version: 2
jobs:
  build: #ディレクトリを指定します。適宜変更してください。
    working_directory: ~/yourdirectory
    docker: #Pythonのバージョンを指定します。
       - image: circleci/python:3.6.6
    steps:
      - checkout
      - run:
          command: | #実行するコマンドを記述します。pipenvでパッケージをとってきます。
            sudo pip install pipenv
            sudo pipenv install -r ./requirements.txt
            sudo pipenv run python3 main.py

workflows:
  version: 2
  build_workflow:
    triggers:
      - schedule: #実行時間を記述します。UTCなので注意
          cron: "0 8,22 * * *"
          filters:
            branches:
              only: #ブランチを指定します。
                - master
    jobs:
      - build
```

##ディレクトリ
画像くらいはディレクトリ作ってまとめてあげた方が良かったかも...

```
root/
├ main.py
├ config.py
├ day.jpg
├ night.jpg
├ requirements.txt
└ .circleci/
  └config.yml
```

#動作結果
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">撮れた📹 <a href="https://t.co/eRogZgX3qE">https://t.co/eRogZgX3qE</a> <a href="https://t.co/ET4xyClGzi">pic.twitter.com/ET4xyClGzi</a></p>&mdash; Oblivion //依頼⭕️ (@OblivionMGD) <a href="https://twitter.com/OblivionMGD/status/1181857288941817856?ref_src=twsrc%5Etfw">October 9, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
動画内の時点ではHerokuで動かしてますがちゃんと動かせてます。中身は大体一緒です。~~24時間プログラムを回し続けるのはアホだった~~
ビルドに30secほどかかるのでパッケージをキャッシュしてあげると実行時間を短縮できるかもしれません。

#まとめ
一応思ってた感じのプログラムが書けました。今もちゃんと使っています。
Twitter APIの扱い方がわかってなかったりpipenvがちゃんと分かってなかったりで右往左往したので日頃のコーディングは大事だなという感じです...
ただ試行錯誤しながら自分のニーズにあったプロダクトを作るのも案外楽しいですね！
また痒いところを掻きたくなったら挑戦してみようと思います。
ではでは:wave: