joplin 0.5.2 → 1.0.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: 25c5fb1c89e4e91404ff3551eab854d7d60d1233dae32089419fadca850c0fc6
4
- data.tar.gz: 1b682ba27da2ef362b92f2d0810e3fedff7e18480f03d82810201bf4e787777e
3
+ metadata.gz: 709555c1917e195e956c526a75979ea74deb8f3da829afe0f6d34ab7d074fad5
4
+ data.tar.gz: a09ac659f62def224a04adf7766d90231d8034335190dc99402d7b3715a763f3
5
5
  SHA512:
6
- metadata.gz: 349baaaacee32d7adb003a921b33a002a3e400980eca1778353777ffa6d2a7c5bb42d05d76b0b5dd9d41a38bab66cc16044cebf64da158784814aa7324c0b3e1
7
- data.tar.gz: 95c59bca854fd21545bab1d3473afe1cb253c2a7d9a7e55463d3091ddc2514dec316e08fb3b9c8c9535652585e85f0eaa99b525614c14e5520783b3d7b146833
6
+ metadata.gz: a53a2aae8f8a7c073cbef92668097171a5038357ad8c16c045e01b4336b16b4369abef498ecb0961dfa14b8592be1b34c0998a4da37e3470e602e314d7f01f91
7
+ data.tar.gz: 50f3207ad27c7eaa968fa031b4bd3b052c8d58014701f2d64166b8594a753fa9422e03e7ecedb758bdce9f9e11a188e19e8a2046ee493ec0f57e08ee79618bc3
data/Gemfile CHANGED
@@ -4,9 +4,3 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in joplin.gemspec
6
6
  gemspec
7
-
8
- gem "faraday", "~> 1.0"
9
-
10
- gem "thor", "~> 1.0"
11
-
12
- gem "sqlite3", "~> 1.4"
data/Gemfile.lock CHANGED
@@ -1,44 +1,63 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- joplin (0.5.2)
5
- faraday (~> 1.0)
4
+ joplin (1.0.1)
5
+ http (~> 5.1.1)
6
+ sqlite3 (~> 1.6.3)
7
+ thor (~> 1.2.2)
6
8
 
7
9
  GEM
8
10
  remote: https://rubygems.org/
9
11
  specs:
12
+ addressable (2.8.4)
13
+ public_suffix (>= 2.0.2, < 6.0)
10
14
  diff-lcs (1.5.0)
11
- faraday (1.0.1)
12
- multipart-post (>= 1.2, < 3)
13
- multipart-post (2.1.1)
15
+ domain_name (0.5.20190701)
16
+ unf (>= 0.0.5, < 1.0.0)
17
+ ffi (1.15.5)
18
+ ffi-compiler (1.0.1)
19
+ ffi (>= 1.0.0)
20
+ rake
21
+ http (5.1.1)
22
+ addressable (~> 2.8)
23
+ http-cookie (~> 1.0)
24
+ http-form_data (~> 2.2)
25
+ llhttp-ffi (~> 0.4.0)
26
+ http-cookie (1.0.5)
27
+ domain_name (~> 0.5)
28
+ http-form_data (2.3.0)
29
+ llhttp-ffi (0.4.0)
30
+ ffi-compiler (~> 1.0)
31
+ rake (~> 13.0)
32
+ public_suffix (5.0.1)
14
33
  rake (13.0.6)
15
- rspec (3.11.0)
16
- rspec-core (~> 3.11.0)
17
- rspec-expectations (~> 3.11.0)
18
- rspec-mocks (~> 3.11.0)
19
- rspec-core (3.11.0)
20
- rspec-support (~> 3.11.0)
21
- rspec-expectations (3.11.0)
34
+ rspec (3.12.0)
35
+ rspec-core (~> 3.12.0)
36
+ rspec-expectations (~> 3.12.0)
37
+ rspec-mocks (~> 3.12.0)
38
+ rspec-core (3.12.2)
39
+ rspec-support (~> 3.12.0)
40
+ rspec-expectations (3.12.3)
22
41
  diff-lcs (>= 1.2.0, < 2.0)
