ever2boost 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a5654e22ae3ea0e870cbc63db4c3864a32055fd0
4
+ data.tar.gz: 75ebf591129a84a1dee6571f7253eb3b1da8dd1f
5
+ SHA512:
6
+ metadata.gz: 37f392c71a769adf2ad90aea3bbf70b517451511dbdacce7dff5bfc2c1ff500c122d7e67f0dfc06f07b960850dd0a80e8ad0a31c639734d97a82ae1627cdb54d
7
+ data.tar.gz: 023ad07816312e67af63cada27275f01169a442375ba384efa8db90845af18f063e0c30d81f42022164c568ee6eddb1265a146c4021e407d760dc84f905e59e1
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /spec/dist
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,64 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2017-01-27 09:19:36 +0900 using RuboCop version 0.44.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 3
10
+ # Cop supports --auto-correct.
11
+ Lint/LiteralInInterpolation:
12
+ Exclude:
13
+ - 'lib/ever2boost/note.rb'
14
+
15
+ # Offense count: 15
16
+ Lint/ParenthesesAsGroupedExpression:
17
+ Exclude:
18
+ - 'spec/cson_generator_spec.rb'
19
+ - 'spec/json_generator_spec.rb'
20
+ - 'spec/md_converter_spec.rb'
21
+
22
+ # Offense count: 1
23
+ # Cop supports --auto-correct.
24
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
25
+ Lint/UnusedMethodArgument:
26
+ Exclude:
27
+ - 'lib/ever2boost/note_list.rb'
28
+
29
+ # Offense count: 2
30
+ Lint/UselessAssignment:
31
+ Exclude:
32
+ - 'lib/ever2boost/cson_generator.rb'
33
+ - 'lib/ever2boost/evernote_authorizer.rb'
34
+
35
+ # Offense count: 2
36
+ Metrics/AbcSize:
37
+ Max: 32
38
+
39
+ # Offense count: 25
40
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives.
41
+ # URISchemes: http, https
42
+ Metrics/LineLength:
43
+ Max: 193
44
+
45
+ # Offense count: 5
46
+ # Configuration parameters: CountComments.
47
+ Metrics/MethodLength:
48
+ Max: 19
49
+
50
+ # Offense count: 10
51
+ Style/Documentation:
52
+ Exclude:
53
+ - 'spec/**/*'
54
+ - 'test/**/*'
55
+ - 'lib/ever2boost.rb'
56
+ - 'lib/ever2boost/cli.rb'
57
+ - 'lib/ever2boost/cson_generator.rb'
58
+ - 'lib/ever2boost/enex_converter.rb'
59
+ - 'lib/ever2boost/evernote_authorizer.rb'
60
+ - 'lib/ever2boost/json_generator.rb'
61
+ - 'lib/ever2boost/md_converter.rb'
62
+ - 'lib/ever2boost/note.rb'
63
+ - 'lib/ever2boost/note_list.rb'
64
+ - 'lib/ever2boost/util.rb'
@@ -0,0 +1,12 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ - 2.2.0
6
+ - 2.1.0
7
+ - 2.0.0
8
+ before_install: gem install bundler
9
+ install:
10
+ - bundle install
11
+ - gem instal rubocop
12
+ script: rubocop --config .rubocop_todo.yml --fail-level=W
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ever2boost.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 asmsuechan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,120 @@
1
+ # ever2boost
2
+ [![Build Status](https://travis-ci.org/BoostIO/ever2boost.svg?branch=master)](https://travis-ci.org/BoostIO/ever2boost)
3
+
4
+ ever2bost is a CLI tool for conversion Evernote to Boostnote.
5
+
6
+ <div align='center'>
7
+ <img width='70%' src="https://raw.githubusercontent.com/BoostIO/ever2boost/master/docs/images/img4.png">
8
+ </div>
9
+
10
+ # Quick start
11
+ Get Evernote developer token from [here](https://www.evernote.com/api/DeveloperToken.action).
12
+
13
+ ```
14
+ $ gem install ever2boost
15
+ $ ever2boost import
16
+ DEVELOPER_TOKEN: <input your developer token>
17
+ ```
18
+
19
+ Limitation? Go [here](docs/api_error.md)
20
+
21
+ ## Connect to your Boostnote
22
+ You need to connect it to Boostnote. Go Menu -> Add Storage and add it.
23
+
24
+ ![how_to_add_storage](docs/images/img2.png)
25
+
26
+ And select your storage. It's at `~/evernote_storage` by default on `import`.
27
+
28
+ ![how_to_chose_the_directory](docs/images/img3.png)
29
+
30
+ ****
31
+
32
+ ## ever2boost command
33
+ Ever2boost has 2 commands for conversion `convert` and `import`.
34
+
35
+ ```
36
+ $ ever2boost -h
37
+ Commands:
38
+ ever2boost convert # convert from .enex
39
+ ever2boost help [COMMAND] # Describe available commands or one specific co...
40
+ ever2boost import # import from evernote
41
+ ```
42
+
43
+ ### Create notes storage from Evernote
44
+ First, you need to create new Boostnote storage by ever2boost. And you can choose which command do you use, `import` or `convert`.
45
+
46
+ #### import
47
+ Import all of notes from cloud storage at Evernote.
48
+
49
+ `import` command has 1 option `d` which specify output directory.
50
+
51
+ ```
52
+ $ ever2boost help import
53
+ Usage:
54
+ ever2boost import
55
+
56
+ Options:
57
+ d, [--directory=DIRCTORY_PATH] # make Boostnote storage in the directory default: ~/evernote_storage
58
+
59
+ import from evernote
60
+ ```
61
+
62
+ 1. get your developer token from https://www.evernote.com/api/DeveloperToken.action
63
+ ![how_to_get_your_developer_token](docs/images/img1.png)
64
+
65
+ 2. run `ever2boost import`
66
+
67
+ ```
68
+ $ ever2boost import
69
+ DEVELOPER_TOKEN: <input your developer token>
70
+ ```
71
+ And `import` will start. It uses EvernoteAPI, thus you should take care access limitations.
72
+
73
+ #### convert
74
+ Convert notes from `.enex` file which is **exported file from Evernote**.
75
+
76
+ You can get how to export from [official document](https://help.evernote.com/hc/en-us/articles/209005557-How-to-back-up-export-and-restore-import-notes-and-notebooks).
77
+
78
+ `convert` has 1 option `d` which specify output directory.
79
+
80
+ ```
81
+ $ ever2boost help convert
82
+ Usage:
83
+ ever2boost convert
84
+
85
+ Options:
86
+ d, [--directory=DIRCTORY_PATH] # make Boostnote storage in the directory default: ~/evernote_storage
87
+
88
+ convert from .enex
89
+ ```
90
+
91
+ ## Requirements
92
+ Ruby: 2.0.0 or above
93
+ bundler: Corresponding to Ruby
94
+
95
+ if you don't have bundler:
96
+
97
+ ```
98
+ $ gem install bundler
99
+ ```
100
+
101
+ > if it fails by permission, you can run as sudo (perhaps you're using preinstalled Ruby in the OS)
102
+
103
+
104
+
105
+ ## Something happens
106
+ If your Boostnote would be broken:
107
+
108
+ * Notes and folders disappear
109
+ * Folder names are something wrong (e.g: Unknown 1)
110
+
111
+ First of all, look over [this document](docs/emergency.md). After that, if you would not find how to solve your error, please report an issue.
112
+
113
+ ## Contributing
114
+ Bug reports and pull requests are welcome on GitHub at https://github.com/BoostIO/ever2boost.
115
+
116
+ More information: [how_to_develop_ever2boost](docs/development.md)
117
+
118
+ ## License
119
+
120
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'ever2boost'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ever2boost'
4
+ Ever2boost::CLI.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # EvernoteAPI
2
+ ever2boost uses EvernoteAPI, therefore there are some limitations.
3
+
4
+ ## Limitations
5
+ * [<font color="orange">Warning</font>] Up to **250** notes in each folder
6
+
7
+ When the folder which ever2boost try to import has over 250 notes, ever2boost downloads first 250 notes from latest. For example, when a folder has 260 notes, the rest 10 old notes are ignored. Then the warning is appear:
8
+
9
+ ```
10
+ Ignore first 10 notes due to EvernoteAPI access limitation in this notebook.
11
+ ```
12
+
13
+ You need to try `convert` command if you just want to import the folder.
14
+
15
+ * [<font color="orange">Fatal</font>] Up to **500** notes on import
16
+
17
+ When it happens, ever2boost tells us an error below:
18
+ ![error_on_import](images/img5.png)
19
+
20
+ Actually I don't know the **exact** terms of number of notes, I just experienced in my environment. And **the limitation is reset every hour**.
21
+
22
+ **IMPORTANT**: The import is success (until the limitation) unless the error happens, thus you can connect the directory to Boostnote normaly.
23
+
24
+ ## References
25
+ * [Rate Limites](https://dev.evernote.com/doc/articles/rate_limits.php)
26
+ * [Rate Limit Best Practices](https://dev.evernote.com/doc/articles/rate_limit_best_practices.php)
@@ -0,0 +1,31 @@
1
+ # How to develop ever2boost
2
+ To develop ever2boost, `Ruby` (above 2.0.0) and `bundler` is required. You can check them by the commands below:
3
+
4
+ ```
5
+ $ ruby -v
6
+ $ gem which bundler
7
+ ```
8
+
9
+ And setup ever2boost:
10
+
11
+ ```
12
+ $ git clone https://github.com/BoostIO/ever2boost.git
13
+ $ cd ever2boost
14
+ $ bundle install
15
+ $ bundle exec exec/ever2boost import
16
+ DEVELOPER_TOKEN: <your developer token>
17
+ ```
18
+
19
+ # Testing
20
+ RSpec is used for testing ever2boost.
21
+
22
+ ```
23
+ $ rspec
24
+ ```
25
+
26
+ And also Rubocop is used, thus you need to install Rubocop if you don't have:
27
+
28
+ ```
29
+ $ gem install rubocop
30
+ $ rubocop -c .rubocop_todo.yml
31
+ ```
@@ -0,0 +1,5 @@
1
+ # Something went wrong?
2
+ Unfortunately, ever2boost is not a perfect tool. Therefore it may contain some bugs. However I am convinced that it will not break your notes/folders.
3
+
4
+ # Folders/notes disappear
5
+ When your folders/notes disappear after import, you need to run `rm -rf ~/evernote_storage` and reload Boostnote. After that perhaps your Boostnote come back life. If your Boostnote is stil dead, please report an issue.
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ever2boost/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'ever2boost'
8
+ spec.version = Ever2boost::VERSION
9
+ spec.authors = ['asmsuechan']
10
+ spec.email = ['suenagaryoutaabc@gmail.com']
11
+
12
+ spec.summary = 'Convert Evernote to Boostnote'
13
+ spec.description = 'ever2boost converts the all of your notes in Evernote into Boostnote'
14
+ spec.homepage = 'https://github.com/BoostIO/ever2boost'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = 'exe'
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'evernote-thrift'
25
+ spec.add_dependency 'thor'
26
+
27
+ spec.add_development_dependency 'pry-byebug'
28
+ spec.add_development_dependency 'bundler', '~> 1.13'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.0'
31
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ever2boost'
4
+ Ever2boost::CLI.start
@@ -0,0 +1,10 @@
1
+ require 'ever2boost/version'
2
+ require 'ever2boost/evernote_authorizer'
3
+ require 'ever2boost/note'
4
+ require 'ever2boost/md_converter'
5
+ require 'ever2boost/cson_generator'
6
+ require 'ever2boost/json_generator'
7
+ require 'ever2boost/cli'
8
+
9
+ module Ever2boost
10
+ end
@@ -0,0 +1,35 @@
1
+ require 'thor'
2
+ require 'ever2boost/evernote_authorizer'
3
+ require 'ever2boost/enex_converter'
4
+ require 'ever2boost/util'
5
+
6
+ module Ever2boost
7
+ class CLI < Thor
8
+ DEFAULT_OUTPUT_DIR = "#{ENV['HOME']}/evernote_storage".freeze
9
+ DEFAULT_OUTPUT_DIR_ENEX = "#{ENV['HOME']}/evernote_storage_enex".freeze
10
+
11
+ desc 'import', 'import from evernote'
12
+ option :directory, aliases: :d, banner: 'DIRCTORY_PATH', desc: 'make Boostnote storage in the directory default: ~/evernote_storage'
13
+ def import
14
+ output_dir = options[:directory] || DEFAULT_OUTPUT_DIR
15
+ developer_token = ask('DEVELOPER_TOKEN:')
16
+ EvernoteAuthorizer.new(developer_token).import(output_dir)
17
+ end
18
+
19
+ desc 'convert', 'convert from .enex'
20
+ option :directory, aliases: :d, banner: 'DIRCTORY_PATH', desc: 'make Boostnote storage in the directory default: ~/evernote_storage'
21
+ def convert(path)
22
+ output_dir = options[:directory] || DEFAULT_OUTPUT_DIR_ENEX
23
+ abort Util.red_output("Error! No such file or directory: #{path}") unless File.exist?(path)
24
+ enex = File.read(path)
25
+ filename = File.basename(path, '.enex')
26
+ EnexConverter.convert(enex, output_dir, filename)
27
+ end
28
+
29
+ map %w[--version -v] => :__print_version
30
+ desc "--version, -v", "print the version"
31
+ def __print_version
32
+ puts Ever2boost::VERSION
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ require 'ever2boost/util'
2
+
3
+ module Ever2boost
4
+ class CsonGenerator
5
+ class << self
6
+ def build(folder_hash, note)
7
+ cson = <<-EOS
8
+ type: "MARKDOWN_NOTE"
9
+ folder: "#{folder_hash}"
10
+ title: "#{note.title}"
11
+ content: '''
12
+ # #{note.title}
13
+ #{note.md_content}
14
+ '''
15
+ tags: []
16
+ isStarred: false
17
+ createdAt: "#{timestamp}"
18
+ updatedAt: "#{timestamp}"
19
+ EOS
20
+ end
21
+
22
+ def timestamp
23
+ Time.now.strftime('%Y-%m-%dT%H:%M:%S')
24
+ end
25
+
26
+ def output(folder_hash, note, output_dir)
27
+ Util.make_notes_dir(output_dir)
28
+ File.open("#{output_dir}/notes/#{note.file_name}.cson", 'w') do |f|
29
+ f.write(build(folder_hash, note))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ require 'rexml/document'
2
+ require 'ever2boost/util'
3
+
4
+ module Ever2boost
5
+ class EnexConverter
6
+ class << self
7
+ def convert(enex, output_dir, filename)
8
+ puts 'converting...'
9
+ en_notes = parse_plural_notes(enex, output_dir)
10
+ notebook_list = [NoteList.new(title: filename)]
11
+ JsonGenerator.output(notebook_list, output_dir)
12
+ en_notes.each do |note|
13
+ puts "converting #{note.title}"
14
+ CsonGenerator.output(notebook_list.first.hash, note, output_dir)
15
+ end
16
+ puts Util.green_output("The notes are created at #{output_dir}")
17
+ end
18
+
19
+ # enex: String
20
+ # "<?xml>(.*)</en-export>"
21
+ # return: Array
22
+ # include Note objects
23
+ # note.content = "<note>(.*)</note>"
24
+ # comment:
25
+ # A .enex file include plural ntoes. Thus I need to handle separation into each note.
26
+ def parse_plural_notes(enex, output_dir)
27
+ REXML::Document.new(enex).elements['en-export'].map do |el|
28
+ if el != "\n"
29
+ xml_document = REXML::Document.new(el.to_s).elements
30
+ Note.new({
31
+ title: xml_document['note/title'].text,
32
+ content: "<div>#{xml_document['note/content/text()'].to_s.sub(/<\?xml(.*?)\?>(.*?)<\!DOCTYPE(.*?)>/m, '')}</div>",
33
+ output_dir: output_dir
34
+ })
35
+ end
36
+ end.compact.flatten
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,113 @@
1
+ require 'evernote-thrift'
2
+ require 'ever2boost/note'
3
+ require 'ever2boost/note_list'
4
+ require 'ever2boost/util'
5
+
6
+ module Ever2boost
7
+ class EvernoteAuthorizer
8
+ EVERNOTE_HOST = 'www.evernote.com'.freeze
9
+
10
+ attr_accessor :developer_token, :note_store
11
+
12
+ def initialize(developer_token)
13
+ user_store_url = "https://#{EVERNOTE_HOST}/edam/user"
14
+ user_store_transport = Thrift::HTTPClientTransport.new(user_store_url)
15
+ user_store_protocol = Thrift::BinaryProtocol.new(user_store_transport)
16
+ user_store = Evernote::EDAM::UserStore::UserStore::Client.new(user_store_protocol)
17
+ note_store_url = user_store.getNoteStoreUrl(developer_token)
18
+ note_store_transport = Thrift::HTTPClientTransport.new(note_store_url)
19
+ note_store_protocol = Thrift::BinaryProtocol.new(note_store_transport)
20
+ note_store = Evernote::EDAM::NoteStore::NoteStore::Client.new(note_store_protocol)
21
+ @developer_token = developer_token
22
+ @note_store = note_store
23
+ rescue => e
24
+ abort_with_message e
25
+ end
26
+
27
+ def fetch_notebook_list
28
+ note_store.listNotebooks(developer_token)
29
+ end
30
+
31
+ def notebook_guids
32
+ fetch_notebook_list.map(&:guid)
33
+ end
34
+
35
+ def notebook_list
36
+ guids = notebook_guids
37
+ fetch_notebook_list.map { |nl| Ever2boost::NoteList.new(title: nl.name, guid: nl.guid) }
38
+ end
39
+
40
+ def number_of_note(filter)
41
+ note_counts_hash = note_store.findNoteCounts(developer_token, filter, true).notebookCounts
42
+ note_counts_hash.nil? ? 0 : note_counts_hash.values.last
43
+ end
44
+
45
+ def fetch_notes(filter)
46
+ spec = Evernote::EDAM::NoteStore::NotesMetadataResultSpec.new(includeTitle: true, includeNotebookGuid: true)
47
+ number_of_note = self.number_of_note(filter)
48
+
49
+ warn Util.yellow_output("Ignore first #{(number_of_note - 250)} notes due to EvernoteAPI access limitation in this notebook.") if number_of_note > 250
50
+ start_index = number_of_note > 250 ? number_of_note - 250 : 0
51
+ note_store.findNotesMetadata(developer_token, filter, start_index, number_of_note, spec)
52
+ end
53
+
54
+ # Download the all of notes from Evernote and generate Boostnote storage from it
55
+ # TODO: move this method to CLI
56
+ def import(output_dir)
57
+ puts 'processing...'
58
+ FileUtils.mkdir_p(output_dir) unless FileTest.exist?(output_dir)
59
+ notebook_list = self.notebook_list
60
+
61
+ Ever2boost::JsonGenerator.output(notebook_list, output_dir)
62
+
63
+ notebook_guids.map do |notebook_guid|
64
+ filter = Evernote::EDAM::NoteStore::NoteFilter.new(notebookGuid: notebook_guid)
65
+ note_guids = fetch_notes(filter).notes.map(&:guid)
66
+ puts "importing #{note_store.getNotebook(developer_token, notebook_guid).name}"
67
+ # TODO: assign the booleans
68
+ en_notes = note_guids.map { |note_guid| note_store.getNote(developer_token, note_guid, true, true, true, false) }
69
+ en_notes.each do |en_note|
70
+ download_image(en_note, output_dir) unless en_note.resources.nil?
71
+ note = Note.new(title: en_note.title, content: en_note.content, notebook_guid: en_note.notebookGuid, output_dir: output_dir)
72
+ # puts "importing #{find_notebook_by_guid_from_notebook_list(notebook_list, note).title}"
73
+ notebook_list.each do |list|
74
+ # TODO: break if note not found
75
+ CsonGenerator.output(list.hash, note, output_dir) if list.guid == note.notebook_guid
76
+ end
77
+ end
78
+ end
79
+ puts Util.green_output('Successfully finished!')
80
+ puts Util.green_output("Imported notes are located at #{output_dir}, mount it to Boostnote!")
81
+ rescue => e
82
+ abort_with_message e
83
+ end
84
+
85
+ def abort_with_message(exception)
86
+ if exception.class == Evernote::EDAM::Error::EDAMUserException
87
+ abort Util.red_output('Error! Confirm your developer token.')
88
+ elsif exception.class == Evernote::EDAM::Error::EDAMSystemException
89
+ abort Util.red_output("Error! You reached EvernoteAPI rate limitation.\nThe notes processed so far have been created successfully.\nMore information: https://github.com/BoostIO/ever2boost/tree/master/docs/api_error.md")
90
+ else
91
+ raise exception
92
+ end
93
+ end
94
+
95
+ def find_notebook_by_guid_from_notebook_list(notebook_list, note)
96
+ notebook_list.map do |nl|
97
+ nl if note.notebook_guid == nl.guid
98
+ end.compact.first
99
+ end
100
+
101
+ # TODO: handle to not image file
102
+ def download_image(en_note, output_dir)
103
+ en_note.resources.each do |resource|
104
+ imagename = resource.data.bodyHash.unpack("H*").first
105
+ extension = resource.mime.gsub(/(.+?)\//, '')
106
+ Util.make_images_dir(output_dir)
107
+ File.open("#{output_dir}/images/#{imagename}.#{extension}", 'w+b' ) do |f|
108
+ f.write note_store.getResourceData(developer_token, resource.guid)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,28 @@
1
+ require 'json'
2
+ require 'ever2boost/util'
3
+
4
+ module Ever2boost
5
+ class JsonGenerator
6
+ class << self
7
+ def build(notebook_list)
8
+ {
9
+ folders: notebook_list.map do |list|
10
+ {
11
+ key: list.hash,
12
+ name: list.title,
13
+ color: list.color
14
+ }
15
+ end,
16
+ version: '1.0'
17
+ }.to_json
18
+ end
19
+
20
+ def output(notebook_list, output_dir)
21
+ Util.make_notes_dir(output_dir)
22
+ File.open("#{output_dir}/boostnote.json", 'w') do |f|
23
+ f.write(build(notebook_list))
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,87 @@
1
+ require 'rexml/document'
2
+ require 'pry-byebug'
3
+
4
+ module Ever2boost
5
+ class MdConverter
6
+ class << self
7
+ # params: String
8
+ # "<note>(/.*/)</note>" (import)
9
+ # or
10
+ # "<?xml>(/.*/)</en-note>" (convert)
11
+ # return:
12
+ # markdown content
13
+ def convert(note_content)
14
+
15
+ en_note = nil
16
+ REXML::Document.new(note_content).elements.each('*') { |el| en_note = el.to_s || en_note + el.to_s }
17
+ if en_note.nil?
18
+ note_content
19
+ else
20
+ # build table
21
+ en_note.sub(/<tr(.*?)>(.*?)<\/tr>/m, '')
22
+ number_of_row = $2.nil? ? 0 : $2.scan(/<\/td>/).size
23
+
24
+ en_note.gsub(/<div(.*?)-en-codeblock(.*?)><div(.*?)>(.*?)<\/div><\/div>/, '\n```\n\4\n```')
25
+ code_block = $4
26
+
27
+ en_note.gsub(/<en-note(.*?)>(.*?)<\/en-note>/m, '\2')
28
+ .gsub(/<en-note\/>/, '')
29
+ .gsub(/<\/en-note>/, '')
30
+ .gsub(/\\n(\ *)/, '\n')
31
+ .gsub(/(\ *?)/m, '')
32
+ .gsub(/^\s*/, '')
33
+ .gsub(/<div(.*?)-en-codeblock(.*?)><div(.*?)>(.*?)<\/div><\/div>/, "\n```\n#{code_block}\n```")
34
+ .gsub(/<div(.*?)>(.*?)<\/div>/m, '\2\n')
35
+ .gsub(/<div(.*?)>/, '')
36
+ .gsub(/<\/div>/, '\n')
37
+ .gsub(/#+/, '\0 ')
38
+ .gsub(/<span(.*?)>(.*?)<\/span>/m, '\2')
39
+ .gsub(/<span(.*?)>/, '\2')
40
+ .gsub(/<\/span>/, '')
41
+ .gsub(/<p(.*?)>(.*?)<\/p>/m, '\2')
42
+ .gsub(/<p(.*?)>(.*?)<p\/>/m, '\2')
43
+ .gsub(/<p(.*?)>/m, '')
44
+ .gsub(/<ul(.*?)>(.*?)<\/ul>/m, '\2')
45
+ .gsub(/<br(.*?)>/, '\n')
46
+ .gsub(/<li(.*?)>(.*?)<\/li>/, '* \2')
47
+ .gsub(/<a\ href=['|"](.*?)['|"](.*?)>(.*?)<\/a>/m, '[\3](\1)')
48
+ .gsub(/<en-todo(.*?)>/, '*\ [\ ]\ ')
49
+ .gsub(/<strong>\\n<\/strong>/, '')
50
+ .gsub(/<strong(.*?)>(.*?)<\/strong>/, '**\2**')
51
+ .gsub(/<center(.*?)>(.*?)<\/center>/, '')
52
+ .gsub(/<s>\\n<\/s>/, '')
53
+ .gsub(/<s>([^\n].+?)<\/s>/, '~~\1~~')
54
+ .gsub(/<i>\\n<\/i>/, '')
55
+ .gsub(/<i>([^\n].+?)<\/i>/, '*\1*')
56
+ .gsub(/<em>\\n<\/em>/, '')
57
+ .gsub(/<em>([^\n].+?)<\/em>/, '_\1_')
58
+ .gsub(/<em(.*?)>(.*?)<\/em>/, '_\2_')
59
+ .gsub(/<b>([^\n].+?)<\/b>/, '**\1**')
60
+ .gsub(/<b>\\n<\/b>/, '')
61
+ .gsub(/<font(.*?)>(.*?)<\/font>/, '\2')
62
+ .gsub(/<tr(.*?)>(.*?)<\/tr>(\n*?)/m, '|\2')
63
+ .gsub(/<td(.*?)>(.*?)\n\\n<\/td>/m, '\2|')
64
+ .gsub(/<td(.*?)>(.*?)<\/td>/m, '\2|')
65
+ .gsub(/<\/tbody>/, '')
66
+ .gsub(/<\/table>/, '')
67
+ .gsub(/<table(.*?)>/, "#{'|' * (number_of_row + 1)}\n#{('|-' * (number_of_row + 1)).chop}")
68
+ .gsub(/<tbody(.*?)>/, '')
69
+ .gsub(/<p(.*?)>(.*?)<\/p>/, '\2')
70
+ .gsub(/<h1(.*?)>(.*?)<\/h1>/, '#\ \2')
71
+ .gsub(/<h2(.*?)>(.*?)<\/h2>/, '##\ \2')
72
+ .gsub(/<h3(.*?)>(.*?)<\/h3>/, '###\ \2')
73
+ .gsub(/<h4(.*?)>(.*?)<\/h4>/, '####\ \2')
74
+ .gsub(/<h5(.*?)>(.*?)<\/h5>/, '#####\ \2')
75
+ .gsub(/<pre(.*?)>(.*?)<code(.*?)>(.*?)<\/code><\/pre>/, '```\n\4\n```')
76
+ .gsub(/<code(.*?)>(.*?)<\/code>/, '\n```\n\2\n```\n')
77
+ .gsub(/<\/pre>/, '')
78
+ .gsub(/<hr(.*?)>/, '****')
79
+ .gsub(/ /m, ' ')
80
+ .gsub(/&gt;/, '>')
81
+ .gsub(/&lt;/, '<')
82
+ .gsub(/&amp;/, '&')
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,23 @@
1
+ require 'securerandom'
2
+
3
+ module Ever2boost
4
+ class Note
5
+ DEFAULT_BYTES_NUMBER = 10
6
+ attr_accessor :title, :content, :hash, :notebook_guid, :file_name, :output_dir
7
+ def initialize(title: nil, content: nil, notebook_guid: nil, output_dir: nil)
8
+ @title = title
9
+ @content = MdConverter.convert(content)
10
+ @notebook_guid = notebook_guid
11
+ @file_name = SecureRandom.hex(DEFAULT_BYTES_NUMBER)
12
+ @output_dir = output_dir
13
+ end
14
+
15
+ def md_content
16
+ build_image_link(self.content)
17
+ end
18
+
19
+ def build_image_link(content_str)
20
+ content_str.gsub(/<en-media\ hash=['|"](.+?)['|"](.*?).\ type=.(.+?)\/(.+?)['|"](.*?)\/>/, "![#{'\1'}](#{self.output_dir}/images/#{'\1'}.#{'\4'})")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ require 'securerandom'
2
+
3
+ module Ever2boost
4
+ class NoteList
5
+ DEFAULT_BYTES_NUMBER = 6
6
+
7
+ FOLDER_COLORS = [
8
+ '#E10051',
9
+ '#FF8E00',
10
+ '#E8D252',
11
+ '#3FD941',
12
+ '#30D5C8',
13
+ '#2BA5F7',
14
+ '#B013A4'
15
+ ].freeze
16
+
17
+ attr_accessor :title, :hash, :guid, :color
18
+
19
+ def initialize(title: nil, hash: nil, guid: nil, color: nil)
20
+ index = ((Random.new.rand * 7) * 10.floor % 7).to_i
21
+ color = FOLDER_COLORS[index]
22
+
23
+ @title = title
24
+ @hash = SecureRandom.hex(DEFAULT_BYTES_NUMBER)
25
+ @guid = guid
26
+ @color = color
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module Ever2boost
2
+ class Util
3
+ class << self
4
+ def make_output_dir(output_dir, dir_name)
5
+ FileUtils.mkdir_p("#{output_dir}/#{dir_name}") unless FileTest.exist?("#{output_dir}/#{dir_name}")
6
+ end
7
+
8
+ def make_notes_dir(output_dir)
9
+ make_output_dir(output_dir, 'notes')
10
+ end
11
+
12
+ def make_images_dir(output_dir)
13
+ make_output_dir(output_dir, 'images')
14
+ end
15
+
16
+ def red_output(str)
17
+ "\e[31m#{str}\e[0m"
18
+ end
19
+
20
+ def green_output(str)
21
+ "\e[32m#{str}\e[0m"
22
+ end
23
+
24
+ def yellow_output(str)
25
+ "\e[33m#{str}\e[0m"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Ever2boost
2
+ VERSION = '0.1.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ever2boost
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - asmsuechan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-02-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: evernote-thrift
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.13'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.13'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description: ever2boost converts the all of your notes in Evernote into Boostnote
98
+ email:
99
+ - suenagaryoutaabc@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop_todo.yml"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/ever2boost
114
+ - bin/setup
115
+ - docs/API_error.md
116
+ - docs/development.md
117
+ - docs/emergency.md
118
+ - docs/images/img1.png
119
+ - docs/images/img2.png
120
+ - docs/images/img3.png
121
+ - docs/images/img4.png
122
+ - docs/images/img5.png
123
+ - ever2boost.gemspec
124
+ - exec/ever2boost
125
+ - lib/ever2boost.rb
126
+ - lib/ever2boost/cli.rb
127
+ - lib/ever2boost/cson_generator.rb
128
+ - lib/ever2boost/enex_converter.rb
129
+ - lib/ever2boost/evernote_authorizer.rb
130
+ - lib/ever2boost/json_generator.rb
131
+ - lib/ever2boost/md_converter.rb
132
+ - lib/ever2boost/note.rb
133
+ - lib/ever2boost/note_list.rb
134
+ - lib/ever2boost/util.rb
135
+ - lib/ever2boost/version.rb
136
+ homepage: https://github.com/BoostIO/ever2boost
137
+ licenses:
138
+ - MIT
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.5.1
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Convert Evernote to Boostnote
160
+ test_files: []