Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.1.0 #1

Merged
merged 17 commits into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ venv.bak/

# mypy
.mypy_cache/

.vscode/
config.json
90 changes: 90 additions & 0 deletions FPLbot/bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import asyncio
import json
import logging
import os
from datetime import datetime

import aiohttp
import praw
from fpl import FPL
from fpl.utils import position_converter
from pymongo import MongoClient

from utils import create_logger, get_player_table, update_players

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


class FPLBot:
def __init__(self, config, session):
self.client = MongoClient()
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"))

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

risers = []
fallers = []

for new_player in new_players:
try:
old_player = next(player for player in old_players
if player["id"] == new_player.id)
# New player has been added to the game
except StopIteration:
logger.info(f"New player added: {new_player}.")
continue

if old_player["now_cost"] > new_player.now_cost:
fallers.append(new_player)
elif old_player["now_cost"] < new_player.now_cost:
risers.append(new_player)

return risers, fallers

async def post_price_changes(self):
"""Posts the price changes to Reddit."""
risers, fallers = await self.get_price_changers()
risers_table = get_player_table(risers, True)
fallers_table = get_player_table(fallers, False)

post_template = open(f"{dirname}/../post_template.md").read()
post_body = post_template.format(
risers_number=len(risers),
risers_table=risers_table,
fallers_number=len(fallers),
fallers_table=fallers_table
)

today = datetime.now()
current_date = f"({today:%B} {today.day}, {today.year})"
post_title = f"Player Price Changes {current_date}"

logger.info(f"Posting price changes to Reddit.\n\n{post_body}")
self.subreddit.submit(post_title, selftext=post_body)
await update_players()


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

await fpl_bot.post_price_changes()


if __name__ == "__main__":
config = json.loads(open(f"{dirname}/../config.json").read())
asyncio.run(main(config))
74 changes: 74 additions & 0 deletions FPLbot/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import asyncio
import logging
import os

import aiohttp
from fpl import FPL
from fpl.utils import position_converter, team_converter
from pymongo import MongoClient, ReplaceOne

client = MongoClient()
database = client.fpl
logger = logging.getLogger("FPLbot")


def create_logger():
"""Creates a logger object for use in logging across all files.

See: https://docs.python.org/3/howto/logging-cookbook.html
"""
dirname = os.path.dirname(os.path.realpath(__file__))

logger = logging.getLogger("FPLbot")
logger.setLevel(logging.DEBUG)

fh = logging.FileHandler(f"{dirname}/FPLbot.log")
fh.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)

formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - "
"%(message)s")

fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh)
logger.addHandler(ch)
return logger


async def update_players():
"""Updates all players in the database."""
async with aiohttp.ClientSession() as session:
fpl = FPL(session)
players = await fpl.get_players(include_summary=True, return_json=True)

requests = [ReplaceOne({"id": player["id"]}, player, upsert=True)
for player in players]

logger.info("Updating players in database.")
database.players.bulk_write(requests)


def get_player_table(players, risers=True):
"""Returns the table used in the player price change posts on Reddit."""
table_header = ("|Name|Team|Position|Ownership|Price|∆|Form|\n"
"|:-|:-|:-|:-:|:-:|:-:|:-:|\n")

table_body = "\n".join([
f"|{player.web_name}|"
f"{team_converter(player.team)}|"
f"{position_converter(player.element_type)}|"
f"{player.selected_by_percent}%|"
f"£{player.now_cost / 10.0:.1f}|"
f"{'+' if risers else '-'}£{abs(player.cost_change_event / 10.0):.1f}|"
f"{sum([fixture['total_points'] for fixture in player.history[-5:]])}|"
for player in players])

return table_header + table_body


if __name__ == "__main__":
asyncio.run(update_players())
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,35 @@
# FantasyPL_bot
A bot for the FantasyPL subreddit
# FPLbot

FPLbot is a bot made for the subreddit [/r/FantasyPL](https://www.reddit.com/r/FantasyPL/).
It can also be used for other subreddits by changing the values in the
configuration file.

Its current features are:

* Posting the price changes of Fantasy Premier League players

## Installation

FPLbot uses MongoDB to store players in a database, and so it is required to
have MongoDB installed. Other than that, it uses [fpl](https://github.com/amosbastian/fpl)
to retrieve information from Fantasy Premier League's API, and thus requires
Python 3.6+.

git clone git@github.com:amosbastian/FPLbot.git
cd FPLbot
pip install -r requirements.txt

Once installed you can schedule a cron job to run the bot whenever you want!

## Configuration

|Option|Value|
|:-|:-|
|USERNAME|The bot's username|
|PASSWORD|The bot's password|
|CLIENT_ID|The bot's client ID|
|CLIENT_SECRET|The bot's client secret|
|USER_AGENT|A unique identifier that helps Reddit determine the source of network requests|
|SUBREDDIT|The subreddit the bot will post to|

For more information about how to set up a bot see [Reddit's guide](https://github.com/reddit-archive/reddit/wiki/OAuth2-Quick-Start-Example#first-steps).
8 changes: 8 additions & 0 deletions config.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"USERNAME": "bigluke575",
"PASSWORD": "baldfraud",
"CLIENT_ID": "p-jcoLKBynTLew",
"CLIENT_SECRET": "gko_LXELoV07ZBNUXrvWZfzE3aI",
"USER_AGENT": "The original FPLbot.",
"SUBREDDIT": "FantasyPL",
}
17 changes: 17 additions & 0 deletions post_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### Risers ({risers_number})

{risers_table}

&nbsp;

### Fallers ({fallers_number})

{fallers_table}

&nbsp;

^∆ ^= ^price ^change ^this ^gameweek. ^Form ^= ^points ^last ^5 ^gameweeks.

---

^Made ^by ^/u/esoemah. ^Source: ^https://github.com/amosbastian/FPLbot
28 changes: 28 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
aiohttp==3.5.4
appdirs==1.4.3
async-timeout==3.0.1
atomicwrites==1.2.1
attrs==18.2.0
certifi==2018.11.29
chardet==3.0.4
Click==7.0
colorama==0.4.1
fpl==0.6.1
idna==2.8
more-itertools==5.0.0
multidict==4.5.2
pep8==1.7.1
pluggy==0.8.1
praw==6.1.1
prawcore==1.0.0
PTable==0.9.2
py==1.7.0
pymongo==3.7.2
pytest==4.2.0
pytest-aiohttp==0.3.0
requests==2.21.0
six==1.12.0
update-checker==0.16
urllib3==1.24.1
websocket-client==0.54.0
yarl==1.3.0