Skip to content

Commit

Permalink
Merge pull request #2 from amosbastian/0.2.0
Browse files Browse the repository at this point in the history
0.2.0
  • Loading branch information
Amos Bastian committed Feb 10, 2019
2 parents 4d53ce5 + e1a5ea0 commit d2809ba
Show file tree
Hide file tree
Showing 5 changed files with 450 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,5 @@ venv.bak/

.vscode/
config.json

*.swp
135 changes: 129 additions & 6 deletions FPLbot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import logging
import os
import re
from datetime import datetime

import aiohttp
Expand All @@ -10,31 +11,34 @@
from fpl.utils import position_converter
from pymongo import MongoClient

from utils import create_logger, get_player_table, update_players
from constants import fpl_team_names, versus_pattern
from utils import create_logger, get_player_table, to_fpl_team, update_players

dirname = os.path.dirname(os.path.realpath(__file__))
logger = create_logger()
client = MongoClient()


class FPLBot:
def __init__(self, config, session):
self.client = MongoClient()
self.config = config
self.database = client.fpl
self.fpl = FPL(session)
self.reddit = praw.Reddit(
client_id=config.get("CLIENT_ID"),
client_secret=config.get("CLIENT_SECRET"),
password=config.get("PASSWORD"),
user_agent=config.get("USER_AGENT"),
username=config.get("USERNAME"))
self.subreddit = self.reddit.subreddit(config.get("SUBREDDIT"))
self.subreddit = self.reddit.subreddit(self.config.get("SUBREDDIT"))

async def get_price_changers(self):
"""Returns a list of players whose price has changed since the last
time the database was updated.
"""
logger.info("Retrieving risers and fallers.")
new_players = await self.fpl.get_players(include_summary=True)
old_players = [player for player in self.client.fpl.players.find()]
old_players = [player for player in self.database.players.find()]

risers = []
fallers = []
Expand Down Expand Up @@ -77,12 +81,132 @@ async def post_price_changes(self):
self.subreddit.submit(post_title, selftext=post_body)
await update_players()

def player_vs_team_table(self, fixtures):
"""Returns a Markdown table showing the player's performance in the
given fixtures.
"""
table = ("|Fixture|Date|MP|G|xG|A|xA|NPG|NPxG|KP|\n"
"|:-|:-:|-:|-:|-:|-:|-:|-:|-:|-:|\n")

for fixture in fixtures:
home_team = f"{fixture['h_team']} {fixture['h_goals']}"
away_team = f"{fixture['a_goals']} {fixture['a_team']}"

# Highlight the winning team
if int(fixture["h_goals"]) > int(fixture["a_goals"]):
home_team = f"**{home_team}**"
elif int(fixture["h_goals"]) < int(fixture["a_goals"]):
away_team = f"**{away_team}**"

# Highlight whether the player was a starter or not
if fixture["position"].lower() != "sub":
fixture["time"] = f"**{fixture['time']}**"

table += (
f"|{home_team}-{away_team}"
f"|{fixture['date']}"
f"|{fixture['time']}"
f"|{fixture['goals']}"
f"|{float(fixture['xG']):.2f}"
f"|{fixture['assists']}"
f"|{float(fixture['xA']):.2f}"
f"|{fixture['npg']}"
f"|{float(fixture['npxG']):.2f}"
f"|{fixture['key_passes']}|\n"
)

return table

def versus_team_handler(self, player_name, team_name, number_of_fixtures):
"""Function for handling player vs. team comment."""
# Find most relevant player using text search
players = self.database.players.find(
{"$text": {"$search": player_name}},
{"score": {"$meta": "textScore"}}
).sort([("score", {"$meta": "textScore"})])

try:
player = list(players.limit(1))[0]
except IndexError:
logger.error(f"Player {player_name} could not be found!")
return

if not number_of_fixtures:
number_of_fixtures = len(player["understat_history"])

fixture_count = 0
relevant_fixtures = []
team_name = to_fpl_team(team_name)
for fixture in player["understat_history"]:
if fixture_count >= int(number_of_fixtures):
break

if (team_name != fixture["h_team"].lower() and
team_name != fixture["a_team"].lower()):
continue

fixture_count += 1
relevant_fixtures.append(fixture)

player_vs_team_table = self.player_vs_team_table(relevant_fixtures)
return player_vs_team_table

