TokiCLI 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f61d327814465ef395578a24ed1ef8d33bc7d8e
4
- data.tar.gz: 41eb44558c632f0e011aca8c2f7b7999cf7471f9
3
+ metadata.gz: db9fe2bb7c5986f94a5990b01813fa6daf6aa17e
4
+ data.tar.gz: bcb36afe15205c5b6cb58a7ac356634ac00d85ed
5
5
  SHA512:
6
- metadata.gz: 4a8462d3658bff7c5403da21f6dadacb9268b6619164197d31ddaa06e06d4a4209caa6cceebc154a624ffaa1907fc54c99591eae5a3ebf6d611c12535e6cc35a
7
- data.tar.gz: 951b0f88dbe1a956f06f0c0778f6fe1050b741a8337f94145f05c5173aa7ae82a77f374c78d7ac06b47032847db0051668bd80000d6cec0bb20f053c76530798
6
+ metadata.gz: a6f27e0aab7776aea2e9778a34ec32e5f01a06f8f36a47c1c16fcea66faccdb5d894d277d607c7eaba35b188064558fde4e7ac22d61ac2f5ccc10afb0637fa68
7
+ data.tar.gz: 96366f7ca1a02727c778895514d5300ba45ff1a738dcac2a4a7a7284f4c265e68fc84002fe12ae4fdd0e6c0b7951f4c326ee5471da0dfff5009c0f5c89cd90fa
@@ -1,3 +1,13 @@
1
+ # 0.1.1
2
+
3
+ - Fixed a dependency in the now yanked 0.1.0
4
+
5
+ # 0.1.0
6
+
7
+ - Introducing the API
8
+ - The CLI client uses the API
9
+ - New commands
10
+
1
11
  # 0.0.9
2
12
 
3
13
  - Skip invalid scanned apps
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
- gem install TokiCLI
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
- The results are sorted by ascending date and time.
113
+ `toki log --bundle 'com.googlecode.iterm2'`
59
114
 
60
- When pulling the data from ADN instead of the local database, the results are sorted by ascending synced message.
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
- ## Toki
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
 
@@ -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 = '>= 1.9.3'
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.8"
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"
@@ -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