timely-calendar 1.0.0 → 1.0.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/lib/timely/sources/google.rb +14 -6
- data/lib/timely/sources/outlook.rb +4 -0
- data/lib/timely/ui/application.rb +16 -1
- data/lib/timely/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: db1c94b2b016e7ce47aaa79da922a03e65956b992251ab0b263f8d2f36cf965e
|
|
4
|
+
data.tar.gz: 5d620757c14c5ffeca1a9e9b1fba5686357cf3ad573780dfa091e2a62f45450a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c86cfd413b6f262f4247473b982b554b395e4d554c185260ebae8c764f26a0399e94503a0ea632406a6f1fca851c1a9fc7eef30c811fb5a91a93fff97e58b1c0
|
|
7
|
+
data.tar.gz: c8d4fb8be5e6aa6b80a2a991e93caaa8bc828cf8085621ccd17c70ad3c5c520b8f203dc4c51b9a6197e8d2b48750d480365de8f25cb9ba8f7d7c9b47c3b8c9ad
|
|
@@ -211,13 +211,15 @@ module Timely
|
|
|
211
211
|
body
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
-
def api_get(path)
|
|
214
|
+
def api_get(path, retries: 2)
|
|
215
215
|
token = get_access_token
|
|
216
216
|
return nil unless token
|
|
217
|
-
|
|
217
|
+
full_url = path.start_with?('http') ? path : "#{API_BASE}#{path}"
|
|
218
|
+
uri = URI(full_url)
|
|
218
219
|
req = Net::HTTP::Get.new(uri)
|
|
219
220
|
req['Authorization'] = "Bearer #{token}"
|
|
220
|
-
|
|
221
|
+
req['Accept-Encoding'] = 'identity' # Disable chunked/gzip (rcurses raw mode breaks chunked reads)
|
|
222
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 60, open_timeout: 15) { |http| http.request(req) }
|
|
221
223
|
if res.is_a?(Net::HTTPSuccess)
|
|
222
224
|
JSON.parse(res.body)
|
|
223
225
|
else
|
|
@@ -225,6 +227,10 @@ module Timely
|
|
|
225
227
|
nil
|
|
226
228
|
end
|
|
227
229
|
rescue Timeout::Error, Net::OpenTimeout, SocketError, Errno::ECONNREFUSED => e
|
|
230
|
+
if retries > 0
|
|
231
|
+
sleep 1
|
|
232
|
+
retry if (retries -= 1) >= 0
|
|
233
|
+
end
|
|
228
234
|
@last_error = "Network error: #{e.message}"
|
|
229
235
|
nil
|
|
230
236
|
rescue => e
|
|
@@ -239,8 +245,9 @@ module Timely
|
|
|
239
245
|
req = Net::HTTP::Post.new(uri)
|
|
240
246
|
req['Authorization'] = "Bearer #{token}"
|
|
241
247
|
req['Content-Type'] = 'application/json'
|
|
248
|
+
req['Accept-Encoding'] = 'identity'
|
|
242
249
|
req.body = JSON.generate(body)
|
|
243
|
-
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout:
|
|
250
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 60, open_timeout: 15) { |http| http.request(req) }
|
|
244
251
|
res.is_a?(Net::HTTPSuccess) ? JSON.parse(res.body) : nil
|
|
245
252
|
rescue => e
|
|
246
253
|
nil
|
|
@@ -253,8 +260,9 @@ module Timely
|
|
|
253
260
|
req = Net::HTTP::Put.new(uri)
|
|
254
261
|
req['Authorization'] = "Bearer #{token}"
|
|
255
262
|
req['Content-Type'] = 'application/json'
|
|
263
|
+
req['Accept-Encoding'] = 'identity'
|
|
256
264
|
req.body = JSON.generate(body)
|
|
257
|
-
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout:
|
|
265
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 60, open_timeout: 15) { |http| http.request(req) }
|
|
258
266
|
res.is_a?(Net::HTTPSuccess) ? JSON.parse(res.body) : nil
|
|
259
267
|
rescue => e
|
|
260
268
|
nil
|
|
@@ -266,7 +274,7 @@ module Timely
|
|
|
266
274
|
uri = URI("#{API_BASE}#{path}")
|
|
267
275
|
req = Net::HTTP::Delete.new(uri)
|
|
268
276
|
req['Authorization'] = "Bearer #{token}"
|
|
269
|
-
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout:
|
|
277
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 60, open_timeout: 15) { |http| http.request(req) }
|
|
270
278
|
res.is_a?(Net::HTTPSuccess) || res.code == '204'
|
|
271
279
|
rescue => e
|
|
272
280
|
false
|
|
@@ -227,6 +227,7 @@ module Timely
|
|
|
227
227
|
uri = URI(full_url)
|
|
228
228
|
req = Net::HTTP::Get.new(uri)
|
|
229
229
|
req['Authorization'] = "Bearer #{token}"
|
|
230
|
+
req['Accept-Encoding'] = 'identity'
|
|
230
231
|
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 30, open_timeout: 10) { |http| http.request(req) }
|
|
231
232
|
if res.is_a?(Net::HTTPSuccess)
|
|
232
233
|
JSON.parse(res.body)
|
|
@@ -248,6 +249,7 @@ module Timely
|
|
|
248
249
|
uri = URI("#{GRAPH_BASE}#{path}")
|
|
249
250
|
req = Net::HTTP::Post.new(uri)
|
|
250
251
|
req['Authorization'] = "Bearer #{token}"
|
|
252
|
+
req['Accept-Encoding'] = 'identity'
|
|
251
253
|
req['Content-Type'] = 'application/json'
|
|
252
254
|
req.body = JSON.generate(body)
|
|
253
255
|
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 30, open_timeout: 10) { |http| http.request(req) }
|
|
@@ -262,6 +264,7 @@ module Timely
|
|
|
262
264
|
uri = URI("#{GRAPH_BASE}#{path}")
|
|
263
265
|
req = Net::HTTP::Patch.new(uri)
|
|
264
266
|
req['Authorization'] = "Bearer #{token}"
|
|
267
|
+
req['Accept-Encoding'] = 'identity'
|
|
265
268
|
req['Content-Type'] = 'application/json'
|
|
266
269
|
req.body = JSON.generate(body)
|
|
267
270
|
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 30, open_timeout: 10) { |http| http.request(req) }
|
|
@@ -276,6 +279,7 @@ module Timely
|
|
|
276
279
|
uri = URI("#{GRAPH_BASE}#{path}")
|
|
277
280
|
req = Net::HTTP::Delete.new(uri)
|
|
278
281
|
req['Authorization'] = "Bearer #{token}"
|
|
282
|
+
req['Accept-Encoding'] = 'identity'
|
|
279
283
|
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 30, open_timeout: 10) { |http| http.request(req) }
|
|
280
284
|
res.is_a?(Net::HTTPSuccess) || res.code == '204'
|
|
281
285
|
rescue => e
|
|
@@ -298,8 +298,23 @@ module Timely
|
|
|
298
298
|
|
|
299
299
|
def clean_description(desc)
|
|
300
300
|
return nil unless desc
|
|
301
|
+
desc = desc.to_s
|
|
302
|
+
# Convert HTML to plain text via w3m if it looks like HTML
|
|
303
|
+
if desc =~ /\A\s*<(!DOCTYPE|html|head|body|div|p\b)/i
|
|
304
|
+
begin
|
|
305
|
+
text = IO.popen(['w3m', '-T', 'text/html', '-dump', '-cols', '200'], 'r+') do |io|
|
|
306
|
+
io.write(desc)
|
|
307
|
+
io.close_write
|
|
308
|
+
io.read
|
|
309
|
+
end
|
|
310
|
+
desc = text if text && !text.strip.empty?
|
|
311
|
+
rescue Errno::ENOENT
|
|
312
|
+
# w3m not installed, strip tags manually
|
|
313
|
+
desc = desc.gsub(/<[^>]+>/, ' ').gsub(/ /i, ' ').gsub(/&/i, '&').gsub(/</i, '<').gsub(/>/i, '>')
|
|
314
|
+
end
|
|
315
|
+
end
|
|
301
316
|
# Remove common garbage from Google/Outlook descriptions
|
|
302
|
-
desc.gsub(/BC\d+-Color:\s*-?\d+\s*/, '').gsub(/-::~:~::~:~.*$/m, '').strip
|
|
317
|
+
desc.gsub(/BC\d+-Color:\s*-?\d+\s*/, '').gsub(/-::~:~::~:~.*$/m, '').gsub(/\s+/, ' ').strip
|
|
303
318
|
end
|
|
304
319
|
|
|
305
320
|
# Find the event at the currently selected time slot
|
data/lib/timely/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: timely-calendar
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Geir Isene
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-03-
|
|
12
|
+
date: 2026-03-24 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rcurses
|