fitnio_export 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jakub Suder
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Fitnio export
2
+
3
+ This tool downloads your activity data from the sports tracking webapp [Fitnio.com](http://fitnio.com). You can use this if you want to back up your data or move it elsewhere (e.g. to [RunKeeper](http://runkeeper.com)). It exports the activity data in [GPX format](https://en.wikipedia.org/wiki/GPS_eXchange_Format), a standard format for representing GPS routes.
4
+
5
+ ## Requirements
6
+
7
+ You need to have Ruby installed on your machine (any recent version will do).
8
+
9
+ ## Installation
10
+
11
+ Just install the gem:
12
+
13
+ gem install fitnio_export
14
+
15
+ ## Running
16
+
17
+ Run the fitnio_export command:
18
+
19
+ fitnio_export
20
+
21
+ The script will ask you for your email and password, and then will try to download your dashboard page with a list of activities. If it works, it will download your activities one by one and will save the converted data as files named e.g. `fitnio-2012-05-03-1730.gpx` in the current directory.
22
+
23
+ ## Importing into RunKeeper
24
+
25
+ I'm not aware of any mass import feature in RunKeeper, so you'll have to import the activities manually one by one. Click "Post new activity", choose activity type, then choose "Import Map" and choose the generated GPX file. You should see the imported map now - if it looks ok, press "Next" and save the map.
26
+
27
+ ## Credits
28
+
29
+ * Fitnio.com is © Fitnio LLC
30
+ * RunKeeper is © FitnessKeeper Inc.
31
+ * fitnio_export is © Jakub Suder and licensed under MIT license
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', 'lib'))
4
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
5
+
6
+ require 'rubygems'
7
+ require 'fitnio_export'
8
+ require 'highline'
9
+
10
+ console = HighLine.new
11
+
12
+ puts "Log in to Fitnio:"
13
+ puts "================="
14
+ puts
15
+
16
+ email = console.ask("Email:")
17
+ puts
18
+
19
+ password = console.ask("Password:") { |q| q.echo = "*" }
20
+ puts
21
+
22
+ begin
23
+ exporter = FitnioExport.new(email, password)
24
+ exporter.start
25
+ rescue FitnioExport::AuthenticationError => e
26
+ puts "Error: #{e}"
27
+ end
@@ -0,0 +1,120 @@
1
+ require 'mechanize'
2
+ require 'json'
3
+ require 'time'
4
+ require 'logger'
5
+
6
+ class FitnioExport
7
+ class AuthenticationError < StandardError; end
8
+
9
+ MILE_TO_KM = 1.609344
10
+
11
+ SIGNIN_URL = "http://fitnio.com/signIn.htm"
12
+ DATA_URL = "http://fitnio.com/mapData.htm"
13
+
14
+ SPORT_TYPES = {
15
+ 'W' => 'Walking',
16
+ 'R' => 'Running',
17
+ 'B' => 'Biking'
18
+ }
19
+
20
+ GPX_HEADER = <<-HEADER
21
+ <?xml version="1.0" encoding="UTF-8"?>
22
+ <gpx
23
+ version="1.1"
24
+ creator="fitnio_export (http://github.com/psionides/fitnio_export)"
25
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
26
+ xmlns="http://www.topografix.com/GPX/1/1"
27
+ xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
28
+ xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1">
29
+ <trk>
30
+ HEADER
31
+
32
+ GPX_FOOTER = <<-FOOTER
33
+ </trkseg>
34
+ </trk>
35
+ </gpx>
36
+ FOOTER
37
+
38
+ def initialize(email, password)
39
+ @email = email
40
+ @password = password
41
+ @logger = Logger.new(STDOUT)
42
+ @logger.formatter = lambda { |type, time, program, text| "#{time}: #{text}\n" }
43
+ @browser = Mechanize.new
44
+ end
45
+
46
+ def start
47
+ rows = get_activity_rows
48
+
49
+ rows.each do |row|
50
+ id = row['id']
51
+ json = get_activity_json(id)
52
+
53
+ date_row = row.search('td')[1]
54
+ date_string = date_row.to_s.gsub(/<.*?>/, ' ').strip
55
+
56
+ sprite = row.search('.gs-sprite')[0]
57
+ type = sprite['class'][/me-(\w)/].split('-').last
58
+
59
+ save_data_file(json, date_string, type)
60
+ end
61
+
62
+ log "Done."
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def log(text)
69
+ @logger.info(text)
70
+ end
71
+
72
+ def get_activity_rows
73
+ log "Downloading dashboard page..."
74
+
75
+ page = @browser.post(SIGNIN_URL, :email => @email, :password => @password, :createAccount => false)
76
+
77
+ if page.search('#me-data').length == 0
78
+ raise AuthenticationError, "Incorrect email or password"
79
+ end
80
+
81
+ page.search('.session-row')
82
+ end
83
+
84
+ def get_activity_json(id)
85
+ log "Downloading activity #{id}..."
86
+
87
+ json_page = @browser.get(DATA_URL, :key => id)
88
+ json = json_page.body.gsub(%r(^//), '')
89
+
90
+ JSON.parse(json)
91
+ end
92
+
93
+ def save_data_file(json, date_string, type)
94
+ start_date = Time.parse(date_string)
95
+ filename = "fitnio-#{start_date.strftime('%Y-%m-%d-%H%M')}.gpx"
96
+ log "Saving #{filename}..."
97
+
98
+ File.open(filename, "w") do |file|
99
+ file.write GPX_HEADER
100
+ file.puts "<name>#{SPORT_TYPES[type]} #{date_string}</name>"
101
+ file.puts "<time>#{start_date.utc.xmlschema}</time>"
102
+ file.puts "<trkseg>"
103
+
104
+ json['points'].each do |point|
105
+ lat = sprintf("%.9f", point['latitude'])
106
+ long = sprintf("%.9f", point['longitude'])
107
+
108
+ # fitnio seems to return incorrect altitude (it shows ~77 m where Runkeeper shows ~230m),
109
+ # but it doesn't matter since Runkeeper finds the correct values by itself
110
+ alt = sprintf("%.2f", point['altitude'] * MILE_TO_KM * 1000)
111
+
112
+ time = (start_date + point['timeOffset'] / 1000.0).utc.xmlschema(3)
113
+
114
+ file.puts %(<trkpt lat="#{lat}" lon="#{long}"><ele>#{alt}</ele><time>#{time}</time></trkpt>)
115
+ end
116
+
117
+ file.write GPX_FOOTER
118
+ end
119
+ end
120
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fitnio_export
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jakub Suder
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-03 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mechanize
16
+ requirement: &70172804489240 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.4'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70172804489240
25
+ - !ruby/object:Gem::Dependency
26
+ name: highline
27
+ requirement: &70172804488540 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.11
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70172804488540
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ requirement: &70172804486160 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.7'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70172804486160
47
+ description:
48
+ email: jakub.suder@gmail.com
49
+ executables:
50
+ - fitnio_export
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - MIT-LICENSE
55
+ - README.markdown
56
+ - lib/fitnio_export.rb
57
+ - bin/fitnio_export
58
+ homepage: http://github.com/psionides/fitnio_export
59
+ licenses: []
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 1.8.10
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: A tool for exporting activity data from Fitnio in GPX format (for importing
82
+ into Runkeeper)
83
+ test_files: []