23
- rspec-support (~> 3.11.0)
24
- rspec-mocks (3.11.0)
42
+ rspec-support (~> 3.12.0)
43
+ rspec-mocks (3.12.5)
25
44
  diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.11.0)
27
- rspec-support (3.11.0)
28
- sqlite3 (1.4.2)
29
- thor (1.2.1)
45
+ rspec-support (~> 3.12.0)
46
+ rspec-support (3.12.1)
47
+ sqlite3 (1.6.3-arm64-darwin)
48
+ thor (1.2.2)
49
+ unf (0.1.4)
50
+ unf_ext
51
+ unf_ext (0.0.8.2)
30
52
 
31
53
  PLATFORMS
32
- ruby
54
+ arm64-darwin-22
33
55
 
34
56
  DEPENDENCIES
35
57
  bundler (~> 2.0)
36
- faraday (~> 1.0)
37
58
  joplin!
38
59
  rake (~> 13.0)
39
- rspec (~> 3.0)
40
- sqlite3 (~> 1.4)
41
- thor (~> 1.0)
60
+ rspec (~> 3.12.0)
42
61
 
43
62
  BUNDLED WITH
44
- 2.0.1
63
+ 2.4.10
data/Makefile CHANGED
@@ -1,14 +1,14 @@
1
- all:
1
+ test:
2
+ rake spec
3
+
4
+ build:
2
5
  gem build joplin.gemspec
3
6
 
4
- push: clean all
7
+ push: clean build
5
8
  gem push *gem
6
9
 
7
10
  clean:
8
11
  rm -f *gem
9
12
 
10
- test:
11
- rake
12
-
13
- install: clean all
13
+ install: clean build
14
14
  gem install --local *gem
data/bin/joplin CHANGED
@@ -1,96 +1,156 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $:.unshift File.expand_path("../../lib", __FILE__)
3
+ $:.unshift File.expand_path('../lib', __dir__)
4
4
 
5
- require "joplin"
5
+ require 'joplin'
6
6
  require 'thor'
7
+ require 'yaml'
7
8
 
