· 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())