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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6828a89cb80defec08b9eadaa1e03cf98e45e90d01efe6770423be86f14d8692
4
- data.tar.gz: c0857481b8a83267cd5289111e333a07d62c5cebf59a7d509e4a0ddceac80346
3
+ metadata.gz: db1c94b2b016e7ce47aaa79da922a03e65956b992251ab0b263f8d2f36cf965e
4
+ data.tar.gz: 5d620757c14c5ffeca1a9e9b1fba5686357cf3ad573780dfa091e2a62f45450a
5
5
  SHA512:
6
- metadata.gz: c62100cb41044387038866e90e8061061be47c1c3e79c77771d60880133ea63312f325cc66084dddb905594f6951535b9cef98383e10386882836a63ff68a76e
7
- data.tar.gz: ce4f9e135b9c64afe3c6a195a8da0f2f3dd688a523051e31dd42af0764181f17710504d805ead890271b44c9660227cab6fe1986c98535fabcf0d4d879fcfc40
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
- uri = URI("#{API_BASE}#{path}")
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
- res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 30, open_timeout: 10) { |http| http.request(req) }
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: 30, open_timeout: 10) { |http| http.request(req) }
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: 30, open_timeout: 10) { |http| http.request(req) }
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: 30, open_timeout: 10) { |http| http.request(req) }
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(/&nbsp;/i, ' ').gsub(/&amp;/i, '&').gsub(/&lt;/i, '<').gsub(/&gt;/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
@@ -1,3 +1,3 @@
1
1
  module Timely
2
- VERSION = '1.0.0'
2
+ VERSION = '1.0.1'
3
3
  end
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.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-23 00:00:00.000000000 Z
12
+ date: 2026-03-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rcurses