8
- DIVIDER = %Q(
9
+ DIVIDER = %(
9
10
 
10
11
  <svg height="50" width="460">
11
12
  <style> .line { stroke-width: 1px; fill: black; stroke: black; } </style>
12
13
  <g id="triangle"><path d="M0 30 L200 30 Q 220 25 200 35 Z" class="line" /></g>
13
- <use xlink:href="#triangle" transform="scale(-1 1) translate(-450 0)"/>
14
+ <use href="#triangle" transform="scale(-1 1) translate(-450 0)"/>
14
15
  <circle cx="225" cy="32" r="7" class="line"/>
15
16
  </svg>
16
17
 
17
18
  )
18
19
 
19
-
20
20
  class MyCLI < Thor
21
- class_option :token, :type => :string #, required: true
22
- class_option :help, :type => :boolean
23
- class_option :version, :type => :boolean
24
- map ["-v", "--version"] => :version
25
- map ["-h", "--help"] => :help
21
+ class_option :token, type: :string # , required: true
22
+ class_option :help, type: :boolean
23
+ class_option :version, type: :boolean
24
+ map ['-v', '--version'] => :version
25
+ map ['-h', '--help'] => :help
26
26
  option :token
27
- option :'dry-run', desc: "dry-run", aliases: '-n'
28
- desc :clean, "clean unused resources"
27
+ option :'dry-run', desc: 'dry-run', aliases: '-n'
28
+ desc :clean, 'clean unused resources'
29
29
  def clean
30
- Joplin::token = Joplinl.get_token || options[:token]
31
- puts "Please wait, this can take while."
32
- Joplin::Resource.orphaned.map { |r|
33
- r.delete if not options['dry-run']
34
- would = "would have " if options['dry-run']
30
+ Joplin.token = Joplinl.get_token || options[:token]
31
+ puts 'Please wait, this can take while.'
32
+ Joplin::Resource.orphaned.map do |r|
33
+ r.delete unless options['dry-run']
34
+ would = 'would have ' if options['dry-run']
35
35
  puts "#{would}deleted #{r.id}"
36
- }
36
+ end
37
37
  end
38
38
 
39
- method_options :force => :boolean
40
- desc "version", "get version of program"
39
+ method_options force: :boolean
40
+ desc 'version', 'get version of program'
41
41
  def version
42
42
  puts Joplin::VERSION
43
43
  end
44
44
 
45
- desc :nb2n, "concate all notes in a notebook to one note. Possible PDF export"
46
- long_desc "The idea is to make a big note from all the notes in a notebook. PDF export or whatever export can happen from that. The notes are concatenated with a separator."
45
+ desc 'write', 'write a note'
46
+ long_desc 'This will write a note in the format of "note title/note title.md and put all resources under the folder'
47
+ def write(id)
48
+ note = Joplin::Note.new(id:)
49
+ note.write
50
+ end
51
+
52
+ desc :nb2n, 'concate all notes in a notebook to one note. Possible PDF export'
53
+ long_desc 'The idea is to make a big note from all the notes in a notebook. PDF export or whatever export can happen from that. The notes are concatenated with a separator.'
47
54
  option :token
48
- option :type, :type => :string
55
+ option :type, type: :string
49
56
  def nb2n(query)
50
- Joplin::token = options[:token] || Joplin::Token.get
57
+ Joplin.token = options[:token] || Joplin::Token.get
51
58
  results = Joplin.search(query, { type: 'folder' })
52
- nb = results[0];
53
- if not (nb and nb['title'] == query)
54
- abort "notebook #{query} not found"
55
- end
59
+ nb = results[0]
60
+ abort "notebook #{query} not found" unless nb and nb['title'] == query
56
61
 
57
62
  notebook = Joplin::Notebook.new nb['id']
58
63
  notes = notebook.notes
59
64
  new_note = Joplin::Note.new
60
65
  new_note.title = query
61
- new_note.body = notes.map { |n| "\# #{n.title}\n\n#{n.body}" }.join(DIVIDER)
66
+ new_note.body = notes.map { |n| "\# #{n.title}\n\n#{n.body}" }.join
62
67
  new_note.save!
63
68
  puts "Saved: #{new_note.title} with id: #{new_note.id}"
64
69
  end
65
70
 
66
- desc :build, "build a note from a note containing references"
71
+ desc :epub,
72
+ 'build a note from a note (help build), write the note, and create an epub from the result. needs pandoc installed'
73
+
74
+ long_desc <<-DESC
75
+ If the building note has a yaml descriptor https://pandoc.org/MANUAL.html#epubs
76
+ then the epub will end up having the meta data.
77
+
78
+ Below is an example note. The for the referenced note are a result from using Joplin's webclipper on https://fiachetti.gitlab.io/mastering-roda/
79
+
80
+ ---\n
81
+ title: Mastering Roda\n
82
+ author: Federico Iachetti\n
83
+ rights: Creative Commons Attribution 4.0 International License\n
84
+ language: en-US\n
85
+ ...
86
+
87
+ [Mastering Roda](:/ca267a317fa544f99f559040696f1cae)
88
+ DESC
89
+
90
+ def epub(id)
91
+ abort 'You need to install pandoc and have it in your path' unless has_exec? 'pandoc'
92
+ build_note = Joplin::Note.new(id:)
93
+ note = build(id)
94
+ note.write
95
+ build_note.write note.title
96
+ FileUtils.cd note.title
97
+ `pandoc '#{note.title}.md' -o '../#{note.title}.epub' -t epub3 -f markdown+smart --title '#{note.title}' --toc --toc-depth=3 --metadata title='#{note.title}'`
98
+ note.delete!
99
+ FileUtils.cd '..'
100
+ FileUtils.rm_rf note.title
101
+ abort 'Omg. pandoc failed!' if $?.exitstatus != 0
102
+ puts "OK. Done. Your book is #{note.title}.epub"
103
+ end
104
+
105
+ desc :build, 'build a note from a note containing references'
67
106
 
68
- long_desc %Q(Takes a note and looks up all the referenced notes and makes a new
69
- note from those. The notes are concatenated with a separator.\n\nIf you have a
107
+ long_desc %(Takes a note and looks up all the referenced notes and makes a new
108
+ note from those in the same folder. The notes are concatenated with a separator.\n\nIf you have a
70
109
  line with 'title: a title' then it will be used for the title of the built
71
- email.)
110
+ note.)
72
111
 
73
112
  def build(id)
74
113
  token
75
- note = Joplin::Note.new id
114
+ note = Joplin::Note.new(id:)
76
115
  notes = []
77
- title = nil
78
- note.body.each_line { |line|
79
- title = $1 if line =~ /title: (.*)$/
80
- line =~ /\(:\/([^)]+)\)/
81
- notes.push Joplin::Note.new $1 if $1
82
- }
83
- new_note = Joplin::Note.new
84
- new_note.title = title || "built: #{note.title}"
85
- new_note.body = notes.map { |n| "\# #{n.title}\n\n#{n.body}" }.join(DIVIDER)
116
+ note.body.each_line do |line|
117
+ match = line.match %r{!?\[(.*)?\]\(:/(\w+)\)}
118
+ next unless match
119
+ next if match[0][0] == '!'
120
+
121
+ begin
122
+ notes.push Joplin::Note.new id: match[2]
123
+ rescue Joplin::Note::NotFound
124
+ puts "Couldn't find note with id #{id} so we skip it. Maybe an image"
125
+ end
126
+ end
127
+ yml = extract_yaml_header_for_epub(note)
128
+ new_note = Joplin::Note.new parent_id: note.parent_id
129
+ new_note.title = yml ? yml['title'] : "built: #{note.title}"
130
+ new_note.body = "#{Psych.dump yml}...\n" if yml
131
+ new_note.body += notes.map { |n| "\# #{n.title}\n\n#{n.body}" }.join
86
132
  new_note.save!
