readwise 0.4.0 → 0.5.0

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
  SHA256:
3
- metadata.gz: 766eb82d68f06591b6e05211877532619182404c3aa29c24720de5cd1788ad0a
4
- data.tar.gz: 70b4affa8b2e46271fb1d690e00328be10e1fcbb5fd6a3d5ae08135947818671
3
+ metadata.gz: 2132de7e8f9fdbc395fc94872968cee73d333c67723b2e81a7554b61105e1469
4
+ data.tar.gz: 4aca80570f7ea3d6d7045cfe0f3fe75c64d578e4ea2de05697d98e747215d74a
5
5
  SHA512:
6
- metadata.gz: f6b8cda492331d61352a83bc01732fee2d30191419b226327334daf4c00338afe6876bfb5b806318506bc42a5706f826225a2c917dcaf17a0172d9c12cc3cd08
7
- data.tar.gz: 7b2e849cc2bff772ebe84c7b93cb0b7bdf9c506c9bce80a79754554590a537717c39882f6b04faa8e43105b5eac20598fd89f1a39002746d8212557a4bdaf42d
6
+ metadata.gz: 35498d0c04b98eab247b3bf78bdf66dc51294f0538273c9515d8122b737c494421a4425f241d25577d77ec55a2ce01455e02fb91281a72769c753a7d74e9690c
7
+ data.tar.gz: 751bfaf4334fcf74cd6f16b685108a8df095a84366b91c76e1978447d839f28ff7234c136f933bd37eb18f7e1b0e437a40e84e7b17a4c5e3641a6d0995519268
data/.github/FUNDING.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  # These are supported funding model platforms
2
2
 