def add_comment_to_database(self, comment):
logger.info(f"Adding comment with ID {comment.id} to the database.")
self.database.comments.update_one(
{"comment_id": comment.id},
{"$set": {"comment_id": comment.id}},
upsert=True
)

def comment_handler(self, comment):
"""Generic comment handler."""
logger.info(f"Handling COMMENT with ID {comment.id}.")
match = re.search(versus_pattern, comment.body.lower())

if not match:
logger.info(f"Comment with ID {comment.id} does not match pattern.")
return

player_name = match.group(1).lower().strip()
opponent_name = match.group(2).lower().replace(".", "").strip()
number = match.group(3)

if to_fpl_team(opponent_name) in fpl_team_names:
reply_text = self.versus_team_handler(
player_name, opponent_name, number)
else:
return

if reply_text:
logger.info(f"Replying ({player_name} vs. {opponent_name}) to "
f"comment with ID {comment.id}.")
comment.reply(reply_text)
self.add_comment_to_database(comment)

def is_new_comment(self, comment_id):
if self.database.comments.count_documents({"comment_id": comment_id}) < 1:
return True
return False

def run(self):
for comment in self.subreddit.stream.comments():
body = comment.body.lower()
if self.config.get("BOT_PREFIX") in body:
if not self.is_new_comment(comment.id):
continue

try:
self.comment_handler(comment)
except Exception as error:
logger.error(f"Something went wrong: {error}")


async def main(config):
async with aiohttp.ClientSession() as session:
fpl_bot = FPLBot(config, session)

await fpl_bot.post_price_changes()
fpl_bot.run()


if __name__ == "__main__":
Expand All @@ -93,4 +217,3 @@ async def main(config):
loop = asyncio.get_event_loop()
loop.run_until_complete(main(config))
loop.close()

185 changes: 185 additions & 0 deletions FPLbot/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import re

player_dict = {
"Fred": "Frederico Rodrigues de Paula Santos",
"Ki Sung-yueng": "Sung-yueng Ki",
"Solly March": "Solomon March",
"Jonny": "Jonathan Castro Otto",
"Felipe Anderson": "Felipe Anderson Pereira Gomes",
"Mat Ryan": "Mathew Ryan",
"Kenedy": "Robert Kenedy Nunes do Nascimento",
"Jorginho": "Jorge Luiz Frello Filho",
"Bernard": "Bernard Anício Caldeira Duarte",
"Romain Saiss": "Romain Saïss",
"Bernardo Silva": "Bernardo Mota Veiga de Carvalho e Silva",
"N&#039;Golo Kanté": "N'Golo Kanté",
"João Moutinho": "João Filipe Iria Santos Moutinho",
"Franck Zambo": "André-Frank Zambo Anguissa",
"Fousseni Diabate": "Fousseni Diabaté",
"Jazz Richards": "Ashley Darel Jazz Richards",
"Danilo": "Danilo Luiz da Silva",
"Richarlison": "Richarlison de Andrade",
"Bernardo": "Bernardo Fernandes da Silva Junior",
"Fernandinho": "Fernando Luiz Rosa",
"Joselu": "Jose Luis Mato Sanmartín",
"Son Heung-Min": "Heung-Min Son",
"Diogo Dalot": "José Diogo Dalot Teixeira",
"José Izquierdo": "José Heriberto Izquierdo Mena",
"Fabri": "Fabricio Agosto Ramírez",
"Eddie Nketiah": "Edward Nketiah",
"Rui Patrício": "Rui Pedro dos Santos Patrício",
"Greg Cunningham": "Greg Cunninghamm",
"Junior Hoilett": "David Junior Hoilett",
"Isaac Success": "Isaac Success Ajayi",
"Xande Silva": "Alexandre Nascimento Costa Silva",
"Bruno": "Bruno Saltor Grau",
"Léo Bonatini": "Bonatini Lohner Maia Bonatini",
"André Gomes": "André Filipe Tavares Gomes",
"Kiko Femenía": "Francisco Femenía Far",
"Dele Alli": "Bamidele Alli",
"Ricardo Pereira": "Ricardo Domingos Barbosa Pereira",
"Sokratis": "Sokratis Papastathopoulos",
"Alisson": "Alisson Ramses Becker",
"Fabinho": "Fabio Henrique Tavares",
"Adrien Silva": "Adrien Sebastian Perruchet Silva",
"David de Gea": "David De Gea",
"Gabriel Jesus": "Gabriel Fernando de Jesus",
"Pedro": "Pedro Rodríguez Ledesma",
"Zanka": "Mathias Jorgensen",
"David Luiz": "David Luiz Moreira Marinho",
"Rúben Neves": "Rúben Diogo da Silva Neves",
"Ben Chilwell": "Benjamin Chilwell",
"Kepa": "Kepa Arrizabalaga",
"Emerson": "Emerson Palmieri dos Santos",
"Ederson": "Ederson Santana de Moraes",
"Chicharito": "Javier Hernández Balcázar",
"Rúben Vinagre": "Rúben Gonçalo Silva Nascimento Vinagre",
"Oriol Romeu": "Oriol Romeu Vidal",
"Lucas Moura": "Lucas Rodrigues Moura da Silva",
"Willian": "Willian Borges Da Silva",
}

