예제 #1
0
    async def sendMatchEvent(channel: Channel, match: Match,
                             event: MatchEventData):
        """
        This function encapsulates the look and feel of the message that is sent when a matchEvent happens.
        It will build the matchString, the embed object, etc. and than send it to the appropiate channel.
        :param channel: The channel where we want to send things to
        :param match: The match that this message applies to (Metadata!)
        :param event: The actual event that happened. It consists of a MatchEvents enum and a DataDict, which in
        itself contains the minute, team and player(s) the event applies to.
        """

        title, content, goalString = await LiveMatch.beautifyEvent(
            event, match)
        embObj = Embed(title=title, description=content)
        embObj.set_author(name=match.competition.clear_name)

        try:
            await client.send_message(channel, embed=embObj)
        except:
            await asyncio.sleep(10)
            for i in client.get_all_channels():
                if i.name == channel.name:
                    logger.debug(f"Sending {embObj} to {i.name}")
                    await client.send_message(i, embed=embObj)

        return title, goalString
예제 #2
0
async def createChannel(server: Server, channelName: str):
    """
    Creates a channel on the discord server.
    :param server: Server object --> relevant server for the channel
    :param channelName: Name of the channel that is to be created
    """
    for i in client.get_all_channels():
        if i.name == toDiscordChannelName(channelName) and i.server == server:
            logger.debug(f"Channel {channelName} already available ")
            return
    logger.info(f"Creating channel {channelName} on {server.name}")
    await client.create_channel(server, channelName)
예제 #3
0
    async def sendMatchEvent(self, channel: TextChannel, match: Match,
                             event: MatchEventData):
        """
        This function encapsulates the look and feel of the message that is sent when a matchEvent happens.
        It will build the matchString, the embed object, etc. and than send it to the appropiate channel.
        :param channel: The channel where we want to send things to
        :param match: The match that this message applies to (Metadata!)
        :param event: The actual event that happened. It consists of a MatchEvents enum and a DataDict, which in
        itself contains the minute, team and player(s) the event applies to.
        """

        title, content, goalString = await LiveMatch.beautifyEvent(
            event, match)
        embObj = Embed(title=title, description=content)
        embObj.set_author(name=match.competition.clear_name)
        embObj.colour = self.color

        lastName = event.player.split(" ")[-1].lower()
        firstName = event.player.split(" ")[0].lower()

        imageList = Player.objects.filter(lastName=lastName)
        image = None

        if len(imageList) != 0:
            if len(imageList) == 1:
                image = imageList.first().imageLink
            else:
                imageList = imageList.filter(firstName=firstName)
                if len(imageList) != 0:
                    image = imageList.first().imageLink
                else:
                    imageList = Player.objects.filter(lastName=lastName)
                    image = imageList.first().imageLink

        if image is not None:
            embObj.set_thumbnail(url=image)

        try:
            msg = await channel.send(embed=embObj)
        except:
            await asyncio.sleep(10)
            for i in client.get_all_channels():
                if i.name == channel.name:
                    logger.debug(f"Sending {embObj} to {i.name}")
                    msg = await channel.send(embed=embObj)

        msgEvent = RedditEvent(event, datetime.utcnow(), self.match,
                               self.updateMsg)
        self.msgList[msgEvent] = msg
        RedditParser.addEvent(msgEvent)

        return title, goalString
예제 #4
0
async def removeOldChannels():
    """
    Removes all channels with the name *-matchday-* in them.
    """
    deleteChannelList = []
    #these two loops are split up, as the it raises an error when the dict changes.
    for i in client.get_all_channels():
        if "-matchday-" in i.name:
            logger.info(f"Deleting old channel {i.name}")
            deleteChannelList.append((i.server, i.name))

    for i in deleteChannelList:
        await deleteChannel(i[0], i[1])
