e621_export_downloader 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.irbrc +14 -0
  3. data/.ruby-version +1 -0
  4. data/LICENSE +21 -0
  5. data/README.md +148 -0
  6. data/Rakefile +8 -0
  7. data/exe/e621-export-downloader +112 -0
  8. data/lib/e621_export_downloader/client/options/builder/parsers.rb +42 -0
  9. data/lib/e621_export_downloader/client/options/builder.rb +44 -0
  10. data/lib/e621_export_downloader/client/options.rb +37 -0
  11. data/lib/e621_export_downloader/client.rb +120 -0
  12. data/lib/e621_export_downloader/constants.rb +17 -0
  13. data/lib/e621_export_downloader/export.rb +128 -0
  14. data/lib/e621_export_downloader/export_helper.rb +83 -0
  15. data/lib/e621_export_downloader/models/pool.rb +69 -0
  16. data/lib/e621_export_downloader/models/post.rb +166 -0
  17. data/lib/e621_export_downloader/models/tag.rb +41 -0
  18. data/lib/e621_export_downloader/models/tag_alias.rb +46 -0
  19. data/lib/e621_export_downloader/models/tag_implication.rb +46 -0
  20. data/lib/e621_export_downloader/models/wiki_page.rb +61 -0
  21. data/lib/e621_export_downloader/types.rb +14 -0
  22. data/lib/e621_export_downloader/version.rb +10 -0
  23. data/lib/e621_export_downloader.rb +12 -0
  24. data/sorbet/config +5 -0
  25. data/sorbet/rbi/annotations/.gitattributes +1 -0
  26. data/sorbet/rbi/annotations/faraday.rbi +17 -0
  27. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  28. data/sorbet/rbi/gems/.gitattributes +1 -0
  29. data/sorbet/rbi/gems/ast@2.4.3.rbi +550 -0
  30. data/sorbet/rbi/gems/benchmark@0.5.0.rbi +621 -0
  31. data/sorbet/rbi/gems/csv@3.3.5.rbi +4462 -0
  32. data/sorbet/rbi/gems/date@3.5.1.rbi +391 -0
  33. data/sorbet/rbi/gems/erb@6.0.4.rbi +1538 -0
  34. data/sorbet/rbi/gems/erubi@1.13.1.rbi +155 -0
  35. data/sorbet/rbi/gems/faraday-net_http@3.4.2.rbi +9 -0
  36. data/sorbet/rbi/gems/faraday@2.14.1.rbi +9 -0
  37. data/sorbet/rbi/gems/io-console@0.8.2.rbi +9 -0
  38. data/sorbet/rbi/gems/json@2.19.5.rbi +2240 -0
  39. data/sorbet/rbi/gems/language_server-protocol@3.17.0.5.rbi +9 -0
  40. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +189 -0
  41. data/sorbet/rbi/gems/logger@1.7.0.rbi +896 -0
  42. data/sorbet/rbi/gems/net-http@0.9.1.rbi +4029 -0
  43. data/sorbet/rbi/gems/netrc@0.11.0.rbi +147 -0
  44. data/sorbet/rbi/gems/parallel@2.1.0.rbi +321 -0
  45. data/sorbet/rbi/gems/parser@3.3.11.1.rbi +5229 -0
  46. data/sorbet/rbi/gems/pp@0.6.3.rbi +377 -0
  47. data/sorbet/rbi/gems/prettyprint@0.2.0.rbi +455 -0
  48. data/sorbet/rbi/gems/prism@1.9.0.rbi +42224 -0
  49. data/sorbet/rbi/gems/psych@5.3.1.rbi +2374 -0
  50. data/sorbet/rbi/gems/racc@1.8.1.rbi +165 -0
  51. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +362 -0
  52. data/sorbet/rbi/gems/rake@13.4.2.rbi +3130 -0
  53. data/sorbet/rbi/gems/rbi@0.3.11.rbi +5505 -0
  54. data/sorbet/rbi/gems/rbs@4.0.2.rbi +6908 -0
  55. data/sorbet/rbi/gems/rdoc@7.2.0.rbi +9 -0
  56. data/sorbet/rbi/gems/regexp_parser@2.12.0.rbi +3398 -0
  57. data/sorbet/rbi/gems/reline@0.6.3.rbi +2446 -0
  58. data/sorbet/rbi/gems/require-hooks@0.4.0.rbi +152 -0
  59. data/sorbet/rbi/gems/rexml@3.4.4.rbi +4905 -0
  60. data/sorbet/rbi/gems/rubocop-ast@1.49.1.rbi +7062 -0
  61. data/sorbet/rbi/gems/rubocop-rake@0.7.1.rbi +314 -0
  62. data/sorbet/rbi/gems/rubocop@1.86.1.rbi +62227 -0
  63. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +988 -0
  64. data/sorbet/rbi/gems/rubydex@0.2.0.rbi +663 -0
  65. data/sorbet/rbi/gems/spoom@1.7.13.rbi +6151 -0
  66. data/sorbet/rbi/gems/stringio@3.2.0.rbi +9 -0
  67. data/sorbet/rbi/gems/tapioca@0.19.1.rbi +3555 -0
  68. data/sorbet/rbi/gems/thor@1.5.0.rbi +3870 -0
  69. data/sorbet/rbi/gems/tsort@0.2.0.rbi +389 -0
  70. data/sorbet/rbi/gems/unicode-display_width@3.2.0.rbi +130 -0
  71. data/sorbet/rbi/gems/unicode-emoji@4.2.0.rbi +332 -0
  72. data/sorbet/rbi/gems/uri@1.1.1.rbi +2400 -0
  73. data/sorbet/rbi/gems/zeitwerk@2.7.5.rbi +1090 -0
  74. data/sorbet/rbi/shims/faraday.rbi +42 -0
  75. data/sorbet/rbi/todo.rbi +7 -0
  76. data/sorbet/tapioca/config.yml +13 -0
  77. data/sorbet/tapioca/require.rb +4 -0
  78. metadata +177 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 07a77d7c815326f0a51b7026c42f89c187fc526cc7caf20af35839e628e5243e
