forked from ahmetmutlugun/imam
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebscrape_and_data.py
368 lines (320 loc) · 13.5 KB
/
webscrape_and_data.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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
import datetime
import json
import http.client
import urllib.parse
import discord
import requests
from discord.ext import commands
from discord.commands import \
slash_command, Option
errorText = "No prayer time found for your location. Please set a new location using imam location <city>"
f = open('data/config.json', 'r+')
config = json.load(f)
f.close()
def set_user_data(userID, dataName, dataValue):
try:
f = open('data/data.json', 'r+')
data = json.load(f)
f.close()
if userID in data:
data[str(userID)][dataName] = dataValue
with open('data/data.json', 'w') as json_file:
json.dump(data, json_file, indent=4)
json_file.truncate()
except Exception as e:
# logging.error(e)
print(e)
def get_location(author_id):
"""
Returns location of a user
:param author_id: user id
:return: city - user's city as string
"""
f = open('data/data.json', 'r+')
data = json.load(f)
f.close()
try:
if str(author_id) in data:
city = data[str(author_id)]['city']
country = data[str(author_id)]['country']
return [city, country]
else:
return ['Cupertino', 'United States of America']
except Exception as e:
# logging.error(e)
return ['Cupertino', 'United States of America']
def web_scrape(city, country):
"""
Returns all prayer times for a specific location
:param: city - string of user's city
:param: country - string of user's country
:rtype: prayer_times - dictionary of all prayer times
"""
url = f'https://api.aladhan.com/v1/timingsByCity?city={city}&country={country}&method=2'
r = requests.get(url)
data = r.json()
prayertimes = ['Fajr', 'Sunrise', 'Dhuhr', 'Asr', 'Maghrib', 'Isha', 'Midnight']
pt = {}
for p in prayertimes:
pt[p] = data['data']['timings'][p]
return pt
def calc_local_time_offset(city, country):
"""
Gets the local utc offset from positionstack's API
:param city: string of a city
:param country: string of a country
:return: int value of utc offset in seconds
"""
# Connect to the position stack API
conn = http.client.HTTPConnection('api.positionstack.com')
params = urllib.parse.urlencode({
'access_key': config['positionstack'],
'query': city,
'country': country,
"output": 'json',
'limit': 1,
'timezone_module': 1,
})
try:
conn.request('GET', '/v1/forward?{}'.format(params))
res = conn.getresponse()
# Obtain the utc offset from the json response
data = res.read()
return json.loads(data.decode('utf-8'))['data'][0]['timezone_module']['offset_sec']
except Exception:
return None
def get_local_time_offset(author_id):
"""
Returns local time offset of a user from data.json
:param author_id: user id
:return: city - user's city as string
"""
with open('data/data.json', 'r+') as f:
data = json.load(f)
try:
if str(author_id) in data:
offset = data[str(author_id)]['utc_offset']
return offset
except Exception as e:
# logging.error(e)
# Return the utc offset of Cupertino by default
return -25200
def create_user(userid: str, imam: int, tovbe: int, city: str, elham: int, utc_offset: int, country: str):
with open('data/data.json', 'r+') as f:
data = json.load(f)
if userid not in data: # see if user doesn't have a saved location
# Save user location, utc_offset, and defaults
new_user = {"imam": imam, "tovbe": tovbe, "city": city, "elham": elham, "utc_offset": utc_offset,
"country": country}
data[userid] = new_user
with open('data/data.json', 'w') as json_file: # write to data.json
json.dump(data, json_file, indent=4)
class Webscraping2(commands.Cog):
def __init__(self, bot):
self.client = bot
self._last_member = None
@slash_command(name='location', description="Set your location for prayer commands. imam location <city>")
async def location(self, ctx, user_loc: str):
"""
Changes user's location to their parameter specified location
:param ctx: Context
:param user_loc: String of user-specified city
:return: String of a success message
"""
if len(user_loc.split(',')) == 2:
city = user_loc.split(',')[0]
country = user_loc.split(',')[1]
# open data.json file to read later
with open('data/data.json', 'r+') as f:
data = json.load(f)
with open('data/countyCodes.json', 'r+') as cc:
countryData = json.load(cc)
if country not in countryData:
await ctx.respond("Please enter a valid country code.")
return
# Adds spaces in the city name: i.e. SanJose is now San Jose
formatted_city = ""
for i in range(len(city)):
add_space = False
# If i isn't the last index
if i < len(city) - 1:
if city[i].islower() and city[i + 1].isupper():
add_space = True
formatted_city += city[i]
if add_space:
formatted_city += " "
# Get the local time offset for the specified city
utc_offset = calc_local_time_offset(formatted_city, country)
if utc_offset is None:
await ctx.respond("Your location is invalid. Please use \"imam location <CityName>,<CountryName>\"")
return
try:
if str(ctx.author.id) not in data: # see if user doesn't have a saved location
create_user(str(ctx.author.id), 1, 0, city, 0, utc_offset, country)
else:
data[str(ctx.message.author.id)]['city'] = formatted_city
data[str(ctx.message.author.id)]['utc_offset'] = utc_offset
data[str(ctx.message.author.id)]['country'] = countryData[country]
with open('data/data.json', 'w') as json_file:
json.dump(data, json_file, indent=4)
except Exception as e:
# logging.error(e)
print(e)
await ctx.respond(
"User location changed to: \nCity: " + formatted_city + "\nCountry: " + countryData[country])
else:
await ctx.respond("Please format as \"imam location City,CountryCode\"")
@slash_command(name='fajr', description="Displays the fajr time.")
async def fajr(self, ctx):
"""
Returns fajr prayer time using web-scrape()'s prayer_times
:param ctx: Context
:return: string of fajr prayer time
"""
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
time = web_scrape(city, country)
if time is None:
await ctx.respond(errorText)
else:
await ctx.respond("Fajr/Sahur is at " + str(time['Fajr']) + " for " + city)
@slash_command(name='dhuhr', description="Displays the dhuhr time.")
async def dhuhr(self, ctx):
"""
Returns dhuhr prayer time using web-scrape()'s prayer_times
:param ctx: Context
:return: string of dhuhr prayer time
"""
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
time = web_scrape(city, country)
if time is None:
await ctx.respond(errorText)
else:
await ctx.respond("Dhuhr is at " + str(time['Dhuhr']) + " for " + city)
@slash_command(name='asr', description="Displays the Asr time.")
async def asr(self, ctx):
"""
Returns asr prayer time using web-scrape()'s prayer_times
:param ctx: Context
:return: string of asr prayer time
"""
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
time = web_scrape(city, country)
if time is None:
await ctx.respond(errorText)
else:
await ctx.respond("Asr is at " + str(time['Asr']) + " for " + city)
@slash_command(name='maghrib', description="Displays the maghrib time.")
async def maghrib(self, ctx):
"""
Returns maghrib prayer time using web-scrape()'s prayer_times
:param ctx: Context
:return: string of maghrib prayer time
"""
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
time = web_scrape(city, country)
if time is None:
await ctx.respond(errorText)
else:
await ctx.respond("Maghrib is at " + str(time['Maghrib']) + " for " + city)
@slash_command(name='isha', description="Displays the isha time.")
async def isha(self, ctx):
"""
Returns isha prayer time using web-scrape()'s prayer_times
:param ctx: Context
:return: string of isha prayer time
"""
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
time = web_scrape(city, country)
if time is None:
await ctx.respond(errorText)
else:
await ctx.respond("Isha is at " + str(time['Isha']) + " for " + city)
@slash_command(name='prayer_times', description="Displays all prayer times.")
async def prayer_times(self, ctx):
"""
Returns all prayer times as a string using web-scrape()
:param ctx: Context
:return: string of all prayer times
"""
# Set up lists and dictionaries
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
# Obtains dictionary from webscrape() and reformats it
prayer_times = web_scrape(city, country)
# Creates a returnable string of all the prayer times
string = "Prayer times for " + city + ", " + country + ":\n"
embed = discord.Embed(title="Prayer times for " + city + ", " + country, type='rich', color=0x048c28)
embed.set_author(name="ImamBot", icon_url="https://ipfs.blockfrost.dev/ipfs"
"/QmbfvtCdRyKasJG9LjfTBaTXAgJv2whPg198vCFAcrgdPQ")
for key in prayer_times:
string += str(key) + ": " + str(prayer_times[key]) + "\n"
embed.add_field(name=str(key) + ":", value=str(prayer_times[key]))
await ctx.respond(embed=embed)
@slash_command(name='prayer_now', description="Displays the current prayer time.")
async def pnow(self, ctx):
"""
Returns the current and next prayer times, and the time left until the next prayertime
:param ctx: Context
:return: String of current & next prayer time + time left
"""
# Set up lists and dictionaries
location = get_location(ctx.author.id) # get user location
city = location[0].replace("_", " ")
country = location[1].replace("_", " ")
# Obtains dictionary from webscrape() and reformats it
prayer_times = web_scrape(city, country)
# Get the local time in seconds
local_time = datetime.timedelta(seconds=get_local_time_offset(ctx.author.id)) + datetime.datetime.utcnow()
# Get rid of the date variables because it is messing with the comparison operation in the forloop
formatted_time = datetime.datetime.strptime(local_time.strftime('%H:%M'), "%H:%M")
pnow = ""
pnext = "N/A"
# Iterate over all prayer times and find prayertime now
for prayer in prayer_times:
p_time = datetime.datetime.strptime(prayer_times[prayer], "%H:%M")
# If local time precedes p_time then 'prayer' is the next prayer
if formatted_time < p_time:
pnext = prayer
break
# If the local time is greater than Isha time and isn't midnight yet
# TODO: refactor with match statements
if pnext == "Midnight":
pnow = "Isha"
elif pnext == "N/A" or pnext == 'Fajr':
pnext = "Fajr"
pnow = "Midnight"
# Otherwise using pnext determine pnow
elif pnext == "Sunrise":
pnow = "Fajr"
elif pnext == "Dhuhr":
pnow = "Sunrise"
elif pnext == "Asr":
pnow = "Dhuhr"
elif pnext == "Maghrib":
pnow = "Asr"
elif pnext == "Isha":
pnow = "Maghrib"
# Get the prayer time for the next prayer
p_next_time = datetime.datetime.strptime(prayer_times[pnext], "%H:%M")
diff = abs(p_next_time - formatted_time)
hours = diff.seconds // 3600
mins = (diff.seconds // 60) % 60
# Because the time loops after 23:59, this needs to be done
if pnow == "Isha":
hours = 23 - hours
mins = 59 - mins
# Return everything
await ctx.respond("Warning: This command is under development. Please double check prayer times.")
await ctx.respond(
f"The current prayer for {city} is {pnow}. There are {hours} hours and {mins} minutes until {pnext}.")