예제 #5
0
async def deleteChannel(server: Server, channelName: str):
    """
    Deletes a channel on the discord server
    :param server: Server object --> relevant server for the channel
    :param channelName: Name of the channel that is to be deleted
    """
    for i in client.get_all_channels():
        if i.name == toDiscordChannelName(channelName) and i.server == server:
            logger.debug(
                f"Deleting channel {toDiscordChannelName(channelName)} on {server.name}"
            )
            await client.delete_channel(i)
            break
예제 #6
0
async def deleteChannel(guild: Guild, channelName: str):
    """
    Deletes a channel on the discord server
    :param guild: Server object --> relevant server for the channel
    :param channelName: Name of the channel that is to be deleted
    """
    for i in client.get_all_channels():
        if i.name == toDiscordChannelName(channelName) and i.guild == guild:
            logger.debug(
                f"Deleting channel {toDiscordChannelName(channelName)} on {guild.name}"
            )
            try:
                await i.delete()
            except discord.errors.NotFound:
                pass
            break
예제 #7
0
async def createChannel(guild: Guild,
                        channelName: str,
                        role: str = None,
                        category: str = None):
    """
    Creates a channel on the discord server.
    :param guild: Server object --> relevant server for the channel
    :param channelName: Name of the channel that is to be created
    """
    for i in client.get_all_channels():
        if i.name == toDiscordChannelName(channelName) and i.guild == guild:
            logger.debug(f"Channel {channelName} already available ")
            return
    logger.info(f"Creating channel {channelName} on {guild.name}")

    targetRole = None
    for i in guild.roles:
        if int(i.id) == role:
            targetRole = i
            break

    if category is not None:
        channelCat = None
        for i in guild.categories:
            if i.name == category:
                channelCat = i
                break

        if channelCat is None:
            channelCat = await guild.create_category(category)
    else:
        channelCat = None

    if targetRole is None:
        overwrites = None
    else:
        overwrites = {
            guild.default_role:
            discord.PermissionOverwrite(read_messages=False,
                                        send_messages=False),
            targetRole:
            discord.PermissionOverwrite(read_messages=True, send_messages=True)
        }
    await guild.create_text_channel(channelName,
                                    overwrites=overwrites,
                                    category=channelCat)
예제 #8
0
    async def runMatchThread(self):
        """
        Start a match threader for a given match. Will read the live data from the middleWare API (data.fifa.com) every
        20 seconds and post the events to the channel that corresponds to the match. This channel has to be created
        previously.
        :param match: Match object.  Will  post to discord channels if the object is a database.models.Match object
        """
        if self.runningStarted:
            logger.warning(f"Match {self.title} already started!")
            return
        else:
            logger.info(f"Starting match {self.title}")
        self.runningStarted = True
        pastEvents = []
        eventList = []
        sleepTime = 600
        endCycles = 10

        matchid = self.match.id
        channelName = toDiscordChannelName(
            f"{self.match.competition.clear_name} Matchday {self.match.matchday}"
        )

        lineupsPosted = False
        while True:
            try:
                data = makeMiddlewareCall(DataCalls.liveData + f"/{matchid}")
            except JSONDecodeError:
                break

            if data["match"]["isFinished"] and not self.running:
                logger.info(f"Match {self.match} allready passed")
                break

            self.running = True
            if data["match"]["isLive"]:
                self.started = True
            else:
                self.started = False

            if not self.lock.is_set():
                self.lock.set()

            if not lineupsPosted and data["match"]["hasLineup"]:
                logger.info(f"Posting lineups for {self.title}")
                await asyncio.sleep(5)
                try:
                    for channel in client.get_all_channels():
                        if channel.name == channelName:
                            await LiveMatch.postLineups(
                                channel, self.match, data["match"])
                            lineupsPosted = True
                            sleepTime = 20
                except RuntimeError:
                    lineupsPosted = False
                    logger.warning("Size of channels has changed")
            else:
                if not lineupsPosted:
                    logger.info(f"Lineups not yet available for {self.title}")

            newEvents, pastEvents = LiveMatch.parseEvents(
                data["match"]["events"], pastEvents)
            eventList += newEvents

            for i in eventList:
                try:
                    for channel in client.get_all_channels():
                        if channel.name == channelName:
                            self.started = True
                            self.title, goalString = await LiveMatch.sendMatchEvent(
                                channel, self.match, i)
                            self.goalList.append(goalString)
                            try:
                                eventList.remove(i)
                            except ValueError:
                                pass
                            logger.info(f"Posting event: {i}")
                except RuntimeError:
                    logger.warning("Size of channels has changed!")
                    break

            if self.lock.is_set():
                self.lock.clear()

            if data["match"]["isFinished"]:
                if endCycles <= 0:
                    logger.info(f"Match {match} finished!")
                    break
                endCycles -= 1

            await asyncio.sleep(sleepTime)

        now = datetime.utcnow().replace(tzinfo=UTC)
        if now < (self.match.date + timedelta(hours=3)).replace(tzinfo=UTC):
            self.passed = True
        self.running = False
        self.started = False
        self.runningStarted = False
        self.lock.set()
        logger.info(f"Ending match {self.title}")
