2020-06-30 22:03:05 +00:00

357 lines
15 KiB
Python

###
# Copyright (c) 2018, cottongin
# Copyright (c) 2020, oddluck <oddluck@riseup.net>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
import pendulum
import requests
import collections
import json
from supybot import utils, plugins, ircutils, callbacks, conf, schedule, ircmsgs
from supybot.commands import *
try:
from supybot.i18n import PluginInternationalization
_ = PluginInternationalization("CBB")
except ImportError:
# Placeholder that allows to run the plugin on a bot
# without the i18n module
_ = lambda x: x
SCOREBOARD = (
"http://site.api.espn.com/apis/site/v2/sports/basketball/"
"mens-college-basketball/scoreboard?lang=en&region=us"
"&calendartype=blacklist&limit=300&groups=50&dates={date}"
)
class CBB(callbacks.Plugin):
"""Fetches College Basketball scores"""
threaded = True
def __init__(self, irc):
self.__parent = super(CBB, self)
self.__parent.__init__(irc)
####################
# PUBLIC FUNCTIONS #
####################
@wrap([getopts({"date": "somethingWithoutSpaces", "all": ""}), optional("text")])
def cbb(self, irc, msg, args, options, team=None):
"""[--date] [--all] [team]
Fetches college basketball scores/schedule for given date and/or team.
Defaults to today and top 25 teams (if playing, otherwise shows all games).
Use --all to show results for all teams.
"""
channel = msg.args[0]
if channel == irc.nick:
channel = msg.nick
options = dict(options)
date = options.get("date")
if "all" in options:
all = True
else:
all = False
if date:
if date.lower() in ["yesterday", "tomorrow", "today"]:
if date.lower() in "yesterday":
date = pendulum.yesterday().format("YYYYMMDD")
elif date.lower() in "tomorrow":
date = pendulum.tomorrow().format("YYYYMMDD")
else:
date = pendulum.now().format("YYYYMMDD")
else:
try:
date = pendulum.parse(date, strict=False).format("YYYYMMDD")
except:
irc.reply("Invalid date format")
return
SCORES = self._checkscores(date)
if date not in SCORES:
niceDate = pendulum.parse(date)
niceDate = "{0}/{1}/{2}".format(
niceDate.month, niceDate.day, niceDate.year
)
irc.reply("No games found for {}.".format(date))
else:
today = pendulum.now().format("YYYYMMDD")
yesterday = pendulum.yesterday().format("YYYYMMDD")
tomorrow = date = pendulum.tomorrow().format("YYYYMMDD")
SCORES = self._checkscores()
if today in SCORES:
date = today
elif yesterday in SCORES:
date = yesterday
elif tomorrow in SCORES:
date = tomorrow
else:
irc.reply("No games found.")
return
if team:
if len(team) > 2:
reply = []
# single team
for key, value in SCORES[date].items():
if team.lower() in value["lookup"]["abbr"].lower():
# print(team.lower(), '\t', value['lookup']['abbr'].lower())
reply.append(value["long"])
# break
if not reply:
for key, value in SCORES[date].items():
if team.lower() in value["lookup"]["full"].lower():
reply.append(value["long"])
# break
if not reply:
irc.reply("ERROR: no match found for your input: {}".format(team))
return
else:
if len(reply) <= 4:
for item in reply:
irc.sendMsg(ircmsgs.privmsg(channel, item))
else:
for item in reply:
irc.reply(item)
return
else:
irc.reply("ERROR: search string too short")
return
else:
niceDate = pendulum.parse(date)
niceDate = "{0}/{1}/{2}".format(niceDate.month, niceDate.day, niceDate.year)
reply = " | ".join(
value["short"] for item, value in SCORES[date].items() if value["top25"]
)
if reply and not all:
irc.reply(
"Showing teams in the top 25 for {0}. Use --all to see more games."
.format(niceDate),
prefixNick=False,
)
irc.reply(reply, prefixNick=False)
else:
reply = " | ".join(
value["short"] for item, value in SCORES[date].items()
)
irc.reply(
"Showing all games for {0}.".format(niceDate), prefixNick=False
)
irc.reply(reply, prefixNick=False)
return
return
######################
# INTERNAL FUNCTIONS #
######################
def _checkscores(self, cdate=None):
if cdate:
# today = pendulum.parse(cdate, strict=False).format('YYYYMMDD')
# yesterday = pendulum.parse(cdate, strict=False).subtract(days=1).format('YYYYMMDD')
# tomorrow = pendulum.parse(cdate, strict=False).add(days=1).format('YYYYMMDD')
dates = [cdate]
else:
today = pendulum.now().format("YYYYMMDD")
yesterday = pendulum.yesterday().format("YYYYMMDD")
tomorrow = pendulum.tomorrow().format("YYYYMMDD")
dates = [yesterday, today, tomorrow]
data = collections.OrderedDict()
for date in dates:
tmp = requests.get(SCOREBOARD.format(date=date), timeout=10)
tmp = json.loads(tmp.content)
tmp_date = (
pendulum.parse(tmp["eventsDate"]["date"], strict=False)
.in_tz("US/Eastern")
.format("YYYYMMDD")
)
data[tmp_date] = tmp["events"]
# print(data)
"""
'day': {'game1': {'short', 'long'},
'game2': {'short', 'long'}}
"""
games = collections.OrderedDict()
for day, d in data.items():
# print(day, d)
if d:
games[day] = collections.OrderedDict()
for event in d:
key = event["id"]
lookup = {
"abbr": "{}".format(event["shortName"]),
"full": "{}".format(event["name"]),
}
comp = event["competitions"][0]
time = pendulum.parse(comp["date"], strict=False).in_tz(
"US/Eastern"
)
short_time = time.format("h:mm A zz")
long_time = time.format("dddd, MMM Do, h:mm A zz")
status = comp["status"]["type"]["state"]
is_ended = comp["status"]["type"]["completed"]
top25 = (
True
if (
0 < comp["competitors"][0]["curatedRank"]["current"] <= 25
or 0
< comp["competitors"][1]["curatedRank"]["current"]
<= 25
)
else False
)
home_rank = (
"(#{})".format(comp["competitors"][0]["curatedRank"]["current"])
if 0 < comp["competitors"][0]["curatedRank"]["current"] <= 25
else ""
)
away_rank = (
"(#{})".format(comp["competitors"][1]["curatedRank"]["current"])
if 0 < comp["competitors"][1]["curatedRank"]["current"] <= 25
else ""
)
home_short = comp["competitors"][0]["team"]["abbreviation"]
home_long = comp["competitors"][0]["team"]["displayName"]
away_short = comp["competitors"][1]["team"]["abbreviation"]
away_long = comp["competitors"][1]["team"]["displayName"]
home_score = int(comp["competitors"][0]["score"])
away_score = int(comp["competitors"][1]["score"])
broadcasts = []
try:
for thing in comp["broadcasts"]:
for station in thing["names"]:
broadcasts.append(station)
except:
pass
# print(home_short, away_short, '\t||\t', top25, status, comp['competitors'][0]['curatedRank']['current'],
# comp['competitors'][1]['curatedRank']['current'])
if status == "pre":
# pre
short = "{} @ {} {}".format(away_short, home_short, short_time)
long = "{}{} @ {}{} | {}{}".format(
away_long,
away_rank,
home_long,
home_rank,
long_time,
" [TV: {}]".format(
", ".join(broadcasts) if broadcasts else ""
),
)
else:
# inp
if is_ended:
clock_short = ircutils.mircColor("F", "red")
clock_long = ircutils.mircColor("Final", "red")
else:
if "Halftime" in comp["status"]["type"]["detail"]:
clock_short = ircutils.mircColor("HT", "orange")
clock_long = ircutils.mircColor("Halftime", "orange")
else:
clock_short = ircutils.mircColor(
comp["status"]["type"]["shortDetail"].replace(
" - ", " "
),
"green",
)
clock_long = ircutils.mircColor(
comp["status"]["type"]["detail"], "green"
)
try:
last_play = (
" | \x02Last Play:\x02 {}".format(
comp["situation"]["lastPlay"]["text"]
)
if "situation" in comp
else ""
)
except:
last_play = ""
if away_score > home_score:
away_short_str = ircutils.bold(
"{} {}".format(away_short, away_score)
)
away_long_str = ircutils.bold(
"{}{} {}".format(away_long, away_rank, away_score)
)
home_short_str = "{} {}".format(home_short, home_score)
home_long_str = "{}{} {}".format(
home_long, home_rank, home_score
)
elif home_score > away_score:
away_short_str = "{} {}".format(away_short, away_score)
away_long_str = "{}{} {}".format(
away_long, away_rank, away_score
)
home_short_str = ircutils.bold(
"{} {}".format(home_short, home_score)
)
home_long_str = ircutils.bold(
"{}{} {}".format(home_long, home_rank, home_score)
)
else:
away_short_str = "{} {}".format(away_short, away_score)
away_long_str = "{}{} {}".format(
away_long, away_rank, away_score
)
home_short_str = "{} {}".format(home_short, home_score)
home_long_str = "{}{} {}".format(
home_long, home_rank, home_score
)
short = "{} {} {}".format(
away_short_str, home_short_str, clock_short
)
long = "{} @ {} - {}{}".format(
away_long_str, home_long_str, clock_long, last_play
)
games[day][key] = {
"short": short,
"long": long,
"ended": is_ended,
"top25": top25,
"lookup": lookup,
}
# sort events
games[day] = collections.OrderedDict(
sorted(games[day].items(), key=lambda k: k[1]["ended"])
)
return games
Class = CBB
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: