-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpost-scheduled-tweets.py
129 lines (105 loc) · 4.78 KB
/
post-scheduled-tweets.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#
# Script to tweet tweets which have been
# scheduled.
#
#
# Version: 1.0
#
from schtweet.storage import TweetStore
from collections import namedtuple
import io
import argparse
import twitter
import shutil
import os
AccessInformation = namedtuple('AccessInformation',
'consumer_key, consumer_secret, access_token_key, access_token_secret')
NO_POST = False
VERBOSE = False
def verbose_log(message):
if VERBOSE:
print(message)
def fetch_access_information(access_file):
"""Loads access information from a file."""
with io.open(access_file, 'r', encoding='utf8') as file:
line = file.readline()
line = ' '.join(line.split())
parts = line.split(' ')
if not len(parts) == 4:
raise SystemExit('Could to read all parts from {}. Expected line with: '
'<consumer_key> <consumer_secret> '
'<access_token_key> <access_token_secret>'.format(access_file))
return AccessInformation(parts[0], parts[1], parts[2], parts[3])
def post_tweets_from_file(storage_file, tokens):
verbose_log('Connecting with consumer_key="{}", '
'access_token_key="{}"'.format(tokens.consumer_key, tokens.access_token_key))
twitter_api = twitter.Api(**tokens._asdict())
processed_tweets = 0
sent_tweets = 0
def process_scheduled_tweet(tweet_text, scheduled_date):
verbose_log("Got tweet: '{}', due to be sent on {}".format(tweet_text, scheduled_date))
nonlocal processed_tweets
processed_tweets += 1
tweet_id = None
try:
status = None
if NO_POST:
print('Would have posted "{}"'.format(tweet_text))
else:
status = twitter_api.PostUpdate(tweet_text)
tweet_id = status.id_str
if status is not None:
nonlocal sent_tweets
sent_tweets += 1
except Exception as e:
print('Failed to send tweet "{}". Exception: {}'.format(tweet_text, e))
return tweet_id
with TweetStore(storage_file) as ts:
ts.process_due_tweets(process_scheduled_tweet)
print('Number of tweets processed: {}'.format(processed_tweets))
print(' Number of tweets sent: {}'.format(sent_tweets))
########################################
# Set up the CLI parse
cli_main_parser = argparse.ArgumentParser()
cli_main_parser.add_argument('-v', '--verbose',
help='Say all the things',
action='store_true')
cli_main_parser.add_argument('-n', '--nopost',
help='Do everything except send tweets',
action='store_true')
cli_main_parser.add_argument('-s', '--showcron',
help='Show an entry suitable for calling this script every 5 minutes via crontab. '
'After showing the crontab entry, exit without posting tweets.', action='store_true')
cli_main_parser.add_argument('-c', '--credentials',
help='File containing the credentials to tweet with. Should be a single line of the '
'format (values are just space separated): consumer_key consumer_secret access_'
'token_key access_token_secret', default='access')
cli_main_parser.add_argument('storage_file',
help='The name of the file to read the scheduled tweets from. Will be updated after '
'the tweet is sent.')
########################################
# Parse the command line and perform
# the user's bidding
args = cli_main_parser.parse_args()
if args.verbose:
VERBOSE = True
if args.nopost:
NO_POST = True
if args.showcron:
pipenv_location = shutil.which('pipenv')
script_location = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
script_name = os.path.basename(__file__)
storage_location = os.path.abspath(os.path.realpath(args.storage_file))
credentials_location = os.path.abspath(os.path.realpath(args.credentials))
command = "cd '{}' && PATH=/usr/bin:/bin:'{}' '{}' run " \
"python post-scheduled-tweets.py --credentials '{}' '{}'".format(
script_location, os.path.dirname(pipenv_location), pipenv_location,
credentials_location, storage_location)
cron = "*/5 * * * * {}".format(command)
print(cron)
else:
verbose_log('Reading access information from "{}"'.format(args.credentials))
access = fetch_access_information(args.credentials)
print('Started processing scheduled tweets from "{}"'.format(args.storage_file))
post_tweets_from_file(args.storage_file, access)
print('Finished processing scheduled tweets from "{}"'.format(args.storage_file))