-
-
Save aaronpk/40d6bb333447ff4265a4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
chdir(dirname(__FILE__)); | |
chdir('..'); | |
require('vendor/autoload.php'); | |
require_once('includes/inc.php'); | |
require_once('includes/database.php'); | |
$places = array( | |
array( | |
'name' => 'Home', | |
'latitude' => Config::$homeLat, | |
'longitude' => Config::$homeLng, | |
'radius' => 200 | |
), | |
array( | |
'name' => 'Esri Portland', | |
'latitude' => 45.52154, | |
'longitude' => -122.6775348, | |
'radius' => 200 | |
) | |
); | |
if(array_key_exists(1, $argv) && $argv[1] == 'auth') { | |
if(array_key_exists(2, $argv)) { | |
$ch = curl_init('https://runkeeper.com/apps/token'); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array( | |
'grant_type' => 'authorization_code', | |
'code' => $argv[2], | |
'client_id' => Config::$runkeeperClientID, | |
'client_secret' => Config::$runkeeperClientSecret, | |
'redirect_uri' => 'http://localhost/' | |
))); | |
$response = curl_exec($ch); | |
$data = json_decode($response); | |
print_r($data); | |
} else { | |
echo "https://runkeeper.com/apps/authorize?response_type=code&redirect_uri=http://localhost/&client_id=" . Config::$runkeeperClientID . "\n"; | |
} | |
die(); | |
} | |
function rk_request($path) { | |
$ch = curl_init('https://api.runkeeper.com' . $path); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_HTTPHEADER, array( | |
'Authorization: Bearer ' . Config::$runkeeperToken | |
)); | |
$response = curl_exec($ch); | |
if($response) { | |
return json_decode($response); | |
} else { | |
return null; | |
} | |
} | |
$lastImportFilename = Config::dataDir().'last-runkeeper.txt'; | |
$lastDate = file_get_contents($lastImportFilename); | |
$should_continue = true; | |
$request_url = '/fitnessActivities?page=0&pageSize=50&noEarlierThan='.$lastDate.'&modifiedNoEarlierThan='.$lastDate; | |
// Find all existing runkeeper IDs to see if we've already imported a run | |
$existingItemIDs = array(); | |
foreach(explode("\n",shell_exec('grep runkeeper content/metrics/*/*/*/*.md')) as $line) { | |
if(preg_match('/activity\/(\d+)/', $line, $match)) { | |
$existingItemIDs[] = $match[1]; | |
} | |
} | |
while($should_continue) { | |
echo "Fetching $request_url\n"; | |
if($activities = rk_request($request_url)) { | |
if($activities->items) { | |
foreach($activities->items as $item) { | |
echo $item->uri . "\n"; | |
if(preg_match('/fitnessActivities\/(\d+)/', $item->uri, $match)) { | |
// Check if it's already been imported | |
if(!in_array($match[1], $existingItemIDs)) { | |
$post = process_rk_item($item); | |
if($post) { | |
file_put_contents($lastImportFilename, $post->date->format('Y-m-d')); | |
} | |
} else { | |
echo "Skipping because it's already been imported\n\n"; | |
} | |
} else { | |
echo "Encountered an unknown activity\n\n"; | |
} | |
} | |
if(property_exists($activities, 'next') && $activities->next) { | |
$request_url = $activities->next; | |
echo "Continuing...\n\n"; | |
} else { | |
$should_continue = false; | |
echo "Stopping because no 'next' URL was found for: $request_url\n\n"; | |
} | |
} else { | |
$should_continue = false; | |
echo "Stopping because no items found in this request: $request_url\n\n"; | |
} | |
} else { | |
$should_continue = false; | |
echo "Stopping because request failed: $request_url\n\n"; | |
} | |
} | |
echo "Done\n"; | |
function process_rk_item($item) { | |
global $places; | |
if($activity=rk_request($item->uri)) { | |
$path = $activity->path; | |
if(count($path) == 0) { | |
echo "skipping because no path data was found\n\n"; | |
return false; | |
} | |
$first = $path[0]; | |
$last = $path[count($path)-1]; | |
$tz = getTimezoneForLocation($first->latitude, $first->longitude); | |
if($tz) { | |
$timezone = new DateTimeZone($tz->timezone); | |
} else { | |
$timezone = null; | |
} | |
// The date from Runkeeper does not include a timezone, so assume it is the timezone | |
// that corresponds to the location of the start of the run | |
$start_date = new DateTime($activity->start_time, $timezone); | |
$end_date = new DateTime($activity->start_time, $timezone); | |
$end_date->add(new DateInterval('PT' . round($activity->duration) . 'S')); | |
echo $activity->activity."\n"; | |
echo $start_date->format('c') . "\n"; | |
// echo $end_date->format('c') . "\n"; | |
switch($activity->type) { | |
case 'Cycling': | |
$type = 'bikeride'; | |
break; | |
case 'Running': | |
$type = 'run'; | |
break; | |
case 'Walking': | |
$type = 'walk'; | |
break; | |
} | |
$post = p3k\Post::newPage('metrics', $start_date, $type); | |
echo $post->fullURL . "\n"; | |
echo $post->filename . "\n"; | |
if(file_exists(Config::contentDir().$post->filename)) { | |
echo "already imported\n\n"; | |
return false; | |
} | |
if(property_exists($activity, 'notes') && $activity->notes) { | |
$post->set('title', trim($activity->notes)); | |
} | |
$context = p3k\ReverseGeocoder::adr($first->latitude, $first->longitude); | |
if($tz) { | |
$post->set('timezone', $tz->timezone); | |
} | |
if($context) { | |
$post->set('locality', $context->localityName); | |
$post->set('region', $context->regionName); | |
$post->set('country', $context->countryName); | |
} | |
$post->set('latitude', $first->latitude); | |
$post->set('longitude', $first->longitude); | |
foreach($places as $place) { | |
if(gc_distance($place['latitude'], $place['longitude'], $first->latitude, $first->longitude) <= $place['radius']) { | |
$post->set('place-name', $place['name']); | |
} | |
} | |
$post->set('syndication', array($activity->activity)); | |
$routeData = array( | |
'start' => array( | |
'date' => $start_date->format('c'), | |
'latitude' => $first->latitude, | |
'longitude' => $first->longitude, | |
), | |
'end' => array( | |
'date' => $end_date->format('c'), | |
'latitude' => $last->latitude, | |
'longitude' => $last->longitude, | |
), | |
'meters' => (int)round($activity->total_distance), | |
'seconds' => (int)round($activity->duration) | |
); | |
if(property_exists($activity, 'average_heart_rate')) { | |
$routeData['heartrate'] = $activity->average_heart_rate; | |
} | |
$post->set('route', $routeData); | |
$geojson = array(); | |
foreach($activity->path as $point) { | |
$feature = array( | |
'type' => 'Feature', | |
'geometry' => array( | |
'type' => 'Point', | |
'coordinates' => array($point->longitude, $point->latitude) | |
), | |
'properties' => array( | |
'date' => date('Y-m-d\TH:i:s', $start_date->format('U')+round($point->timestamp)).'Z', | |
'altitude' => $point->altitude | |
) | |
); | |
if(property_exists($activity, 'heart_rate')) { | |
foreach($activity->heart_rate as $hr) { | |
if($hr->timestamp == $point->timestamp) { | |
$feature['properties']['heartrate'] = $hr->heart_rate; | |
} | |
} | |
} | |
$geojson[] = $feature; | |
} | |
$post->body = json_encode(array( | |
'path' => $geojson, | |
)); | |
$filesAdded = array(Config::contentDir().$post->filename); | |
@mkdir($post->assetFolder, 0755, true); | |
file_put_contents($post->assetFolder.'/runkeeper.json', json_encode($activity)); | |
$filesAdded[] = $post->assetFolder.'/runkeeper.json'; | |
// If there are any photos, download those too! | |
if(property_exists($activity, 'images')) { | |
$photos = array(); | |
foreach($activity->images as $i=>$image) { | |
$fn = 'photo-'.$i.'.jpg'; | |
file_put_contents($post->assetFolder.'/'.$fn, file_get_contents($image->uri)); | |
$filesAdded[] = $post->assetFolder.'/'.$fn; | |
$photos[] = $fn; | |
} | |
$post->set('photos', $photos); | |
} | |
$post->save(); | |
p3k\irc\alert('[runkeeper:' . $type . '] ' . round($routeData['meters']/1000,1) . 'km ' . round($routeData['seconds']/60) . ' minutes ' . $post->fullURL); | |
// Generate the two map images | |
$mapImages = $post->generateMapImages(false); | |
$filesAdded = array_merge($filesAdded, $mapImages); | |
\DeferredTask::queue('GitClient', 'addCommitPush', array($filesAdded, '[route] imported from runkeeper: '.$post->fullURL)); | |
echo "\n"; | |
return $post; | |
} else { | |
echo "Error: request for $item failed\n"; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment