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 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