kindle-notebook 0.2.1 → 0.3.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
  SHA256:
3
- metadata.gz: bec53d52818fd1e01eb99bba9b302edf0cf2b9b688f64224f1d624ac785f86ff
4
- data.tar.gz: 7dcc6e513cb7c1f62abee9607f34fbfd488d6925458fe7c051e67abfd4604bfd
3
+ metadata.gz: fdf9f8aae86d86694218ea71a942afad7dc5867970b79671f0dede3372bdb5ee
4
+ data.tar.gz: 6a132ae2b4b7291693c0e72992cb02b59248a908fdb0ded0fd220a6c20de2646
5
5
  SHA512:
6
- metadata.gz: 69f552342621a69d601ddea394b2c7ab3c85934d92d363b5c8fbeac9d7c6dbf008afa68d249892d17b32e8542ab7d5100c6efcfdd132fd0444941e550844abe5
7
- data.tar.gz: 7c525530ddfefea76be5b3c88bcce5a936858e80b118c7d9d92a22429b9cc4aac45b371791c9df16327f47be7d75d31c50c238c7e39f8d450094dd0f9fc9fa8f
6
+ metadata.gz: ab04dbcf4e7e721f8bd5f2f85b879998ca6f235b8485e55b82d3ab07a8273bf90740f14f9d40a6c064c2ecab136e64a5294138e0d54c6411633390456db69ae4
7
+ data.tar.gz: 15b4d1b7ab4d83bcb98d7b092734ae3d617ae7b4da6c9b3d08c32c2caadd79fadd10768d5334cbb29fd6e0b4794ee14d38b3dcfff3fd0bb85b4832b0621e523f
data/.rubocop.yml CHANGED
@@ -9,6 +9,15 @@ Naming/FileName:
9
9
  Exclude:
10
10
  - lib/kindle-notebook.rb
11
11
 
12
+ RSpec/ExampleLength:
13
+ Max: 7
14
+
15
+ RSpec/MultipleExpectations:
16
+ Max: 7
17
+
18
+ RSpec/MultipleMemoizedHelpers:
19
+ Max: 7
20
+
12
21
  Style/Documentation:
13
22
  Enabled: false
14
23
 
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in kindle-notebook.gemspec
6
6
  gemspec
7
7
 
8
+ gem "puffing-billy", "~> 3.1"
8
9
  gem "rake", "~> 13.0"
9
10
  gem "rspec", "~> 3.0"
10
11
  gem "rubocop", "~> 1.21"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kindle-notebook (0.2.1)
4
+ kindle-notebook (0.3.1)
5
5
  capybara (~> 3.39)
6
6
  capybara-sessionkeeper (~> 0.2.0)
7
7
  selenium-webdriver (~> 4.9)
@@ -25,12 +25,27 @@ GEM
25
25
  capybara
26
26
  selenium-webdriver
27
27
  coderay (1.1.3)
28
+ cookiejar (0.3.3)
28
29
  diff-lcs (1.5.0)
29
30
  dotenv (2.8.1)
31
+ em-http-request (1.1.7)
32
+ addressable (>= 2.3.4)
33
+ cookiejar (!= 0.3.1)
34
+ em-socksify (>= 0.3)
35
+ eventmachine (>= 1.0.3)
36
+ http_parser.rb (>= 0.6.0)
37
+ em-socksify (0.3.2)
38
+ eventmachine (>= 1.0.0.beta.4)
39
+ em-synchrony (1.0.6)
40
+ eventmachine (>= 1.0.0.beta.1)
41
+ eventmachine (1.2.7)
42
+ eventmachine_httpserver (0.2.1)
43
+ http_parser.rb (0.6.0)
30
44
  json (2.6.3)
31
45
  matrix (0.4.2)
32
46
  method_source (1.0.0)
33
47
  mini_mime (1.1.2)
48
+ multi_json (1.15.0)
34
49
  nokogiri (1.14.3-x86_64-linux)
