apkg-to-csv 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1124f2bbb1471a711a6ffdd2e7fbb9316c2580b7c457a07f131411bf099f3a42
4
+ data.tar.gz: 741c2b58d53e1e3f4bdf7235c29f4a73a37a78c2dc4f9f23833ca539e94c87ba
5
+ SHA512:
6
+ metadata.gz: 6368553fbb0bd6923e1b65f05b75184a1d5861b3da959242dc664930b9df29097b792f6c4818351be03e90b228f126ca3c454063c074e530461268e87add5162
7
+ data.tar.gz: 6ddb8294e29d7bc289e16df4b0e7a9d963b11c6fc58fca7a9835bf957a78f564bd85e7c54bdd12d046f4638f83e0cdd341987795cdbade7f3821a7d9be9cf5c6
@@ -0,0 +1,34 @@
1
+ name: test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ matrix:
11
+ ruby-version: [3.0, 2.7, 2.6, 2.5]
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
18
+ with:
19
+ ruby-version: ${{ matrix.ruby-version }}
20
+
21
+ - name: Delete lockfile (to make sure it works with gem install)
22
+ run: rm Gemfile.lock
23
+
24
+ - name: Install dependencies
25
+ run: bundle install
26
+
27
+ - name: Run tests
28
+ run: bundle exec bash ./test/test.sh
29
+
30
+ - name: Lint code
31
+ run: bundle exec rubocop
32
+
33
+ - name: Audit code
34
+ run: bundle exec bundler-audit check --update
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ inherit_gem:
2
+ gnar-style:
3
+ - "rubocop/rubocop.yml"
4
+
5
+ AllCops:
6
+ NewCops: enable
7
+ TargetRubyVersion: 2.5
8
+
9
+ Layout/LineLength:
10
+ Max: 120
11
+ Severity: refactor
12
+
13
+ Style/StringLiterals:
14
+ EnforcedStyle: single_quotes
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.0
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'bundler-audit'
7
+ gem 'gnar-style'
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ apkg-to-csv (0.1.0)
5
+ rubyzip (~> 2.3.0)
6
+ sqlite3 (~> 1.4.2)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.2)
12
+ bundler-audit (0.9.0.1)
13
+ bundler (>= 1.2.0, < 3)
14
+ thor (~> 1.0)
15
+ gnar-style (0.13.0)
16
+ rubocop (>= 1.0.0, < 2.0)
17
+ rubocop-performance
18
+ rubocop-rails (~> 2.2.0)
19
+ thor
20
+ parallel (1.21.0)
21
+ parser (3.0.2.0)
22
+ ast (~> 2.4.1)
23
+ rack (2.2.3)
24
+ rainbow (3.0.0)
25
+ regexp_parser (2.1.1)
26
+ rexml (3.2.5)
27
+ rubocop (1.22.3)
28
+ parallel (~> 1.10)
29
+ parser (>= 3.0.0.0)
30
+ rainbow (>= 2.2.2, < 4.0)
31
+ regexp_parser (>= 1.8, < 3.0)
32
+ rexml
33
+ rubocop-ast (>= 1.12.0, < 2.0)
34
+ ruby-progressbar (~> 1.7)
35
+ unicode-display_width (>= 1.4.0, < 3.0)
36
+ rubocop-ast (1.12.0)
37
+ parser (>= 3.0.1.1)
38
+ rubocop-performance (1.11.5)
39
+ rubocop (>= 1.7.0, < 2.0)
40
+ rubocop-ast (>= 0.4.0)
41
+ rubocop-rails (2.2.1)
42
+ rack (>= 1.1)
43
+ rubocop (>= 0.72.0)
44
+ ruby-progressbar (1.11.0)
45
+ rubyzip (2.3.2)
46
+ sqlite3 (1.4.2)
47
+ thor (1.1.0)
48
+ unicode-display_width (2.1.0)
49
+
50
+ PLATFORMS
51
+ x86_64-darwin-19
52
+
53
+ DEPENDENCIES
54
+ apkg-to-csv!
55
+ bundler-audit
56
+ gnar-style
57
+
58
+ BUNDLED WITH
59
+ 2.2.30
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # APKG to CSV
2
+
3
+ Convert [Anki](https://apps.ankiweb.net/) deck (`.apkg`) files to comma-separated values (`.csv`) files.
4
+
5
+ ## Motivation
6
+
7
+ There is a large collection of [shared Anki decks](https://ankiweb.net/shared/decks/) available online.
8
+ It can be difficult to work with these decks without first importing them into Anki.
9
+
10
+ `apkg-to-csv` converts these decks into comma-separated values so that they can be modified without first importing them into Anki.
11
+
12
+ ## Requirements
13
+
14
+ * `ruby >= 2.5`
15
+
16
+ ## Installation
17
+
18
+ * `gem install apkg-to-csv`
19
+
20
+ ## Usage
21
+
22
+ * `apkg-to-csv deck.apkg > deck.csv`
23
+
24
+ ## Development Installation
25
+
26
+ ```
27
+ gem install bundler
28
+ bundle install
29
+ ```
30
+
31
+ ## Running Tests
32
+
33
+ * `bundle exec bash ./test/test.sh`
@@ -0,0 +1,26 @@
1
+ require_relative 'lib/apkg_to_csv/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'apkg-to-csv'
5
+ spec.version = ApkgToCsv::VERSION
6
+ spec.authors = ['zfletch']
7
+ spec.email = ['zf.rubygems@gmail.com']
8
+
9
+ spec.summary = 'Convert Anki deck (.apkg) files to comma-separated values (.csv) files.'
10
+ spec.homepage = 'https://github.com/zfletch/apkg-to-csv'
11
+ spec.license = 'MIT'
12
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
13
+
14
+ spec.metadata['homepage_uri'] = spec.homepage
15
+ spec.metadata['source_code_uri'] = spec.homepage
16
+
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ end
20
+ spec.bindir = 'bin'
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'rubyzip', '~> 2.3.0'
25
+ spec.add_dependency 'sqlite3', '~> 1.4.2'
26
+ end
data/bin/apkg-to-csv ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sqlite3'
4
+ require 'zip'
5
+ require 'tempfile'
6
+ require_relative '../lib/apkg_to_csv'
7
+
8
+ filename = ARGV[0]
9
+
10
+ unless filename
11
+ puts 'Filename required'
12
+ exit 1
13
+ end
14
+
15
+ file_written = false
16
+ tempfile = Tempfile.new('db')
17
+
18
+ Zip::File.open(filename) do |zip_file|
19
+ zip_file.each do |entry|
20
+ if entry.name == 'collection.anki2'
21
+ tempfile.write(entry.get_input_stream.read)
22
+ file_written = true
23
+ end
24
+ end
25
+ end
26
+
27
+ unless file_written
28
+ puts 'Could not extract zip file correctly'
29
+ exit 1
30
+ end
31
+
32
+ db = SQLite3::Database.new(tempfile.path)
33
+
34
+ puts ApkgToCsv.csv(db).csv
@@ -0,0 +1,35 @@
1
+ require 'csv'
2
+
3
+ module ApkgToCsv
4
+ class Csv
5
+ def self.from_notes(notes, models: [])
6
+ csv_hash = {}
7
+
8
+ models.each do |m|
9
+ csv_hash[m.id] ||= []
10
+ csv_hash[m.id] << m.fields
11
+ end
12
+
13
+ notes.each do |n|
14
+ csv_hash[n.model_id] ||= []
15
+ csv_hash[n.model_id] << n.fields
16
+ end
17
+
18
+ new(csv_hash)
19
+ end
20
+
21
+ attr_reader :csv
22
+
23
+ def initialize(hash)
24
+ @csv = CSV.generate do |csv|
25
+ first, *rest = hash.values
26
+
27
+ first.each { |f| csv << f }
28
+ rest.each do |fields_array|
29
+ csv << []
30
+ fields_array.each { |f| csv << f }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ require 'json'
2
+ require 'sqlite3'
3
+
4
+ module ApkgToCsv
5
+ class Model
6
+ def self.from_db(db)
7
+ db.execute('SELECT models FROM col').flat_map do |row|
8
+ from_row(row)
9
+ end
10
+ end
11
+
12
+ def self.from_row(row)
13
+ row.flat_map do |models_json|
14
+ JSON.parse(models_json).map { |k, v| new(k, v) }
15
+ end
16
+ end
17
+
18
+ attr_reader :id
19
+
20
+ def initialize(id, model_hash)
21
+ @id = id.to_s
22
+ @model_hash = model_hash
23
+ end
24
+
25
+ def fields
26
+ @fields ||= model_hash['flds'].map { |f| f['name'] }
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :model_hash
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ module ApkgToCsv
2
+ class Note
3
+ def self.from_db(db)
4
+ db.execute('SELECT mid, flds FROM notes').map do |model_id, field_string|
5
+ new(model_id, field_string)
6
+ end
7
+ end
8
+
9
+ attr_reader :model_id
10
+
11
+ def initialize(model_id, field_string)
12
+ @model_id = model_id.to_s
13
+ @field_string = field_string
14
+ end
15
+
16
+ def fields
17
+ @fields ||= field_string.split("\x1f")
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :field_string
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module ApkgToCsv
2
+ VERSION = '2.0.0'.freeze
3
+ end
@@ -0,0 +1,12 @@
1
+ require_relative './apkg_to_csv/model'
2
+ require_relative './apkg_to_csv/note'
3
+ require_relative './apkg_to_csv/csv'
4
+
5
+ module ApkgToCsv
6
+ def self.csv(db)
7
+ models = Model.from_db(db)
8
+ notes = Note.from_db(db)
9
+
10
+ Csv.from_notes(notes, models: models)
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apkg-to-csv
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - zfletch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubyzip
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.4.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.4.2
41
+ description:
42
+ email:
43
+ - zf.rubygems@gmail.com
44
+ executables:
45
+ - apkg-to-csv
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".github/workflows/test.yml"
50
+ - ".rubocop.yml"
51
+ - ".ruby-version"
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - LICENSE
55
+ - README.md
56
+ - apkg-to-csv.gemspec
57
+ - bin/apkg-to-csv
58
+ - lib/apkg_to_csv.rb
59
+ - lib/apkg_to_csv/csv.rb
60
+ - lib/apkg_to_csv/model.rb
61
+ - lib/apkg_to_csv/note.rb
62
+ - lib/apkg_to_csv/version.rb
63
+ homepage: https://github.com/zfletch/apkg-to-csv
64
+ licenses:
65
+ - MIT
66
+ metadata:
67
+ homepage_uri: https://github.com/zfletch/apkg-to-csv
68
+ source_code_uri: https://github.com/zfletch/apkg-to-csv
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 2.5.0
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubygems_version: 3.2.3
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Convert Anki deck (.apkg) files to comma-separated values (.csv) files.
88
+ test_files: []