87
- puts "Saved: #{new_note.title} with id: #{new_note.id}"
133
+ new_note
88
134
  end
89
135
 
90
136
  private
91
- def token()
92
- Joplin::token = Joplin.get_token || options[:token]
93
- raise "Couldn't find token in local database and it wasn't passed as an option. You better check yourself!" if not Joplin::token
137
+
138
+ def extract_yaml_header_for_epub(note)
139
+ yml = Psych.load note.body
140
+ return nil unless yml.is_a? Hash
141
+
142
+ yml
143
+ end
144
+
145
+ def has_exec?(command)
146
+ !`which #{command}`.empty?
147
+ end
148
+
149
+ def token
150
+ Joplin.token = Joplin.get_token || options[:token]
151
+ return if Joplin.token
152
+
153
+ raise "Couldn't find token in local database and it wasn't passed as an option. You better check yourself!"
94
154
  end
95
155
  end
96
156
 
data/joplin.gemspec CHANGED
@@ -1,42 +1,42 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "joplin/version"
3
+ require 'joplin/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "joplin"
6
+ spec.name = 'joplin'
8
7
  spec.version = Joplin::VERSION
9
- spec.authors = ["Daniel Bretoi"]
10
- spec.email = ["daniel@bretoi.com"]
8
+ spec.authors = ['Daniel Bretoi']
9
+ spec.email = ['daniel@bretoi.com']
11
10
 
12
- spec.summary = %q{joplin API}
13
- spec.description = %q{joplin API}
14
- spec.homepage = "http://github.com/danielb2/joplin-ruby"
15
- spec.license = "MIT"
11
+ spec.summary = 'joplin API'
12
+ spec.description = 'joplin API'
13
+ spec.homepage = 'http://github.com/danielb2/joplin-ruby'
14
+ spec.license = 'MIT'
16
15
 
