Twitterいいね画像定期保存Bot

#イントロ

##ウマ娘っ!!
ケモミミストでありTwitterランドに生息している身としては
ウマ娘は今や生活必需コンテンツとなっている。
平日のお昼休み終了5分前、APEX初動落ち、
ありとあらゆるストレスを軽減する効力を持ち、いつかガンにも効くのは言うまでもないだろう。

尊い画像が無限に流れてくるTL、一つ一つの画像に合掌しているわけだが、
多すぎて見返せない。あれっ、ネイチャがトレーナー宅で同棲している激エモ漫画どこいった....
2次絵は一期一会、今保存しておかないと後々、神絵師垢が突然鍵垢にするかもしれないし、必ず見返せると保証できない。

##ゴール
* いいねした画像を定期的にチェックして、保存するBotの運用
* 保存した画像をGoogleフォトに保存、尊いアルバムを作成する

##対象読者
* 自分のいいね欄の絵でアルバムを作ってニヤニヤしたい人

##非対象読者
* TwitterAPIを使用するための導入手順が知りたい人
 * (はるか昔にdevアカウントを作っており、各種鍵が残ってたので今回はそれをそのまま使って作りました。私も今どうやって作るのか知りません... )

##最終的な運用システム
![2021-05-23 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216625/1dea636b-a5f4-6538-edc7-e233bfb8bef3.png)

なんか図に起こすとややっこしいことやってるような気がする。
毎時自分の最新いいね200件を取得して、画像であれば保存しまくる。
GoogleフォトにももちろんAPIは存在していて、それを叩くともっとスマートなんだけど、

1.RaspiにGoogleフォトを操作するための認証を通す手順がダルそう
2.わざわざいいね画像を拝みに行くためにRaspiのネットワークドライブにアクセスするラグを俺が許容できない

以上の理由により、ローカルにも画像を同期しておいて、アクセスも早くお手軽に拝めるようにしたいな...
ってことでこうなってる。

本記事では①に関しての説明が主となる。


 
#事前準備フェーズ

##使用ライブラリなど
* tweepy
    * twitterのAPIを簡単にキックできるようになるラッパー

```bash:HowToInstall
>pip install tweepy
```

* exiv2
    * 画像のexifをコマンドで書き換えるために使う(使い所は後述)

```bash:HowToInstall
>sudo apt-get install -y exiv2
```

##Googleフォトにアップするにあたって
###課題
普段の写真とかもGoogleフォトにアップロードして管理しているので、
何千枚もあるTwitterのいいね画像で、現実の写真が埋もれるのは困る。
###対策
いいね画像のexif情報上の撮影日を大昔に設定して、Googleフォト上のタイムラインで事実上の区分けを行う。
今回はいいね画像は2000年1月1日に撮影されたものとしてGoogleフォトにアップロードして、
現実の写真と棲み分けする。
技術的にはexiv2を使って、画像のメタデータを編集する。
(exif情報を扱うため、Twitterから画像を保存する際は拡張子はpngではなく、jpgにする必要がある)

```bash:撮影日変更
>exiv2 -M 'set Exif.Photo.DateTimeOriginal "2000:01:01 08:00:00" "test.jpg"'
```

##Twitter APIについて
###GET favorites/list
サンプルとして、いいね欄最新2件を要求したときのレスポンスJSONを以下に示す。
(一部畳んで表示している)
![2021-05-23 (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216625/87d2d0ac-ab8d-ab9f-602f-c3eb28f9a212.png)
.....つまり、extended_entities{}内のmedia[]プロパティ内に画像の情報があって、media_urlでjpgにアクセスできそう。

##仕様
###ファイル名フォーマットの決定

"ユーザ名__ツイートID.jpg"
にする。
もし、4枚画像がある場合、
"ユーザ名_ツイートID_0.jpg"～"ユーザ名_ツイートID_3.jpg"
として保存する。
これで、画像が投稿された実際のツイートにも行けるようにしておける。
ツイートURLは以下フォーマットで作成、アクセス可能。
https://twitter.com/i/web/status/ツイートID


#コード

```python:いいねダウンローダ

import os
import pprint
import time
import urllib
import re

import tweepy

consumer_key ="XXXXX"
consumer_secret ="XXXXX"
access_token="XXXXX"
access_token_secret ="XXXXX"
 
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# 画像の撮影日を2000/01/01 00:00 に設定する
def setExifDate(img, date):
    command = "exiv2 -M \'set Exif.Photo.DateTimeOriginal \"" + date + "\"\' " + "'" + img + "'"
    print(command)
    os.system(command)

# URLから画像をダウンロードする
def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file:
            data = web_file.read()
            with open(dst_path, mode='wb') as local_file:
                local_file.write(data)
    except urllib.error.URLError as e:
        print(e)

# 画像を保存するようのフォルダ作成
# 既に作成済みなら何もしない
try:
    os.makedirs("images/likes")
except:
    pass

# @hxbdy625のいいね欄から最新200件取得する、
likeList = api.favorites(screen_name='hxbdy625', count=200)

failue_tweet = []
dir_path = 'images/likes'
date = '2000:01:01 08:00:00'
for tweet in likeList:
    user  = tweet.user.screen_name
    page = 0
    print(user,':',tweet.id_str)
    try:
        # ツイートの内容にmediaエンティティが含まれている
        for data in tweet.extended_entities['media']:
            # 画像が2枚以上である場合、ファイル名の末尾に連番pageを付加する
            if(len(tweet.extended_entities['media']) > 1):
                if(data['type'] == 'photo'):
                    download_file(data['media_url'], '/'+dir_path+'/'+user+'_'+tweet.id_str+'_'+str(page)+'.jpg')
                    setExifDate('/'+dir_path+'/'+user+'_'+tweet.id_str+'_'+str(page)+'.jpg', date)
                    page += 1
　　　　　　# 画像が1枚
            else:
                if(data['type'] == 'photo'):
                    download_file(data['media_url'], '/'+dir_path+'/'+user+'_'+tweet.id_str+'.jpg')
                    setExifDate('/'+dir_path+'/'+user+'_'+tweet.id_str+'.jpg', date)
    except AttributeError:
        msg = '[NotFoundImg] : https://twitter.com/i/web/status/'+ tweet.id_str+'\n'
        failue_tweet.append(msg)
        continue

f = open('error.txt','a')
f.writelines(failue_tweet)
f.close()

```

#実行結果
これを定期実行するとこんな感じで、Raspi内の保存フォルダ内に尊い画像が追加されていく。

https://twitter.com/hxbdy625/status/1392501060380413952?s=20

このフォルダをGoogleの「同期とバックアップ」を使って、Googleフォトに自動アップロードする。
以下、Googleフォトでアップロードを確認できたときのスクショ。一部隠したけど。
![2021-05-23 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216625/4fbe856f-6efd-103d-4d43-715d8713887b.png)
ちゃんと2000/01/01になってる!

で、Googleフォト内でTwitter用のアルバムを作って、楽しむ(手動。ここ自動化できねぇのか?)
![2021-05-23 (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216625/15591a0d-6a94-7767-380a-17437f76f316.png)

#参考
https://syncer.jp/Web/API/Twitter/REST_API/GET/favorites/list/