picdown 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a75b84f17db156d3c6cca720730d2083e50dff9053e978815ee207cfdf9dcf57
4
+ data.tar.gz: 920d7ac38131c39c5169d241760fd045bea326e4c120505a8ddd86dd7853ed92
5
+ SHA512:
6
+ metadata.gz: 97a63677439f6b0b48e9c09e1ae2c16b5256cf41b59b36df52cddb4a0444e4ee78ac80b09f4ec1d0cceb9bdcae5638a112d5360568fe476552ba04423109ef74
7
+ data.tar.gz: 6935d87ded479c182e7e579fed07677f0196ef7b01cc3ef52c5b917f6f840e4e52748e75454a10c2e13ad4a9713087aa9158b68cc2e58528fbe9943fd2c36e9c
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ Picdown ![pipeline](https://gitlab.com/htkaslan/picdown/badges/master/pipeline.svg) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/349123cc896d48cb97f54f9393465f0c)](https://www.codacy.com/gl/htkaslan/picdown/dashboard?utm_source=gitlab.com&utm_medium=referral&utm_content=htkaslan/picdown&utm_campaign=Badge_Grade)
2
+ =======
3
+
4
+ Picdown is a command line tool that downloads the given images from a source file.
5
+ It also allows you to make parallel requests to download images. Picdown provides
6
+ fancy outputs such as progress bar for each request to inform the user.
7
+
8
+ [![asciicast](https://asciinema.org/a/ljSjsRVrkroGLHpPBFzltIIDx.svg)](https://asciinema.org/a/ljSjsRVrkroGLHpPBFzltIIDx)
9
+
10
+ Installation
11
+ ------------
12
+
13
+ Picdown is dockerised, which means you can experiment it by building the image
14
+ from Dockerfile. Please run the below command to do that.
15
+
16
+ Note that you need to have a proper docker environment first.
17
+
18
+ ```sh
19
+ docker build . -t picdown
20
+ ```
21
+
22
+ If you want to build it manually, please follow the following instructions.
23
+
24
+ ```sh
25
+ bundle config --global silence_root_warning true
26
+ bundle config --global set path vendor/bundle
27
+ bundle install
28
+ bundle exec rake install
29
+ gem install pkg/picdown-*.gem
30
+ ```
31
+
32
+ Picdown is also a gem published on GitLab. You can have it by skipping installation
33
+ steps. Please ensure that you have set up [GitLab Rubygems Registry](https://docs.gitlab.com/ce/user/packages/rubygems_registry/index.html)
34
+ before running the following command.
35
+
36
+ ```sh
37
+ gem install picdown --version <VERSION>
38
+ ```
39
+
40
+ Usage
41
+ -----
42
+
43
+ Please have a look at the help text of `picdown` for more information.
44
+
45
+ ```
46
+ ➜ picdown -h
47
+ Commands:
48
+ picdown download FILE # Download files from the specified source file.
49
+ picdown validate PATH # Validate source file
50
+ picdown version # Print version
51
+ ```
52
+
53
+ ### `validate`
54
+
55
+ It validates the given source file if it contains valid URLs.
56
+
57
+ ```sh
58
+ picdown validate SOURCE
59
+ ```
60
+
61
+ ### `download`
62
+
63
+ It downloads the images given by the source file. It needs a valid file path.
64
+
65
+ ```sh
66
+ picdown download SOURCE
67
+ ```
68
+
69
+ To download the images parallel:
70
+
71
+ ```sh
72
+ picdown download SOURCE --parallel=4
73
+ ```
74
+
75
+ You are also able to configure the download parameters. Please check the below
76
+ help text for additional parameters.
77
+
78
+ ```sh
79
+ ➜ picdown download -h
80
+ ...
81
+
82
+ Options:
83
+ --destination=VALUE # Destination where files to be downloaded., default: "."
84
+ --parallel=VALUE # Number of parallel download processes., default: 1
85
+ --open-timeout=VALUE # Open timeout for connections. (secs), default: 15
86
+ --read-timeout=VALUE # Read timeout for connections. (secs), default: 15
87
+ --max-size=VALUE # Max file size. (bytes), default: 5242880
88
+ --max-redirects=VALUE # Max redirections., default: 3
89
+
90
+ ...
91
+ ```
92
+
93
+ Demo
94
+ ----
95
+
96
+ Picdown includes a demo file, which is located in `assets`, that you can use.
97
+
98
+ ```sh
99
+ picdown download assets/test.txt
100
+ ```
101
+
102
+ or
103
+
104
+ ```sh
105
+ docker run -t picdown download assets/test.txt
106
+ ```
107
+
108
+ License
109
+ -------
110
+
111
+ Not licensed yet.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ require 'rubocop/rake_task'
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
data/bin/picdown ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'picdown/cli'
5
+
6
+ def run
7
+ Dry::CLI.new(Picdown::CLI).call
8
+ rescue StandardError => e
9
+ abort e.message
10
+ end
11
+
12
+ run
data/lib/picdown.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'picdown/version'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/cli'
4
+
5
+ require 'picdown/error'
6
+ require 'picdown/support'
7
+ require 'picdown/config'
8
+ require 'picdown/source'
9
+ require 'picdown/source_file'
10
+ require 'picdown/multithread'
11
+ require 'picdown/download'
12
+
13
+ module Picdown
14
+ module CLI
15
+ extend Dry::CLI::Registry
16
+
17
+ Dir[File.join(__dir__, 'cli/*.rb')].sort.each { |command| require command }
18
+
19
+ register 'download', Download
20
+ register 'validate', Validate
21
+ register 'version', Version, aliases: ['v', '-v', '--version']
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ module CLI
5
+ class Download < Dry::CLI::Command
6
+ desc 'Download files from the specified source file.'
7
+
8
+ option :destination, type: :string, default: '.', desc: 'Destination where files to be downloaded.'
9
+ option :parallel, type: :string, default: 1, desc: 'Number of parallel download processes.'
10
+ option :open_timeout, type: :string, default: 15, desc: 'Open timeout for connections. (secs)'
11
+ option :read_timeout, type: :string, default: 15, desc: 'Read timeout for connections. (secs)'
12
+ option :max_size, type: :string, default: 5 * 1024 * 1024, desc: 'Max file size. (bytes)'
13
+ option :max_redirects, type: :string, default: 3, desc: 'Max redirections.'
14
+
15
+ argument :file, type: :string, required: true, desc: 'File to be used as a URL source.'
16
+
17
+ example [
18
+ '/path/to/file # Download files normally.',
19
+ '/path/to/file --parallel=2 # Perform parallel downloads.',
20
+ '/path/to/file --destination=/path/to/target # Download to a specific destination.'
21
+ ]
22
+
23
+ def call(file:, **options)
24
+ Picdown::Download.from_file(file, **options)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ module CLI
5
+ class Validate < Dry::CLI::Command
6
+ desc 'Validate source file'
7
+
8
+ argument :path, type: :string, required: true, desc: 'File path to be validated.'
9
+
10
+ def call(path:, **)
11
+ sources = Picdown::SourceFile.load(path)
12
+ print_results(sources)
13
+ end
14
+
15
+ protected
16
+
17
+ def print_results(sources)
18
+ return warn 'The source file is valid!' if sources.nondownloadable.empty?
19
+
20
+ warn 'The source file contains invalid sources.'
21
+ sources.nondownloadable.each do |src|
22
+ warn ''
23
+ warn "on #{sources.path} line #{src.line}:"
24
+ warn " #{src.url}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'picdown'
4
+
5
+ module Picdown
6
+ module CLI
7
+ class Version < Dry::CLI::Command
8
+ desc 'Print version'
9
+
10
+ def call(*)
11
+ puts Picdown::VERSION
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ Config = Struct.new(
5
+ :destination,
6
+ :parallel,
7
+ :open_timeout,
8
+ :read_timeout,
9
+ :max_size,
10
+ :max_redirects,
11
+ keyword_init: true
12
+ ) do
13
+ def initialize(**)
14
+ super
15
+ self.parallel = parallel.to_i
16
+ self.open_timeout = open_timeout.to_i
17
+ self.read_timeout = read_timeout.to_i
18
+ self.max_size = max_size.to_i
19
+ self.max_redirects = max_redirects.to_i
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'down'
4
+ require 'tty-progressbar'
5
+
6
+ module Picdown
7
+ class Download
8
+ using Support::Refinements
9
+
10
+ attr_reader :source, :config, :bars
11
+
12
+ def initialize(file, **opts)
13
+ @source = SourceFile.load(file)
14
+ @config = Config.new(opts)
15
+ @bars = TTY::ProgressBar::Multi.new
16
+ end
17
+
18
+ def call
19
+ config.parallel <= 1 ? perform_sequential : perform_parallel
20
+ end
21
+
22
+ def perform_sequential
23
+ source.downloadable.each { |src| download(src) }
24
+ end
25
+
26
+ def perform_parallel
27
+ threads = MultiThread.new(config.parallel)
28
+ source.downloadable.each { |src| threads.add { download(src) } }
29
+ threads.invoke
30
+ end
31
+
32
+ class << self
33
+ def from_file(file, **opts)
34
+ new(file, **opts).call
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def download(src) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
41
+ bar = bars.register "#{src.url.shorten} [:bar] :percent", total: 100, width: 30
42
+ total_size = 0
43
+
44
+ tempfile = Down.download(
45
+ src.url,
46
+ **config.to_h.except(:destination, :parallel),
47
+ content_length_proc: ->(content_length) { total_size += content_length },
48
+ progress_proc: lambda do |progress|
49
+ break if progress == total_size
50
+
51
+ bar.current = (progress.to_f / total_size) * 100
52
+ end
53
+ )
54
+
55
+ # Safely interrupt the download if the file is not an image.
56
+ content_type = tempfile.content_type
57
+ raise MimeTypeError, 'The file is not an image.' unless Support::MIME_TYPES.include?(content_type)
58
+
59
+ # Move the tempfile to the destination.
60
+ name = tempfile.original_filename || File.basename(tempfile.path)
61
+ dest = File.join(config.destination, name)
62
+ FileUtils.mv(tempfile.path, dest)
63
+ rescue Down::Error => e
64
+ raise DownloadError, "FAILED: #{src.url}: #{e.message}"
65
+ ensure
66
+ bar.finish
67
+ tempfile&.close
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ Error = Class.new(StandardError)
5
+ MimeTypeError = Class.new(Error)
6
+ DownloadError = Class.new(Error)
7
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ class MultiThread
5
+ Thread.report_on_exception = false
6
+
7
+ attr_reader :pool, :threads, :queue
8
+
9
+ def initialize(pool)
10
+ @pool = pool
11
+ @threads = []
12
+ @queue = Queue.new
13
+ end
14
+
15
+ def add(*args, &block)
16
+ queue << [block, args]
17
+ end
18
+
19
+ def invoke
20
+ 1.upto(pool) { threads << spawn_thread }
21
+ threads.each do |t|
22
+ trap('INT') { Thread.kill(t) }
23
+ t.join
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def spawn_thread
30
+ Thread.new do
31
+ until queue.empty?
32
+ block, args = queue.pop
33
+ block&.call(*args)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ Source = Struct.new(:line, :url) do
5
+ def valid?
6
+ url.match?(URI::DEFAULT_PARSER.make_regexp)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ class SourceFile
5
+ include Enumerable
6
+
7
+ attr_reader :path, :sources
8
+
9
+ def initialize(path)
10
+ @path = path
11
+ @sources = []
12
+ end
13
+
14
+ def <<(src)
15
+ sources << src
16
+ end
17
+
18
+ def each(&block)
19
+ sources.each(&block)
20
+ end
21
+
22
+ def load
23
+ File.readlines(path).each_with_index do |line, i|
24
+ sources << Source.new(i + 1, line.chomp)
25
+ end
26
+
27
+ self
28
+ end
29
+
30
+ def downloadable
31
+ select(&:valid?)
32
+ end
33
+
34
+ def nondownloadable
35
+ sources - downloadable
36
+ end
37
+
38
+ class << self
39
+ def load(path)
40
+ new(path).load
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ module Support
5
+ # Adapted from: https://www.iana.org/assignments/media-types/media-types.xhtml#image
6
+ MIME_TYPES = %w[
7
+ image/aces
8
+ image/avci
9
+ image/avcs
10
+ image/avif
11
+ image/bmp
12
+ image/cgm
13
+ image/dicom-rle
14
+ image/emf
15
+ image/example
16
+ image/fits
17
+ image/g3fax
18
+ image/gif
19
+ image/heic
20
+ image/heic-sequence
21
+ image/heif
22
+ image/heif-sequence
23
+ image/hej2k
24
+ image/hsj2
25
+ image/jls
26
+ image/jp2
27
+ image/jpeg
28
+ image/jph
29
+ image/jphc
30
+ image/jpm
31
+ image/jpx
32
+ image/jxr
33
+ image/jxrA
34
+ image/jxrS
35
+ image/jxs
36
+ image/jxsc
37
+ image/jxsi
38
+ image/jxss
39
+ image/ktx
40
+ image/ktx2
41
+ image/naplps
42
+ image/png
43
+ image/prs.btif
44
+ image/prs.pti
45
+ image/pwg-raster
46
+ image/svg+xml
47
+ image/t38
48
+ image/tiff
49
+ image/tiff-fx
50
+ image/vnd.adobe.photoshop
51
+ image/vnd.airzip.accelerator.azv
52
+ image/vnd.cns.inf2
53
+ image/vnd.dece.graphic
54
+ image/vnd.djvu
55
+ image/vnd.dwg
56
+ image/vnd.dxf
57
+ image/vnd.dvb.subtitle
58
+ image/vnd.fastbidsheet
59
+ image/vnd.fpx
60
+ image/vnd.fst
61
+ image/vnd.fujixerox.edmics-mmr
62
+ image/vnd.fujixerox.edmics-rlc
63
+ image/vnd.globalgraphics.pgb
64
+ image/vnd.microsoft.icon
65
+ image/vnd.mix
66
+ image/vnd.ms-modi
67
+ image/vnd.mozilla.apng
68
+ image/vnd.net-fpx
69
+ image/vnd.pco.b16
70
+ image/vnd.radiance
71
+ image/vnd.sealed.png
72
+ image/vnd.sealedmedia.softseal.gif
73
+ image/vnd.sealedmedia.softseal.jpg
74
+ image/vnd.svf
75
+ image/vnd.tencent.tap
76
+ image/vnd.valve.source.texture
77
+ image/vnd.wap.wbmp
78
+ image/vnd.xiff
79
+ image/vnd.zbrush.pcx
80
+ image/wmf
81
+ image/emf
82
+ image/wmf
83
+ ].freeze
84
+
85
+ module Refinements
86
+ refine String do
87
+ def shorten(limit: 15)
88
+ "#{self[..(limit - 1)]}...#{self[-limit..]}"
89
+ end
90
+ end
91
+
92
+ refine Hash do
93
+ def except(*keys)
94
+ slice(*self.keys - keys)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Picdown
4
+ VERSION = '0.1.1'
5
+ end
data/picdown.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
+ require 'picdown/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'picdown'
8
+ spec.author = 'Hüseyin Tekinaslan'
9
+ spec.email = 'htkaslan@gmail.com'
10
+ spec.summary = 'Download the given images from a source file.'
11
+ spec.description = spec.summary
12
+ spec.homepage = 'https://github.com/huseyin/picdown'
13
+ spec.files = Dir['README.md', 'Rakefile', 'picdown.gemspec', 'lib/**/*']
14
+ spec.require_paths = ['lib']
15
+ spec.bindir = 'bin'
16
+ spec.executables = ['picdown']
17
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7')
18
+ spec.version = Picdown::VERSION
19
+
20
+ spec.add_dependency 'down', '~> 5.0'
21
+ spec.add_dependency 'dry-cli'
22
+ spec.add_dependency 'tty-progressbar'
23
+
24
+ spec.add_development_dependency 'bundler'
25
+ spec.add_development_dependency 'minitest-focus'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'rubocop'
28
+ spec.add_development_dependency 'rubocop-minitest'
29
+ spec.add_development_dependency 'rubocop-performance'
30
+ spec.add_development_dependency 'rubocop-rake'
31
+ spec.add_development_dependency 'vcr'
32
+ spec.add_development_dependency 'webmock'
33
+ end
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: picdown
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Hüseyin Tekinaslan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: down
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-cli
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: tty-progressbar
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
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: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-focus
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-performance
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-rake
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: vcr
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: webmock
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description: Download the given images from a source file.
182
+ email: htkaslan@gmail.com
183
+ executables:
184
+ - picdown
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - README.md
189
+ - Rakefile
190
+ - bin/picdown
191
+ - lib/picdown.rb
192
+ - lib/picdown/cli.rb
193
+ - lib/picdown/cli/download.rb
194
+ - lib/picdown/cli/validate.rb
195
+ - lib/picdown/cli/version.rb
196
+ - lib/picdown/config.rb
197
+ - lib/picdown/download.rb
198
+ - lib/picdown/error.rb
199
+ - lib/picdown/multithread.rb
200
+ - lib/picdown/source.rb
201
+ - lib/picdown/source_file.rb
202
+ - lib/picdown/support.rb
203
+ - lib/picdown/version.rb
204
+ - picdown.gemspec
205
+ homepage: https://github.com/huseyin/picdown
206
+ licenses: []
207
+ metadata: {}
208
+ post_install_message:
209
+ rdoc_options: []
210
+ require_paths:
211
+ - lib
212
+ required_ruby_version: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '2.7'
217
+ required_rubygems_version: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ requirements: []
223
+ rubygems_version: 3.1.4
224
+ signing_key:
225
+ specification_version: 4
226
+ summary: Download the given images from a source file.
227
+ test_files: []