This repository has been archived by the owner on Jul 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
hearthscan-bot.py
232 lines (172 loc) · 6.73 KB
/
hearthscan-bot.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#!/usr/bin/env python3
import logging as log
import re
import time
from cardDB import CardDB
from constants import Constants
from helper import HSHelper
from praww import RedditBot
import commentDB
import credentials
import formatter
# answer pms of the same user only every x seconds
PM_RATE_LIMIT = 60
def answerComment(r, comment, answeredDB, helper):
"""read and answer a comment"""
cards, answer = helper.parseText(comment.body)
if cards and answer and not answeredDB.exists(comment.parent_id, cards):
# reply to comment
log.info("replying to comment: %s %s with %s",
comment.id, comment.author.name, cards)
comment.reply(answer)
def answerMention(r, comment, answeredDB, helper):
"""read and answer a mention"""
cards, answer = helper.parseText(comment.body)
if cards and answer:
if not answeredDB.exists(comment.parent_id, cards):
# reply to comment
log.info("replying to comment: %s %s with %s",
comment.id, comment.author.name, cards)
comment.reply(answer)
else:
log.debug("forwarded mention with id: %s", comment.id)
# forward mentions without cards to admin
subject = '${} /u/{} in /r/{}/ "{}"'.format(comment.id, comment.author,
comment.subreddit, comment.submission.title)
r.redditor(credentials.admin_username).message(subject, comment.body)
def answerSubmission(submission, helper):
"""read and answer a submission"""
text = submission.title
if submission.is_self:
text += ' ' + submission.selftext
cards, answer = helper.parseText(text)
if cards and answer:
log.info("replying to submission: %s %s with %s",
submission.id, submission.author.name, cards)
submission.reply(answer)
def answerPM(r, msg, pmUserCache, helper):
""" read and answer a pm """
subject_author = ""
# subreddit mod pm
if msg.subreddit:
author = msg.subreddit.display_name
subject_author += " /r/" + author
if msg.author:
author = msg.author.name
subject_author += " /u/" + author
log.debug("found message with id: %s from %s", msg.id, author)
if msg.author and not msg.distinguished and author in pmUserCache:
log.debug("user %s is in recent msg list", author)
return
if author == credentials.admin_username and msg.subject[:5] == 're: #':
forwardPMAnswer(r, msg)
return
if author == credentials.admin_username and msg.subject[:5] == 're: $':
forwardMentionAnswer(r, msg)
return
pmUserCache[author] = int(time.time()) + PM_RATE_LIMIT
text = msg.subject + ' ' + msg.body
cards, answer = helper.parseText(text)
# some ui and clients do escape the brackets
if re.search(r'\\?\[\\?\[info\\?\]\\?\]', text):
answer = helper.getInfoText(author) + answer
if cards or answer:
if cards:
log.info("sending msg: %s with %s", author, cards)
msg.reply(answer)
else:
# vip tags (mod, admin usw)
if msg.distinguished:
subject_author += " [" + msg.distinguished + "]"
log.debug("forwarded message with id: %s", msg.id)
# forward messages without cards to admin
subject = '#{}{}: "{}"'.format(msg.id, subject_author, msg.subject)
r.redditor(credentials.admin_username).message(subject, msg.body)
def getIdFromSubject(subject):
first_space = subject.find(' ', 6)
slice_to = first_space if first_space > 1 else len(subject)
if slice_to > 5:
return subject[5:slice_to]
def forwardPMAnswer(r, answer_msg):
"""handle messages from bot admin which are answers to
forwarded messages
"""
message_id = getIdFromSubject(answer_msg.subject)
if message_id:
old_message = r.inbox.message(message_id)
if old_message:
log.debug("forwarded answer to message id: %s", old_message.id)
old_message.reply(answer_msg.body)
answer_msg.reply("answer forwarded")
def forwardMentionAnswer(r, answer_msg):
"""handle messages from bot admin which are answers to
forwarded mentions
"""
comment_id = getIdFromSubject(answer_msg.subject)
if comment_id:
src_comment = r.comment(comment_id)
if src_comment:
log.debug("forwarded answer to comment id: %s", src_comment.id)
src_comment.reply(answer_msg.body)
answer_msg.reply("answer forwarded")
def cleanPMUserCache(cache):
""" clean recent user msg cache """
removeUser = []
now = int(time.time())
for user, utime in cache.items():
if now > utime:
log.debug("removing author %s from recent list", user)
removeUser.append(user)
for ku in removeUser:
del cache[ku]
def main():
log.debug('main() hearthscan-bot starting')
# load constant values
constants = Constants()
# init answered comments sqlite DB
answeredDB = commentDB.DB()
# load card DB
url = 'https://raw.githubusercontent.com/d-schmidt/hearthscan-bot/master/data/tempinfo.json'
cardDB = CardDB(constants=constants, tempJSONUrl=url)
# init hs helper for hearthstone stuff
helper = HSHelper(cardDB, constants)
# pm spam filter cache
pmUserCache = {}
def submissionListener(r, submission):
answerSubmission(submission, helper)
def commentListener(r, comment):
answerComment(r, comment, answeredDB, helper)
def mentionListener(r, comment):
answerMention(r, comment, answeredDB, helper)
def pmListener(r, message):
answerPM(r, message, pmUserCache, helper)
def postAction():
cleanPMUserCache(pmUserCache)
cardDB.refreshTemp()
try:
RedditBot(subreddits=credentials.subreddits,
newLimit=250,
connectAttempts=5,
userBlacklist=set(credentials.userBlacklist)) \
.withSubmissionListener(submissionListener) \
.withCommentListener(commentListener) \
.withMentionListener(mentionListener) \
.withPMListener(pmListener) \
.run(postAction)
except:
log.exception('main() RedditBot failed unexpectedly')
finally:
log.warning('main() leaving hearthscan-bot')
answeredDB.close()
if __name__ == "__main__":
log.basicConfig(filename="bot.log",
format='%(asctime)s %(levelname)s %(module)s:%(name)s %(message)s',
level=log.DEBUG)
log.getLogger('prawcore').setLevel(log.INFO)
log.getLogger('urllib3.connectionpool').setLevel(log.INFO)
# start
try:
main()
except:
log.exception('main() failed unexpectedly')
exit(1)