RFAの記録をネットでする。（Twitterだけでなく）

# RFA→Twitter→Simplenote（→Scrapbox）

## 初めに

日々リングフィットアドベンチャー（RFA）をやっていまして、その結果をRFAやSwitchだけに留めとくだけでは記録としてはもったいないので、ネットに上げたいと思いました。ただSwitchから直接アップロード出来るのはTwitterぐらい。（フェイスブックもあるけど笑）
Twitterだと垂れ流しには便利だけと記録には向いてないので、記録に向いているサービス、例えばSimplenoteやScrapboxにちゃんとタグとかリンクを付けて上げていくようにしたいと考えました。

## ロジック

+ RFA→Switch: プレイ後の記録のスクリーンショットをSwitchの機能で撮る。手動。
+ Switch→Twitter: ここはSwitchの機能でTwitterに上げる。手動。
+ **Twitter→Simplenote: ここが今回のメイン部分。自動。**
+ Simplenote→Scrapbox: ここも自動化したかった。コピペ手動。

というかTwitterからScrapboxに直接処理させたかったけど、Scrapboxのプログラム用APIが存在しないみたいで無理みたい。なのでSimplenoteからコピペしやすいように上のプログラムで整形させる。

## メイン部分のPythonプログラム

まずは結論から。これを実行すると対象のユーザーの直近のツイート郡からハッシュタグや画像が載ってる実行当日のツイートから画像のURLをコピーして整頓してSimplenoteに追加する。

```python:TwitterからSimplenoteに画像URLをコピーする
# -*- coding: utf-8 -*-

from configparser import ConfigParser
import urllib3
import json
from datetime import datetime, timezone
import time
import pytz
import simplenote

# TwitterAPIを使うための認証用トークンを読み込む
config = ConfigParser()
config.read('config.ini')
TW = 'Twitter'
BT = 'bearer_token'
USER = 'user_name'
bearer_token = config.get(TW, BT)
user_name = config.get(TW, USER)

http = urllib3.PoolManager()

# Twitterから検索して必要な情報を読み取る
def call_api(url:str, search_field:dict={}) -> dict:
    """
    param url              :  エンドポイントURL
    param search_field     :  検索用パラメータ
    return                 :  レスポンス内容
    """
    headers = {'Authorization': 'Bearer '+bearer_token}
    res = http.request(method='GET',
                       url=url,
                       headers=headers,
                       fields=search_field)
    if res.status != 200:
        raise urllib3.exceptions.HTTPError(res.status)
    return json.loads(res.data)

def change_timezone_day(created_at:str) -> str:
    """
    created_at          :TwitterAPIから取得した日時
                        :タイムゾーンが日本とは異なるため補正する
    return              :補正後の日にち
    """
    st = time.strptime(created_at, '%Y-%m-%dT%H:%M:%S.000Z')
    utc_daytime = datetime(st.tm_year,
                           st.tm_mon,
                           st.tm_mday,
                           st.tm_hour,
                           st.tm_min,
                           st.tm_sec,
                           tzinfo=timezone.utc)
    jst_daytime = utc_daytime.astimezone(pytz.timezone('Asia/Tokyo'))
    return_day = datetime.date(jst_daytime)
    return str(return_day)

# 必要なツイートを取得する。自分のアカウントのハッシュタグと画像が含まれている直近のツイートを探す
search_url = r'https://api.twitter.com/2/tweets/search/recent'
query = 'from:{user_name} #リングフィットアドベンチャー #RingFitAdventure #NintendoSwitch has:images'.format(user_name=user_name)
params = {
    'query': query,
    'expansions': 'attachments.media_keys',
    'tweet.fields' : 'created_at',
    'media.fields' : 'url',
}
result = call_api(url=search_url, search_field=params)

# 不要な日にちのツイートも含まれている可能性があるので、必要な日にち（基本今日）だけを取り出す
# その対象のツイートのmedia_keyだけ取り出す
today = datetime.date(datetime.today())
for tw_data in result['data']:
    created_at = change_timezone_day(tw_data['created_at'])
    if created_at == str(today):
        medias = tw_data['attachments']['media_keys']
        break

# media_keyから画像のURLを取り出す
setting_url = []
if 'medias' in locals():
    tweet_media_list = result['includes']['media']
    for media_key in medias:
        for item_media in tweet_media_list:
            if item_media['media_key'] == media_key:
                setting_url.append(item_media['url'])
                break

if len(setting_url) != 0:
    SN = 'Simplenote'
    SN_USER = 'user_name'
    SN_PASS = 'password'

    user = config.get(SN, SN_USER)
    password = config.get(SN, SN_PASS)
    sn = simplenote.Simplenote(user, password)

    str_today = today.strftime('%Y/%m/%d')

    sn_title = str_today + 'のRFA¥n'
    link_day = '[{day}]¥n'.format(day=str_today)
    link_RFA = '[リングフィット アドベンチャー]¥n'
    tags = '#任天堂¥n#NintendoSwitch¥n#ゲーム¥n#日記¥n¥n'

    note = """{day}のRFA
[{day}]
[リングフィット アドベンチャー]
#任天堂
#NintendoSwitch
#ゲーム
#日記
""".format(day=str_today)
    for su in setting_url:
        note += """[{url}]
""".format(url=su)

    sn.add_note(note=note)
```