35
50
  racc (~> 1.4)
36
51
  parallel (1.22.1)
@@ -40,6 +55,14 @@ GEM
40
55
  coderay (~> 1.1)
41
56
  method_source (~> 1.0)
42
57
  public_suffix (5.0.1)
58
+ puffing-billy (3.1.0)
59
+ addressable (~> 2.5)
60
+ em-http-request (~> 1.1, >= 1.1.0)
61
+ em-synchrony
62
+ eventmachine (~> 1.2)
63
+ eventmachine_httpserver
64
+ http_parser.rb (~> 0.6.0)
65
+ multi_json
43
66
  racc (1.6.2)
44
67
  rack (3.0.7)
45
68
  rack-test (2.1.0)
@@ -98,6 +121,7 @@ DEPENDENCIES
98
121
  dotenv (~> 2.8, >= 2.8.1)
99
122
  kindle-notebook!
100
123
  pry (~> 0.14.2)
124
+ puffing-billy (~> 3.1)
101
125
  rake (~> 13.0)
102
126
  rspec (~> 3.0)
103
127
  rubocop (~> 1.21)
data/README.md CHANGED
@@ -18,12 +18,37 @@ If bundler is not being used to manage dependencies, install the gem by executin
18
18
  $ gem install kindle-notebook
19
19
  ```
20
20
 
21
+ ## Configuration
22
+
23
+ You can either create a `.env` file and add your credentials, the default values will be fetched from this file, or configure the gem, for example in an initializer file.
24
+
25
+ ```rb
26
+ KindleNotebook.configure do |config|
27
+ config.url = "https://read.amazon.com/"
28
+ config.login = ENV["AMAZON_EMAIL"]
29
+ config.password = ENV["AMAZON_PASSWORD"]
30
+ config.selenium_driver = :firefox
31
+ config.headless_mode = false
32
+ config.min_highlight_words = 1
33
+ config.max_highlight_words = 3
34
+ end
35
+ ```
36
+
37
+ The configuration options `min_highlight_words` and `max_highlight_words` determine the range for a highlight's word count. Highlights with a word count outside this range will not be considered will be filtered out.
38
+
21
39
  ## Usage
22
40
 
23
- To get the highlights from a book:
41
+ Sign in:
24
42
  ```rb
25
- books = KindleNotebook::Client.books
26
- book = books.first.fetch_highlights
43
+ client = KindleNotebook::Client.new
44
+ client.sign_in
45
+ ```
46
+
47
+ Get the highlights from a book:
48
+ ```rb
49
+ books = client.books
50
+ book = books.first
51
+ book.fetch_highlights
27
52
  book.highlights
28
53
  ```
29
54
 
@@ -59,7 +84,7 @@ Highlight:
59
84
  Book CSV:
60
85
  ```csv
61
86
  text,page,context,book_asin,raw_text,raw_context
62
- journald,120,,B09FJ3411G,"journald,",
87
+ journald,120,"If you get stuck, the logging component of systemd, called journald, can also help.",B09FJ3411G,"journald,","used, for example. If you get stuck, the logging component of systemd, called journald, can also help. This journald command displays the last 20 entries in the"
63
88
  swarm,225,"Docker Swarm In this chapter, you're going to learn how to create and use a Docker",B09FJ3411G,swarm.,"Docker Swarm In this chapter, you're going to learn how to create and use a Docker"
64
89
  ```
65
90
 
@@ -69,6 +94,19 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
69
94
 
70
95
  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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
71
96
 
97
+ ### Testing
98
+
99
+ This gem is using [puffing-billy](https://github.com/oesmith/puffing-billy) for testing which needs the geckodriver executable. It can be installed with:
100
+ ```sh
101
+ $ sudo apt-get install firefox-geckodriver # or
102
+ $ brew install geckodriver
103
+ ```
104
+
105
+ The executable should be in your `PATH`, if it is not you can run the following command (please adapt the location of the geckodriver executable with yours):
106
+ ```sh
107
+ $ echo 'export PATH=$PATH:/home/user/.cache/selenium/geckodriver/linux64/0.33.0' >> ~/.zshrc
108
+ ```
109
+
72
110
  ## Contributing
73
111
 
74
112
  Bug reports and pull requests are welcome on GitHub at https://github.com/b1anca/kindle-notebook. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/b1anca/kindle-notebook/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/kindle_notebook/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "kindle-notebook"
7
+ spec.version = KindleNotebook::VERSION
8
+ spec.authors = ["Bianca Vieira"]
9
+ spec.email = ["bncvr@outlook.com"]
10
+
11
+ spec.summary = "Kindle Notebook"
12
+ spec.description = "Fetch your Kindle Highlights along with their context using the Selenium Webdriver"
13
+ spec.homepage = "https://github.com/b1anca/kindle-notebook"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/b1anca/kindle-notebook"
21
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
28
+ end
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ spec.add_dependency "capybara", "~> 3.39"
36
+ spec.add_dependency "capybara-sessionkeeper", "~> 0.2.0"
37
+ spec.add_dependency "selenium-webdriver", "~> 4.9"
38
+
39
+ spec.add_development_dependency "dotenv", "~> 2.8", ">= 2.8.1"
40
+ spec.add_development_dependency "pry", "~> 0.14.2"
41
+
42
+ # For more information and examples about making a new gem, check out our
43
+ # guide at: https://bundler.io/guides/creating_gem.html
44
+ end
@@ -4,6 +4,7 @@ require "capybara"
4
4
  require "capybara/sessionkeeper"
5
5
  require "csv"
6
6
  require "selenium-webdriver"
7
+ require "dotenv"
7
8
 
8
9
  require_relative "kindle_notebook/amazon_auth"
9
10
  require_relative "kindle_notebook/book"
@@ -14,35 +15,36 @@ require_relative "kindle_notebook/highlights"
14
15
  require_relative "kindle_notebook/highlight"
15
16
  require_relative "kindle_notebook/version"
16
17
 
18
+ Dotenv.load
19
+
17
20
  module KindleNotebook
18
21
  class Error < StandardError; end
19
22
 
20
- Capybara.register_driver :chrome do |app|
21
- options = Selenium::WebDriver::Chrome::Options.new
22
- options.add_argument("--headless") if configuration.headless_mode
23
- options.add_argument("--disable-gpu")
24
- options.add_argument("--no-sandbox")
25
-
26
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
27
- end
28
-
29
- Capybara.register_driver :firefox do |app|
30
- options = Selenium::WebDriver::Firefox::Options.new
31
- options.add_argument("--headless") if configuration.headless_mode
32
-
33
- Capybara::Selenium::Driver.new(app, browser: :firefox, options: options)
23
+ class Configuration
24
+ attr_accessor :url, :login, :password, :selenium_driver, :headless_mode, :min_highlight_words,
25
+ :max_highlight_words
26
+
27
+ def initialize
28
+ @url = ENV["KINDLE_READER_URL"]
29
+ @login = ENV["AMAZON_EMAIL"]
30
+ @password = ENV["AMAZON_PASSWORD"]
31
+ @selenium_driver = ENV["SELENIUM_DRIVER"]
32
+ @headless_mode = ENV["HEADLESS_MODE"] == "true"
33
+ @min_highlight_words = ENV["MIN_HIGHLIGHT_WORDS"].to_i
34
+ @max_highlight_words = ENV["MAX_HIGHLIGHT_WORDS"].to_i
35
+ end
34
36
  end
35
37
 
36
38
  class << self
37
- attr_accessor :configuration
39
+ attr_writer :configuration
40
+ attr_accessor :session
41
+ end
38
42
 
39
- def configure
40
- self.configuration ||= Configuration.new
41
- yield(configuration)
42
- end
43
+ def self.configuration
44
+ @configuration ||= KindleNotebook::Configuration.new
45
+ end
43
46
 
44
- def session
45
- @session ||= AmazonAuth.new.sign_in
46
- end
47
+ def self.configure
48
+ yield(configuration)
47
49
  end
48
50
  end
@@ -2,52 +2,69 @@
2
2
 
3
3
  module KindleNotebook
4
4
  class AmazonAuth
5
- def initialize
6
- @auth_session = Capybara::Session.new(KindleNotebook.configuration.selenium_driver.to_sym)
5
+ def initialize(email:, password:)
6
+ @email = email
7
+ @password = password
7
8
  end
8
9
 
9
10
  def sign_in
10
- auth_session.visit(KindleNotebook.configuration.url)
11
- return auth_session if valid_cookies?
11
+ session.visit(KindleNotebook.configuration.url)
12
+ if valid_cookies?
13
+ puts "Session restored!"
14
+ return session
15
+ end
12
16
 
13
17
  submit_sign_in_form
14
- auth_session.save_cookies
15
- auth_session
18
+ submit_otp_form if mfa?
19
+ session.save_cookies
20
+ puts "You're signed in!"
16
21
  end
17
22
 
18
23
  private
19
24
 
20
- attr_reader :auth_session
25
+ attr_reader :email, :password
26
+
27
+ def session
28
+ KindleNotebook.session
29
+ end
21
30
 
22
31
  def valid_cookies?
23
- auth_session.find_latest_cookie_file
24
- auth_session.restore_cookies
25
- auth_session.refresh
26
- auth_session.has_current_path?("/kindle-library")
32
+ session.find_latest_cookie_file
33
+ session.restore_cookies
34
+ session.refresh
35
+ session.has_current_path?("/kindle-library")
27
36
  end
28
37
 
29
38
  def submit_otp_form
30
39
  print "Enter OTP: "
31
- mfa_code = gets.chomp
32
- auth_session.fill_in("auth-mfa-otpcode", with: mfa_code)
33
- auth_session.first("#auth-signin-button").click
40
+ otp = gets.chomp
41
+ session.fill_in("auth-mfa-otpcode", with: otp)
42
+ session.first("#auth-signin-button").click
43
+ check_errors
34
44
  end
35
45
 
36
46
  def submit_sign_in_form
37
- auth_session.click_button("Sign in with your account", match: :first)
47
+ session.click_button("Sign in with your account", match: :first)
38
48
  fill_in_credentials
39
- auth_session.check("rememberMe")
40
- auth_session.first("#signInSubmit").click
41
- submit_otp_form if mfa?
49
+ session.check("rememberMe")
50
+ session.first("#signInSubmit").click
51
+ check_errors
42
52
  end
43
53
 
44
54
  def fill_in_credentials
45
- auth_session.fill_in("ap_email", with: KindleNotebook.configuration.login)
46
- auth_session.fill_in("ap_password", with: KindleNotebook.configuration.password)
55
+ session.fill_in("ap_email", with: email)
56
+ session.fill_in("ap_password", with: password)
47
57
  end
48
58
 
49
59
  def mfa?
50
- auth_session.current_path.match?(%r{ap/mfa})
60
+ session.current_path.match?(%r{ap/mfa})
61
+ end
62
+
63
+ def check_errors
64
+ return unless session.all("h4", text: "There was a problem").any?
65
+
66
+ message = session.all("div", class: "a-alert-content").map(&:text).join(", ") || "There was a problem"
67
+ raise StandardError, message
51
68
  end
52
69
  end
53
70
  end
@@ -31,8 +31,7 @@ module KindleNotebook
31
31
 
32
32
  def open_book
33
33
  session.visit(KindleNotebook.configuration.url) unless session.has_selector?("p", text: title)
34
- session.find("p", text: title).click
35
- sleep 3 # book might take a bit to load
34
+ session.find("p", text: title, wait: 3).click
36
35
  end
37
36
  end
38
37
  end
@@ -1,20 +1,64 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KindleNotebook
4
- module Client
5
- class << self
6
- def books
7
- @books ||= fetch_books
4
+ class Client
5
+ attr_reader :session
6
+
7
+ def initialize(email: KindleNotebook.configuration.login,
8
+ password: KindleNotebook.configuration.password,
9
+ headless_mode: KindleNotebook.configuration.headless_mode,
10
+ selenium_driver: KindleNotebook.configuration.selenium_driver)
11
+ @email = email
12
+ @password = password
13
+ @headless_mode = headless_mode
14
+ @selenium_driver = selenium_driver.to_sym
15
+ @session = new_capybara_session
16
+ end
17
+
18
+ def books
19
+ @books ||= fetch_books
20
+ end
21
+
22
+ def sign_in
23
+ AmazonAuth.new(password: password, email: email).sign_in
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :email, :password, :headless_mode, :selenium_driver
29
+
30
+ def fetch_books
31
+ session.find("ul#cover").all("li").map do |element|
32
+ Book.new(author: element.find("div", id: /author-/).text,
33
+ title: element.find("div", id: /title-/).text,
34
+ asin: element.find("div", match: :first)["data-asin"])
8
35
  end
36
+ end
37
+
38
+ def new_capybara_session
39
+ chrome_driver
40
+ firefox_driver
41
+
42
+ KindleNotebook.session = Capybara::Session.new(selenium_driver)
43
+ end
44
+
45
+ def firefox_driver
46
+ Capybara.register_driver :firefox do |app|
47
+ options = Selenium::WebDriver::Firefox::Options.new
48
+ options.add_argument("--headless") if headless_mode
49
+
50
+ Capybara::Selenium::Driver.new(app, browser: :firefox, options: options)
51
+ end
52
+ end
9
53
 
10
- private
54
+ def chrome_driver
55
+ Capybara.register_driver :chrome do |app|
56
+ options = Selenium::WebDriver::Chrome::Options.new
57
+ options.add_argument("--headless") if headless_mode
58
+ options.add_argument("--disable-gpu")
59
+ options.add_argument("--no-sandbox")
11
60
 
12
- def fetch_books
13
- KindleNotebook.session.find("ul#cover").all("li").map do |element|
14
- Book.new(author: element.find("div", id: /author-/).text,
15
- title: element.find("div", id: /title-/).text,
16
- asin: element.find("div", match: :first)["data-asin"])
17
- end
61
+ Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
18
62
  end
19
63
  end
20
64
  end
@@ -29,7 +29,8 @@ module KindleNotebook
29
29
 
30
30
  # fetch all highlights (without context) from notebook
31
31
  def notebook_highlights
32
- content = session.find("div", class: "notebook-content").all("ion-item")
32
+ notebook_content = session.all("div", class: "notebook-content")
33
+ content = notebook_content.any? ? notebook_content.first.all("ion-item") : []
33
34
  puts "#{content.count} highlights in this book \n"
34
35
  book.highlights_count = content.count
35
36
  content.map { |h| parse_notebook_highlight(h) }
@@ -82,7 +83,7 @@ module KindleNotebook
82
83
  end
83
84
 
84
85
  def show_toolbar
85
- session.first(:xpath, "//ion-header", wait: 2).hover
86
+ session.first(:xpath, "//ion-header", wait: 3).hover
86
87
  end
87
88
 
88
89
  def search_highlight_context(text, page)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KindleNotebook
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kindle-notebook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bianca Vieira
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-06 00:00:00.000000000 Z
11
+ date: 2023-07-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -103,8 +103,7 @@ files:
103
103
  - LICENSE.txt
104
104
  - README.md
105
105
  - Rakefile
106
- - kindle_notebook-0.2.0.gem
107
- - kindle_notebook-0.2.1.gem
106
+ - kindle-notebook.gemspec
108
107
  - lib/kindle-notebook.rb
109
108
  - lib/kindle_notebook/amazon_auth.rb
110
109
  - lib/kindle_notebook/book.rb
Binary file
Binary file