4
+ data.tar.gz: 23e2cd461ce89e9be5ff79d4a398e84762560e19a6edc9afffb323954ec37ba9
5
+ SHA512:
6
+ metadata.gz: 25ac18b83938e29298b3221b162594c6112a679b11d510ac70c46aff148f5fb08ede1b26466ccc942aa74a898a3680d7eb2087fb4374f49387b133ecf3974dc2
7
+ data.tar.gz: 316c7856999ce0ef76a24ba7dcaa7870969a0c1c41a8efe9a4ba30d63447bccc55d172a6c797359b916da2f76d89d2433f0047810798f23a859726e3ed21052b
data/.irbrc ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require_relative("lib/e621_export_downloader")
5
+ require("sorbet-runtime")
6
+
7
+ extend(T::Sig) # rubocop:disable Style/MixinUsage
8
+
9
+ E621ExportDownloader::Client::Logger.level = Logger::DEBUG
10
+
11
+ sig { returns(E621ExportDownloader::Client) }
12
+ def client
13
+ E621ExportDownloader::Client.new
14
+ end
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Donovan_DMC
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.
data/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # E621 Export Downloader
2
+
3
+ A utility for downloading and parsing e621's exports.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install e621_export_downloader
9
+ ```
10
+
11
+ Or add it to your Gemfile:
12
+
13
+ ```bash
14
+ bundle add e621_export_downloader
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```ruby
20
+ require("e621_export_downloader")
21
+
22
+ client = E621ExportDownloader::Client.new
23
+
24
+ # configure options after creation
25
+ client.config do |c|
26
+ c.cache = true # keep export files after reading, defaults to true
27
+ c.rewind_on_not_found = 2 # decrease date by one day if no export is found for that date,
28
+ # provide an integer to limit how many days can be rewound,
29
+ # `true` is equivalent to `2`, defaults to false
30
+ end
31
+
32
+ # or pass an Options struct directly
33
+ client = E621ExportDownloader::Client.new(
34
+ E621ExportDownloader::Client::Options.new(
35
+ cache: true,
36
+ rewind_on_not_found: 2,
37
+ )
38
+ )
39
+
40
+ # get the helper for interacting with a type of export
41
+ # types: pools, posts, tag_aliases, tag_implications, tags, wiki_pages
42
+ helper = client.get("posts")
43
+ # or use the named shorthand:
44
+ helper = client.posts
45
+
46
+ # get a wrapper for a specific date (time components are ignored)
47
+ # using this directly will not trigger rewinding regardless of rewind_on_not_found
48
+ export = helper.get(Date.today)
49
+
50
+ # convenience shorthand on the client — also skips rewinding
51
+ export = client.get_posts(Date.today)
52
+
53
+ # all of the following methods can also be called on the helper with a date argument;
54
+ # if rewind_on_not_found is enabled the helper decrements the date by one day until it
55
+ # finds an export or exhausts the rewind limit, at which point it raises ResolveError
56
+
57
+ # check whether the export exists for the date
58
+ exists = export.exists?
59
+ exists = helper.exists?(Date.today)
60
+
61
+ # download the export, returns the file path — not required before reading
62
+ # if you move or remove the file do not reuse the export object
63
+ file = export.download
64
+ file = helper.download(Date.today)
65
+
66
+ # delete the downloaded file, if it exists
67
+ export.delete
68
+ helper.delete(Date.today)
69
+
70
+ # get all of the records as a single array, DO NOT use this for large exports, arrays will millions of items do not perform well and will likely crash your process!
71
+ # (not to mention that the posts export is more than 5 gigabytes)
72
+ records = export.read_all
73
+
74
+ # read streams the CSV and yields each parsed record together with the total row count
75
+ # this is the recommended approach for large exports (the posts export exceeds 5 GB)
76
+ export.read do |record, total|
77
+ # record is an E621ExportDownloader::Models::Post instance
78
+ end
79
+ ```
80
+
81
+ ## Replace or extend a parser
82
+
83
+ ```ruby
84
+ require("e621_export_downloader")
85
+
86
+ client = E621ExportDownloader::Client.new
87
+
88
+ client.config do |c|
89
+ c.parsers do |p|
90
+ # replace a parser with a custom proc that receives the raw CSV row hash
91
+ # return nil to skip a record
92
+ p.posts = proc do |record|
93
+ post = E621ExportDownloader::Models::Post.new(record)
94
+ # attach extra data or wrap in your own class
95
+ post
96
+ end
97
+ end
98
+ end
99
+ ```
100
+
101
+ ## Models
102
+
103
+ Each export type is parsed into a corresponding model class:
104
+
105
+ | Export type | Model class |
106
+ |-------------------|---------------------------------------------------|
107
+ | `pools` | `E621ExportDownloader::Models::Pool` |
108
+ | `posts` | `E621ExportDownloader::Models::Post` |
109
+ | `tag_aliases` | `E621ExportDownloader::Models::TagAlias` |
110
+ | `tag_implications`| `E621ExportDownloader::Models::TagImplication` |
111
+ | `tags` | `E621ExportDownloader::Models::Tag` |
112
+ | `wiki_pages` | `E621ExportDownloader::Models::WikiPage` |
113
+
114
+ ## CLI
115
+
116
+ ```bash
117
+ # check if an export exists for a given date; date is optional and defaults to today
118
+ # outputs "true" or "false" with no trailing newline
119
+ e621-export-downloader exists posts 2024-01-01
120
+
121
+ # download an export for a given date; date is optional and defaults to today
122
+ # outputs the path to the downloaded file with no trailing newline
123
+ e621-export-downloader download posts 2024-01-01
124
+
125
+ # read an export as individual JSON lines; date is optional and defaults to today
126
+ # outputs each record as a JSON object on its own line
127
+ e621-export-downloader read posts 2024-01-01
128
+
129
+ # read an export as a JSON array; date is optional and defaults to today
130
+ # streams the CSV internally, so it is safe to use with large exports
131
+ e621-export-downloader read-all posts 2024-01-01
132
+
133
+ e621-export-downloader --help
134
+ e621-export-downloader --version
135
+ e621-export-downloader --cache # enable caching (default)
136
+ e621-export-downloader --no-cache # disable caching
137
+ e621-export-downloader --rewind-on-not-found # enable rewinding (up to 2 days)
138
+ e621-export-downloader --rewind-on-not-found 5 # enable rewinding (up to 5 days)
139
+ e621-export-downloader --no-rewind-on-not-found # disable rewinding (default)
140
+ ```
141
+
142
+ ## Contributing
143
+
144
+ Bug reports and pull requests are welcome on GitHub at https://github.com/DonovanDMC/E621ExportDownloader.rb.
145
+
146
+ ## License
147
+
148
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require("bundler/gem_tasks")
4
+ require("rubocop/rake_task")
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task(default: :rubocop)
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require("optparse")
5
+ require("date")
6
+ require("e621_export_downloader")
7
+
8
+ options = {
9
+ cache: true,
10
+ rewind_on_not_found: false,
11
+ }
12
+
13
+ parser = OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
14
+ opts.program_name = "e621-export-downloader"
15
+ opts.banner = <<~BANNER
16
+ Usage: e621-export-downloader [options] <command> [args]
17
+
18
+ Commands:
19
+ exists <name> [date] Check if an export exists for a given date
20
+ download <name> [date] Download an export for a given date
21
+ read <name> [date] Read an export as individual JSON lines
22
+ read-all <name> [date] Read an export as a JSON array
23
+
24
+ Options:
25
+ BANNER
26
+
27
+ opts.on("--[no-]cache", "Cache downloaded exports (default: enabled)") { |v| options[:cache] = v }
28
+
29
+ opts.on("--rewind-on-not-found [DAYS]", Integer,
30
+ "Rewind date if export not found; optionally limit how many days (true = 2)") do |v|
31
+ options[:rewind_on_not_found] = v || true
32
+ end
33
+ opts.on("--no-rewind-on-not-found", "Disable rewinding of export dates (default)") do
34
+ options[:rewind_on_not_found] = false
35
+ end
36
+
37
+ opts.on("-v", "--version", "Print the version") do
38
+ puts(E621ExportDownloader::Constants::VERSION)
39
+ exit
40
+ end
41
+
42
+ opts.on_tail("-h", "--help", "Print this help") do
43
+ puts(opts)
44
+ exit
45
+ end
46
+ end
47
+
48
+ parser.order!(ARGV)
49
+
50
+ command = ARGV.shift
51
+ if command.nil?
52
+ puts(parser)
53
+ exit(1)
54
+ end
55
+
56
+ name = ARGV.shift
57
+ if name.nil?
58
+ warn("Error: export name is required")
59
+ exit(1)
60
+ end
61
+
62
+ date_str = ARGV.shift
63
+ date = date_str ? Date.parse(date_str) : Date.today
64
+
65
+ client = E621ExportDownloader::Client.new(
66
+ E621ExportDownloader::Client::Options.new(
67
+ cache: options[:cache],
68
+ rewind_on_not_found: options[:rewind_on_not_found],
69
+ ),
70
+ )
71
+
72
+ # Downloads via the helper (respects rewind_on_not_found) and returns an Export
73
+ # handle that is already marked as downloaded so read won't re-fetch.
74
+ def download_and_open(helper, date)
75
+ path = helper.download(date)
76
+ resolved_date = Date.parse(File.basename(path, ".csv")[-10..])
77
+ E621ExportDownloader::Export.new(date: resolved_date, helper: helper)
78
+ end
79
+
80
+ helper = client.get(name)
81
+
82
+ case command
83
+ when "exists"
84
+ print(helper.exists?(date))
85
+
86
+ when "download"
87
+ print(helper.download(date))
88
+
89
+ when "read"
90
+ export = download_and_open(helper, date)
91
+ first = true
92
+ export.read do |record, _total|
93
+ $stdout.write("\n") unless first
94
+ first = false
95
+ $stdout.write(record.to_json)
96
+ end
97
+
98
+ when "read-all"
99
+ export = download_and_open(helper, date)
100
+ $stdout.write("[")
101
+ first = true
102
+ export.read do |record, _total|
103
+ $stdout.write(",") unless first
104
+ first = false
105
+ $stdout.write(record.to_json)
106
+ end
107
+ $stdout.write("]")
108
+
109
+ else
110
+ warn("Error: unknown command '#{command}'. Run with --help for usage.")
111
+ exit(1)
112
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module E621ExportDownloader
5
+ class Client
6
+ class Options
7
+ class Builder
8
+ class Parsers
9
+ extend(T::Sig)
10
+
11
+ sig { returns(Parser) }
12
+ attr_accessor(:pools)
13
+
14
+ sig { returns(Parser) }
15
+ attr_accessor(:posts)
16
+
17
+ sig { returns(Parser) }
18
+ attr_accessor(:tag_aliases)
19
+
20
+ sig { returns(Parser) }
21
+ attr_accessor(:tag_implications)
22
+
23
+ sig { returns(Parser) }
24
+ attr_accessor(:tags)
25
+
26
+ sig { returns(Parser) }
27
+ attr_accessor(:wiki_pages)
28
+
29
+ sig { params(defaults: Options::Parsers).void }
30
+ def initialize(defaults = Options::Parsers.defaults)
31
+ @pools = T.let(T.must(defaults.pools), Parser)
32
+ @posts = T.let(T.must(defaults.posts), Parser)
33
+ @tag_aliases = T.let(T.must(defaults.tag_aliases), Parser)
34
+ @tag_implications = T.let(T.must(defaults.tag_implications), Parser)
35
+ @tags = T.let(T.must(defaults.tags), Parser)
36
+ @wiki_pages = T.let(T.must(defaults.wiki_pages), Parser)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module E621ExportDownloader
5
+ class Client
6
+ class Options
7
+ class Builder
8
+ extend(T::Sig)
9
+
10
+ sig { returns(T::Boolean) }
11
+ attr_accessor(:cache)
12
+
13
+ sig { returns(T.any(T::Boolean, Integer)) }
14
+ attr_accessor(:rewind_on_not_found)
15
+
16
+ sig { params(parsers: Options::Parsers).returns(Options::Parsers) }
17
+ attr_writer(:parsers)
18
+
19
+ sig { params(defaults: Options).void }
20
+ def initialize(defaults = Options.new)
21
+ @cache = T.let(defaults.cache, T::Boolean)
22
+ @rewind_on_not_found = T.let(defaults.rewind_on_not_found, T.any(T::Boolean, Integer))
23
+ @parsers = T.let(defaults.parsers, Options::Parsers)
24
+ end
25
+
26
+ sig { params(block: T.nilable(T.proc.params(arg0: Builder::Parsers).void)).returns(Options::Parsers) }
27
+ def parsers(&block)
28
+ return @parsers if block.nil?
29
+ parsers = Builder::Parsers.new(@parsers)
30
+ block.call(parsers)
31
+
32
+ @parsers = Options::Parsers.new(
33
+ pools: parsers.pools,
34
+ posts: parsers.posts,
35
+ tag_aliases: parsers.tag_aliases,
36
+ tag_implications: parsers.tag_implications,
37
+ tags: parsers.tags,
38
+ wiki_pages: parsers.wiki_pages,
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module E621ExportDownloader
5
+ class Client
6
+ class Options < T::Struct
7
+ Parser = T.type_alias { T.proc.params(arg0: T::Hash[String, String]).returns(T.untyped) }
8
+
9
+ class Parsers < T::Struct
10
+ extend(T::Sig)
11
+
12
+ const(:pools, T.nilable(Parser), default: nil)
13
+ const(:posts, T.nilable(Parser), default: nil)
14
+ const(:tag_aliases, T.nilable(Parser), default: nil)
15
+ const(:tag_implications, T.nilable(Parser), default: nil)
16
+ const(:tags, T.nilable(Parser), default: nil)
17
+ const(:wiki_pages, T.nilable(Parser), default: nil)
18
+
19
+ sig { returns(Parsers) }
20
+ def self.defaults
21
+ Parsers.new(
22
+ pools: ->(record) { Models::Pool.new(record) },
23
+ posts: ->(record) { Models::Post.new(record) },
24
+ tag_aliases: ->(record) { Models::TagAlias.new(record) },
25
+ tag_implications: ->(record) { Models::TagImplication.new(record) },
26
+ tags: ->(record) { Models::Tag.new(record) },
27
+ wiki_pages: ->(record) { Models::WikiPage.new(record) },
28
+ )
29
+ end
30
+ end
31
+
32
+ const(:cache, T::Boolean, default: true)
33
+ const(:rewind_on_not_found, T.any(T::Boolean, Integer), default: false)
34
+ const(:parsers, Parsers, default: Parsers.defaults)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ require("faraday")
5
+
6
+ module E621ExportDownloader
7
+ class Client
8
+ extend(T::Sig)
9
+
10
+ Logger = ::Logger.new($stdout)
11
+
12
+ sig { returns(Options) }
13
+ attr_reader(:options)
14
+
15
+ sig { params(options: T.nilable(Options)).void }
16
+ def initialize(options = nil)
17
+ @options = T.let(options || Options.new, Options)
18
+ end
19
+
20
+ sig { params(block: T.proc.params(arg0: Options::Builder).void).void }
21
+ def config(&block)
22
+ block.call(Options::Builder.new(@options))
23
+ end
24
+
25
+ sig { returns(Faraday::Connection) }
26
+ def connection
27
+ Faraday.new(url: Constants::BASE_URL, headers: { "User-Agent" => Constants::USER_AGENT })
28
+ end
29
+
30
+ sig { params(msg: String, header: T::Array[String]).void }
31
+ def debug(msg, header: [])
32
+ Logger.debug("[e621_export_downloader#{":#{header.join(':')}" unless header.empty?}] #{msg}")
33
+ end
34
+
35
+ sig { params(type: T.any(Types, String)).returns(ExportHelper[T.untyped]) }
36
+ def get(type)
37
+ if type.is_a?(String)
38
+ case type
39
+ when "pools"
40
+ type = Types::Pools
41
+ when "posts"
42
+ type = Types::Posts
43
+ when "tag_aliases"
44
+ type = Types::TagAliases
45
+ when "tag_implications"
46
+ type = Types::TagImplications
47
+ when "tags"
48
+ type = Types::Tags
49
+ when "wiki_pages"
50
+ type = Types::WikiPages
51
+ else
52
+ raise(ArgumentError, "invalid type: #{type}")
53
+ end
54
+ end
55
+
56
+ T.assert_type!(type, Types)
57
+ ExportHelper.new(client: self, type: type, parser: options.parsers.public_send(type.serialize))
58
+ end
59
+
60
+ sig { returns(ExportHelper[Models::Pool]) }
61
+ def pools
62
+ get(Types::Pools)
63
+ end
64
+
65
+ sig { params(date: T.any(Date, DateTime)).returns(Export[Models::Pool]) }
66
+ def get_pools(date = Date.today)
67
+ pools.get(date)
68
+ end
69
+
70
+ sig { returns(ExportHelper[Models::Post]) }
71
+ def posts
72
+ get(Types::Posts)
73
+ end
74
+
75
+ sig { params(date: T.any(Date, DateTime)).returns(Export[Models::Post]) }
76
+ def get_posts(date = Date.today)
77
+ posts.get(date)
78
+ end
79
+
80
+ sig { returns(ExportHelper[Models::TagAlias]) }
81
+ def tag_aliases
82
+ get(Types::TagAliases)
83
+ end
84
+
85
+ sig { params(date: T.any(Date, DateTime)).returns(Export[Models::TagAlias]) }
86
+ def get_tag_aliases(date = Date.today)
87
+ tag_aliases.get(date)
88
+ end
89
+
90
+ sig { returns(ExportHelper[Models::TagImplication]) }
91
+ def tag_implications
92
+ get(Types::TagImplications)
93
+ end
94
+
95
+ sig { params(date: T.any(Date, DateTime)).returns(Export[Models::TagImplication]) }
96
+ def get_tag_implications(date = Date.today)
97
+ tag_implications.get(date)
98
+ end
99
+
100
+ sig { returns(ExportHelper[Models::Tag]) }
101
+ def tags
102
+ get(Types::Tags)
103
+ end
104
+
105
+ sig { params(date: T.any(Date, DateTime)).returns(Export[Models::Tag]) }
106
+ def get_tags(date = Date.today)
107
+ tags.get(date)
108
+ end
109
+
110
+ sig { returns(ExportHelper[Models::WikiPage]) }
111
+ def wiki_pages
112
+ get(Types::WikiPages)
113
+ end
114
+
115
+ sig { params(date: T.any(Date, DateTime)).returns(Export[Models::WikiPage]) }
116
+ def get_wiki_pages(date = Date.today)
117
+ wiki_pages.get(date)
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ require("tmpdir")
5
+ require("sorbet-runtime")
6
+ require_relative("version")
7
+
8
+ module E621ExportDownloader
9
+ module Constants
10
+ extend(T::Sig)
11
+
12
+ BASE_URL = "https://e621.net/db_export/"
13
+ EXPORT_NAMES = %w[pools posts tag_aliases tag_implications tags wiki_pages].freeze
14
+ TEMP_DIR = T.let(File.join(Dir.tmpdir, "e621-export-downloader"), String)
15
+ USER_AGENT = T.let("E621ExportDownloader.rb/#{VERSION} (#{WEBSITE})", String)
16
+ end
17
+ end