예제 #9
0
    async def postLineups(channel: Channel, match: Match, data: Dict):
        lineup = OrderedDict()
        for i in ['home', 'away']:
            lineup[i] = OrderedDict()
            lineup[i]['starting'] = []
            lineup[i]['bench'] = []
            lineup[i]['coach'] = []
            for player in data['lineups']['teams'][i]:
                playerInfo = OrderedDict()
                playerInfo['name'] = player['personName']
                playerInfo['number'] = player['shirtNumber']
                playerInfo['captain'] = player['isCaptain']
                playerInfo['gk'] = player['isGoalKeeper']

                if player['isCoach']:
                    lineup[i]['coach'].append(playerInfo)
                elif player['startingLineUp']:
                    lineup[i]['starting'].append(playerInfo)
                else:
                    lineup[i]['bench'].append(playerInfo)

        def getLineupPlayerString(teamString):
            def listPlayers(position):
                fullLineupString = ""
                for startingPlayer in lineup[teamString][position]:
                    lineupString = LiveMatch.styleSheetLineups(
                        "PlayerTemplate")
                    lineupString = lineupString.replace(
                        "$number$", str(startingPlayer['number']))
                    lineupString = lineupString.replace(
                        "$player$", startingPlayer['name'])
                    if startingPlayer['gk']:
                        lineupString = lineupString.replace(
                            "$gkTemplate$",
                            LiveMatch.styleSheetLineups("GKTemplate"))
                    else:
                        lineupString = lineupString.replace("$gkTemplate$", "")
                    if startingPlayer['captain']:
                        lineupString = lineupString.replace(
                            "$captainTemplate$",
                            LiveMatch.styleSheetLineups("CaptainTemplate"))
                    else:
                        lineupString = lineupString.replace(
                            "$captainTemplate$", "")
                    fullLineupString += lineupString
                return fullLineupString

            lineupString = LiveMatch.styleSheetLineups("Layout")
            lineupString = lineupString.replace("$playerTemplate$",
                                                listPlayers('starting'))
            coachString = LiveMatch.styleSheetLineups("CoachTemplate")
            coachString = coachString.replace(
                "$coach$", lineup[teamString]['coach'][0]['name'])
            lineupString = lineupString.replace("$coachTemplate$", coachString)
            return lineupString

        homeString = getLineupPlayerString('home')
        awayString = getLineupPlayerString('away')

        title = LiveMatch.styleSheetLineups("cardTitle")
        description = LiveMatch.styleSheetLineups("cardDescription")
        description = description.replace("$home_team$",
                                          match.home_team.clear_name)
        description = description.replace("$away_team$",
                                          match.away_team.clear_name)

        embObj = Embed(title=title, description=description)

        teamTitle = LiveMatch.styleSheetLineups("TeamTitle")
        homeTeamTitle = teamTitle.replace("$team$", match.home_team.clear_name)
        awayTeamTitle = teamTitle.replace("$team$", match.away_team.clear_name)

        embObj.add_field(name=homeTeamTitle, value=homeString)
        embObj.add_field(name=awayTeamTitle, value=awayString)

        try:
            await client.send_message(channel, embed=embObj)
        except:
            await asyncio.sleep(10)
            for i in client.get_all_channels():
                if channel.name == i.name:
                    await client.send_message(channel, embed=embObj)