17
16
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
17
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
18
  if spec.respond_to?(:metadata)
20
- spec.metadata["homepage_uri"] = spec.homepage
21
- spec.metadata["source_code_uri"] = "http://github.com/danielb2/joplin-ruby"
22
- spec.metadata["changelog_uri"] = "http://github.com/danielb2/joplin-ruby"
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = 'http://github.com/danielb2/joplin-ruby'
21
+ spec.metadata['changelog_uri'] = 'http://github.com/danielb2/joplin-ruby'
23
22
  else
24
- raise "RubyGems 2.0 or newer is required to protect against " \
25
- "public gem pushes."
23
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
24
+ 'public gem pushes.'
26
25
  end
27
26
 
28
27
  # Specify which files should be added to the gem when it is released.
29
28
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
29
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
31
30
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
31
  end
33
- spec.bindir = "bin"
32
+ spec.bindir = 'bin'
34
33
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }.reject { |f| f =~ /(console|setup)/ }
35
- spec.require_paths = ["lib"]
34
+ spec.require_paths = ['lib']
36
35
 
37
- spec.add_dependency "faraday", "~> 1.0"
38
- spec.add_development_dependency "bundler", "~> 2.0"
39
- spec.add_development_dependency "rake", "~> 13.0"
40
- spec.add_development_dependency "rspec", "~> 3.0"
41
- spec.add_development_dependency "thor", "~> 1.0.1"
36
+ spec.add_dependency 'http', '~> 5.1.1'
37
+ spec.add_dependency 'sqlite3', '~> 1.6.3'
38
+ spec.add_dependency 'thor', '~> 1.2.2'
39
+ spec.add_development_dependency 'bundler', '~> 2.0'
40
+ spec.add_development_dependency 'rake', '~> 13.0'
41
+ spec.add_development_dependency 'rspec', '~> 3.12.0'
42
42
  end
@@ -1,3 +1,3 @@
1
1
  module Joplin
2
- VERSION = "0.5.2"
2
+ VERSION = "1.0.1"
3
3
  end
data/lib/joplin.rb CHANGED
@@ -1,37 +1,36 @@
1
- require "joplin/version"
2
- require "faraday"
3
- require "json"
1
+ require 'joplin/version'
2
+ require 'http'
3
+ require 'json'
4
4
 
5
+ # https://joplinapp.org/api/overview/
5
6
  module Joplin
6
7
  class Error < StandardError; end
7
8
  attr_accessor :token
9
+
8
10
  @@token = nil
9
11
 
10
- def self.token= token
12
+ def self.token=(token)
11
13
  @@token = token
12
14
  end
13
15
 
14
16
  def self.search(query, opts = {})
15
- url = "#{Joplin::uri}/search/?query=#{query}&token=#{Joplin::token}&type=#{opts[:type]}"
16
- res = Faraday.get url
17
- parsed = JSON.parse res.body
18
- return parsed
17
+ url = "#{Joplin.uri}/search/?query=#{query}&token=#{Joplin.token}&type=#{opts[:type]}"
18
+ res = HTTP.get url
19
+ JSON.parse res.body
19
20
  end
20
21
 
21
22
  def self.get_token
22
- begin
23
- settings = JSON.parse File.read("#{ENV['HOME']}/.config/joplin-desktop/settings.json")
24
- return settings['api.token']
25
- rescue
26
- return nil
27
- end
23
+ settings = JSON.parse File.read("#{ENV['HOME']}/.config/joplin-desktop/settings.json")
24
+ settings['api.token']
25
+ rescue StandardError
26
+ nil
28
27
  end
29
28
 
30
29
  def self.token
31
30
  @@token || get_token
32
31
  end
33
32
 
34
- def self.uri= uri
33
+ def self.uri=(uri)
35
34
  @@uri = uri
36
35
  end
37
36
 
@@ -39,42 +38,55 @@ module Joplin
39
38
  @@uri
40
39
  end
41
40
 
42
- self.uri = "http://localhost:41184"
41
+ self.uri = 'http://localhost:41184'
43
42
 
