2023-11-26 10:30:42 +00:00
import pandas as pd
from icalendar import Calendar , Event
from datetime import datetime , timedelta
import uuid
import os
2024-01-16 11:58:05 +00:00
import csv
2023-12-05 13:30:53 +00:00
import requests
2024-01-16 11:58:05 +00:00
import lxml . html as lh
2023-12-05 13:30:53 +00:00
telegram_bot_api_key = USER = os . getenv ( ' TELEGRAM_BOT_API_KEY ' )
telegram_bot_chat_id = USER = os . getenv ( ' TELEGRAM_BOT_CHAT_ID ' )
def send_message ( message : str ) - > None :
""" Send message to me on Telegram when updated.
Args :
message ( str ) : String of message to send .
"""
requests . post ( f ' https://api.telegram.org/bot { telegram_bot_api_key } /sendMessage ' , json = { ' chat_id ' : telegram_bot_chat_id , ' text ' : message } )
2023-11-26 10:30:42 +00:00
2024-01-13 15:37:08 +00:00
def store_df_as_csv ( df : pd . DataFrame , name : str ) - > None :
2023-11-27 09:41:06 +00:00
""" Store dataframe as a CSV file.
2023-11-26 10:30:42 +00:00
Args :
2023-11-27 09:41:06 +00:00
df ( pd . DataFrame ) : Dataframe of fixtures .
2024-01-13 15:37:08 +00:00
name ( str ) : Name of the CSV file .
2023-11-26 10:30:42 +00:00
"""
2024-01-13 15:37:08 +00:00
df . to_csv ( f ' ./ { name } .csv ' , index = False )
2024-01-13 16:02:27 +00:00
def compare_dfs ( df : pd . DataFrame , name : str ) - > bool :
2023-11-27 09:41:06 +00:00
""" Compare the latest DF with the stored DF for any changes.
2023-11-26 10:30:42 +00:00
Args :
2023-11-27 09:41:06 +00:00
df ( pd . DataFrame ) : Latest copy of fixtures in dataframe
2024-01-13 16:02:27 +00:00
name ( str ) : Name of the CSV file .
2023-11-26 10:30:42 +00:00
Returns :
2023-11-27 09:41:06 +00:00
bool : True if match , False if no match .
2023-11-26 10:30:42 +00:00
"""
2024-01-13 16:02:27 +00:00
df2 = pd . read_csv ( f ' ./ { name } .csv ' )
2023-11-26 10:30:42 +00:00
return df . equals ( df2 )
def write_calendar ( cal : Calendar ) - > None :
2023-11-27 09:41:06 +00:00
""" Write the cal object to an ics file.
2023-11-26 10:30:42 +00:00
Args :
2023-11-27 09:41:06 +00:00
cal ( Calendar ) : iCalendar object with all the ics details .
2023-11-26 10:30:42 +00:00
"""
f = open ( os . path . join ( ' ./ ' , ' fixtures.ics ' ) , ' wb ' )
f . write ( cal . to_ical ( ) )
f . close ( )
def does_csv_exist ( ) - > bool :
2023-11-27 09:41:06 +00:00
""" Check if the CSV file exists.
2023-11-26 10:30:42 +00:00
Returns :
2023-11-27 09:41:06 +00:00
bool : True if CSV file exists , False if not .
2023-11-26 10:30:42 +00:00
"""
return os . path . isfile ( ' ./fixtures.csv ' )
2024-01-13 15:37:08 +00:00
def make_ordinal ( n : int ) - > str :
'''
Convert an integer into its ordinal representation : :
make_ordinal ( 0 ) = > ' 0th '
make_ordinal ( 3 ) = > ' 3rd '
make_ordinal ( 122 ) = > ' 122nd '
make_ordinal ( 213 ) = > ' 213th '
'''
n = int ( n )
if 11 < = ( n % 100 ) < = 13 :
suffix = ' th '
else :
suffix = [ ' th ' , ' st ' , ' nd ' , ' rd ' , ' th ' ] [ min ( n % 10 , 4 ) ]
return str ( n ) + suffix
def create_ical_file ( df : pd . DataFrame , cal : Calendar , table : pd . DataFrame ) - > None :
2023-11-27 09:41:06 +00:00
""" Create an iCalendar file from a dataframe.
Args :
df ( pd . DataFrame ) : Dataframe of fixtures .
cal ( Calendar ) : iCalendar object with all the ics details .
2024-01-13 15:37:08 +00:00
table ( pd . DataFrame ) : Dataframe of table details .
2023-11-27 09:41:06 +00:00
"""
2023-11-26 10:30:42 +00:00
for index , row in df . iterrows ( ) :
event = Event ( )
2024-01-13 15:37:08 +00:00
match_type = str ( row [ ' Type ' ] )
home_team = str ( row [ ' Home Team ' ] )
if ( " Tongham " ) not in home_team :
home_team = str ( row [ ' Home Team ' ] ) . replace ( " U12 " , " " )
away_team = str ( row [ ' Away Team.1 ' ] )
if ( " Tongham " ) not in away_team :
away_team = str ( row [ ' Away Team.1 ' ] ) . replace ( " U12 " , " " )
venue = str ( row [ ' Venue ' ] )
print ( row [ ' Date / Time ' ] , home_team , away_team , venue )
2024-01-29 08:14:12 +00:00
if row [ ' Date / Time ' ] == ' TBC ' :
continue
2023-11-26 10:30:42 +00:00
start_date_time = datetime . strptime ( row [ ' Date / Time ' ] , ' %d / % m/ % y % H: % M ' )
2023-11-27 09:41:06 +00:00
# Set default 8am start time to normal 930 kickoff time.
2023-11-26 10:30:42 +00:00
if start_date_time . hour == 8 :
start_date_time = start_date_time + timedelta ( hours = 1 , minutes = 30 )
2023-11-27 09:41:06 +00:00
# Arrival time is 30 mins before kickoff time.
2023-11-26 10:30:42 +00:00
arrival_time = start_date_time + timedelta ( minutes = - 30 )
2024-01-13 15:37:08 +00:00
if match_type == ' L ' :
summary = " (League) " + home_team + f " ( { make_ordinal ( table . loc [ table [ ' Team ' ] == home_team , ' POS ' ] . iloc [ 0 ] ) } ) " + f " { str ( row [ ' Unnamed: 4 ' ] ) } " + away_team + f " ( { make_ordinal ( table . loc [ table [ ' Team ' ] == away_team , ' POS ' ] . iloc [ 0 ] ) } ) "
else :
summary = " (Cup) " + home_team + f " { str ( row [ ' Unnamed: 4 ' ] ) } " + away_team
event . add ( ' summary ' , summary )
2024-01-09 19:03:18 +00:00
notes = row [ ' Status / Notes ' ]
2024-01-13 15:37:08 +00:00
if pd . isna ( notes ) :
2024-01-14 13:30:24 +00:00
notes = ' No Match Notes '
2024-01-23 08:31:41 +00:00
elif notes == ' Postponed ' :
continue
2024-02-19 11:32:28 +00:00
event . add ( ' description ' , " Arrive by - " + str ( arrival_time ) + " \n " + notes + " \n Table - \n " + " https://fulltime.thefa.com/index.html?league=9268728&selectedSeason=19010414&selectedDivision=165601607&selectedCompetition=0&selectedFixtureGroupKey=1_579285719 " )
2023-11-26 10:30:42 +00:00
event . add ( ' dtstart ' , start_date_time )
2023-11-27 09:42:15 +00:00
# End 2 hours after start_date_time
2023-11-26 10:30:42 +00:00
event . add ( ' dtend ' , start_date_time + timedelta ( hours = 2 ) )
event . add ( ' dtstamp ' , start_date_time )
event . add ( ' uid ' , str ( uuid . uuid4 ( ) ) )
2024-01-13 15:37:08 +00:00
event . add ( ' location ' , venue )
2023-11-26 10:30:42 +00:00
cal . add_component ( event )
write_calendar ( cal )
2024-01-13 15:37:08 +00:00
2024-01-13 16:02:27 +00:00
def process_table ( table_df : pd . DataFrame ) - > pd . DataFrame :
2024-01-13 15:37:08 +00:00
table_df = table_df [ : - 1 ]
table_df . drop ( table_df . columns [ len ( table_df . columns ) - 1 ] , axis = 1 , inplace = True )
2024-01-13 16:02:27 +00:00
table_df [ ' POS ' ] = table_df [ ' POS ' ] . astype ( ' int ' )
table_df [ ' P ' ] = table_df [ ' P ' ] . astype ( ' int ' )
table_df [ ' W ' ] = table_df [ ' W ' ] . astype ( ' int ' )
table_df [ ' D ' ] = table_df [ ' D ' ] . astype ( ' int ' )
table_df [ ' L ' ] = table_df [ ' L ' ] . astype ( ' int ' )
table_df [ ' PTS ' ] = table_df [ ' PTS ' ] . astype ( ' int ' )
2024-01-13 15:37:08 +00:00
store_df_as_csv ( table_df , " table " )
return table_df
2023-11-26 10:30:42 +00:00
2024-01-16 11:58:05 +00:00
def process_results ( ) - > None :
2024-01-29 08:24:38 +00:00
req = requests . get ( " https://fulltime.thefa.com/results.html?selectedSeason=19010414&selectedFixtureGroupAgeGroup=11&selectedFixtureGroupKey=1_579285719&selectedRelatedFixtureOption=3&selectedClub=&selectedTeam=466317969&selectedDateCode=all&previousSelectedFixtureGroupAgeGroup=11&previousSelectedFixtureGroupKey=1_579285719&previousSelectedClub= " )
2024-01-16 11:58:05 +00:00
doc = lh . fromstring ( req . text )
headers = [ ' Date ' , ' Home Team ' , ' Score ' , ' Away Team ' ]
with open ( ' results.csv ' , ' w ' , newline = ' ' ) as fp :
file = csv . writer ( fp )
file . writerow ( headers )
for idx , row in enumerate ( doc . xpath ( " //div[contains(@id, ' fixture ' )] " ) , start = 1 ) :
date = row . xpath ( f ' /html[1]/body[1]/main[1]/div[2]/section[1]/div[1]/div[3]/div[1]/div[2]/div[ { idx } ]/div[1]/div[3]/a[1]/span[1]//text() ' ) [ 0 ]
home_team = row . xpath ( f ' /html[1]/body[1]/main[1]/div[2]/section[1]/div[1]/div[3]/div[1]/div[2]/div[ { idx } ]/div[1]/div[4]/div[1]/a[1]//text() ' ) [ 0 ] . strip ( )
score = row . xpath ( f ' /html[1]/body[1]/main[1]/div[2]/section[1]/div[1]/div[3]/div[1]/div[2]/div[ { idx } ]/div[1]/div[5]//text() ' ) [ 0 ] . strip ( )
2024-01-29 08:24:38 +00:00
if score == ' X - X ' :
continue
2024-01-16 11:58:05 +00:00
away_team = row . xpath ( f ' /html[1]/body[1]/main[1]/div[2]/section[1]/div[1]/div[3]/div[1]/div[2]/div[ { idx } ]/div[1]/div[6]/div[2]/a[1]//text() ' ) [ 0 ] . strip ( )
file . writerow ( [ date , home_team , score , away_team ] )
2024-01-13 16:02:27 +00:00
def compare_table ( ) :
2024-01-29 08:19:37 +00:00
table_df = pd . read_html ( " https://fulltime.thefa.com/table.html?league=9268728&selectedSeason=19010414&selectedDivision=165601607&selectedCompetition=0&selectedFixtureGroupKey=1_579285719 " ) [ 0 ]
2024-01-13 16:02:27 +00:00
store_df_as_csv ( table_df , " base_table " )
return table_df
2023-11-26 10:30:42 +00:00
cal = Calendar ( )
cal . add ( ' prodid ' , ' Down Grange Pumas Fixtures ' )
cal . add ( ' version ' , ' 2.0 ' )
2024-01-13 15:37:08 +00:00
fixtures_df = pd . read_html ( " https://fulltime.thefa.com/fixtures.html?selectedSeason=19010414&selectedFixtureGroupAgeGroup=11&selectedFixtureGroupKey=1_579285719&selectedDateCode=all&selectedClub=&selectedTeam=466317969&selectedRelatedFixtureOption=3&selectedFixtureDateStatus=&selectedFixtureStatus=&previousSelectedFixtureGroupAgeGroup=11&previousSelectedFixtureGroupKey=1_579285719&previousSelectedClub=&itemsPerPage=25 " ) [ 0 ]
fixtures_df . head ( )
2024-01-16 11:58:05 +00:00
process_results ( )
2024-01-13 16:02:27 +00:00
table = compare_table ( )
2023-11-26 10:30:42 +00:00
exists = does_csv_exist ( )
if exists :
2024-01-13 16:02:27 +00:00
fixtures_change = compare_dfs ( fixtures_df , " fixtures " )
table_change = compare_dfs ( table , " base_table " )
if not table_change :
send_message ( " Table has updated " )
if not all ( [ fixtures_change , table_change ] ) :
print ( " Data Updated, ical updated " )
2024-01-13 15:37:08 +00:00
store_df_as_csv ( fixtures_df , " fixtures " )
2024-01-13 16:02:27 +00:00
create_ical_file ( fixtures_df , cal , process_table ( table ) )
2023-12-05 13:30:53 +00:00
send_message ( " Fixtures updated, ical updated " )
2023-11-27 14:03:29 +00:00
else :
2024-01-13 16:02:27 +00:00
print ( " No Data Updated, No update to ical " )
2023-11-26 10:30:42 +00:00
else :
2024-01-13 15:37:08 +00:00
store_df_as_csv ( fixtures_df , " fixtures " )
2024-01-13 16:02:27 +00:00
create_ical_file ( fixtures_df , cal , process_table ( table ) )
2023-12-05 13:30:53 +00:00
send_message ( " New ical file created " )
2023-11-27 14:03:29 +00:00
print ( " New ical file created " )