OSDN Git Service

[feature]ツイッターへの投稿処理をモジュールに分離
authorHabu <habu@users.sourceforge.jp>
Thu, 12 Apr 2018 14:41:36 +0000 (23:41 +0900)
committerHabu <habu@users.sourceforge.jp>
Thu, 12 Apr 2018 14:41:36 +0000 (23:41 +0900)
score/tools/tweet_score.cfg
score/tools/tweet_score.py
score/tools/twitter.py [new file with mode: 0644]

index 4b3b431..d08627f 100644 (file)
@@ -1,8 +1,8 @@
 [TwitterOAuth]
-client_key=XXXXXXXXXXXXXXXXXXXXXXXXX
-client_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-resource_owner_key=000000000000000000-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-resource_owner_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+consumer_key=XXXXXXXXXXXXXXXXXXXXXXXXX
+consumer_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+access_token=000000000000000000-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+access_token_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
 [ScoreDB]
 path=db/score.db
index feb2405..647b710 100755 (executable)
@@ -2,28 +2,6 @@
 # -*- coding: utf-8
 
 '''スコアをツイートする
-
-OSDNのサーバでrequests_oauthlibを使う方法のメモ
-
-1. 環境変数PYTHONUSERBASEでインストール先をWebコンテンツ上の任意のディレクトリに指定し、
-   pipに--userオプションをつけてインストールを実行
-   以下は /home/groups/h/he/hengband/htdocs/score/local 以下にインストールする例
-
-   `$ PYTHONUSERBASE=/home/groups/h/he/hengband/htdocs/score/local
-      pip install --user requests_oauthlib`
-
-2. パスは通っているはずなのにシステムにインストールされているrequestsとurllib3が何故か読み込みに失敗するので、
-   上でインストールしたディレクトリにコピーする
-
-   `$ cp -a /usr/lib/python2.7/dist-packages/requests
-      /usr/lib/python2.7/dist-packages/urllib3
-      /home/groups/h/he/hengband/htdocs/score/local/lib/python2.7/site-packages`
-
-3. sys.path.appendで上でインストールしたディレクトリにパスを通してからrequests_oauthlibをimportする
-
-   `import sys`
-   `sys.path.append('/home/groups/h/he/hengband/htdocs/score/local/lib/python2.7/site-packages')`
-   `import requests_oauthlib`
 '''
 
 import sys
@@ -32,6 +10,7 @@ import sqlite3
 import gzip
 import re
 import config
+import twitter
 
 
 def get_score_data(score_id):
@@ -137,7 +116,7 @@ def get_death_reason_detail(score_id):
     return match.group(1) if match else None
 
 
-def create_tweet(score_id):
+def create_score_tweet(score_id):
     '''ツイートするメッセージを生成する。
 
     Args:
@@ -207,37 +186,6 @@ def create_daily_stats_tweet(year, month, day):
     return tweet
 
 
-def tweet(tweet_contents):
-    '''ツイートする。
-
-    Args:
-        oauth: requests_oauthlib.OAuth1Sessionの引数に渡すOAuth認証パラメータ。
-        tweet_contents: ツイートする内容を表す文字列。
-    '''
-    from requests_oauthlib import OAuth1Session
-    from requests.adapters import HTTPAdapter
-    from requests import codes
-    from logging import getLogger
-    logger = getLogger(__name__)
-
-    twitter = OAuth1Session(**config.config['TwitterOAuth'])
-
-    url = "https://api.twitter.com/1.1/statuses/update.json"
-
-    params = {"status": tweet_contents}
-    twitter.mount("https://", HTTPAdapter(max_retries=5))
-
-    logger.info("Posting to Twitter...")
-    logger.info(u"Tweet contents:\n{}".format(tweet_contents))
-    res = twitter.post(url, params=params)
-
-    if res.status_code == codes.ok:
-        logger.info("Success.")
-    else:
-        logger.warning("Failed to post: {code}, {json}"
-                       .format(code=res.status_code, json=res.json()))
-
-
 def parse_option():
     '''コマンドライン引数をパースする。
 
@@ -308,16 +256,23 @@ if __name__ == '__main__':
                 target_datetime.day
             )
         else:
-            tweet_contents = create_tweet(options.score_id)
+            tweet_contents = create_score_tweet(options.score_id)
 
         if tweet_contents is None:
             logger.warning('No score data found.')
             sys.exit(1)
 
         if (options.dry_run):
-            print(tweet_contents.encode("UTF-8"))
+            if isinstance(tweet_contents, basestring):
+                tweet_contents = [tweet_contents]
+            for tw in tweet_contents:
+                print(tw.encode("UTF-8"))
         else:
-            tweet(tweet_contents)
+            twitter = twitter.Twitter(
+                logger=logger,
+                **config.config['TwitterOAuth']
+            )
+            twitter.post_tweet(tweet_contents)
     except Exception:
         from traceback import format_exc
         logger.critical(format_exc())
diff --git a/score/tools/twitter.py b/score/tools/twitter.py
new file mode 100644 (file)
index 0000000..cb08d1c
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+# -*- coding: utf-8
+
+'''ツイッタークラス
+
+OSDNのサーバでrequests_oauthlibを使う方法のメモ
+
+1. 環境変数PYTHONUSERBASEでインストール先をWebコンテンツ上の任意のディレクトリに指定し、
+   pipに--userオプションをつけてインストールを実行
+   以下は /home/groups/h/he/hengband/htdocs/score/local 以下にインストールする例
+
+   `$ PYTHONUSERBASE=/home/groups/h/he/hengband/htdocs/score/local
+      pip install --user requests_oauthlib`
+
+2. パスは通っているはずなのにシステムにインストールされているrequestsとurllib3が何故か読み込みに失敗するので、
+   上でインストールしたディレクトリにコピーする
+
+   `$ cp -a /usr/lib/python2.7/dist-packages/requests
+      /usr/lib/python2.7/dist-packages/urllib3
+      /home/groups/h/he/hengband/htdocs/score/local/lib/python2.7/site-packages`
+
+3. sys.path.appendで上でインストールしたディレクトリにパスを通してからrequests_oauthlibをimportする
+
+   `import sys`
+   `sys.path.append('/home/groups/h/he/hengband/htdocs/score/local/lib/python2.7/site-packages')`
+   `import requests_oauthlib`
+'''
+
+
+class Twitter:
+    def __init__(self,
+                 consumer_key, consumer_secret,
+                 access_token, access_token_secret,
+                 logger=None):
+        self.__oauth = {
+            'client_key': consumer_key,
+            'client_secret': consumer_secret,
+            'resource_owner_key': access_token,
+            'resource_owner_secret': access_token_secret,
+        }
+
+        from logging import getLogger
+        self.__logger = logger if logger else getLogger(__name__)
+
+    def post_tweet(self, tweet_contents):
+        '''ツイートを投稿する。
+
+        Args:
+            tweet_contents: ツイートする内容を表す文字列。または文字列の配列。
+                文字列の配列の場合、それぞれの内容を一連のスレッドとして投稿する。
+        '''
+        from requests_oauthlib import OAuth1Session
+        from requests.adapters import HTTPAdapter
+        from requests import codes
+
+        if isinstance(tweet_contents, basestring):
+            tweet_contents = [tweet_contents]
+
+        twitter = OAuth1Session(**self.__oauth)
+        twitter.mount("https://", HTTPAdapter(max_retries=5))
+
+        self.__logger.info("Posting to Twitter...")
+        in_reply_to_status_id = None
+        screen_name = None
+        for tw in tweet_contents:
+            if in_reply_to_status_id:
+                params = {"status":
+                          u"@{screen_name} {tw}"
+                          .format(screen_name=screen_name, tw=tw),
+                          "in_reply_to_status_id": in_reply_to_status_id}
+            else:
+                params = {"status": tw}
+
+            self.__logger.info(u"Tweet contents:\n{}".format(tw))
+            res = twitter.post(
+                "https://api.twitter.com/1.1/statuses/update.json",
+                params=params)
+
+            if res.status_code == codes['ok']:
+                self.__logger.info("Success.")
+                res_json = res.json()
+                in_reply_to_status_id = res_json["id"]
+                screen_name = res_json["user"]["screen_name"]
+            else:
+                self.__logger.warning(
+                    "Failed to post: {code}, {json}"
+                    .format(code=res.status_code, json=res.json()))
+
+
+def main():
+    import sys
+    import config
+
+    if len(sys.argv) < 3:
+        return
+
+    config.parse(sys.argv[1])
+
+    from logging import getLogger, StreamHandler, INFO
+    logger = getLogger(__name__)
+    logger.setLevel(INFO)
+    sh = StreamHandler()
+    logger.addHandler(sh)
+
+    twitter = Twitter(logger=logger, **config.config['TwitterOAuth'])
+    tweet_contents = [i.decode('UTF-8') for i in sys.argv[2:]]
+    twitter.post_tweet(tweet_contents)
+
+
+if __name__ == '__main__':
+    main()