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