· 4 years ago · Apr 03, 2021, 07:36 PM
1from typing import Collection
2from redbot.core import commands, Config, checks
3from redbot.core.data_manager import cog_data_path, bundled_data_path
4import discord
5from discord.ext import tasks
6from .lineup import lineup
7import aiohttp
8import asyncio
9import json
10import pandas as pd
11import matplotlib.pyplot as plt
12from pandas.plotting import table
13import pathlib
14import datetime
15import pytz
16
17class Soccer(commands.Cog):
18 def __init__(self, bot):
19 self.bot = bot
20 self.config = Config.get_conf(self, identifier=757509)
21 self.base_url = "https://football.elenasport.io/v2"
22 self.basic_key = ""
23 self.temp_key = None
24
25 self.api_key_paid = ""
26
27 self.guild = None
28 self.plscore = None
29 self.message = None
30 self.goals = {}
31 self.bookings = {}
32 self.substitutions = {}
33 self.c_messages = {}
34
35 self.previous_pl_table = None
36 self.previous_cl_table = None
37 self.previous_fa_table = None
38 self.time_for_loop = datetime.time(hour=0, minute=1)
39 self.subscribed_leagues = ["pl", "fa", "cl", "lc"]
40
41 self.league_id_pl = 234
42 self.country_id_en = 42
43 self.team_id_mc = 2892
44
45 default_global = {
46 "guild_id": None,
47 "channel_live_id": None,
48 "channel_commentary_id": [],
49
50 "pl": {
51 "league_id": 0,
52 "league_id_elena": 234,
53 "stage_id": None,
54 "season_id_latest": None,
55 "season_ids": {}
56 },
57 "cl": {
58 "league_id": 0,
59 "league_id_elena": 7,
60 "stages": {},
61 "season_id_latest": None,
62 "season_ids": {}
63 },
64 "fa": {
65 "league_id": 0,
66 "league_id_elena": 240,
67 "stages": {},
68 "season_id_latest": None,
69 "season_ids": {}
70 },
71 "lc": {
72 "league_id": 0,
73 "league_id_elena": 241,
74 "stages": {},
75 "season_id_latest": None,
76 "season_ids": {}
77 },
78
79 "country_id_en": 2072,
80 "team_id_mc": None,
81 "team_id_mc_elena": 99,
82 "live_match_id": None,
83 "live_match_id_elena": None,
84 "lineup": None,
85 "lineup_elena": None,
86 "last_match": None
87 }
88
89 self.config.register_global(**default_global)
90
91 self.fetch_guilds.start()
92 self.get_api_key.start()
93 task_main = asyncio.create_task(self.match_for_today())
94 task_main.add_done_callback(self.exception_catching_callback)
95
96 def cog_unload(self):
97 self.get_api_key.cancel()
98 self.fetch_live_match.cancel()
99 self.get_lineups.cancel()
100 self.fetch_guilds.cancel()
101 self.start_live.cancel()
102
103 def convert_time(self, time, return_datetime=False):
104 time = datetime.datetime.strptime(time, "%Y-%m-%dT%H:%M:%SZ")
105 tz_time = pytz.timezone("UTC").localize(time)
106 if return_datetime == False:
107 london_date = tz_time.astimezone(pytz.timezone("Europe/London")).strftime("%Y-%m-%d")
108 london_time = tz_time.astimezone(pytz.timezone("Europe/London")).strftime("%H:%M")
109 return london_date, london_time
110 else:
111 return tz_time.astimezone(pytz.timezone("Europe/London"))
112
113 async def config_set(self, dict, subdict, value):
114 try:
115 async with getattr(self.config, dict)() as dict:
116 dict[subdict] = value
117 except AttributeError:
118 pass
119
120 async def config_get(self, dict, subdict = None):
121 try:
122 async with getattr(self.config, dict)() as dict:
123 if subdict == None:
124 return dict
125 else:
126 return dict[subdict]
127 except AttributeError:
128 pass
129
130 async def reset_live(self):
131 await self.config.lineup.set(None)
132 await self.config.lineup_elena.set(None)
133 await self.config.live_match_id.set(None)
134 await self.config.live_match_id_elena.set(None)
135 self.message = None
136 self.plscore = None
137 self.goals = {}
138 self.bookings = {}
139 self.substitutions = {}
140 self.score = {}
141
142 self.start_live.cancel()
143 self.fetch_live_match.cancel()
144 self.get_lineups.cancel()
145
146 async def fetch_defaults(self):
147 """Get league ids"""
148 url = "https://api.football-data.org/v2/competitions"
149 resp, status = await self.api_call_paid(url, return_status=True)
150 if status == 200:
151 for comp in resp["competitions"]:
152 if (comp["area"]["name"] == "England") and (comp["name"] == "Premier League"):
153 await self.config_set("pl", "league_id", comp["id"])
154 elif comp["name"] == "UEFA Champions League":
155 await self.config_set("cl", "league_id", comp["id"])
156 elif (comp["area"]["name"] == "England") and (comp["name"] == "Football League Cup"):
157 await self.config_set("lc", "league_id", comp["id"])
158 elif (comp["area"]["name"] == "England") and (comp["name"] == "FA Cup"):
159 await self.config_set("fa", "league_id", comp["id"])
160
161 for idx, league in enumerate(self.subscribed_leagues):
162 topic = "/leagues/" + str(await self.config_get(league, "league_id_elena")) + "/seasons"
163 resp, status = await self.api_call(topic, return_status=True)
164 await self.config_set(league, "season_id_latest", resp["data"][0]["id"])
165 dict = await self.config_get(league, "season_ids")
166 for idx, item in enumerate(resp["data"]):
167 dict[item["id"]] = item["leagueName"]
168 await self.config_set(league, "season_ids", dict)
169 await asyncio.sleep(1)
170
171 """Get stages"""
172 topic = "/seasons/" + str(await self.config_get("pl", "season_id_latest")) + "/stages"
173 resp = await self.api_call(topic)
174 for idx, item in enumerate(resp["data"]):
175 if item["name"] == "Regular Season":
176 await self.config_set("pl", "stage_id", item["id"])
177 await asyncio.sleep(1)
178 topic = "/seasons/" + str(await self.config_get("cl", "season_id_latest")) + "/stages"
179 resp = await self.api_call(topic)
180 stages = {}
181 for idx, item in enumerate(resp["data"]):
182 if item["hasStanding"] == True:
183 group = str(item["name"]).split(" ")
184 stages[group[4]] = item["id"]
185 await self.config_set("cl", "stages", stages)
186 await asyncio.sleep(1)
187
188 def create_png(self, resp, name, figsize: tuple = (5.5, 6.4), fontsize: int = 11, height: int = None):
189 try:
190 pathlib.Path(str(cog_data_path(self)) + "/" + name).unlink()
191 except:
192 pass
193 cell_text = []
194 ranking = []
195 rowColor = []
196
197 for idx, item in enumerate(resp["standings"][0]["table"]):
198 list = []
199 list.append(item["team"]["name"])
200 list.append(item["playedGames"])
201 list.append(item["points"])
202 list.append(item["won"])
203 list.append(item["draw"])
204 list.append(item["lost"])
205 ranking.append(item["position"])
206 cell_text.append(list)
207 rowColor.append("grey")
208
209 if item["team"]["id"] == 65:
210 ranking_mc = item["position"]
211
212 columns = ("Team", "MP", "P", "W", "D", "L")
213 colColors = []
214 for i in range(len(columns)):
215 colColors.append("grey")
216 rows = ranking
217 colWidths = (0.6, 0.1, 0.1, 0.1, 0.1, 0.1)
218 fig, ax = plt.subplots(figsize=figsize)
219 ax.axis("off")
220
221 table = ax.table(cellText=cell_text, colLabels=columns, colColours=colColors, rowLabels=rows, rowColours=rowColor, cellLoc="center", colWidths=colWidths, loc="center")
222 table.auto_set_font_size(False)
223 table.set_fontsize(fontsize)
224
225 for cell in table.get_celld():
226 if cell[0] == ranking_mc:
227 table[cell].set_facecolor("#56b5fd")
228 if height == None:
229 height = 1 / len(ranking)
230 for pos, cell in table.get_celld().items():
231 cell.set_height(height)
232
233 plt.savefig(str(cog_data_path(self) / name), transparent=True)
234
235 async def api_call(self, topic: str = "", identifier: str = "", api_url: str = "", return_status: bool = False, headers: dict = {}):
236 if api_url == "":
237 api_url = self.base_url + topic
238
239 if headers == {}:
240 headers = {
241 "Authorization": self.temp_key
242 }
243
244 async with aiohttp.ClientSession() as session:
245 async with session.get(api_url, headers=headers) as resp:
246 dict_resp = json.loads(await resp.text())
247 if return_status == False:
248 return dict_resp
249 else:
250 return dict_resp, resp.status
251
252 async def api_call_paid(self, url: str, return_status: bool = False):
253 headers = {
254 "X-Auth-Token": self.api_key_paid
255 }
256
257 async with aiohttp.ClientSession() as session:
258 async with session.get(url, headers=headers) as resp:
259 dict_resp = json.loads(await resp.text())
260 if return_status == False:
261 return dict_resp
262 else:
263 return dict_resp, resp.status
264
265 async def standings_final(self, ctx):
266 async with ctx.typing():
267 resp = await self.standings()
268 embed = discord.Embed(color=discord.Color.blue(), description="Upcoming Fixtures")
269
270 name = []
271 value = []
272
273 for idx, match in enumerate(resp["matches"]):
274 if idx > 5:
275 break
276 date, time = match["utcDate"].split("T")
277 time = time.replace("Z", "")
278 name.append(match["homeTeam"]["name"] + " vs. " + match["awayTeam"]["name"])
279 if match["venue"] != None:
280 value.append(date + " at " + time + "\n" + match["venue"])
281 else:
282 value.append(date + " at " + time)
283
284 for i in range(0, len(name)):
285 embed.add_field(name=name[i], value=value[i], inline=False)
286
287 await ctx.send(embed=embed)
288
289 async def standings(self):
290 time = datetime.datetime.now(pytz.UTC)
291 current_time = time.strftime("%G-%m-%d")
292 next_time = (time + datetime.timedelta(days=30)).strftime("%G-%m-%d")
293
294 url = "http://api.football-data.org/v2/teams/{}/matches?dateFrom={}&dateTo={}".format(65, current_time, next_time)
295 resp = await self.api_call_paid(url)
296
297 return resp
298
299 async def clear_live_channel(self, channel):
300 async for msg in channel.history(limit=None):
301 try:
302 await msg.delete()
303 except:
304 pass
305
306 async def commentary(self, resp):
307 print("start")
308 resp = resp["match"]
309 updated = False
310 if resp["score"]["fullTime"] != self.score:
311 if resp["score"]["fullTime"]["homeTeam"] != self.score["homeTeam"]:
312 embed = discord.Embed(discord.Color.blue(), description="Goal for {}!".format(resp["homeTeam"]["name"]))
313 else:
314 embed = discord.Embed(discord.Color.blue(), description="Goal for {}!".format(resp["awayTeam"]["name"]))
315 await self.send_commentary(embed, "goal")
316 updated = True
317 self.score = resp["score"]
318 print("goal")
319 if resp["goals"] != self.goals:
320 for goal in resp["goals"]:
321 if goal not in self.goals:
322 embed = discord.Embed(color=discord.Color.blue(), description="Goal for {}!".format(goal["team"]["name"]))
323 embed.add_field(name="Scorer", value=goal["scorer"]["name"], inline=True)
324 embed.add_field(name="Assist", value=goal["assist"]["name"], inline=True)
325 embed.set_footer(text="Min: {}".format(goal["minute"]))
326 await self.send_commentary(embed, "goal")
327 updated = True
328 self.goals = resp["goals"]
329 print("goal2")
330 if resp["bookings"] != self.bookings:
331 for booking in resp["bookings"]:
332 if booking not in self.bookings:
333 if booking["card"] == "YELLOW_CARD":
334 text = "Yellow card for {} from {}!".format(booking["player"]["name"], booking["team"]["name"])
335 elif booking["card"] == "RED_CARD":
336 text = "Red card for {} from {}!".format(booking["player"]["name"], booking["team"]["name"])
337 else:
338 text = "Event not found: {}".format(booking["card"])
339 embed = discord.Embed(color=discord.Color.blue(), description=text)
340 embed.set_footer(text="Min: {}".format(booking["minute"]))
341 await self.send_commentary(embed)
342 updated = True
343 self.bookings = resp["bookings"]
344 print("bookings")
345 if resp["substitutions"] != self.substitutions:
346 for substitution in resp["substitutions"]:
347 if substitution not in self.substitutions:
348 embed = discord.Embed(color=discord.Color.blue(), description="Substitution for {}!".format(substitution["team"]["name"]))
349 embed.add_field(name="Player in", value=substitution["playerIn"]["name"], inline=True)
350 embed.add_field(name="Player out", value=substitution["playerOut"]["name"], inline=True)
351 embed.set_footer(text="Min: {}".format(substitution["minute"]))
352 await self.send_commentary(embed)
353 updated = True
354 self.substitutions = resp["substitutions"]
355
356 print("return")
357 return updated
358 # except:
359 # return False
360
361 async def send_commentary(self, embed, c_type: str = None):
362 channels = await self.config.channel_commentary_id()
363 for channel_id in channels:
364 if c_type == None:
365 channel = discord.utils.get(self.guild.channels, id=channel_id)
366 message = await channel.send(embed=embed)
367 else:
368 for channel_id in channels:
369 if self.c_messages[channel_id] == None:
370 channel = discord.utils.get(self.guild.channels, id=channel_id)
371 message = await channel.send(embed=embed)
372 self.c_messages[channel_id] = message
373 else:
374 self.c_messages[channel_id].edit(embed=embed)
375 self.c_messages[channel_id] = None
376
377 @commands.command(name="mcfclineup")
378 async def lineup(self, ctx):
379 """Delivers the lineup of Manchester City"""
380 filename = "lineup.png"
381 try:
382 await ctx.send(file=discord.File(str(cog_data_path(self) / filename)))
383 except:
384 await ctx.send("No match found.")
385
386 @commands.group(name="table")
387 async def table(self, ctx):
388 """Standings for various leagues"""
389 pass
390
391 @table.command(name="pl", aliases=["PremierLeague"])
392 async def table_pl(self, ctx, season: str = "2020/2021"):
393 """Delivers the Premier League table"""
394 async with ctx.typing():
395 url = "https://api.football-data.org/v2/competitions/{}/standings?standingType=TOTAL".format(await self.config_get("pl", "league_id"))
396 resp, status = await self.api_call_paid(url, return_status=True)
397
398 if status == 200:
399 if resp != self.previous_pl_table:
400 self.previous_pl_table = resp
401 self.create_png(resp, "rankingpl.png")
402
403 await ctx.send(file=discord.File(str(cog_data_path(self) / "rankingpl.png")))
404
405 @table.command(name="cl", aliases=["ChampionsLeague"])
406 async def table_cl(self, ctx, group: str = "A"):
407 """Delivers the Champions League table"""
408 group = group.upper()
409 valid_groups = ["A", "B", "C", "D", "E", "F", "G", "H"]
410 if not group in valid_groups:
411 await ctx.send("Group is not valid. Valid Groups are `A, B, C, D, E, F, G, H`")
412 else:
413 async with ctx.typing():
414 url = "https://api.football-data.org/v2/competitions/{}/standings?standingType=TOTAL".format(await self.config_get("cl", "league_id"))
415 resp, status = await self.api_call_paid(url, return_status=True)
416
417 if status == 200:
418 if resp != self.previous_cl_table:
419 self.previous_cl_table = resp
420 figsize = (5, 3)
421 fontsize = 11
422 height = 0.12
423 self.create_png(resp, "rankingcl.png", figsize, fontsize, height)
424
425 await ctx.send(file=discord.File(str(cog_data_path(self) / "rankingcl.png")))
426
427 @commands.command(name="timestamp")
428 async def timestamp(self, ctx):
429 """Current matchtime"""
430 if self.plscore != None:
431 resp_score = self.plscore["match"]
432 embed = discord.Embed(color=discord.Color.blue(), description="Current Time")
433 embed.add_field(name="Min", value=resp_score["minute"])
434 await ctx.send(embed=embed)
435 else:
436 await ctx.send("No live match found")
437
438 @commands.command(name="score")
439 async def score(self, ctx):
440 """Score in the current Manchester City match"""
441 if self.plscore != None:
442 resp_score = self.plscore
443 if resp_score["match"]["minute"] == "BREAK":
444 resp_score["match"]["minute"] = "Half Time"
445
446 embed = discord.Embed(color=discord.Color.blue(), description="Live Standings")
447 name = "{} {} - {} {}".format(resp_score["match"]["homeTeam"]["name"], resp_score["match"]["score"]["fullTime"]["homeTeam"], resp_score["match"]["score"]["fullTime"]["awayTeam"], resp_score["match"]["awayTeam"]["name"])
448 embed.add_field(name=name, value="Min: " + str(resp_score["match"]["minute"]))
449 await ctx.send(embed=embed)
450 elif await self.config.last_match() != None:
451 resp_score = await self.config.last_match()
452 resp_score = resp_score["match"]
453
454 embed = discord.Embed(color=discord.Color.blue(), description="Standings of last match")
455 date, time = resp_score["utcDate"].split("T")
456 hour, min, sec = time.split(":")
457 time = "{}:{}".format(hour, min)
458 value = "Match from {} at {}".format(date, time)
459
460 name = "{} {} - {} {}".format(resp_score["homeTeam"]["name"], resp_score["score"]["fullTime"]["homeTeam"], resp_score["score"]["fullTime"]["awayTeam"], resp_score["awayTeam"]["name"])
461 embed.add_field(name=name, value=value)
462 await ctx.send(embed=embed)
463 else:
464 await ctx.send("No live match found")
465
466 @commands.command(name="mcfcfixtures")
467 async def mcfcfixtures(self, ctx):
468 """Upcoming fixtures of Manchester City"""
469 await self.standings_final(ctx)
470
471 @checks.mod()
472 @commands.group(name="channel")
473 async def channel(self, ctx):
474 """Channel settings for live posts"""
475 pass
476
477 @channel.command(name="live")
478 async def channel_live(self, ctx, channel: discord.TextChannel):
479 """Channel for standings/match updates"""
480 await self.config.channel_live_id.set(channel.id)
481 await self.config.guild_id.set(ctx.guild.id)
482 await ctx.send("Channel set to {}".format(channel.mention))
483
484 @channel.group(name="commentary")
485 async def channel_commentary(self, ctx):
486 """Add/remove commentary channel"""
487 pass
488
489 @channel_commentary.command(name="add")
490 async def channel_commentary_add(self, ctx, channel: discord.TextChannel):
491 async with self.config.channel_commentary_id() as current_channels:
492 current_channels.append(channel.id)
493 self.c_messages[channel.id] = None
494 await ctx.send("Channel {} will now receive commentary!".format(channel.mention))
495
496 @channel_commentary.command(name="remove")
497 async def channel_commentary_remove(self, ctx, channel: discord.TextChannel):
498 async with self.config.channel_commentary_id() as current_channels:
499 if channel.id in current_channels:
500 current_channels.remove(channel.id)
501 await ctx.send("Channel {} removed".format(channel.mention))
502 else:
503 await ctx.send("Channel {} is not added yet.".format(channel.mention))
504
505 @checks.mod()
506 @commands.command(name="mcfcupdate")
507 async def update_data(self, ctx):
508 async with ctx.typing():
509 await self.config.guild_id.set(int(ctx.guild.id))
510 self.guild = ctx.guild
511 await self.fetch_defaults()
512 await ctx.send("Done")
513
514 @tasks.loop(seconds=5.0)
515 async def fetch_live_match(self):
516 try:
517 if (await self.config.live_match_id()) != None:
518 channel = discord.utils.get(self.guild.channels, id=await self.config.channel_live_id())
519 url = "https://api.football-data.org/v2/matches/{}".format(await self.config.live_match_id())
520 resp_score, status_score = await self.api_call_paid(url, return_status=True)
521
522 if resp_score["match"]["status"] == "FINISHED":
523 if self.message != None:
524 try:
525 await self.message.delete()
526 except:
527 pass
528 embed = discord.Embed(color=discord.Color.blue(), description="Join us on Social Media!")
529 embed.add_field(name="The Manchester Discord FC Socials!", value=(
530 "*Twitter* - http://www.twitter.com/mancitydiscord\n" +
531 "*Patreon* - https://www.patreon.com/mancitydiscord\n" +
532 "*Merch* - https://teespring.com/en-GB/stores/manchester-city-fc-discord"
533 ))
534 await channel.send(embed=embed)
535 await self.config.last_match.set(resp_score)
536 await self.reset_live()
537
538 if status_score == 200:
539 if (resp_score != self.plscore):
540 if (resp_score["match"]["status"] == "IN_PLAY") or (resp_score["match"]["status"] == "PAUSED"):
541 self.plscore = resp_score
542
543 print("trying to send")
544 updated = await self.commentary(resp_score)
545 print("c sent")
546
547 if resp_score["match"]["minute"] == "BREAK":
548 resp_score["match"]["minute"] = "Half Time"
549
550 embed = discord.Embed(color=discord.Color.blue(), description="Live Standings")
551 name = "{} {} - {} {}".format(resp_score["match"]["homeTeam"]["name"], resp_score["match"]["score"]["fullTime"]["homeTeam"], resp_score["match"]["score"]["fullTime"]["awayTeam"], resp_score["match"]["awayTeam"]["name"])
552 embed.add_field(name=name, value="Min: " + str(resp_score["match"]["minute"]))
553
554 if self.message == None:
555 self.message = await channel.send(embed=embed)
556 else:
557 if updated == True:
558 await self.message.delete()
559 self.message = await channel.send(embed=embed)
560 else:
561 await self.message.edit(embed=embed)
562 except:
563 pass
564
565 @tasks.loop(seconds=1.0, count=1)
566 async def fetch_guilds(self):
567 if (await self.config.guild_id()) != None:
568 for guild in self.bot.guilds:
569 if guild.id == await self.config.guild_id():
570 self.guild = guild
571 print(guild)
572 break
573 for channel_id in await self.config.channel_commentary_id():
574 self.c_messages[channel_id] = None
575
576 @tasks.loop(seconds=3000.0)
577 async def get_api_key(self):
578 async with aiohttp.ClientSession() as session:
579 headers = {
580 "Authorization": self.basic_key,
581 "Content-Type": "application/x-www-form-urlencoded"
582 }
583 payload = {
584 "grant_type": "client_credentials"
585 }
586 async with session.post("https://oauth2.elenasport.io/oauth2/token", headers=headers, data=payload) as resp:
587 if resp.status != 200:
588 print("Something went wrong while fetching the new api key")
589 else:
590 resp = json.loads(await resp.text())
591 self.temp_key = resp["token_type"] + " " + resp["access_token"]
592
593 @tasks.loop(seconds=90.0)
594 async def get_lineups_elena(self):
595 if (await self.config.live_match_id_elena() != None):
596
597 page = 1
598 topic = "/fixtures/" + str(await self.config.live_match_id_elena()) + "/lineups?page=" + str(page)
599 resp = await self.api_call(topic)
600 print(resp)
601
602 if resp["data"] != []:
603 lineup_total = resp["data"]
604 nextPage = resp["pagination"]["hasNextPage"]
605 while nextPage == True:
606 await asyncio.sleep(1)
607 page += 1
608 topic = "/fixtures/" + str(await self.config.live_match_id_elena()) + "/lineups?page=" + str(page)
609 resp, status = await self.api_call(topic)
610 if status == 200:
611 nextPage = resp["pagination"]["hasNextPage"]
612
613 for item in resp["data"]:
614 lineup_total.append(item)
615
616 await self.config.lineup_elena.set(lineup_total)
617 filename = "lineup.png"
618 filepath = str(cog_data_path(self)) + "/"
619 path = str(bundled_data_path(self)) + "/"
620
621 try:
622 pathlib.Path(str(cog_data_path(self)) + "/" + filename).unlink()
623 except:
624 pass
625
626 await lineup.create_lineup(lineup_total, path, filepath, filename)
627 channel = discord.utils.get(self.guild.channels, id=await self.config.channel_id())
628 await channel.send(file=discord.File(str(cog_data_path(self) / filename)))
629
630 self.get_lineups_elena.cancel()
631
632 @tasks.loop(seconds=20.0)
633 async def get_lineups(self):
634 if (await self.config.live_match_id() != None):
635 url = "https://api.football-data.org/v2/matches/{}".format(await self.config.live_match_id())
636 resp, status = await self.api_call_paid(url, return_status=True)
637
638 if (resp["match"]["homeTeam"]["lineup"] != []) and (resp["match"]["awayTeam"]["lineup"] != []):
639 embed = discord.Embed(color=discord.Color.blue(), description="Lineup for `{}` vs `{}`".format(resp["match"]["homeTeam"]["name"], resp["match"]["awayTeam"]["name"]))
640 lp_home = ""
641 lp_away = ""
642 for i in range(2):
643 if i == 0:
644 gk, df, mf, at = "**Goalkeeper**", "**Defender**", "**Midfielder**", "**Attacker**"
645 for item in resp["match"]["homeTeam"]["lineup"]:
646 if item["position"] == "Goalkeeper":
647 gk += "\n" + item["name"]
648 elif item["position"] == "Defender":
649 df += "\n" + item["name"]
650 elif item["position"] == "Midfielder":
651 mf += "\n" + item["name"]
652 elif item["position"] == "Attacker":
653 at += "\n" + item["name"]
654 string_home = gk + "\n\n" + df + "\n\n" + mf + "\n\n" + at
655
656 else:
657 gk, df, mf, at = "**Goalkeeper**", "**Defence**", "**Midfield**", "**Attack**"
658 for item in resp["match"]["awayTeam"]["lineup"]:
659 if item["position"] == "Goalkeeper":
660 gk += "\n" + item["name"]
661 elif item["position"] == "Defender":
662 df += "\n" + item["name"]
663 elif item["position"] == "Midfielder":
664 mf += "\n" + item["name"]
665 elif item["position"] == "Attacker":
666 at += "\n" + item["name"]
667 string_away = gk + "\n\n" + df + "\n\n" + mf + "\n\n" + at
668 embed.add_field(name=resp["match"]["homeTeam"]["name"], value=string_home, inline=True)
669 embed.add_field(name=resp["match"]["awayTeam"]["name"], value=string_away, inline=True)
670 await self.config.lineup.set(resp["match"])
671 await self.send_commentary(embed)
672 self.get_lineups.cancel()
673
674 def exception_catching_callback(self, task):
675 if task.exception():
676 task.print_stack()
677
678 async def match_for_today(self):
679 while True:
680 now = datetime.datetime.utcnow()
681 date = now.date()
682 if now.time() > self.time_for_loop:
683 date = now.date() + datetime.timedelta(days=1)
684 then = datetime.datetime.combine(date, self.time_for_loop)
685 await discord.utils.sleep_until(then)
686
687 await self.reset_live()
688
689 url = "http://api.football-data.org/v2/teams/65/matches?dateFrom={}&dateTo={}".format(str(date), str(date))
690 resp, status = await self.api_call_paid(url, return_status=True)
691 if status == 200:
692 if resp["matches"] != []:
693 date, time = resp["matches"][0]["utcDate"].split("T")
694 hour, min, sec = time.split(":")
695 time = "{}:{}".format(hour, min)
696 embed = discord.Embed(color=discord.Color.blue(), description="Match for today")
697 if resp["matches"][0]["venue"] != None:
698 embed.add_field(name="{} vs. {}".format(resp["matches"][0]["homeTeam"]["name"], resp["matches"][0]["awayTeam"]["name"]), value="{} at {} \n{}".format(date, time, resp["matches"][0]["venue"]))
699 else:
700 embed.add_field(name="{} vs. {}".format(resp["matches"][0]["homeTeam"]["name"], resp["matches"][0]["awayTeam"]["name"]), value="{} at {}".format(date, time))
701 channel = discord.utils.get(self.guild.channels, id=await self.config.channel_live_id())
702
703 url = "https://api.football-data.org/v2/matches/{}".format(resp["matches"][0]["id"])
704 resp_match, status = await self.api_call_paid(url, return_status=True)
705
706 try:
707 h2h = resp_match["head2head"]
708 embed.add_field(name="Head to head statistics", value="Matches: {}\nTotal goals: {}".format(h2h["numberOfMatches"], h2h["totalGoals"]), inline=False)
709 if h2h["homeTeam"]["name"] == "Manchester City FC":
710 embed.add_field(name=h2h["homeTeam"]["name"], value="Wins: {}\nDraws: {}\nLosses: {}".format(h2h["homeTeam"]["wins"], h2h["homeTeam"]["draws"], h2h["homeTeam"]["losses"]), inline=True)
711 else:
712 embed.add_field(name=h2h["awayTeam"]["name"], value="Wins: {}\nDraws: {}\nLosses: {}".format(h2h["awayTeam"]["wins"], h2h["awayTeam"]["draws"], h2h["awayTeam"]["losses"]), inline=True)
713 except:
714 pass
715
716 embed.set_footer(text="More stats: https://native-stats.org/team/65/stats")
717 embed.set_author(name="Manchester City", icon_url=resp_match["match"]["competition"]["area"]["ensignUrl"])
718
719 league = resp_match["match"]["competition"]["name"]
720 if league == "Premier League":
721 league = "pl"
722 elif league == "UEFA Champions League":
723 league = "cl"
724 elif league == "FA Cup":
725 league = "fa"
726
727 await self.config.live_match_id.set(resp["matches"][0]["id"])
728 await channel.send(embed=embed)
729
730 if league in self.subscribed_leagues:
731 league_id = await self.config_get(league, "season_id_latest")
732 url = "https://football.elenasport.io/v2/seasons/{}/upcoming".format(league_id)
733 resp_elena, status = await self.api_call(api_url=url, return_status=True)
734 if (status == 200) and (resp_elena["data"] != []):
735 for item in resp_elena["data"]:
736 if (item["idHome"] == 99) or (item["idAway"] == 99):
737 await self.config.live_match_id_elena.set(item["id"])
738
739 self.start_live.start(resp_match["match"])
740
741 @tasks.loop(seconds=10)
742 async def start_live(self, match):
743 time = self.convert_time(match["utcDate"], return_datetime=True)
744 time_lineup = time - datetime.timedelta(hours=1)
745 time_live = time - datetime.timedelta(minutes=5)
746
747 date = datetime.datetime.now(time.tzinfo)
748 if (date > time_lineup) and (self.get_lineups.is_running() == False) and (await self.config.lineup() == None):
749 self.get_lineups.start()
750 # if (date > time_lineup) and (self.get_lineups_elena.is_running() == False) and (await self.config.lineup_elena() == None):
751 # self.get_lineups_elena.start()
752 if (date > time_live) and (self.fetch_live_match.is_running() == False):
753 self.fetch_live_match.start()
754 if (await self.config.linuep() != None) and (self.fetch_live_match.is_running() == True):
755 self.start_live.cancel()
756
757 @commands.command()
758 async def temp(self, ctx):
759 await self.reset_live()
760 channel = discord.utils.get(self.guild.channels, id=await self.config.channel_live_id())
761 await channel.purge(limit=100)
762 date = datetime.datetime.utcnow().date()
763
764 url = "http://api.football-data.org/v2/teams/57/matches?dateFrom={}&dateTo={}".format(str(date), str(date))
765 resp, status = await self.api_call_paid(url, return_status=True)
766 if status == 200:
767 if resp["matches"] != []:
768 date, time = self.convert_time(resp["matches"][0]["utcDate"])
769 embed = discord.Embed(color=discord.Color.blue(), description="Match for today", url="https://native-stats.org/team/65/stats")
770 if resp["matches"][0]["venue"] != None:
771 embed.add_field(name="{} vs. {}".format(resp["matches"][0]["homeTeam"]["name"], resp["matches"][0]["awayTeam"]["name"]), value="{} at {} \n{}".format(date, time, resp["matches"][0]["venue"]))
772 else:
773 embed.add_field(name="{} vs. {}".format(resp["matches"][0]["homeTeam"]["name"], resp["matches"][0]["awayTeam"]["name"]), value="{} at {}".format(date, time))
774
775 url = "https://api.football-data.org/v2/matches/{}".format(resp["matches"][0]["id"])
776 resp_match, status = await self.api_call_paid(url, return_status=True)
777
778 try:
779 h2h = resp_match["head2head"]
780 embed.add_field(name="**Head to head statistics**", value="Matches: {}\nTotal goals: {}".format(h2h["numberOfMatches"], h2h["totalGoals"]), inline=False)
781 if h2h["homeTeam"]["name"] == "Manchester City FC":
782 embed.add_field(name=h2h["homeTeam"]["name"], value="Wins: {}\nDraws: {}\nLosses: {}".format(h2h["homeTeam"]["wins"], h2h["homeTeam"]["draws"], h2h["homeTeam"]["losses"]), inline=True)
783 else:
784 embed.add_field(name=h2h["awayTeam"]["name"], value="Wins: {}\nDraws: {}\nLosses: {}".format(h2h["awayTeam"]["wins"], h2h["awayTeam"]["draws"], h2h["awayTeam"]["losses"]), inline=True)
785 except:
786 pass
787
788 embed.set_footer(text="More stats: https://native-stats.org/team/65/stats")
789 embed.set_author(name="The Manchester City Discord", icon_url=self.guild.icon_url)
790 embed.set_thumbnail(url=self.guild.icon_url)
791 embed.set_image(url=resp_match["match"]["competition"]["area"]["ensignUrl"])
792
793 league = resp_match["match"]["competition"]["name"]
794 if league == "Premier League":
795 league = "pl"
796 elif league == "UEFA Champions League":
797 league = "cl"
798 elif league == "FA Cup":
799 league = "fa"
800
801 await self.config.live_match_id.set(resp["matches"][0]["id"])
802 await channel.send(embed=embed)
803
804 if league in self.subscribed_leagues:
805 league_id = await self.config_get(league, "season_id_latest")
806 url = "https://football.elenasport.io/v2/seasons/{}/upcoming".format(league_id)
807 resp, status = await self.api_call(api_url=url, return_status=True)
808 print(resp)
809 if (status == 200) and (resp["data"] != []):
810 for item in resp["data"]:
811 if (item["idHome"] == 99) or (item["idAway"] == 99):
812 await self.config.live_match_id_elena.set(item["id"])
813 print(item["id"])
814
815 self.start_live.start(resp_match["match"])
816
817 @commands.command()
818 async def temp2(self, ctx):
819 print(self.start_live.is_running())
820 print(self.get_lineups_elena.is_running())
821 print(await self.config.live_match_id_elena())