44
43
  class Resource
45
- attr_reader :id
44
+ class NotFound < Joplin::Error; end
45
+ attr_reader :id, :filename, :mime
46
46
 
47
47
  def self.all
48
- url = "#{Joplin::uri}/resources/?token=#{Joplin::token}&fields=id"
49
- res = Faraday.get url
50
- parsed = JSON.parse res.body
51
- if res.status != 200
52
- throw Error.new(parsed['error'])
53
- end
54
- parsed.map do |resource|
55
- Resource.new resource['id']
56
- end
48
+ url = "#{Joplin.uri}/resources/?token=#{Joplin.token}&fields=id,filename"
49
+ response = HTTP.get url
50
+
51
+ parsed = JSON.parse res.body
52
+ throw Error.new(parsed['error']) if response.status != 200
53
+ parsed.map do |resource|
54
+ Resource.new resource['id']
55
+ end
57
56
  end
58
57
 
59
- def initialize(id=nil)
58
+ def initialize(id)
59
+ raise Error, 'need id' unless id
60
60
 
61
- raise Error.new("need id") unless id
62
61
  @id = id
63
- url = "#{Joplin::uri}/resources/#{id}?token=#{Joplin::token}&fields=mime,filename,id"
64
- res = Faraday.get url
65
- @parsed = JSON.parse res.body
62
+ url = "#{Joplin.uri}/resources/#{id}?token=#{Joplin.token}&fields=mime,filename,id"
63
+ response = HTTP.get url
64
+ raise NotFound, "No resource found with id: #{id}" if response.code == 404
65
+
66
+ resource = @parsed = JSON.parse response.body
67
+ @filename = resource['filename']
68
+ @mime = resource['mime']
69
+ end
70
+
71
+ def file
72
+ url = "#{Joplin.uri}/resources/#{id}/file?token=#{Joplin.token}"
73
+ response = HTTP.get url
74
+ throw Error if response.status != 200
75
+ response.body
76
+ end
77
+
78
+ def write(path = nil)
79
+ IO.write path || id, file
66
80
  end
67
81
 
68
82
  def delete
69
- url = "#{Joplin::uri}/resources/#{id}?token=#{Joplin::token}"
70
- res = Faraday.delete url
83
+ url = "#{Joplin.uri}/resources/#{id}?token=#{Joplin.token}"
84
+ res = HTTP.delete url
71
85
  res.status == 200
72
86
  end
73
87
 
74
88
  def to_s
