TokiCLI 0.0.9 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +166 -20
- data/TokiCLI.gemspec +2 -2
- data/lib/API/dbapi.rb +451 -0
- data/lib/API/helpers.rb +151 -0
- data/lib/TokiCLI/app.rb +225 -106
- data/lib/TokiCLI/authorize.rb +6 -4
- data/lib/TokiCLI/export.rb +81 -0
- data/lib/TokiCLI/import.rb +122 -0
- data/lib/TokiCLI/scan.rb +19 -0
- data/lib/TokiCLI/version.rb +1 -1
- data/lib/TokiCLI/view.rb +100 -43
- metadata +10 -7
- data/lib/TokiCLI/module.rb +0 -224
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db9fe2bb7c5986f94a5990b01813fa6daf6aa17e
|
4
|
+
data.tar.gz: bcb36afe15205c5b6cb58a7ac356634ac00d85ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6f27e0aab7776aea2e9778a34ec32e5f01a06f8f36a47c1c16fcea66faccdb5d894d277d607c7eaba35b188064558fde4e7ac22d61ac2f5ccc10afb0637fa68
|
7
|
+
data.tar.gz: 96366f7ca1a02727c778895514d5300ba45ff1a738dcac2a4a7a7284f4c265e68fc84002fe12ae4fdd0e6c0b7951f4c326ee5471da0dfff5009c0f5c89cd90fa
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Access your Toki data from the local database or from the App.net backup channel
|
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
|
-
|
12
|
+
`gem install TokiCLI`
|
13
13
|
|
14
14
|
## Usage
|
15
15
|
|
@@ -39,25 +39,80 @@ The date you type has to be formatted like this: year-month-day
|
|
39
39
|
|
40
40
|
`toki day 2014-04-19`
|
41
41
|
|
42
|
+
### Since
|
43
|
+
|
44
|
+
The **since** command shows your top used apps since a specific day.
|
45
|
+
|
46
|
+
`toki since 2014-04-19`
|
47
|
+
|
48
|
+
### Before
|
49
|
+
|
50
|
+
The **before** command shows your top used apps before a specific day.
|
51
|
+
|
52
|
+
`toki before 2014-04-19`
|
53
|
+
|
42
54
|
### Range
|
43
55
|
|
44
56
|
The **range** command shows your top used apps between two specific days.
|
45
57
|
|
46
|
-
The dates you type have to be formatted like this: year-month-day and separated by a single space.
|
47
|
-
|
48
58
|
`toki range 2014-04-17 2014-04-19`
|
49
59
|
|
60
|
+
### App
|
61
|
+
|
62
|
+
Total tracked time for an app
|
63
|
+
|
64
|
+
`toki app iterm`
|
65
|
+
|
66
|
+
You don't have to specify the exact name of the identifier: for example, typing 'iterm' will find 'com.googlecode.iterm2'.
|
67
|
+
|
68
|
+
However, you can specify a bundle identifier if you need it.
|
69
|
+
|
70
|
+
`toki app --bundle 'com.googlecode.iterm2'`
|
71
|
+
|
72
|
+
### App before
|
73
|
+
|
74
|
+
Total tracked time for an app before a specific day
|
75
|
+
|
76
|
+
`toki app_before iterm 2014-04-19`
|
77
|
+
|
78
|
+
`toki app_before --bundle 'com.googlecode.iterm2' 2014-04-19`
|
79
|
+
|
80
|
+
|
81
|
+
### App since
|
82
|
+
|
83
|
+
Total tracked time for an app since a specific day
|
84
|
+
|
85
|
+
`toki app_since iterm 2014-04-19`
|
86
|
+
|
87
|
+
`toki app_since --bundle 'com.googlecode.iterm2' 2014-04-19`
|
88
|
+
|
89
|
+
|
90
|
+
### App day
|
91
|
+
|
92
|
+
Total tracked time for an app on a specific day
|
93
|
+
|
94
|
+
`toki app_day iterm 2014-04-19`
|
95
|
+
|
96
|
+
`toki app_day --bundle 'com.googlecode.iterm2' 2014-04-19`
|
97
|
+
|
98
|
+
### App range
|
99
|
+
|
100
|
+
Total tracked time for an app between two specific days
|
101
|
+
|
102
|
+
`toki app_range iterm 2014-04-19 2014-04-23`
|
103
|
+
|
104
|
+
`toki app_range --bundle 'com.googlecode.iterm2' 2014-04-19 2014-04-23`
|
105
|
+
|
106
|
+
|
50
107
|
### Log
|
51
108
|
|
52
109
|
The **log** command shows the entire log (history) for one app.
|
53
110
|
|
54
|
-
You don't have to specify the exact name of the identifier: for example, typing 'iterm' will find 'com.googlecod.iterm2'.
|
55
|
-
|
56
111
|
`toki log iterm`
|
57
112
|
|
58
|
-
|
113
|
+
`toki log --bundle 'com.googlecode.iterm2'`
|
59
114
|
|
60
|
-
|
115
|
+
The results are sorted by ascending date and time.
|
61
116
|
|
62
117
|
### Scan
|
63
118
|
|
@@ -73,18 +128,6 @@ In order to be able to access your ADN channel (optional), TokiCLI has to obtain
|
|
73
128
|
|
74
129
|
Just do `toki auth` and follow the steps, this is fast and easy.
|
75
130
|
|
76
|
-
### Global option: ADN
|
77
|
-
|
78
|
-
TokiCLI accesses the local Toki database by default.
|
79
|
-
|
80
|
-
If you want to access the App.net backup channel instead, you have to specify the `-a` option:
|
81
|
-
|
82
|
-
`toki total -a`
|
83
|
-
|
84
|
-
`toki log vlc -a`
|
85
|
-
|
86
|
-
`toki top -n 10 -a`
|
87
|
-
|
88
131
|
### Global option: JSON
|
89
132
|
|
90
133
|
Export the Toki results as a JSON file with the `-j` option:
|
@@ -105,8 +148,111 @@ Export the Toki results as a CSV file with the `-c` option:
|
|
105
148
|
|
106
149
|
`toki top -n 10 -c`
|
107
150
|
|
151
|
+
## Restore database from App.net
|
152
|
+
|
153
|
+
Toki.app backs up your Toki tracked apps data 'in the cloud' via an App.net channel.
|
154
|
+
|
155
|
+
TokiCLI is able to download this data and *rebuild the Toki database* if you lost your local install or you're simply moving toki.app to a new machine.
|
156
|
+
|
157
|
+
`toki auth`
|
158
|
+
|
159
|
+
`toki restore`
|
160
|
+
|
161
|
+
# API
|
162
|
+
|
163
|
+
There's a special API if you want to use TokiCLI as a module in another app.
|
164
|
+
|
165
|
+
```
|
166
|
+
require 'TokiCLI/API/dbapi'
|
167
|
+
```
|
168
|
+
|
169
|
+
First of all, create a TokiCLI/API instance:
|
170
|
+
|
171
|
+
`toki = TokiCLI::DBAPI.new`
|
172
|
+
|
173
|
+
## Endpoints
|
174
|
+
|
175
|
+
Get the total time for an app, in seconds, given its exact bundle identifier:
|
176
|
+
|
177
|
+
`time = toki.bundle_total 'com.sublimetext.3'`
|
178
|
+
|
179
|
+
With a (partial) name:
|
180
|
+
|
181
|
+
`time = toki.name_total 'sublime'`
|
182
|
+
|
183
|
+
Get the total time for an app, in seconds, given its exact bundle identifier, since a specific day:
|
184
|
+
|
185
|
+
`time = toki.bundle_total_since 'com.sublimetext.3', '2014-05-15'`
|
186
|
+
|
187
|
+
With a (partial) name:
|
188
|
+
|
189
|
+
`time = toki.name_total_since 'sublime', '2014-05-15'`
|
190
|
+
|
191
|
+
Get the total time for an app, in seconds, given its exact bundle identifier, before a specific day:
|
192
|
+
|
193
|
+
`time = toki.bundle_total_before 'com.sublimetext.3', '2014-05-15'`
|
194
|
+
|
195
|
+
With a (partial) name:
|
196
|
+
|
197
|
+
`time = toki.name_total_before 'sublime', '2014-05-15'`
|
198
|
+
|
199
|
+
Get the total time for an app, in seconds, given its exact bundle identifier, before and since a specific day:
|
200
|
+
|
201
|
+
`time = toki.bundle_total_split 'com.sublimetext.3', '2014-05-15'`
|
202
|
+
|
203
|
+
With a (partial) name:
|
204
|
+
|
205
|
+
`time = toki.name_total_split 'sublime', '2014-05-15'`
|
206
|
+
|
207
|
+
Get the total time for an app, in seconds, given its exact bundle identifier, between two specific days:
|
208
|
+
|
209
|
+
`time = toki.bundle_total_range 'com.sublimetext.3', '2014-05-15', '2014-05-17'`
|
210
|
+
|
211
|
+
With a (partial) name:
|
212
|
+
|
213
|
+
`time = toki.name_total_range 'sublime', '2014-05-15', '2014-05-17'`
|
214
|
+
|
215
|
+
Get the total time of all apps used between day 1 and day 2:
|
216
|
+
|
217
|
+
`apps = toki.apps_range '2014-05-15', '2014-05-17'`
|
218
|
+
|
219
|
+
Get the total time of all apps used on a specific day:
|
220
|
+
|
221
|
+
`apps = toki.apps_day '2014-05-15'`
|
222
|
+
|
223
|
+
Get the total time of all tracked apps:
|
224
|
+
|
225
|
+
`apps = toki.apps_total`
|
226
|
+
|
227
|
+
Get the top x tracked apps (5 by default):
|
228
|
+
|
229
|
+
`apps = toki.apps_top 10`
|
230
|
+
|
231
|
+
Get the complete log for an app:
|
232
|
+
|
233
|
+
`log = toki.bundle_log 'com.sublimetext.3'`
|
234
|
+
|
235
|
+
With a (partial) name:
|
236
|
+
|
237
|
+
`log = toki.name_log 'sublime text'`
|
238
|
+
|
239
|
+
|
240
|
+
## Tools
|
241
|
+
|
242
|
+
Scan disk for installed apps, get their names from their bundle identifiers and save the file (ignores unresolved identifiers):
|
243
|
+
|
244
|
+
`app_names = toki.scan_apps`
|
245
|
+
|
246
|
+
Get apps names and bundle identifiers (without re-scanning, and including unresolved identifiers):
|
247
|
+
|
248
|
+
`app_names = toki.tracked_apps`
|
249
|
+
|
250
|
+
Get bundle_id from app name or partial app name:
|
251
|
+
|
252
|
+
`bundle_id = toki.get_bundle_from_name 'sublime'`
|
253
|
+
|
108
254
|
|
109
|
-
|
255
|
+
# Toki
|
110
256
|
|
111
257
|
[Toki](https://itunes.apple.com/fr/app/toki/id861749202?mt=12) is a Mac OS X app written by [Keitaroh Kobayashi](http://app.net/keita).
|
112
258
|
|
data/TokiCLI.gemspec
CHANGED
@@ -18,13 +18,13 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.required_ruby_version = '>=
|
21
|
+
spec.required_ruby_version = '>= 2.0.0'
|
22
22
|
|
23
23
|
spec.add_dependency "thor", "~> 0.18"
|
24
24
|
spec.add_dependency "rest-client", "~> 1.6"
|
25
25
|
spec.add_dependency "amalgalite", "~> 1.3"
|
26
26
|
spec.add_dependency "terminal-table", "~> 1.4"
|
27
|
-
spec.add_dependency "CFPropertyList", "~> 2.2
|
27
|
+
spec.add_dependency "CFPropertyList", "~> 2.2"
|
28
28
|
|
29
29
|
spec.add_development_dependency "bundler", "~> 1.6"
|
30
30
|
spec.add_development_dependency "rake"
|
data/lib/API/dbapi.rb
ADDED
@@ -0,0 +1,451 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module TokiCLI
|
3
|
+
class DBAPI
|
4
|
+
|
5
|
+
require 'ostruct'
|
6
|
+
require 'amalgalite'
|
7
|
+
require 'CFPropertyList'
|
8
|
+
require 'terminal-table/import'
|
9
|
+
require 'json'
|
10
|
+
require 'fileutils'
|
11
|
+
require_relative "../TokiCLI/version"
|
12
|
+
require_relative "helpers"
|
13
|
+
|
14
|
+
attr_accessor :helpers, :db, :table
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@helpers = Helpers.new
|
18
|
+
@db = @helpers.db
|
19
|
+
@table = @helpers.table
|
20
|
+
end
|
21
|
+
|
22
|
+
## ENDPOINTS
|
23
|
+
|
24
|
+
# Get the total time for an app given its exact bundle identifier
|
25
|
+
def bundle_total bundle_id, orig = nil
|
26
|
+
sec = (@db.execute("SELECT sum(totalSeconds) FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}'").flatten)[0]
|
27
|
+
args = if orig.nil?
|
28
|
+
[bundle_id]
|
29
|
+
else
|
30
|
+
[bundle_id, orig]
|
31
|
+
end
|
32
|
+
{ meta: {
|
33
|
+
code: 200,
|
34
|
+
request: {command: 'bundle_total', args: args, processed_at: Time.now}
|
35
|
+
},
|
36
|
+
data: {
|
37
|
+
bundle: bundle_id,
|
38
|
+
name: @helpers.find_app_name(bundle_id),
|
39
|
+
total: {
|
40
|
+
seconds: sec,
|
41
|
+
time: @helpers.sec_to_time(sec)
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get the total time for an app given a (partial) name
|
48
|
+
def name_total name
|
49
|
+
bun = JSON.parse(get_bundle_from_name(name))
|
50
|
+
if bun['meta']['code'] == 200
|
51
|
+
bundle_total bun['data']['bundle'], name
|
52
|
+
else
|
53
|
+
@helpers.json_nodata
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get the total time for an app given its exact bundle identifier, since a specific day
|
58
|
+
def bundle_total_since bundle_id, day, orig = nil
|
59
|
+
since = (@db.execute("SELECT sum(totalSeconds) FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}' AND activeFrom >= #{Time.parse(day).to_i}").flatten)[0]
|
60
|
+
args = if orig.nil?
|
61
|
+
[bundle_id, day]
|
62
|
+
else
|
63
|
+
[bundle_id, day, orig]
|
64
|
+
end
|
65
|
+
{ meta: {
|
66
|
+
code: 200,
|
67
|
+
request: {command: 'bundle_total_since', args: args, processed_at: Time.now}
|
68
|
+
},
|
69
|
+
data: {
|
70
|
+
bundle: bundle_id,
|
71
|
+
name: @helpers.find_app_name(bundle_id),
|
72
|
+
since: day,
|
73
|
+
total: {
|
74
|
+
seconds: since,
|
75
|
+
time: @helpers.sec_to_time(since)
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}.to_json
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get the total time for an app given a (partial) name, since a specific day
|
82
|
+
def name_total_since name, day
|
83
|
+
bun = JSON.parse(get_bundle_from_name(name))
|
84
|
+
if bun['meta']['code'] == 200
|
85
|
+
bundle_total_since bun['data']['bundle'], day, name
|
86
|
+
else
|
87
|
+
@helpers.json_nodata
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get the total time for an app given its exact bundle identifier, before a specific day
|
92
|
+
def bundle_total_before bundle_id, day, orig = nil
|
93
|
+
before = (@db.execute("SELECT sum(totalSeconds) FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}' AND activeFrom < #{Time.parse(day).to_i}").flatten)[0]
|
94
|
+
args = if orig.nil?
|
95
|
+
[bundle_id, day]
|
96
|
+
else
|
97
|
+
[bundle_id, day, orig]
|
98
|
+
end
|
99
|
+
{ meta: {
|
100
|
+
code: 200,
|
101
|
+
request: {command: 'bundle_total_before', args: args, processed_at: Time.now}
|
102
|
+
},
|
103
|
+
data: {
|
104
|
+
bundle: bundle_id,
|
105
|
+
name: @helpers.find_app_name(bundle_id),
|
106
|
+
before: day,
|
107
|
+
total: {
|
108
|
+
seconds: before,
|
109
|
+
time: @helpers.sec_to_time(before)
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}.to_json
|
113
|
+
end
|
114
|
+
|
115
|
+
# Get the total time for an app given a (partial) name, before a specific day
|
116
|
+
def name_total_before name, day
|
117
|
+
bun = JSON.parse(get_bundle_from_name(name))
|
118
|
+
if bun['meta']['code'] == 200
|
119
|
+
bundle_total_before bun['data']['bundle'], day, name
|
120
|
+
else
|
121
|
+
@helpers.json_nodata
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Get the total time for an app given its exact bundle identifier, before and since a specific day
|
126
|
+
def bundle_total_split bundle_id, day, orig = nil
|
127
|
+
before = (@db.execute("SELECT sum(totalSeconds) FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}' AND activeFrom < #{Time.parse(day).to_i}").flatten)[0]
|
128
|
+
since = (@db.execute("SELECT sum(totalSeconds) FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}' AND activeFrom >= #{Time.parse(day).to_i}").flatten)[0]
|
129
|
+
args = if orig.nil?
|
130
|
+
[bundle_id, day]
|
131
|
+
else
|
132
|
+
[bundle_id, day, orig]
|
133
|
+
end
|
134
|
+
{ meta: {
|
135
|
+
code: 200,
|
136
|
+
request: {command: 'bundle_total_split', args: args, processed_at: Time.now}
|
137
|
+
},
|
138
|
+
data: {
|
139
|
+
bundle: bundle_id,
|
140
|
+
name: @helpers.find_app_name(bundle_id),
|
141
|
+
split: day,
|
142
|
+
total: {
|
143
|
+
seconds: {
|
144
|
+
before: before,
|
145
|
+
since: since
|
146
|
+
},
|
147
|
+
time: {
|
148
|
+
before: @helpers.sec_to_time(before),
|
149
|
+
since: @helpers.sec_to_time(since)
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}.to_json
|
154
|
+
end
|
155
|
+
|
156
|
+
# Get the total time for an app given a (partial) name, before and since a specific day
|
157
|
+
def name_total_split name, day
|
158
|
+
bun = JSON.parse(get_bundle_from_name(name))
|
159
|
+
if bun['meta']['code'] == 200
|
160
|
+
bundle_total_split bun['data']['bundle'], day, name
|
161
|
+
else
|
162
|
+
@helpers.json_nodata
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Get the total time for an app given its exact bundle identifier, between two specific days
|
167
|
+
def bundle_total_range bundle_id, day1, day2, orig = nil
|
168
|
+
total = (@db.execute("SELECT sum(totalSeconds) FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}' AND activeFrom >= #{Time.parse(day1).to_i} AND activeFrom < #{Time.parse(day2).to_i}").flatten)[0]
|
169
|
+
args = if orig.nil?
|
170
|
+
[bundle_id, day1, day2]
|
171
|
+
else
|
172
|
+
[bundle_id, day1, day2, orig]
|
173
|
+
end
|
174
|
+
if total.nil?
|
175
|
+
@helpers.json_nodata
|
176
|
+
else
|
177
|
+
{ meta: {
|
178
|
+
code: 200,
|
179
|
+
request: {command: 'bundle_total_range', args: args, processed_at: Time.now}
|
180
|
+
},
|
181
|
+
data: {
|
182
|
+
bundle: bundle_id,
|
183
|
+
name: @helpers.find_app_name(bundle_id),
|
184
|
+
from: day1,
|
185
|
+
to: day2,
|
186
|
+
total: {
|
187
|
+
seconds: total,
|
188
|
+
time: @helpers.sec_to_time(total)
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}.to_json
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Get the total time for an app given a (partial) name, between two specific days
|
196
|
+
def name_total_range name, day1, day2
|
197
|
+
bun = JSON.parse(get_bundle_from_name(name))
|
198
|
+
if bun['meta']['code'] == 200
|
199
|
+
bundle_total_range bun['data']['bundle'], day1, day2, name
|
200
|
+
else
|
201
|
+
@helpers.json_nodata
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Get all apps used between day 1 and day 2
|
206
|
+
def apps_range day1, day2
|
207
|
+
result = []
|
208
|
+
range = @db.execute("SELECT bundleIdentifier,sum(totalSeconds) FROM #{@table} WHERE activeFrom >= #{Time.parse(day1).to_i} AND activeFrom < #{Time.parse(day2).to_i} GROUP BY bundleIdentifier")
|
209
|
+
range.each {|id,sec| result << {
|
210
|
+
bundle: id,
|
211
|
+
name: @helpers.find_app_name(id),
|
212
|
+
total: {
|
213
|
+
seconds: sec,
|
214
|
+
time: @helpers.sec_to_time(sec)
|
215
|
+
}}
|
216
|
+
}
|
217
|
+
result.sort_by! {|obj| obj[:total][:seconds]}
|
218
|
+
{
|
219
|
+
meta: {
|
220
|
+
code: 200,
|
221
|
+
request: {command: 'apps_range', args: [day1, day2], processed_at: Time.now}
|
222
|
+
},
|
223
|
+
data: {
|
224
|
+
from: day1,
|
225
|
+
to: day2,
|
226
|
+
apps: result
|
227
|
+
}
|
228
|
+
}.to_json
|
229
|
+
end
|
230
|
+
|
231
|
+
# Get all apps used on a specific day
|
232
|
+
def apps_day day
|
233
|
+
date = DateTime.strptime(day, '%Y-%m-%d')
|
234
|
+
response = @db.execute("SELECT bundleIdentifier,sum(totalSeconds) FROM #{@table} WHERE activeFrom >= #{date.to_time.to_i} AND activeFrom < #{date.next_day.to_time.to_i} GROUP BY bundleIdentifier")
|
235
|
+
result = make_apps response
|
236
|
+
{
|
237
|
+
meta: {
|
238
|
+
code: 200,
|
239
|
+
request: {command: 'apps_day', args: [day], processed_at: Time.now}
|
240
|
+
},
|
241
|
+
data: {
|
242
|
+
date: day,
|
243
|
+
apps: result
|
244
|
+
}
|
245
|
+
}.to_json
|
246
|
+
end
|
247
|
+
|
248
|
+
def apps_since day
|
249
|
+
date = DateTime.strptime(day, '%Y-%m-%d')
|
250
|
+
response = @db.execute("SELECT bundleIdentifier,sum(totalSeconds) FROM #{@table} WHERE activeFrom >= #{date.to_time.to_i} GROUP BY bundleIdentifier")
|
251
|
+
result = make_apps response
|
252
|
+
{
|
253
|
+
meta: {
|
254
|
+
code: 200,
|
255
|
+
request: {command: 'apps_since', args: [day], processed_at: Time.now}
|
256
|
+
},
|
257
|
+
data: {
|
258
|
+
since: day,
|
259
|
+
apps: result
|
260
|
+
}
|
261
|
+
}.to_json
|
262
|
+
end
|
263
|
+
|
264
|
+
def apps_before day
|
265
|
+
date = DateTime.strptime(day, '%Y-%m-%d')
|
266
|
+
response = @db.execute("SELECT bundleIdentifier,sum(totalSeconds) FROM #{@table} WHERE activeFrom < #{date.to_time.to_i} GROUP BY bundleIdentifier")
|
267
|
+
result = make_apps response
|
268
|
+
{
|
269
|
+
meta: {
|
270
|
+
code: 200,
|
271
|
+
request: {command: 'apps_before', args: [day], processed_at: Time.now}
|
272
|
+
},
|
273
|
+
data: {
|
274
|
+
before: day,
|
275
|
+
apps: result
|
276
|
+
}
|
277
|
+
}.to_json
|
278
|
+
end
|
279
|
+
|
280
|
+
# Get totals of all tracked apps
|
281
|
+
def apps_total
|
282
|
+
result = make_total
|
283
|
+
{
|
284
|
+
meta: {
|
285
|
+
code: 200,
|
286
|
+
request: {command: 'apps_total', args: [], processed_at: Time.now}
|
287
|
+
},
|
288
|
+
data: {
|
289
|
+
apps: result
|
290
|
+
}
|
291
|
+
}.to_json
|
292
|
+
end
|
293
|
+
|
294
|
+
# Get totals of top tracked apps
|
295
|
+
def apps_top number = 5
|
296
|
+
result = make_total
|
297
|
+
index = -number
|
298
|
+
{
|
299
|
+
meta: {
|
300
|
+
code: 200,
|
301
|
+
request: {command: 'apps_top', args: [number], processed_at: Time.now}
|
302
|
+
},
|
303
|
+
data: {
|
304
|
+
apps: result[index..-1]
|
305
|
+
}
|
306
|
+
}.to_json
|
307
|
+
end
|
308
|
+
|
309
|
+
# Get the complete log for an app
|
310
|
+
def bundle_log bundle_id, orig = nil
|
311
|
+
log = @db.execute("SELECT * FROM #{@table} WHERE bundleIdentifier IS '#{bundle_id}'")
|
312
|
+
# id (INTEGER) 0, bundleIdentifier (VARCHAR) 1, activeFrom (INTEGER) 2, activeTo (INTEGER) 3, totalSeconds (INTEGER) 4, UUID (VARCHAR) 5, synced (INTEGER) 6, availableToSync (INTEGER) 7
|
313
|
+
result = {}
|
314
|
+
log.each do |arr|
|
315
|
+
result[arr[0]] = {
|
316
|
+
start: @helpers.epoch_to_date(arr[2]),
|
317
|
+
duration: {
|
318
|
+
seconds: arr[4],
|
319
|
+
time: @helpers.seconds_to_time(arr[4])
|
320
|
+
}
|
321
|
+
}
|
322
|
+
end
|
323
|
+
args = if orig.nil?
|
324
|
+
[bundle_id]
|
325
|
+
else
|
326
|
+
[bundle_id, orig]
|
327
|
+
end
|
328
|
+
{ meta: {
|
329
|
+
code: 200,
|
330
|
+
request: {command: 'bundle_total', args: args, processed_at: Time.now}
|
331
|
+
},
|
332
|
+
data: {
|
333
|
+
bundle: bundle_id,
|
334
|
+
name: @helpers.find_app_name(bundle_id),
|
335
|
+
log: result
|
336
|
+
}
|
337
|
+
}.to_json
|
338
|
+
end
|
339
|
+
|
340
|
+
# Get the complete log for an app, given a (partial) name
|
341
|
+
def name_log name
|
342
|
+
bun = JSON.parse(get_bundle_from_name(name))
|
343
|
+
if bun['meta']['code'] == 200
|
344
|
+
bundle_log bun['data']['bundle'], name
|
345
|
+
else
|
346
|
+
@helpers.json_nodata
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
|
351
|
+
## TOOLS
|
352
|
+
|
353
|
+
# Get all data from database
|
354
|
+
def get_all_data
|
355
|
+
(@helpers.get_all_data).to_json
|
356
|
+
end
|
357
|
+
|
358
|
+
# Scan disk for installed apps
|
359
|
+
def scan_apps
|
360
|
+
apps = []
|
361
|
+
(@helpers.scan).each do |id,name|
|
362
|
+
apps << {bundle: id, name: name}
|
363
|
+
end
|
364
|
+
{
|
365
|
+
meta: {
|
366
|
+
code: 200,
|
367
|
+
request: {
|
368
|
+
command: 'scan_apps',
|
369
|
+
processed_at: Time.now
|
370
|
+
}
|
371
|
+
},
|
372
|
+
data: {
|
373
|
+
apps: apps
|
374
|
+
}
|
375
|
+
}.to_json
|
376
|
+
end
|
377
|
+
|
378
|
+
# List of tracked apps
|
379
|
+
# (Run scan_apps before if necessary)
|
380
|
+
def tracked_apps
|
381
|
+
apps, ids = [], (@db.execute("SELECT bundleIdentifier FROM #{@table}")).flatten.uniq!
|
382
|
+
ids.each do |id|
|
383
|
+
@helpers.bundles.has_key?(id) ? apps << {bundle: id, name: @helpers.bundles[id]} : apps << {bundle: id, name: id}
|
384
|
+
end
|
385
|
+
{
|
386
|
+
meta: {
|
387
|
+
code: 200,
|
388
|
+
request: {
|
389
|
+
command: 'tracked_apps',
|
390
|
+
processed_at: Time.now
|
391
|
+
}
|
392
|
+
},
|
393
|
+
data: {
|
394
|
+
apps: apps
|
395
|
+
}
|
396
|
+
}.to_json
|
397
|
+
end
|
398
|
+
|
399
|
+
# Get bundle_id from app name or partial app name
|
400
|
+
# (Run scan_apps before if necessary)
|
401
|
+
def get_bundle_from_name name
|
402
|
+
resp = @helpers.get_bundle_from_name name
|
403
|
+
meta = {
|
404
|
+
request: {
|
405
|
+
command: 'get_bundle_from_name',
|
406
|
+
args: [name],
|
407
|
+
processed_at: Time.now
|
408
|
+
}
|
409
|
+
}
|
410
|
+
resp.empty? ?
|
411
|
+
{
|
412
|
+
meta: meta.merge!({
|
413
|
+
code: 404,
|
414
|
+
error: { message: "Unable to find an app containing '#{name}'" }
|
415
|
+
}),
|
416
|
+
data: {}
|
417
|
+
}.to_json :
|
418
|
+
{
|
419
|
+
meta: meta.merge!({code: 200}),
|
420
|
+
data: {
|
421
|
+
request: name,
|
422
|
+
bundle: resp[1],
|
423
|
+
name: resp[0]
|
424
|
+
}
|
425
|
+
}.to_json
|
426
|
+
end
|
427
|
+
|
428
|
+
private
|
429
|
+
|
430
|
+
def make_total
|
431
|
+
response = @db.execute("SELECT bundleIdentifier,sum(totalSeconds) FROM #{@table} GROUP BY bundleIdentifier")
|
432
|
+
make_apps response
|
433
|
+
end
|
434
|
+
|
435
|
+
def make_apps response
|
436
|
+
result = []
|
437
|
+
response.each {|id,sec| result << {
|
438
|
+
bundle: id,
|
439
|
+
name: @helpers.find_app_name(id),
|
440
|
+
total: {
|
441
|
+
seconds: sec,
|
442
|
+
time: @helpers.sec_to_time(sec)
|
443
|
+
}
|
444
|
+
}
|
445
|
+
}
|
446
|
+
result.sort_by! {|obj| obj[:total][:seconds]}
|
447
|
+
result
|
448
|
+
end
|
449
|
+
|
450
|
+
end
|
451
|
+
end
|