예제 #10
0
    async def matchScheduler():
        """
        Parses all available matches for a given matchday and starts them if necessary.
        """
        logger.debug("Waiting for client ready.")
        await client.wait_until_ready()
        logger.debug("Client ready, starting loop")
        Scheduler.matchDayObject = getNextMatchDayObjects(
        )  #add competition adds new competitions to this.
        Scheduler.runMatchSchedulerFlag = True
        try:
            while True:
                if Scheduler.stopFlag:
                    logger.info("Stop Flag raised! Match ends")
                    break

                Scheduler.matchSchedulerRunning.set()
                Scheduler.maintananceSynchronizer.wait()
                time = datetime.utcnow()

                try:
                    for competition, matchObject in Scheduler.matchDayObject.items(
                    ):
                        for md, data in matchObject.items():
                            currentTime = datetime.utcnow().replace(tzinfo=UTC)

                            if data['start'] < currentTime and data[
                                    'end'] > currentTime:
                                logger.debug(
                                    "Current time within boundaries, starting match"
                                )
                                await asyncCreateChannel(
                                    data['channel_name'],
                                    role=data['role'],
                                    category=data['category'])
                                logger.debug("Looking into upcoming matches: ")
                                for i in data['upcomingMatches']:
                                    logger.debug(
                                        f"Match {i}, flag runningStarted {i.runningStarted}"
                                    )
                                    if not i.runningStarted:
                                        logger.debug(f"Starting task {i}")
                                        client.loop.create_task(
                                            i.runMatchThread())
                                        logger.debug(
                                            f"Waiting for {i} to have started")
                                        i.lock.wait()
                                        logger.debug(f"{i} started")
                                    data['currentMatches'].append(i)
                                    data['upcomingMatches'].remove(i)

                                    if datetime.utcnow() - time > timedelta(
                                            seconds=30):
                                        client.get_all_channels()
                                        logger.warning(
                                            "Didnt sleep for 30 seconds, sleeping now"
                                        )
                                        await asyncio.sleep(10)
                                        time = datetime.utcnow()

                                await asyncio.sleep(5)

                                logger.debug("Looking into currentMatches")
                                for i in data['currentMatches']:
                                    logger.debug(
                                        f"Match {i}, flags runningStarted {i.runningStarted}, passed {i.passed}"
                                    )

                                    if not i.runningStarted:
                                        logger.debug(
                                            f"Starting i, as it is not started but in currentMatches"
                                        )
                                        client.loop.create_task(
                                            i.runMatchThread())
                                        logger.debug(
                                            f"Watiting for {i} to have started"
                                        )
                                        i.lock.wait()

                                    if i.passed:
                                        logger.debug(
                                            f"{i} has passed, moving it to passedMatches"
                                        )
                                        data['passedMatches'].append(i)
                                        data['currentMatches'].remove(i)

                                    if datetime.utcnow() - time > timedelta(
                                            seconds=30):
                                        client.get_all_channels()
                                        logger.warning(
                                            "Didnt sleep for 30 seconds, sleeping now"
                                        )
                                        await asyncio.sleep(10)
                                        time = datetime.utcnow()

                                await asyncio.sleep(5)
                    await asyncio.sleep(10)

                except RuntimeError:
                    logger.error("Dict size changed!")
                    await asyncio.sleep(5)
                    continue
                Scheduler.matchSchedulerRunning.clear()
                await asyncio.sleep(60)
        finally:
            Scheduler.runMatchSchedulerFlag = False