75
- """id: #{@id},
76
- mime: #{@parsed['mime']}
77
- filename: #{@parsed['filename']}"""
89
+ %(id: #{id}, mime: #{mime} filename: #{filename})
78
90
  end
79
91
 
80
92
  def self.orphaned
@@ -85,91 +97,116 @@ filename: #{@parsed['filename']}"""
85
97
  end
86
98
 
87
99
  class Note
88
- attr_accessor :body
89
- attr_accessor :title
90
- attr_reader :id
100
+ class NotFound < Joplin::Error; end
91
101
 
92
- def initialize(id=nil)
102
+ attr_accessor :body, :title, :parent_id
103
+ attr_reader :id
93
104
 
105
+ def initialize(id: nil, parent_id: nil)
94
106
  @id = id
95
- if id
96
- url = "#{Joplin::uri}/notes/#{id}?token=#{Joplin::token}&fields=title,body,id"
97
- parse Faraday.get url
98
- end
107
+ @parent_id = parent_id
108
+ return unless id
109
+
110
+ url = "#{Joplin.uri}/notes/#{id}?token=#{Joplin.token}&fields=title,body,id,parent_id"
111
+ parse HTTP.get url
99
112
  end
100
113
 
101
114
  def resources
102
- url = "#{Joplin::uri}/notes/#{id}/resources?token=#{Joplin::token}&fields=id"
103
- res = Faraday.get url
104
- parsed = JSON.parse res.body
105
- parsed.map do |resource_data|
106
- id = resource_data['id']
107
- Resource.new id
108
- end
115
+ url = "#{Joplin.uri}/notes/#{id}/resources?token=#{Joplin.token}&fields=id,filename"
116
+ response = HTTP.get url
117
+ raise Error, "#{response}" if response.code != 200
118
+
119
+ parsed = JSON.parse response.body
120
+ parsed['items'].map do |resource_data|
121
+ id = resource_data['id']
122
+ Resource.new id
123
+ end
124
+ end
125
+
126
+ def prepare_body_for_writing_by_fixing_resources
127
+ prepared = String(body)
128
+ prepared.each_line do |line|
129
+ end
130
+ end
131
+
132
+ def write(path = nil)
133
+ dir = path || title
134
+ FileUtils.mkdir_p "#{dir}/resources"
135
+ body_to_write = String(body) # make a copy
136
+ resources.each do |resource|
137
+ resource.write "#{dir}/resources/#{resource.id}"
138
+ body_to_write.gsub!(%r{:/#{resource.id}}, "./resources/#{resource.id}")
139
+ end
140
+ IO.write "#{dir}/#{title}.md", body_to_write
109
141
  end
110
142
 
111
- def to_json
143
+ def to_json(*_args)
112
144
  {
113
- title: @title,
114
- body: @body
145
+ title:,
146
+ body:,
147
+ parent_id:
115
148
  }.to_json
116
149
  end
117
150
 
118
151
  def save!
119
152
  if @id
120
- url = "#{Joplin::uri}/notes/#{@id}?token=#{Joplin::token}"
121
- response = Faraday.put url, self.to_json
153
+ url = "#{Joplin.uri}/notes/#{@id}?token=#{Joplin.token}"
154
+ response = HTTP.put url, body: to_json
122
155
  return response.status == 200
123
156
  end
124
157
 
125
- url = "#{Joplin::uri}/notes/?token=#{Joplin::token}"
126
- parse Faraday.post url, self.to_json
158
+ url = "#{Joplin.uri}/notes/?token=#{Joplin.token}"
159
+ parse HTTP.post url, body: to_json
127
160
  end
128
161
 
129
162
  def to_s
130
- """id: #{self.id}
131
- title: #{self.title}
132
- body: #{self.body}"""
163
+ %(id: #{id} title: #{title} parent_id: #{parent_id} body: #{body})
133
164
  end
134
165
 
135
166
  def self.all
136
- url = "#{Joplin::uri}/notes/?token=#{Joplin::token}&fields=id"
137
- res = Faraday.get url
138
- parsed = JSON.parse res.body
139
- parsed.map do |note|
140
- Note.new note['id']
141
- end
167
+ url = "#{Joplin.uri}/notes/?token=#{Joplin.token}&fields=id"
168
+ res = HTTP.get url
169
+ parsed = JSON.parse res.body
170
+ parsed.map do |note|
171
+ Note.new note['id']
172
+ end
173
+ end
174
+
175
+ def delete!
176
+ url = "#{Joplin.uri}/notes/#{@id}?token=#{Joplin.token}"
177
+ response = HTTP.delete url
178
+ response.status == 200
142
179
  end
143
180
 
144
181
  private
145
- def parse response
146
- if response.body.empty?
147
- raise "No note found with id #{@id}"
148
- end
182
+
183
+ def parse(response)
184
+ raise "No note found with id #{@id}" if response.body.empty?
185
+
149
186
  note = JSON.parse response.body
150
- if response.status != 200
151
- raise Error.new note["error"]
152
- end
187
+ raise NotFound, "No note found with id: #{id}" if response.code == 404
188
+ raise Error, "#{note['error']}\nid: #{id}" if response.code != 200
189
+
153
190
  @body = note['body']
154
191
  @title = note['title']
155
- @id = note["id"]
192
+ @id = note['id']
193
+ @parent_id = note['parent_id']
156
194
  end
157
195
  end
158
196
 
159
197
  class Notebook
160
- def initialize(id=nil)
161
-
198
+ def initialize(id = nil)
162
199
  @id = id
163
- if id
164
- url = "#{Joplin::uri}/folders/#{id}?token=#{Joplin::token}"
165
- res = Faraday.get url
166
- parsed = JSON.parse res.body
167
- end
200
+ return unless id
201
+
202
+ url = "#{Joplin.uri}/folders/#{id}?token=#{Joplin.token}"
203
+ res = HTTP.get url
204
+ parsed = JSON.parse res.body
168
205
  end
169
206
 
170
207
  def notes
171
- url = "#{Joplin::uri}/folders/#{@id}/notes?token=#{Joplin::token}"
172
- res = Faraday.get url
208
+ url = "#{Joplin.uri}/folders/#{@id}/notes?token=#{Joplin.token}"
209
+ res = HTTP.get url
173
210
  notes = JSON.parse res.body
174
211
  notes.map! { |n| Joplin::Note.new n['id'] }
175
212
  end
@@ -19,7 +19,7 @@ end
19
19
 
20
20
  updating a note
21
21
  ```ruby
22
- note = Joplin::Note.new "6e3811c7a73148a" # note id can be found in the information of any note
22
+ note = Joplin::Note.new id: "6e3811c7a73148a" # note id can be found in the information of any note
23
23
  note.title = "a new note title"
24
24
  note.save!
25
25
  ```
@@ -35,6 +35,13 @@ token = Joplin::Token.get
35
35
 
36
36
  to get the token programatically. It reads from the sqlite database located in `~/.config/joplin-desktop`
37
37
 
38
+ ### Saving to a specific notebook
39
+
40
+ You can specify the id of the notebook
41
+
42
+ ```ruby
43
+ note = Joplin::Note.new parent_id: 'c5e6827be8c946c78210d3508cce7ea6'
44
+ ```
38
45
 
39
46
  ## CLI
40
47
 
@@ -43,3 +50,9 @@ to get the token programatically. It reads from the sqlite database located in `
43
50
  Will take a notebook and concatenate all notes into one for easy export to PDF
44
51
 
45
52
  The token argument is optional and if you have it installed locally it will find the token
53
+
54
+ ### joplin epub <id of note>
55
+
56
+ This will generate an epub from the referenced notes in the note. It will not
57
+ include the actual note, but only linked markdown notes within. Rendering
58
+ things like tables, mermaid diagrams etc is not supported
metadata CHANGED
@@ -1,85 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joplin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Bretoi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-21 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
- name: faraday
14
+ name: http
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: 5.1.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: 5.1.1
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: sqlite3
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.0'
34
- type: :development
33
+ version: 1.6.3
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.0'
40
+ version: 1.6.3
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: thor
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '13.0'
47
+ version: 1.2.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '13.0'
68
+ version: '2.0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: rspec
70
+ name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '3.0'
75
+ version: '13.0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '3.0'
82
+ version: '13.0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: thor
84
+ name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: 1.0.1
89
+ version: 3.12.0
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: 1.0.1
96
+ version: 3.12.0
83
97
  description: joplin API
84
98
  email:
85
99
  - daniel@bretoi.com
@@ -95,7 +109,6 @@ files:
95
109
  - Gemfile.lock
96
110
  - LICENSE.txt
97
111
  - Makefile
98
- - README.md
99
112
  - Rakefile
100
113
  - bin/console
101
114
  - bin/joplin
@@ -103,6 +116,7 @@ files:
103
116
  - joplin.gemspec
104
117
  - lib/joplin.rb
105
118
  - lib/joplin/version.rb
119
+ - readme.md
106
120
  homepage: http://github.com/danielb2/joplin-ruby
107
121
  licenses:
108
122
  - MIT
@@ -125,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
139
  - !ruby/object:Gem::Version
126
140
  version: '0'
127
141
  requirements: []
128
- rubygems_version: 3.0.3
142
+ rubygems_version: 3.4.10
129
143
  signing_key:
130
144
  specification_version: 4
131
145
  summary: joplin API