diff --git a/.gitignore b/.gitignore index b4c67b3..ff8b567 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ tmp/ tmp/auth/ tmp/data/ tmp/data/players/ -test.php constants.php +*.tar.gz diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..de3ddf6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/PHPMailer"] + path = lib/PHPMailer + url = https://github.com/PHPMailer/PHPMailer.git diff --git a/Analytics.php b/Analytics.php index fbd65d5..5807322 100644 --- a/Analytics.php +++ b/Analytics.php @@ -1,67 +1,87 @@ player_stats = [ + 'Roster' => $this->createPlayerStats('Roster'), + 'FA' => $this->createPlayerStats('FA'), + ]; } return $this; } /** - * @return string + * @return array */ - function generateReport() + function generateSuggestion() { - $averages['FA'] = $this->createPlayerAverages('FA'); - $averages['Roster'] = $this->createPlayerAverages('Roster'); - $player_weight = []; - $data = ""; + $player_delta = [ + 'FA' => [ + ONE_WEEK_AVG => $this->getPlayerDelta('FA', ONE_WEEK_AVG), + TWO_WEEK_AVG => $this->getPlayerDelta('FA', TWO_WEEK_AVG), + ONE_MO_AVG => $this->getPlayerDelta('FA', ONE_MO_AVG), + ], + 'Roster' => [ + ONE_WEEK_AVG => $this->getPlayerDelta('Roster', ONE_WEEK_AVG), + TWO_WEEK_AVG => $this->getPlayerDelta('Roster', TWO_WEEK_AVG), + ONE_MO_AVG => $this->getPlayerDelta('Roster', ONE_MO_AVG), + ], + ]; + + $player_score = []; - foreach ($averages['Roster'] as $rplayer => $rplayer_avg) { - $free_agents = -1; - foreach ($averages['FA'] as $fplayer => $fplayer_avg) { - $free_agents++; - if ($fplayer_avg >= $rplayer_avg) { - $player_weight[$fplayer] = isset($player_weight[$fplayer]) ? $player_weight[$fplayer] + 1 : 1 - $free_agents; - $player_weight[$rplayer] = isset($player_weight[$rplayer]) ? $player_weight[$rplayer] - 1 : -1; - } else { - break; + // TODO: Maybe use central limit theorem here to better rank players + foreach ($player_delta as $type => $data) { + foreach ($data as $stat => $week_values) { + foreach ($week_values as $week => $player_averages) { + foreach ($player_averages as $player => $delta) { + if (empty($player_score[$type][$player])) { + $player_score[$type][$player] = $this->player_stats[$type][$week][$player]; + } + switch ($stat) { + case ONE_WEEK_AVG: + $player_score[$type][$player] += 1 * $delta; + break; + case TWO_WEEK_AVG: + $player_score[$type][$player] += 1.5 * $delta; + break; + case ONE_MO_AVG: + $player_score[$type][$player] += 3 * $delta; + break; + } + } } } } - foreach ($player_weight as $player => $weight) { - if (array_key_exists($player, $averages['Roster'])) { - print "You should consider dropping: ${player}. (${weight})" . PHP_EOL; - $data .= "You should consider dropping: ${player}. (${weight})" . PHP_EOL; - } else { - if ($weight > 0) { - print "You should consider picking up: ${player}. (${weight})" . PHP_EOL; - $data .= "You should consider picking up: ${player}. (${weight})" . PHP_EOL; + $player_suggestions = []; + foreach ($player_score['FA'] as $fa_player => $fa_score) { + foreach ($player_score['Roster'] as $r_player => $r_score) { + if ($fa_score > $r_score) { + $player_suggestions[$r_player][$fa_player] = $fa_score - $r_score; } } } - writeToFile(json_encode($player_weight), 'bin/analysis_' . time() . '.json'); - return $data; + return $player_suggestions; } /** @@ -70,14 +90,15 @@ function generateReport() * @return array */ function createPlayerStats($type, $player = '') { + global $scored_stats; // If we've specified a player, get their weekly stats (if available) if (empty($player)) { - $files = glob("tmp/data/players/${type}/*.json", GLOB_BRACE); + $files = glob(TMP_DATA_PLAYERS_DIR . "${type}/*.json", GLOB_BRACE); } else { - $files = glob("tmp/data/players/${type}/player_${player}_week_*.json", GLOB_BRACE); - if (count($files) < 2) { + $files = glob(TMP_DATA_PLAYERS_DIR . "${type}/player_${player}_week_*.json", GLOB_BRACE); + if (count($files) == 0) { print "Not enough data given for player ${player}!"; - return FALSE; + return []; } } @@ -85,7 +106,6 @@ function createPlayerStats($type, $player = '') { foreach ($files as $file) { $week = substr($file, -7, 2); $data = getContents($file); - global $scored_stats; $gp = $data['player']['player_stats']['stats']['stat']['0']['value']; $averages = []; if ($gp > 0) { @@ -101,31 +121,34 @@ function createPlayerStats($type, $player = '') { return $players; } - function getSevenDayAverage($type, $player = '') { - $data = $this->createPlayerStats($type, $player); + function getPlayerDelta($type, $stat, $player = '') { + if (empty($this->player_stats[$type])) { + $this->player_stats[$type] = $this->createPlayerStats($type, $player); + } + $data = $this->player_stats[$type]; $stats = []; foreach ($data as $week => $players) { foreach ($players as $player => $value) { - if (!empty($data[$week-1][$player])) { - $stats[$week][$player] = $data[$week][$player] - $data[$week-1][$player]; + if (!empty($data[$week-$stat][$player])) { + $stats[$week][$player] = $data[$week][$player] - $data[$week-$stat][$player]; } } } return $stats; } - // TODO: Maybe add another parameter to merge 2 functions ... - function getFourteenDayAverage($type, $player = '') { - $data = $this->createPlayerStats($type, $player); - $stats = []; - foreach ($data as $week => $players) { - foreach ($players as $player => $value) { - if (!empty($data[$week-2][$player])) { - $stats[$week][$player] = $data[$week][$player] - $data[$week-2][$player]; - } + function generateReport() { + $suggestions = $this->generateSuggestion(); + $data = ''; + foreach ($suggestions as $r_player => $fa_players) { + arsort($fa_players); + $data .= "

$r_player can be replaced by:
"; + foreach ($fa_players as $fa_player => $diff) { + $data .= "

  $fa_player: $diff

"; } + $data .= "


"; } - return $stats; + writeToFile($data, BIN_DIR . 'analysis.csv'); + return $data; } - } diff --git a/FantasyAPI.php b/FantasyAPI.php index 08b9d77..5299ee5 100644 --- a/FantasyAPI.php +++ b/FantasyAPI.php @@ -1,7 +1,7 @@ auth_json_file = 'tmp/auth/auth_credentials_' . CONSUMER_KEY . '.json'; + $this->auth_json_file = TMP_AUTH_DIR . 'auth_credentials_' . CONSUMER_KEY . '.json'; if (file_exists($this->auth_json_file)) { $this->credentials = json_decode(file_get_contents($this->auth_json_file), TRUE); } else { @@ -40,8 +40,8 @@ function __construct() */ function makeAPIRequest($url) { - $curl = curl_init(); - curl_setopt_array($curl, array( + $ch = curl_init(); + curl_setopt_array($ch, array( CURLOPT_RETURNTRANSFER => 1, CURLOPT_URL => $url, CURLOPT_HTTPHEADER => array('authorization: Bearer ' . $this->credentials['access_token'], @@ -49,41 +49,41 @@ function makeAPIRequest($url) 'Accept-Language: en-US,en;q=0.5', 'Cache-Control: no-cache', 'Content-Type: application/x-www-form-urlencoded; charset=utf-8', - 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:28.0) Gecko/20100101 Firefox/28.0'), + ), )); - $resp = curl_exec($curl); - if (strpos($resp, "token_expired")) { + $resp = curl_exec($ch); + curl_close($ch); + if (strpos($resp, "token_expired") !== FALSE) { if ($this->refreshToken()) { - $this->makeAPIRequest($url); + return $this->makeAPIRequest($url); } else { print 'Trouble Getting Refresh Token...'; - } - } else if (strpos($resp, "error")) { + } else if (strpos($resp, "error") !== FALSE) { print "Error in making the API Request"; + } else if (strpos($resp, "Request denied") !== FALSE) { + print "Request denied: " . $url; } else { $xml = simplexml_load_string($resp, "SimpleXMLElement", LIBXML_NOCDATA); $json = json_encode($xml); - curl_close($curl); return json_decode($json, TRUE); } - curl_close($curl); return FALSE; } /** - * @return bool|mixed + * @return bool */ function refreshToken() { // If our auth file doesn't exist, make one if (!file_exists($this->auth_json_file)) { - return $this->initializeToken(); + $this->initializeToken(); } // If our token has not expired yet, return the existing auth if ($this->credentials['expiry_time'] > time()) { - return json_decode($this->auth_json_file, TRUE); + return TRUE; } $ch = curl_init(); @@ -99,25 +99,21 @@ function refreshToken() CURLOPT_HTTPHEADER => array( 'Authorization: Basic ' . base64_encode(CONSUMER_KEY . ":" . CONSUMER_SECRET), 'Content-Type: application/x-www-form-urlencoded', - 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'), + ), CURLOPT_POSTFIELDS => http_build_query($post_values) )); $resp = curl_exec($ch); - if (strpos($resp, "error") || empty($resp)) { - curl_close($ch); + curl_close($ch); + if (strpos($resp, "error") !== FALSE || empty($resp)) { print "Error getting Refresh Token"; return FALSE; } - curl_close($ch); writeToFile($resp, $this->auth_json_file); + $this->credentials = json_decode($resp, TRUE); $this->credentials['expiry_time'] = time() + 3600; - print_r($resp); - return json_decode($resp, TRUE); + return TRUE; } - /** - * @return bool|mixed - */ function initializeToken() { $auth_code = readline('Go to: https://api.login.yahoo.com/oauth2/request_auth?client_id=' . CONSUMER_KEY . '&redirect_uri=oob&response_type=code&language=en-us and copy the code: '); @@ -136,19 +132,19 @@ function initializeToken() CURLOPT_HTTPHEADER => array( 'Authorization: Basic ' . base64_encode(CONSUMER_KEY . ":" . CONSUMER_SECRET), 'Content-Type: application/x-www-form-urlencoded', - 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'), + ), CURLOPT_POSTFIELDS => http_build_query($post_values) )); $resp = curl_exec($ch); - if (empty($resp) || strpos($resp, 'error')) { - curl_close($ch); + curl_close($ch); + if (strpos($resp, 'error') !== FALSE || empty($resp)) { print 'Error Initializing Token'; return FALSE; } - curl_close($ch); writeToFile($resp, $this->auth_json_file); + $this->credentials = json_decode($resp, TRUE); $this->credentials['expiry_time'] = time() + 3600; - return json_decode($resp, TRUE); + return TRUE; } } diff --git a/Mail.php b/Mail.php new file mode 100644 index 0000000..f639c48 --- /dev/null +++ b/Mail.php @@ -0,0 +1,58 @@ +username = FANTASY_TRACKER_EMAIL; + $this->password = FANTASY_TRACKER_PASSWORD; + } + + function initializeMail() + { + $mail = new PHPMailer(); + + // SMTP Settings + $mail->isSMTP(); + $mail->SMTPDebug = 0; + $mail->SMTPAuth = TRUE; + $mail->SMTPSecure = 'tls'; + $mail->SMTPAuth = true; + $mail->Host= 'smtp.gmail.com'; + $mail->Port = 587; + // AUTH Settings + $mail->Username = $this->username; + $mail->Password = $this->password; + // Subject and Sender + $mail->SetFrom($this->username, "Fantasy Tracker"); + $mail->Subject = "Your Fantasy Tracker Update!"; + $this->mail = $mail; + } + + function sendEmail($recipient, $data) + { + // Add Recipient Address + $this->mail->addAddress($recipient); + // Add body content + $this->mail->isHTML(TRUE); + $this->mail->msgHTML($data); + + return $this->mail->send(); + } +} diff --git a/ServiceCall.php b/ServiceCall.php index 9540b14..9c673c5 100644 --- a/ServiceCall.php +++ b/ServiceCall.php @@ -1,8 +1,8 @@ api->makeAPIRequest($my_team); - writeToFile(json_encode($answer), 'tmp/data/' . LEAGUE_KEY . '_my_team.json'); + writeToFile(json_encode($answer), TMP_DATA_DIR . LEAGUE_KEY . '_my_team.json'); return $answer; } @@ -66,7 +66,7 @@ function getFreeAgents() { $free_agents = "https://fantasysports.yahooapis.com/fantasy/v2/league/". LEAGUE_KEY ."/players;status=FA;start=${num};sort=OR"; $answer = array_merge_recursive($answer, $this->api->makeAPIRequest($free_agents)); } - writeToFile(json_encode($answer), 'tmp/data/' . LEAGUE_KEY . '_free_agents.json'); + writeToFile(json_encode($answer), TMP_DATA_DIR . LEAGUE_KEY . '_free_agents.json'); return $answer; } @@ -79,7 +79,7 @@ function getPlayerStats($player_key, $type) { $week = $this->week; $player = "https://fantasysports.yahooapis.com/fantasy/v2/player/395.p.${player_key}/stats"; $answer = $this->api->makeAPIRequest($player); - writeToFile(json_encode($answer), "tmp/data/players/${type}/player_${player_key}_week_${week}.json"); + writeToFile(json_encode($answer), TMP_DATA_PLAYERS_DIR . "${type}/player_${player_key}_week_${week}.json"); return $answer; } @@ -100,5 +100,4 @@ function getRosterStats() { $this->getPlayerStats($player['player_id'], 'Roster'); } } - } diff --git a/backups/.gitkeep b/backups/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/bin/.gitkeep b/bin/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/bin/.gitkeep @@ -0,0 +1 @@ + diff --git a/constants.php b/constants.php index df44174..1c64556 100644 --- a/constants.php +++ b/constants.php @@ -8,6 +8,8 @@ define('CONSUMER_SECRET', ''); define('LEAGUE_KEY', ''); define('TEAM_ID', ''); +define('FANTASY_TRACKER_EMAIL', ''); +define('FANTASY_TRACKER_PASSWORD', ''); define('FREE_AGENTS_MAX', 50); static $scored_stats = [ '12' => 1, //PTS @@ -21,6 +23,17 @@ /* * Non-Configurable Constants */ - define('AUTH_ENDPOINT', 'https://api.login.yahoo.com/oauth2/get_token'); +// Define Directories for referencing +define('BIN_DIR', __DIR__ . '/bin/'); +define('TMP_DIR', __DIR__ . '/tmp/'); +define('TMP_AUTH_DIR', __DIR__ . '/tmp/auth/'); +define('TMP_DATA_DIR', __DIR__ . '/tmp/data/'); +define('TMP_DATA_PLAYERS_DIR', __DIR__ . '/tmp/data/players/'); + +// Define Stat Types +define('ONE_WEEK_AVG', 1); +define('TWO_WEEK_AVG', 2); +define('ONE_MO_AVG', 4); + diff --git a/helper.php b/helper.php index e80a4f4..2128c21 100644 --- a/helper.php +++ b/helper.php @@ -33,9 +33,3 @@ function getContents($filepath) { } } -function sendEmail($recipient, $data) -{ - $headers = "From: fantasytracker@project.com"; - mail($recipient, 'Your FantasyTrader Update!', $data, $headers); -} - diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/PHPMailer b/lib/PHPMailer new file mode 160000 index 0000000..a8bf068 --- /dev/null +++ b/lib/PHPMailer @@ -0,0 +1 @@ +Subproject commit a8bf068f64a580302026e484ee29511f661b2ad3 diff --git a/pi.php b/pi.php new file mode 100644 index 0000000..7987814 --- /dev/null +++ b/pi.php @@ -0,0 +1,20 @@ +getRosterStats(); +$request->getFreeAgentsStats(); +// Then we generate the report +$data = $analytics->generateReport(); + +// Initialize mailer credentials and send email from generated CSV +$mailer->initializeMail(); +$status = $mailer->sendEmail('', $data); + diff --git a/scripts/.gitkeep b/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100644 index 0000000..62764a2 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Creates a backup of the tmp/ directory + +if [ -z "$1" ]; then + echo "Help : To compress file use argument with directory" + exit 0 +fi + +filename="backups/$1_$(date '+%F').tar.gz" + +if [ -e "$filename" ]; then + echo "WARNING: file exists: $filename" >&2 +else + tar -czvf "$filename" "$@" +fi diff --git a/scripts/update.sh b/scripts/update.sh new file mode 100644 index 0000000..d65b5cd --- /dev/null +++ b/scripts/update.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +cd /home/pi/Sites/fantasytracker && git checkout dev && git up