team_dict = {
"Manchester City": "Man City",
"Tottenham": "Spurs",
"Manchester United": "Man Utd",
"Wolverhampton Wanderers": "Wolves"
}

desired_attributes = [
"xG",
"xA",
"key_passes",
"npg",
"npxG",
"xGChain",
"xGBuildup",
"shots",
"understat_history"
]

versus_pattern = re.compile(r"!fplbot\s+([^\W\d]+(?:[\s-][^\W\d]+)*)\s+(?:vs.|vs)\s+([a-zA-Z ]+)(\d+)?")

to_fpl_team_dict = {
"arsenal fc": "arsenal",
"the gunners": "arsenal",
"afc bournemouth": "bournemouth",
"the cherries": "bournemouth",
"boscombe": "bournemouth",
"the seagulls": "brighton",
"albion": "brighton",
"brighton and hove albion": "brighton",
"brighton & hove albion": "brighton",
"brighton fc": "brighton",
"bha": "brighton",
"burnley fc": "burnley",
"the clarets": "burnley",
"cardiff city": "cardiff",
"cardiff city fc": "cardiff",
"ccfc": "cardiff",
"car": "cardiff",
"the bluebirds": "cardiff",
"chelsea fc": "chelsea",
"cfc": "chelsea",
"che": "chelsea",
"the pensioners": "chelsea",
"crystal palace fc": "crystal palace",
"cpfc": "crystal palace",
"cp": "crystal palace",
"the eagles": "crystal palace",
"the glaziers": "crystal palace",
"everton fc": "everton",
"the toffees": "everton",
"fulham fc": "fulham",
"the cottagers": "fulham",
"huddersfield town": "huddersfield",
"huddersfield town afc": "huddersfield",
"huddersfield afc": "huddersfield",
"the terriers": "huddersfield",
"leicester city": "leicester",
"leicester city fc": "leicester",
"the foxes": "leicester",
"lfc": "liverpool",
"liverpool fc": "liverpool",
"mcfc": "man city",
"manchester city": "man city",
"manchester city fc": "man city",
"man city fc": "man city",
"citizens": "man city",
"mufc": "man utd",
"manchester united": "man utd",
"manchester utd": "man utd",
"man u": "man utd",
"man united": "man utd",
"the red devils": "man utd",
"red devils": "man utd",
"newcastle united": "newcastle",
"newcastle united fc": "newcastle",
"nufc": "newcastle",
"newcastle utd": "newcastle",
"the magpies": "newcastle",
"southampton fc": "southampton",
"the saints": "southampton",
"tottenham": "spurs",
"thfc": "spurs",
"tottenham hotspur": "spurs",
"tottenham hotspurs": "spurs",
"tottenham fc": "spurs",
"watford fc": "watford",
"wfc": "watford",
"the hornets": "watford",
"west ham united": "west ham",
"west ham utd": "west ham",
"the hammers": "west ham",
"west ham fc": "west ham",
"west ham united fc": "west ham",
"wolverhampton": "wolves",
"wolverhampton wanderers": "wolves",
"wolves fc": "wolves",
"wolverhampton fc": "wolves",
"wolverhampton wanderers fc": "wolves",
"the wanderers": "wolves"
}

fpl_team_names = [
"arsenal",
"bournemouth",
"brighton",
"burnley",
"cardiff",
"chelsea",
"crystal palace",
"everton",
"fulham",
"huddersfield",
"leicester",
"liverpool",
"man city",
"man utd",
"newcastle",
"southampton",
"spurs",
"watford",
"west ham",
"wolves"
]
Loading

0 comments on commit d2809ba

Please sign in to comment.