-
Notifications
You must be signed in to change notification settings - Fork 3
/
reddit_response.py
316 lines (270 loc) · 10.8 KB
/
reddit_response.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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import time
import praw
import prawcore
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
import Config
import re
import urllib
import urllib.request
reddit = praw.Reddit(client_id=Config.cid,
client_secret=Config.secret,
password=Config.password,
user_agent=Config.agent,
username=Config.user)
subreddit = reddit.subreddit(Config.subreddit)
class Error(Exception):
"""Base class"""
pass
class LinkError(Error):
"""Could not parse the URL"""
pass
class BlacklistedDev(Error):
"""This developer is blacklisted"""
pass
class AppInfo:
# Get the name of the app from the store page
def getName(self):
return self.store_page.find("h1", class_="Fd93Bb").get_text()
def get_downloads(self):
for item in self.expanded_details:
if "Downloads" in item.text:
downloads = item.text[len("Downloads"):]
return downloads
return "Couldn't get downloads"
def get_rating(self):
try:
rating = self.store_page.find("div", class_="TT9eCd").get_text()
except AttributeError:
return "NA "
return rating[:-4] + "/5"
def get_developer(self):
dev = self.store_page.find("div", class_="Vbfug auoIOc")
dev_url = dev.find("a").get("href")
if dev.get_text() in Config.blacklisted_devs:
raise BlacklistedDev
return "[" + dev.get_text() + "]" + "(https://play.google.com" + dev_url + ")"
def get_update_date(self):
for item in self.expanded_details:
if "Updated on" in item.text:
return item.text[len("Updated on"):]
return "Couldn't get update date"
#def getSize(self):
# return "Currently unavailable"
def getPriceInfo(self):
try:
temp = self.store_page.find("span", class_="VfPpkd-vQzf8d").get_text()
except TypeError:
return "incorrect link"
split_price = temp.split(" ")
full_price = split_price[0]
try:
sale_price = split_price[1]
except IndexError:
sale_price = "Buy"
if sale_price == "Buy":
sale_price = full_price
if sale_price == "Install":
sale_price = "Free"
if full_price == "Install":
full_price = "Free"
return sale_price + " was " + full_price
def get_play_pass(self):
play_pass = self.store_page.find("a", class_="pFise")
if play_pass:
return "\n**Included with Play Pass** "
return ""
def get_ads(self):
check = self.store_page.findAll("span", class_="UIuSk")
for item in check:
if "Contains ads" in item.get_text():
return "Yes"
return "No"
def get_iap_info(self):
iap_info = "No"
check = self.store_page.findAll("span", class_="UIuSk")
for item in check:
if "In-app purchases" in item.get_text():
iap_info = "Yes"
if iap_info == "Yes":
for selenium_item in self.expanded_details:
if "In-app purchases" in selenium_item.text:
iap_info += ", " + selenium_item.text[len("In-app purchases"):]
return iap_info
def get_permissions(self):
perm_list = ""
for perm in self.expanded_permissions:
perm_list += ", "
if perm_list == ", ":
perm_list = perm_list[:-2]
perm_list += perm.text
if perm_list == "":
perm_list = "No permmissisons requested"
return "Permissions: " + perm_list + " "
def get_description(self):
desc_strings = self.store_page.find("div", class_="bARER").stripped_strings
desc = ''
total_chars = 0
total_lines = 0
for string in desc_strings:
desc += '>' + string + ' \n'
total_chars += len(string)
total_lines += 1
if total_chars >= 400:
break
if total_lines >= 10:
break
return desc
def __init__(self, submission, url):
self.blacklist = False
self.invalid = False
self.submission = submission
page = requests.get(url).text
self.store_page = BeautifulSoup(page, "html.parser")
self.name = self.getName()
self.rating = self.get_rating()
try:
self.developer = self.get_developer()
except BlacklistedDev:
self.blacklist = True
self.price_info = self.getPriceInfo()
self.play_pass = self.get_play_pass()
self.description = self.get_description()
self.url = url
self.ads = self.get_ads()
self.selenium = webdriver.Firefox()
self.selenium.get(url)
time.sleep(5)
details_button = self.selenium.find_element(By.XPATH, "/html/body/c-wiz[2]/div/div/div[1]/div/div[2]/div/div[1]/div[1]/c-wiz[3]/div/section/header/div/div[2]/button/i")
details_button.click()
time.sleep(1)
self.expanded_details = self.selenium.find_elements(By.CLASS_NAME, "sMUprd")
self.downloads = self.get_downloads()
self.last_update = self.get_update_date()
#self.size = self.getSize()
self.iap_info = self.get_iap_info()
permissions_button = self.selenium.find_element(By.CSS_SELECTOR, "span.TCqkTe")
permissions_button.click()
time.sleep(1)
self.expanded_permissions = self.selenium.find_elements(By.CLASS_NAME, "aPeBBe")
self.permissions = self.get_permissions()
self.selenium.close()
def flair(app_rating, num_installs, sub):
inst = num_installs.split("+")
if inst[0] == "Couldn't":
return
try:
val = int(inst[0].replace(',', ''))
except (ValueError):
return
if val <= 500:
sub.mod.flair(text='New app', css_class=None)
elif val >= 100000 and int(app_rating[0:1]) >= 4:
sub.mod.flair(text= 'Popular app', css_class=None)
# make an empty file for first run
f = open("postids.txt","a+")
f.close()
def logID(postid):
f = open("postids.txt","a+")
f.write(postid + "\n")
f.close()
def respond(submission):
footer = """
*****
^^^[Source](https://github.com/a-ton/gpd-bot)
^^^|
^^^[Suggestions?](https://www.reddit.com/message/compose?to=Swimmer249)"""
all_urls = []
if submission.is_self:
all_urls = re.findall('(?:(?:https?):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+', submission.selftext)
if len(all_urls) == 0:
print("NO LINK FOUND skipping: " + submission.title)
logID(submission.id)
return
else:
all_urls.append(submission.url)
# remove duplicate URLs
unique_urls = [*set(all_urls)]
# find apps that we can respond to
valid_apps = []
required_url = ["http", "play.google"]
disallowed_url = ["collection/cluster", "dev?id=", "store/search"]
for url in unique_urls:
# check if strings in required_url are part of url and if strings in disallowed_url do not exist in url
if not all(x in url for x in required_url):
continue
if any(x in url for x in disallowed_url):
continue
app = AppInfo(submission, url)
if app.blacklist:
reply_text = "Sorry, deals from one or more of the developers in your post have been blacklisted. Here is the full list of blacklisted developers: https://www.reddit.com/r/googleplaydeals/wiki/blacklisted_devlopers"
submission.mod.remove()
submission.reply(body=reply_text).mod.distinguish()
print("Removed (developer blacklist): " + submission.title)
logID(submission.id)
return
if app.invalid:
continue
valid_apps.append(app)
if len(valid_apps) >= 10:
break
if len(valid_apps) == 0:
print("All invalid links, skipping: " + submission.title)
logID(submission.id)
return
reply_text = ""
if len(valid_apps) == 1:
flair(app.rating, app.downloads, submission)
reply_text = f"""Info for {app.name}:
Current price (USD): {app.price_info} {app.play_pass}
Developer: {app.developer}
Rating: {app.rating}
Installs: {app.downloads}
Last updated: {app.last_update}
Contains IAPs: {app.iap_info}
Contains Ads: {app.ads}
{app.permissions}
Short description:
{app.description}
*****
If this deal has expired, please reply to this comment with \"expired\". ^^^Abuse ^^^will ^^^result ^^^in ^^^a ^^^ban."""
if len(valid_apps) > 1:
reply_text = ""
for app_num, app in enumerate(valid_apps):
if app_num >= 10:
break
reply_text += f"Info for [{app.name}]({app.url}): Price (USD): {app.price_info} | Rating: {app.rating} | Installs: {app.downloads} | Updated: {app.last_update} | IAPs/Ads: {app.iap_info}/{app.ads}\n\n*****\n\n"
if len(valid_apps) >= 10:
reply_text += "...and more. Max of 10 apps reached.\n\n*****\n\n"
reply_text += "If any of these deals have expired, please reply to this comment with \"expired\". ^^^Abuse ^^^will ^^^result ^^^in ^^^a ^^^ban."
reply_text += footer
submission.reply(body=reply_text)
print("Replied to: " + submission.title)
logID(submission.id)
while True:
try:
print("Initializing bot...")
for submission in subreddit.stream.submissions():
if submission.created < int(time.time()) - 86400:
continue
if submission.title[0:2].lower() == "[a" or submission.title[0:2].lower() == "[i" or submission.title[0:2].lower() == "[g":
if submission.id in open('postids.txt').read():
continue
for top_level_comment in submission.comments:
try:
if top_level_comment.author and top_level_comment.author.name == "GPDBot":
logID(submission.id)
break
except AttributeError:
pass
else: # no break before, so no comment from GPDBot
respond(submission)
continue
except (prawcore.exceptions.RequestException, prawcore.exceptions.ResponseException):
print ("Error connecting to reddit servers. Retrying in 5 minutes...")
time.sleep(300)
except praw.exceptions.APIException:
print ("Rate limited, waiting 5 seconds")
time.sleep(5)