## 個別のロジックの説明

### 1.Twitterの認証

``ConfigParser``を使ってiniファイルを読み込んで認証用のbearerトークンとTwitterユーザーを読み込むようにする。

```python:ConfigParserを使う
# TwitterAPIを使うための認証用トークンを読み込む
config = ConfigParser()
config.read('config.ini')
TW = 'Twitter'
BT = 'bearer_token'
USER = 'user_name'
bearer_token = config.get(TW, BT)
user_name = config.get(TW, USER)
```

### 2.Twitterから検索する

```python:
http = urllib3.PoolManager()

# Twitterから検索して必要な情報を読み取る
def call_api(url:str, search_field:dict={}) -> dict:
    """
    param url              :  エンドポイントURL
    param search_field     :  検索用パラメータ
    return                 :  レスポンス内容
    """
    headers = {'Authorization': 'Bearer '+bearer_token}
    res = http.request(method='GET',
                       url=url,
                       headers=headers,
                       fields=search_field)
    if res.status != 200:
        raise urllib3.exceptions.HTTPError(res.status)
    return json.loads(res.data)
```

### 3.Twitterから実際に必要な情報を取得する

ユーザー名とタグを指定して必要なつぶやきだけ取得する。

```python
# 必要なツイートを取得する。自分のアカウントのハッシュタグと画像が含まれている直近のツイートを探す
search_url = r'https://api.twitter.com/2/tweets/search/recent'
query = 'from:{user_name} #リングフィットアドベンチャー #RingFitAdventure #NintendoSwitch has:images'.format(user_name=user_name)
params = {
    'query': query,
    'expansions': 'attachments.media_keys',
    'tweet.fields' : 'created_at',
    'media.fields' : 'url',
}
result = call_api(url=search_url, search_field=params)
```

### 4.Twitterから取得した情報の日時を日本時間に修正する

取得した情報のタイムゾーンはUTCみたいなので、JSTに直す。

```python
def change_timezone_day(created_at:str) -> str:
    """
    created_at          :TwitterAPIから取得した日時
                        :タイムゾーンが日本とは異なるため補正する
    return              :補正後の日にち
    """
    st = time.strptime(created_at, '%Y-%m-%dT%H:%M:%S.000Z')
    utc_daytime = datetime(st.tm_year,
                           st.tm_mon,
                           st.tm_mday,
                           st.tm_hour,
                           st.tm_min,
                           st.tm_sec,
                           tzinfo=timezone.utc)
    jst_daytime = utc_daytime.astimezone(pytz.timezone('Asia/Tokyo'))
    return_day = datetime.date(jst_daytime)
    return str(return_day)
```

### 5.必要な情報だけ抜き出す

必要な日にち（基本実行当日）のRFAの結果画像が載っているつぶやきの画像URLだけ取得する。

```python
# 不要な日にちのツイートも含まれている可能性があるので、必要な日にち（基本今日）だけを取り出す
# その対象のツイートのmedia_keyだけ取り出す
today = datetime.date(datetime.today())
for tw_data in result['data']:
    created_at = change_timezone_day(tw_data['created_at'])
    if created_at == str(today):
        medias = tw_data['attachments']['media_keys']
        break

# media_keyから画像のURLを取り出す
setting_url = []
if 'medias' in locals():
    tweet_media_list = result['includes']['media']
    for media_key in medias:
        for item_media in tweet_media_list:
            if item_media['media_key'] == media_key:
                setting_url.append(item_media['url'])
                break
```

### 6.Simplenoteに書き出す

```python
if len(setting_url) != 0:
    SN = 'Simplenote'
    SN_USER = 'user_name'
    SN_PASS = 'password'

    user = config.get(SN, SN_USER)
    password = config.get(SN, SN_PASS)
    sn = simplenote.Simplenote(user, password)

    str_today = today.strftime('%Y/%m/%d')

    sn_title = str_today + 'のRFA¥n'
    link_day = '[{day}]¥n'.format(day=str_today)
    link_RFA = '[リングフィット アドベンチャー]¥n'
    tags = '#任天堂¥n#NintendoSwitch¥n#ゲーム¥n#日記¥n¥n'

    note = """{day}のRFA
[{day}]
[リングフィット アドベンチャー]
#任天堂
#NintendoSwitch
#ゲーム
#日記
""".format(day=str_today)
    for su in setting_url:
        note += """[{url}]
""".format(url=su)

    sn.add_note(note=note)
```