3
- github: andjosh
3
+ github: joshbeckman
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.5.0] - 2023-06-15
6
+ - Add methods to create/update highlights ([#8](https://github.com/joshbeckman/readwise-ruby/pull/12))
7
+ - Add methods to add/update/remove highlight tags
8
+ - Add method to get book
9
+
5
10
  ## [0.4.0] - 2023-03-19
6
11
 
7
12
  - Add `get_highlight` client method ([#10](https://github.com/andjosh/readwise-ruby/pull/10) from [@ajistrying](https://github.com/ajistrying))
data/README.md CHANGED
@@ -33,11 +33,30 @@ books = client.export(book_ids: ['123']) # export specific highlights
33
33
 
34
34
  puts books.first.title # books are Readwise::Book structs
35
35
  puts books.first.highlights.map(&:text) # highlights are Readwise::Highlight structs
36
+
37
+ # create a highlight
38
+ create = Readwise::HighlightCreate.new(text: 'foobar', author: 'Joan')
39
+ highlight = client.create_highlight(highlight: create)
40
+
41
+ # update a highlight
42
+ update = Readwise::HighlightUpdate.new(text: 'foobaz', color: 'yellow')
43
+ updated = client.update_highlight(highlight: highlight, update: update)
44
+
45
+ # add a tag to a highlight
46
+ tag = Readwise::Tag.new(name: 'foobar')
47
+ added_tag = client.add_highlight_tag(highlight: highlight, tag: tag)
48
+
49
+ # update a tag on a highlight
50
+ added_tag.name = 'bing'
51
+ updated_tag = client.update_highlight_tag(highlight: highlight, tag: added_tag)
52
+
53
+ # remove a tag from a highlight
54
+ client.remove_highlight_tag(highlight: highlight, tag: added_tag)
36
55
  ```
37
56
 
38
57
  ## Development
39
58
 
40
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
59
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
41
60
 
42
61
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
43
62
 
data/lib/readwise/book.rb CHANGED
@@ -10,6 +10,7 @@ module Readwise
10
10
  :cover_image_url,
11
11
  :highlights,
12
12
  :note,
13
+ :num_highlights,
13
14
  :readable_title,
14
15
  :readwise_url,
15
16
  :source,
@@ -12,25 +12,81 @@ module Readwise
12
12
 
13
13
  def initialize(token: nil)
14
14
  raise ArgumentError unless token
15
+
15
16
  @token = token.to_s
16
17
  end
17
18
 
18
19
  def create_highlight(highlight:)
19
- create_highlights([highlight])
20
+ create_highlights(highlights: [highlight]).first
20
21
  end
21
22
 
22
23
  def create_highlights(highlights: [])
23
- raise NotImplementedError
24
+ raise ArgumentError unless highlights.all? { |item| item.is_a?(Readwise::HighlightCreate) }
25
+ return [] unless highlights.any?
26
+
27
+ url = BASE_URL + 'highlights/'
28
+
29
+ payload = { highlights: highlights.map(&:serialize) }
30
+ res = post_readwise_request(url, payload: payload)
31
+
32
+ modified_ids = res.map { |book| book['modified_highlights'] }.flatten
33
+ modified_ids.map { |id| get_highlight(highlight_id: id) }
24
34
  end
25
35
 
26
36
  def get_highlight(highlight_id:)
27
- url = BASE_URL + 'highlights/' + highlight_id
37
+ url = BASE_URL + "highlights/#{highlight_id}"
28
38
 
29
39
  res = get_readwise_request(url)
30
40
 
31
41
  transform_highlight(res)
32
42
  end
33
43
 
44
+ def update_highlight(highlight:, update:)
45
+ raise ArgumentError unless update.is_a?(Readwise::HighlightUpdate)
46
+
47
+ url = BASE_URL + "highlights/#{highlight.highlight_id}"
48
+
49
+ res = patch_readwise_request(url, payload: update.serialize)
50
+
51
+ transform_highlight(res)
52
+ end
53
+
54
+ def remove_highlight_tag(highlight:, tag:)
55
+ url = BASE_URL + "highlights/#{highlight.highlight_id}/tags/#{tag.tag_id}"
56
+
57
+ delete_readwise_request(url)
58
+ end
59
+
60
+ def add_highlight_tag(highlight:, tag:)
61
+ raise ArgumentError unless tag.is_a?(Readwise::Tag)
62
+
63
+ url = BASE_URL + "highlights/#{highlight.highlight_id}/tags"
64
+
65
+ payload = tag.serialize.select { |k, v| k == :name }
66
+ res = post_readwise_request(url, payload: payload)
67
+
68
+ transform_tag(res)
69
+ end
70
+
71
+ def update_highlight_tag(highlight:, tag:)
72
+ raise ArgumentError unless tag.is_a?(Readwise::Tag)
73
+
74
+ url = BASE_URL + "highlights/#{highlight.highlight_id}/tags/#{tag.tag_id}"
75
+
76
+ payload = tag.serialize.select { |k, v| k == :name }
77
+ res = patch_readwise_request(url, payload: payload)
78
+
79
+ transform_tag(res)
80
+ end
81
+
82
+ def get_book(book_id:)
83
+ url = BASE_URL + "books/#{book_id}"
84
+
85
+ res = get_readwise_request(url)
86
+
87
+ transform_book(res)
88
+ end
89
+
34
90
  def export(updated_after: nil, book_ids: [])
35
91
  resp = export_page(updated_after: updated_after, book_ids: book_ids)
36
92
  next_page_cursor = resp[:next_page_cursor]
@@ -48,22 +104,7 @@ module Readwise
48
104
  def export_page(page_cursor: nil, updated_after: nil, book_ids: [])
49
105
  parsed_body = get_export_page(page_cursor: page_cursor, updated_after: updated_after, book_ids: book_ids)
50
106
  results = parsed_body.dig('results').map do |item|
51
- Book.new(
52
- asin: item['asin'],
53
- author: item['author'],
54
- book_id: item['user_book_id'].to_s,
55
- category: item['category'],
56
- cover_image_url: item['cover_image_url'],
57
- note: item['document_note'],
58
- readable_title: item['readable_title'],
59
- readwise_url: item['readwise_url'],
60
- source: item['source'],
61
- source_url: item['source_url'],
62
- tags: item['book_tags'].map { |tag| transform_tag(tag) },
63
- title: item['title'],
64
- unique_url: item['unique_url'],
65
- highlights: item['highlights'].map { |highlight| transform_highlight(highlight) },
66
- )
107
+ transform_book(item)
67
108
  end
68
109
  {
69
110
  results: results,
@@ -82,6 +123,27 @@ module Readwise
82
123
 
83
124
  end
84
125
 
126
+ def transform_book(res)
127
+ highlights = (res['highlights'] || []).map { |highlight| transform_highlight(highlight) }
128
+ Book.new(
129
+ asin: res['asin'],
130
+ author: res['author'],
131
+ book_id: res['user_book_id'].to_s,
132
+ category: res['category'],
133
+ cover_image_url: res['cover_image_url'],
134
+ note: res['document_note'],
135
+ readable_title: res['readable_title'],
136
+ readwise_url: res['readwise_url'] || res['highlights_url'],
137
+ source: res['source'],
138
+ source_url: res['source_url'],
139
+ tags: (res['book_tags'] || res['tags'] || []).map { |tag| transform_tag(tag) },
140
+ title: res['title'],
141
+ unique_url: res['unique_url'],
142
+ highlights: highlights,
143
+ num_highlights: res['num_highlights'] || highlights.size,
144
+ )
145
+ end
146
+
85
147
  def transform_highlight(res)
86
148
  Highlight.new(
87
149
  book_id: res['book_id'].to_s,
@@ -118,10 +180,51 @@ module Readwise
118
180
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
119
181
  http.request(req)
120
182
  end
121
-
122
- raise Error, 'Export request failed' unless res.is_a?(Net::HTTPSuccess)
123
-
183
+
184
+ raise Error, 'Get request failed' unless res.is_a?(Net::HTTPSuccess)
185
+
186
+ JSON.parse(res.body)
187
+ end
188
+
189
+ def patch_readwise_request(url, payload:)
190
+ uri = URI.parse(url)
191
+ req = Net::HTTP::Patch.new(uri)
192
+ req['Authorization'] = "Token #{@token}"
193
+ req['Content-Type'] = 'application/json'
194
+ req.body = payload.to_json
195
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
196
+ http.request(req)
197
+ end
198
+
199
+ raise Error, 'Patch request failed' unless res.is_a?(Net::HTTPSuccess)
200
+
201
+ JSON.parse(res.body)
202
+ end
203
+
204
+ def post_readwise_request(url, payload:)
205
+ uri = URI.parse(url)
206
+ req = Net::HTTP::Post.new(uri)
207
+ req['Authorization'] = "Token #{@token}"
208
+ req['Content-Type'] = 'application/json'
209
+ req.body = payload.to_json
210
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
211
+ http.request(req)
212
+ end
213
+
214
+ raise Error, 'Post request failed' unless res.is_a?(Net::HTTPSuccess)
215
+
124
216
  JSON.parse(res.body)
125
217
  end
218
+
219
+ def delete_readwise_request(url)
220
+ uri = URI.parse(url)
221
+ req = Net::HTTP::Delete.new(uri)
222
+ req['Authorization'] = "Token #{@token}"
223
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
224
+ http.request(req)
225
+ end
226
+
227
+ raise Error, 'Delete request failed' unless res.is_a?(Net::HTTPSuccess)
228
+ end
126
229
  end
127
230
  end
@@ -39,5 +39,45 @@ module Readwise
39
39
 
40
40
  Time.parse(highlighted_at)
41
41
  end
42
+
43
+ def serialize
44
+ to_h
45
+ end
46
+ end
47
+
48
+ HighlightCreate = Struct.new(
49
+ 'ReadwiseHighlightCreate',
50
+ :author,
51
+ :category, # One of: books, articles, tweets or podcasts.
52
+ # (default: articles when source_url is provided, otherwise: books)
53
+ :highlight_url,
54
+ :highlighted_at,
55
+ :image_url,
56
+ :location,
57
+ :location_type, # One of: page, order or time_offset (default: order)
58
+ :note,
59
+ :source_type,
60
+ :source_url,
61
+ :text,
62
+ :title,
63
+ keyword_init: true
64
+ ) do
65
+ def serialize
66
+ to_h.compact
67
+ end
68
+ end
69
+
70
+ HighlightUpdate = Struct.new(
71
+ 'ReadwiseHighlightUpdate',
72
+ :color,
73
+ :location,
74
+ :note,
75
+ :text,
76
+ :url,
77
+ keyword_init: true
78
+ ) do
79
+ def serialize
80
+ to_h.compact
81
+ end
42
82
  end
43
83
  end
data/lib/readwise/tag.rb CHANGED
@@ -4,5 +4,9 @@ module Readwise
4
4
  :tag_id,
5
5
  :name,
6
6
  keyword_init: true
7
- )
7
+ ) do
8
+ def serialize
9
+ to_h
10
+ end
11
+ end
8
12
  end
@@ -1,3 +1,3 @@
1
1
  module Readwise
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readwise
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Beckman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-03-19 00:00:00.000000000 Z
11
+ date: 2023-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
114
  - !ruby/object:Gem::Version
115
115
  version: '0'
116
116
  requirements: []
117
- rubygems_version: 3.4.7
117
+ rubygems_version: 3.4.14
118
118
  signing_key:
119
119
  specification_version: 4
120
120
  summary: Readwise API client