-
Notifications
You must be signed in to change notification settings - Fork 0
/
twitter.py
131 lines (102 loc) · 3.58 KB
/
twitter.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
130
131
from collections import Counter
import os
from camel import Camel
import tweepy
from duck import now, registry, _sample_duck
from secrets import TWITTER
DUCK_DIR = os.path.join(
os.path.dirname(__file__),
'duck-storage',
)
if not os.path.exists(DUCK_DIR):
os.mkdir(DUCK_DIR)
DUCK_IMAGE_LOCATION = os.path.join(
os.path.dirname(__file__),
'duck.png',
)
camel = Camel([registry])
auth = tweepy.OAuthHandler(TWITTER['consumer_key'], TWITTER['consumer_secret'])
auth.set_access_token(TWITTER['access_token'], TWITTER['access_token_secret'])
twitter = tweepy.API(auth)
def get_duck():
duck_filenames = [
fn for fn in os.listdir(DUCK_DIR)
if fn.endswith('.yaml') and not fn.startswith('.')
]
if duck_filenames:
latest_duck_filename = sorted(duck_filenames)[-1]
with open(os.path.join(DUCK_DIR, latest_duck_filename)) as f:
latest_duck = camel.load(f.read())
if latest_duck.success is None:
return (latest_duck, latest_duck_filename)
else:
# start from where we finished
return (latest_duck.make_successor(), None)
else:
return (_sample_duck(), None) # start from scratch
def get_latest_duck_tweet():
tweets = [
tw for tw in
twitter.user_timeline(screen_name=auth.username)
if tw.in_reply_to_status_id is None
and not tw.retweeted
]
if tweets:
return tweets[0]
if __name__ == '__main__':
duck, filename = get_duck()
latest_tweet = None
# respecting next_active here makes sense even if similar logic is already
# in Duck, since on the CLI there's no reason to force the player to wait,
# but on twitter we really want people to get an opportunity to vote
if duck.scenario and (now() > duck.next_active):
latest_tweet = get_latest_duck_tweet()
if latest_tweet:
replies = [
s for s in twitter.mentions_timeline(
since_id=latest_tweet.id,
tweet_mode='extended',
) if s.in_reply_to_status_id == latest_tweet.id
] if duck.scenario and latest_tweet else []
votes = {}
for reply in replies:
if reply.user.id in votes:
continue
answer = duck.scenario.answer_for(reply.full_text)
if answer is None:
continue
votes[reply.user.id] = answer['answer']
if votes:
counter = Counter(votes.values())
most_common, = counter.most_common(1)
response, _ = most_common
else:
response = None
else:
response = None
image = None
if filename is None:
# this is a fresh duck! we want an image of it at the start point
image = duck.make_image()
advancement = duck.advance(response)
if advancement is not None:
for string in advancement:
if (
duck.scenario is None and
duck.success is None and
image is None
):
twitter.update_status(
string,
in_reply_to_status_id=latest_tweet.id
if latest_tweet else None
)
else:
if image is None:
image = duck.make_image()
image.save(DUCK_IMAGE_LOCATION)
twitter.update_with_media(DUCK_IMAGE_LOCATION, string)
if filename is None:
filename = '{}.yaml'.format(now().isoformat())
with open(os.path.join(DUCK_DIR, filename), 'w') as f:
f.write(camel.dump(duck))