ebook_renamer 0.0.7 → 0.0.8
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 +4 -4
- data/README.md +63 -105
- data/Rakefile +0 -2
- data/bin/ebook_renamer +6 -30
- data/ebook_renamer.gemspec +1 -0
- data/lib/ebook_renamer.rb +128 -6
- data/lib/ebook_renamer/core_ext/hash.rb +36 -0
- data/lib/ebook_renamer/helper.rb +168 -0
- data/lib/ebook_renamer/version.rb +1 -1
- data/test/lib/ebook_renamer/helpers_test.rb +26 -26
- data/test/test_helper.rb +1 -1
- metadata +18 -10
- data/lib/ebook_renamer/cli.rb +0 -60
- data/lib/ebook_renamer/configuration.rb +0 -30
- data/lib/ebook_renamer/helpers.rb +0 -175
- data/lib/ebook_renamer/options.rb +0 -71
- data/test/lib/ebook_renamer/configuration_test.rb +0 -22
- data/test/lib/ebook_renamer/version_test.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a2139b4a762320fd57c0f4fa7bc7a596fa9fe7e
|
4
|
+
data.tar.gz: 9e398f2a27d81053475b3fae18fe92b7de07d8d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48751c782e8240b4a539a04bbaed42235c0e620c016fa3c3f298874c7de6f7c4d4eae4cfd08afa56a0d45a6769a2dae7f127c369536d39ace8db3b3c3157c4da
|
7
|
+
data.tar.gz: c88f3706a48f84c46c4cb102e89502d6fe943d05fabe6e39baa1b16b1da909f665ec3193350b3195b6fb4cd16bb73284d15ac120cec61aae79fdfc477b7e3553
|
data/README.md
CHANGED
@@ -5,15 +5,12 @@ the metadata within the ebook itself (if available).
|
|
5
5
|
|
6
6
|
### Why do I wrote this gem
|
7
7
|
|
8
|
-
Almost always when I
|
9
|
-
|
8
|
+
Almost always, when I get an ebook it does not have a good file name.
|
9
|
+
This is very annoying as it does not work well when you want to search for it later.
|
10
10
|
|
11
|
-
I wrote this gem just to make it
|
12
|
-
|
13
|
-
|
14
|
-
meta-data that embedded within them.
|
15
|
-
|
16
|
-
So if you don't like to spend time renaming them manually then this gem is for you.
|
11
|
+
I wrote this gem just to make it possible to rename multiple ebook files at once using the
|
12
|
+
available meta-data from each file. I like to be able to use this on the single folder or recursively from
|
13
|
+
a given folder.
|
17
14
|
|
18
15
|
### How the file is renamed
|
19
16
|
|
@@ -22,10 +19,12 @@ The file will be renamed using the following format `<title>.by.<author(s)>`.`<e
|
|
22
19
|
Also the final file name will be sanitized e.g. any multiple occurence of special characters will be
|
23
20
|
replace by one dot `.`.
|
24
21
|
|
25
|
-
For example if the
|
26
|
-
and the author is `Simon Sinek` then the output will be `Start.with.Why.How.Great.Leader.Inspire.Everyone.to.Take.Action.by.Simon.Sinek.pdf`
|
22
|
+
For example if the ebook contain the title `Start with Why: How Grate Leader Inspire Everyone to Take Action`
|
23
|
+
and the author is `Simon Sinek` then the default output will be `Start.with.Why.How.Great.Leader.Inspire.Everyone.to.Take.Action.by.Simon.Sinek.pdf`
|
27
24
|
Note that the `:` and one space before the word `How` is replaced with just one dot string.
|
28
25
|
|
26
|
+
if the `--sep-string` is used then the output will be `Start_with_Why_How_Great_Leader_Inspire_Everyone_to_Take_Action_by_Simon_Sinek.pdf` for `--sep-string _` argument.
|
27
|
+
|
29
28
|
### What you will need
|
30
29
|
|
31
30
|
* You will need to install the [Calibre](http://www.calibre-ebook.com/) and
|
@@ -33,12 +32,6 @@ Note that the `:` and one space before the word `How` is replaced with just one
|
|
33
32
|
|
34
33
|
* Linux or Mac OSX operating system
|
35
34
|
|
36
|
-
### Problems/Issues
|
37
|
-
|
38
|
-
- Error may be raised if the combined meta-data is too long.
|
39
|
-
e.g. if your files is stored in NTFS drive then you may get the error indicate the file is too long
|
40
|
-
or something similar. I will try to handle this error in the next few release.
|
41
|
-
|
42
35
|
### Installation and Usage:
|
43
36
|
|
44
37
|
```sh
|
@@ -52,20 +45,20 @@ Run the following command from the directory that contain the file(s) that
|
|
52
45
|
you want to rename.
|
53
46
|
|
54
47
|
```sh
|
55
|
-
#
|
56
|
-
cd ~/Dropbox/ebooks/
|
48
|
+
# Cd to the directory containing the file(s) you like to rename
|
49
|
+
$cd ~/Dropbox/ebooks/
|
57
50
|
|
58
|
-
#
|
59
|
-
ebook_renamer --base-dir ~/Dropbox/ebooks/samples
|
51
|
+
# Or specify the directory as an option from any where you have access to the gem
|
52
|
+
$ebook_renamer rename --base-dir ~/Dropbox/ebooks/samples
|
60
53
|
|
61
|
-
#
|
62
|
-
ebook_renamer
|
54
|
+
# For help on how to use the gem just type without any options.
|
55
|
+
ebook_renamer
|
63
56
|
|
64
|
-
# Run the command without making any changes to the files (dry-run)
|
65
|
-
|
57
|
+
# Run the command without making any changes to the files (dry-run) in the current directory
|
58
|
+
$ebook_renamer --base-dir . --recursive
|
66
59
|
|
67
|
-
# Once you are happy with what
|
68
|
-
ebook_renamer --
|
60
|
+
# Once you are happy with what result then
|
61
|
+
$ebook_renamer --base-dir . --recursive --commit
|
69
62
|
```
|
70
63
|
|
71
64
|
### Example Outputs
|
@@ -78,115 +71,80 @@ test/fixtures/
|
|
78
71
|
├── demo1.pdf
|
79
72
|
├── demo2.epub
|
80
73
|
└── subdir
|
81
|
-
├──
|
82
|
-
└──
|
74
|
+
├── demo1.pdf
|
75
|
+
└── demo2.epub
|
83
76
|
2 directories, 4 files
|
84
77
|
```
|
85
78
|
|
86
79
|
Run the command without making any changes
|
87
80
|
|
88
81
|
```sh
|
89
|
-
./bin/ebook_renamer --base-dir ./test/fixtures/ebooks --recursive
|
82
|
+
./bin/ebook_renamer rename --base-dir ./test/fixtures/ebooks --recursive
|
90
83
|
```
|
91
84
|
|
92
85
|
You should see the result like the following
|
93
86
|
|
94
87
|
```
|
95
|
-
Your
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
Output:test/fixtures/ebooks/subdir/Reliably.Deploying.Rails.Applications.by.Ben.Dixon.pdf
|
102
|
-
Input :test/fixtures/ebooks/subdir/demo4.epub
|
103
|
-
Output:test/fixtures/ebooks/subdir/EPUB.3.0.Specification.by.EPUB.3.Working.Group.epub
|
88
|
+
Your argument: {:base_dir=>".", :exts=>["pdf", "epub", "mobi"], :sep_string=>".", :commit=>false, :recursive=>true, :version=>false}
|
89
|
+
Changes will not be applied without the --commit option.
|
90
|
+
[./test/fixtures/ebooks/demo1.pdf] -> [./test/fixtures/ebooks/Fearless.Refactoring.by.Andrzej.Krzywda.pdf]
|
91
|
+
[./test/fixtures/ebooks/demo2.epub] -> [./test/fixtures/ebooks/EPUB.3.0.Specification.by.EPUB.3.Working.Group.epub]
|
92
|
+
[./test/fixtures/ebooks/subdir/demo1.pdf] -> [./test/fixtures/ebooks/subdir/Reliably.Deploying.Rails.Applications.by.Ben.Dixon.pdf]
|
93
|
+
[./test/fixtures/ebooks/subdir/demo2.epub] -> [./test/fixtures/ebooks/subdir/EPUB.3.0.Specification.by.EPUB.3.Working.Group.epub]
|
104
94
|
```
|
105
95
|
|
106
|
-
To actually
|
96
|
+
To actually make the actual rename just pass in the `--commit` option like
|
107
97
|
|
108
98
|
```sh
|
109
|
-
./bin/ebook_renamer --base-dir ./test/fixtures/ebooks --recursive --commit
|
110
|
-
|
111
|
-
./bin/ebook_renamer -b ./test/fixtures/ebooks -r -c
|
99
|
+
./bin/ebook_renamer rename --base-dir ./test/fixtures/ebooks --recursive --commit
|
100
|
+
./bin/ebook_renamer rename -b ./test/fixtures/ebooks -r -c
|
112
101
|
```
|
113
102
|
|
114
|
-
|
115
|
-
|
116
|
-
The file will be renamed using the following format `<title>.by.<author(s)>`.`<extension>`
|
117
|
-
Also the final file name will be sanitized e.g. any special characters will be
|
118
|
-
converted to one dot `.`.
|
119
|
-
|
120
|
-
For example if the title is `Start with Why: How Grate Leader Inspire Everyone to Take Action` and the author is `Simon Sinek` then
|
121
|
-
the output will be something like `Start.with.Why.How.Great.Leader.Inspire.Everyone.to.Take.Action.by.Simon.Sinek.pdf` etc.
|
122
|
-
|
123
|
-
### Sample Usage (from `ebook_renamer --help`)
|
103
|
+
The final output should be like
|
124
104
|
|
125
105
|
```
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
--recursive
|
136
|
-
|
137
|
-
4) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
138
|
-
--recursive
|
139
|
-
|
140
|
-
5) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
141
|
-
--recursive
|
142
|
-
--commit
|
143
|
-
|
144
|
-
6) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
145
|
-
--recursive
|
146
|
-
--commit
|
106
|
+
test/fixtures/
|
107
|
+
└── ebooks
|
108
|
+
├── Fearless.Refactoring.by.Andrzej.Krzywda.pdf
|
109
|
+
├── EPUB.3.0.Specification.by.EPUB.3.Working.Group.epub
|
110
|
+
└── subdir
|
111
|
+
├── Fearless.Refactoring.by.Andrzej.Krzywda.pdf
|
112
|
+
└── EPUB.3.0.Specification.by.EPUB.3.Working.Group.epub
|
113
|
+
2 directories, 4 files
|
114
|
+
```
|
147
115
|
|
148
|
-
|
149
|
-
--recursive
|
150
|
-
--sep-string '_'
|
151
|
-
--commit
|
152
|
-
Options:
|
116
|
+
### Sample Usage
|
153
117
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
118
|
+
```
|
119
|
+
Usage:
|
120
|
+
ebook_renamer rename
|
121
|
+
|
122
|
+
Options:
|
123
|
+
-b, [--base-dir=BASE_DIR] # Base directory
|
124
|
+
# Default: /home/bchoomnuan/Dropbox/spikes/ebooks-renamer
|
125
|
+
-e, [--exts=one two three] # List of extensions to search for
|
126
|
+
# Default: ["pdf", "epub", "mobi"]
|
127
|
+
-s, [--sep-string=SEP_STRING] # Separator string between words in filename
|
128
|
+
# Default: .
|
129
|
+
-c, [--commit], [--no-commit] # Make change permanent
|
130
|
+
-r, [--recursive], [--no-recursive] # Search for files recursively
|
131
|
+
-v, [--version], [--no-version] # Display version information
|
132
|
+
|
133
|
+
Rename ebook files (pdf,epub,mobi)
|
160
134
|
```
|
161
135
|
|
162
136
|
### Changelog
|
163
137
|
|
164
|
-
#### 0.0.
|
165
|
-
|
166
|
-
- More improvement and code cleanup
|
167
|
-
|
168
|
-
#### 0.0.6
|
138
|
+
#### 0.0.8
|
169
139
|
|
170
|
-
-
|
140
|
+
- Use Thor instead of OptionParser for parsing of options
|
171
141
|
|
172
|
-
#### 0.0.
|
142
|
+
#### 0.0.2 - 0.0.7
|
173
143
|
|
174
|
-
-
|
175
|
-
|
176
|
-
#### 0.0.4
|
177
|
-
|
178
|
-
- fix the stupid bug with the `which` method which raise invalid error
|
179
|
-
- update README.md to reflect the change
|
180
|
-
|
181
|
-
#### 0.0.3
|
182
|
-
|
183
|
-
- make it possible to change the path to the binary
|
184
|
-
|
185
|
-
#### 0.0.2
|
186
|
-
|
187
|
-
- fix the silly refactoring bug
|
144
|
+
- Improvement of code and fix the few bugs a long the way
|
188
145
|
|
189
146
|
#### 0.0.1
|
147
|
+
|
190
148
|
- Initial release
|
191
149
|
|
192
150
|
### Contributing
|
data/Rakefile
CHANGED
@@ -9,7 +9,6 @@ end
|
|
9
9
|
|
10
10
|
task :default => :test
|
11
11
|
|
12
|
-
## see: http://erniemiller.org/2014/02/05/7-lines-every-gems-rakefile-should-have/
|
13
12
|
task :irb do
|
14
13
|
require 'irb'
|
15
14
|
require 'awesome_print'
|
@@ -20,7 +19,6 @@ task :irb do
|
|
20
19
|
IRB.start
|
21
20
|
end
|
22
21
|
|
23
|
-
## see: http://lucapette.com/pry/pry-everywhere/
|
24
22
|
task :pry do
|
25
23
|
require 'pry'
|
26
24
|
require 'awesome_print'
|
data/bin/ebook_renamer
CHANGED
@@ -1,32 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
|
2
|
+
require 'thor'
|
3
|
+
require 'pry'
|
4
|
+
require_relative '../lib/ebook_renamer'
|
5
|
+
require_relative '../lib/ebook_renamer/helper'
|
6
|
+
require_relative '../lib/ebook_renamer/version'
|
9
7
|
include EbookRenamer
|
10
|
-
|
11
|
-
require 'ostruct'
|
12
|
-
|
13
|
-
begin
|
14
|
-
options = parse_options()
|
15
|
-
EbookRenamer.logger.debug "Your options: #{options}"
|
16
|
-
|
17
|
-
#meta_binary = options.delete(:meta_binary)
|
18
|
-
sep_string = options.delete(:sep_string)
|
19
|
-
|
20
|
-
EbookRenamer.configure do |config|
|
21
|
-
#config.meta_binary = meta_binary if meta_binary
|
22
|
-
config.sep_string = sep_string if sep_string
|
23
|
-
end
|
24
|
-
|
25
|
-
cli = EbookRenamer::CLI.new(EbookRenamer.configuration)
|
26
|
-
cli.rename(options[:base_dir], options)
|
27
|
-
exit 0
|
28
|
-
rescue ArgumentError => e
|
29
|
-
puts e
|
30
|
-
exit 1
|
31
|
-
end
|
32
|
-
# vim: ft=ruby
|
8
|
+
EbookRenamer::Command.start(ARGV)
|
data/ebook_renamer.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_development_dependency "bundler", "~> 1.3"
|
21
21
|
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "thor"
|
22
23
|
|
23
24
|
spec.add_development_dependency "minitest-spec-context", "~> 0.0.3"
|
24
25
|
spec.add_development_dependency "guard-minitest", "~> 2.2"
|
data/lib/ebook_renamer.rb
CHANGED
@@ -1,6 +1,128 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
require 'thor'
|
2
|
+
require 'ap'
|
3
|
+
module EbookRenamer
|
4
|
+
class Command < Thor
|
5
|
+
desc "rename", "Rename ebook files (pdf,epub,mobi)"
|
6
|
+
|
7
|
+
method_option :base_dir,
|
8
|
+
aliases: "-b",
|
9
|
+
desc: "Base directory",
|
10
|
+
default: Dir.pwd
|
11
|
+
|
12
|
+
method_option :exts,
|
13
|
+
aliases: "-e",
|
14
|
+
desc: "List of extensions to search for",
|
15
|
+
type: :array,
|
16
|
+
default: %w(pdf epub mobi)
|
17
|
+
|
18
|
+
method_option :sep_string,
|
19
|
+
aliases: "-s",
|
20
|
+
desc: "Separator string between words in filename",
|
21
|
+
default: "."
|
22
|
+
|
23
|
+
method_option :commit,
|
24
|
+
aliases: "-c",
|
25
|
+
desc: "Make change permanent",
|
26
|
+
type: :boolean,
|
27
|
+
default: false
|
28
|
+
|
29
|
+
method_option :recursive,
|
30
|
+
aliases: "-r",
|
31
|
+
desc: "Search for files recursively",
|
32
|
+
type: :boolean,
|
33
|
+
default: false
|
34
|
+
|
35
|
+
method_option :version,
|
36
|
+
aliases: "-v",
|
37
|
+
desc: "Display version information",
|
38
|
+
type: :boolean,
|
39
|
+
default: false
|
40
|
+
|
41
|
+
def rename
|
42
|
+
args = options.symbolize_keys
|
43
|
+
puts "Your argument: #{args}"
|
44
|
+
|
45
|
+
if options[:version]
|
46
|
+
puts EbookRenamer::VERSION
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
|
50
|
+
execute(args)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "help", "Display help screen"
|
54
|
+
def help
|
55
|
+
puts <<-EOS
|
56
|
+
Usage:
|
57
|
+
ebook_renamer rename
|
58
|
+
|
59
|
+
Options:
|
60
|
+
-b, [--base-dir=BASE_DIR] # Base directory
|
61
|
+
# Default: /home/bchoomnuan/Dropbox/spikes/ebooks-renamer
|
62
|
+
-e, [--exts=one two three] # List of extensions to search for
|
63
|
+
# Default: ["pdf", "epub", "mobi"]
|
64
|
+
-s, [--sep-string=SEP_STRING] # Separator string between words in filename
|
65
|
+
# Default: .
|
66
|
+
-c, [--commit], [--no-commit] # Make change permanent
|
67
|
+
-r, [--recursive], [--no-recursive] # Search for files recursively
|
68
|
+
-v, [--version], [--no-version] # Display version information
|
69
|
+
|
70
|
+
Rename ebook files (pdf,epub,mobi)
|
71
|
+
EOS
|
72
|
+
end
|
73
|
+
|
74
|
+
default_task :help
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Rename the file from the given directory
|
79
|
+
# Using the with the argurment options as follow
|
80
|
+
#
|
81
|
+
# :base_dir - the base directory
|
82
|
+
# :recursive - perform the rename recursively (true|false)
|
83
|
+
# :commit - make the rename permanent (true|false)
|
84
|
+
# :exts - list of extensions to be processed default to ['epub,mobi,pdf']
|
85
|
+
#
|
86
|
+
# @param args [Hash<Symbol, Object>] options argument
|
87
|
+
def execute(args = {})
|
88
|
+
meta_binary = "ebook-meta"
|
89
|
+
options = default_options.merge(args)
|
90
|
+
|
91
|
+
input_files = files(options[:base_dir], options).sort
|
92
|
+
|
93
|
+
if input_files.empty?
|
94
|
+
puts "No file found for your option:", options
|
95
|
+
ap options
|
96
|
+
return
|
97
|
+
end
|
98
|
+
|
99
|
+
unless options[:commit]
|
100
|
+
puts "Changes will not be applied without the --commit option."
|
101
|
+
end
|
102
|
+
|
103
|
+
input_files.each do |file|
|
104
|
+
extension = File.extname(file)
|
105
|
+
begin
|
106
|
+
hash = meta_to_hash(meta(file, meta_binary))
|
107
|
+
full_name = formatted_name(hash, sep_char: " by ")
|
108
|
+
new_name = "#{File.dirname(file)}/#{sanitize_filename(full_name, options[:sep_string])}#{extension}"
|
109
|
+
puts "[#{file}] -> [#{new_name}]"
|
110
|
+
FileUtils.mv(file,new_name) if options[:commit] && file != new_name
|
111
|
+
rescue RuntimeError => e
|
112
|
+
puts e.backtrace
|
113
|
+
next
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def default_options
|
119
|
+
options = {
|
120
|
+
base_dir: Dir.pwd,
|
121
|
+
recursive: false,
|
122
|
+
commit: false,
|
123
|
+
exts: %w(epub mobi pdf),
|
124
|
+
sep_string: '.'
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# File activesupport/lib/active_support/core_ext/hash/keys.rb
|
4
|
+
#
|
5
|
+
# hash = { name: 'Rob', age: '28' }
|
6
|
+
# hash.transform_keys{ |key| key.to_s.upcase }
|
7
|
+
# => { "NAME" => "Rob", "AGE" => "28" }
|
8
|
+
def transform_keys
|
9
|
+
result = {}
|
10
|
+
each_key do |key|
|
11
|
+
result[yield(key)] = self[key]
|
12
|
+
end
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
def transform_keys!(&block)
|
17
|
+
keys.each do |key|
|
18
|
+
value = delete(key)
|
19
|
+
self[yield(key)] = value.is_a?(Hash) ? value.transform_keys!(&block) : value
|
20
|
+
end
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# hash = { 'name' => 'Rob', 'age' => '28' }
|
25
|
+
# hash.symbolize_keys
|
26
|
+
# => { name: "Rob", age: "28" }
|
27
|
+
def symbolize_keys
|
28
|
+
transform_keys{ |key| key.to_sym rescue key }
|
29
|
+
end
|
30
|
+
|
31
|
+
# File activesupport/lib/active_support/core_ext/hash/keys.rb, line 135
|
32
|
+
def symbolize_keys!
|
33
|
+
transform_keys!{ |key| key.to_sym rescue key }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'shellwords'
|
4
|
+
require_relative "./core_ext/hash"
|
5
|
+
module EbookRenamer
|
6
|
+
|
7
|
+
EbookMetaNotInstall = Class.new(StandardError)
|
8
|
+
|
9
|
+
# Extract meta data from the input file using the ebook-meta tool
|
10
|
+
#
|
11
|
+
# @param [String] filename the input file name
|
12
|
+
# @param [String] binary the executable for use to extract the metadata
|
13
|
+
# @return [String] result of the output from running the command
|
14
|
+
def meta(filename, binary = 'ebook-meta')
|
15
|
+
raise EbookMetaNotInstall, "Need to install ebook-meta to use this gem" if which(binary).nil?
|
16
|
+
command = [
|
17
|
+
binary,
|
18
|
+
Shellwords.escape(filename)
|
19
|
+
]
|
20
|
+
|
21
|
+
stdout_str, stderr_str, status = Open3.capture3(command.join(" "))
|
22
|
+
raise "Problem processing #{filename}" unless status.success?
|
23
|
+
stdout_str
|
24
|
+
end
|
25
|
+
|
26
|
+
# Convert the output string to hash
|
27
|
+
#
|
28
|
+
# @param [String] text output string from the 'ebook-meta' command
|
29
|
+
# @return [Hash<String,String>] hash pair for the input string
|
30
|
+
def meta_to_hash(text)
|
31
|
+
hash = {}
|
32
|
+
return hash if text.nil?
|
33
|
+
result_list = []
|
34
|
+
|
35
|
+
text.split(/\n/).each do |meta|
|
36
|
+
# split by the first ':' string
|
37
|
+
list = meta.split /^(.*?):/
|
38
|
+
|
39
|
+
# ignore the empty string element
|
40
|
+
list.delete_at(0)
|
41
|
+
|
42
|
+
unless list.empty?
|
43
|
+
list.map(&:strip!)
|
44
|
+
# downcase the first item to make it easy
|
45
|
+
result_list << [list[0].downcase, list[1]]
|
46
|
+
hash = Hash[*result_list.flatten]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
hash
|
50
|
+
end
|
51
|
+
|
52
|
+
# Clean the filename to remove the special characters
|
53
|
+
#
|
54
|
+
# @param [String] filename input file
|
55
|
+
# @param [String] sep_char separator character to use
|
56
|
+
#
|
57
|
+
# @return [String] the new file name with special characters replaced or removed.
|
58
|
+
def sanitize_filename(filename, sep_char = nil)
|
59
|
+
dot = "."
|
60
|
+
|
61
|
+
# Note exclude the '.' (dot)
|
62
|
+
filename.gsub!(/[^0-9A-Za-z\-_ ]/, dot)
|
63
|
+
|
64
|
+
# replace multiple occurrences of a given char with a dot
|
65
|
+
['-','_',' '].each do |c|
|
66
|
+
filename.gsub!(/#{Regexp.quote(c)}+/, dot)
|
67
|
+
end
|
68
|
+
|
69
|
+
# replace multiple occurrence of dot with one dot
|
70
|
+
filename.gsub!(/#{Regexp.quote(dot)}+/, dot)
|
71
|
+
|
72
|
+
if sep_char
|
73
|
+
# File.basename("demo.txt", ".*") #=> "demo"
|
74
|
+
name_only = File.basename(filename, ".*")
|
75
|
+
# File.extname("demo.txt") #=> ".txt"
|
76
|
+
ext_only = File.extname(filename)
|
77
|
+
name_only.gsub!(/#{Regexp.quote(dot)}+/, sep_char)
|
78
|
+
return "#{name_only}#{ext_only}"
|
79
|
+
end
|
80
|
+
|
81
|
+
filename.strip
|
82
|
+
end
|
83
|
+
|
84
|
+
# Cross-platform way of finding an executable in the $PATH.
|
85
|
+
#
|
86
|
+
# @param command [String] the command to look up
|
87
|
+
# @return [String, NilClass] full path to the executable file or nil if the
|
88
|
+
# executable is not valid or available.
|
89
|
+
# Example:
|
90
|
+
# which('ruby') #=> /usr/bin/ruby
|
91
|
+
# which('bad-executable') #=> nil
|
92
|
+
def which(command)
|
93
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
94
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
95
|
+
exts.each { |ext|
|
96
|
+
exe = File.join(path, "#{command}#{ext}")
|
97
|
+
return exe if File.executable? exe
|
98
|
+
}
|
99
|
+
end
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return formatted file name using the metadata values
|
104
|
+
#
|
105
|
+
# @param [Hash<Symbol,String>] meta_hash output from the program 'ebook-meta' or 'exiftoo'
|
106
|
+
# @param [Hash<Symbol,String>] fields list of fields that will be used to set the name
|
107
|
+
def formatted_name(meta_hash = {}, fields = {})
|
108
|
+
if hash.nil? || fields.nil?
|
109
|
+
raise ArgumentError.new("Argument must not be nil")
|
110
|
+
end
|
111
|
+
|
112
|
+
# The keys that we get from the 'mdls' or 'exiftool'
|
113
|
+
args = {
|
114
|
+
keys: ['title',
|
115
|
+
'author(s)'],
|
116
|
+
sep_char: ' '
|
117
|
+
}.merge(fields)
|
118
|
+
|
119
|
+
keys = args[:keys]
|
120
|
+
sep_char = args[:sep_char]
|
121
|
+
|
122
|
+
# Note: only show if we have the value for title
|
123
|
+
result = []
|
124
|
+
if meta_hash.fetch('title', nil)
|
125
|
+
keys.each do |k|
|
126
|
+
value = meta_hash.fetch(k, nil)
|
127
|
+
# Note: don't add 'Author(s)' => 'Unknown' to keep the result clean
|
128
|
+
if value && value.downcase != 'unknown'
|
129
|
+
result << meta_hash[k]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
return result.join(sep_char)
|
133
|
+
end
|
134
|
+
# Note: if no title we choose to return empty value for result
|
135
|
+
return ""
|
136
|
+
end
|
137
|
+
|
138
|
+
# Ensure that the values in hash are sanitized
|
139
|
+
#
|
140
|
+
# @param [Hash<Symbol,String>] hash input hash to be sanitized
|
141
|
+
# @return [Hash<Symbol,String>] original hash with values sanitized
|
142
|
+
# @see #sanitize_filename
|
143
|
+
def sanitize_values(hash = {})
|
144
|
+
hash.each do |key, value|
|
145
|
+
hash[key] = sanitize_filename(value, " ")
|
146
|
+
end
|
147
|
+
hash
|
148
|
+
end
|
149
|
+
|
150
|
+
# List files base on given options
|
151
|
+
# options:
|
152
|
+
# :recursive - process the directory recursively (default false)
|
153
|
+
# :exts - list of extensions to be search (default ['epub','mobi','pdf'])
|
154
|
+
#
|
155
|
+
# @param base_dir [String] the starting directory
|
156
|
+
# @param options [Hash<Symbol,Object>] the options to be used
|
157
|
+
# @return [List<String>] list of matching files or empty list if none are found
|
158
|
+
def files(base_dir = Dir.pwd, options = {})
|
159
|
+
args = {
|
160
|
+
recursive: false,
|
161
|
+
exts: %w(epub mobi pdf)
|
162
|
+
}.merge(options)
|
163
|
+
|
164
|
+
wildcard = args[:recursive] ? '**' : ''
|
165
|
+
patterns = File.join(base_dir, wildcard, "*.{#{(args[:exts]).join(',')}}")
|
166
|
+
Dir.glob(patterns) || []
|
167
|
+
end
|
168
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require_relative '../../test_helper'
|
2
2
|
describe EbookRenamer do
|
3
3
|
|
4
|
-
|
4
|
+
include EbookRenamer
|
5
5
|
|
6
6
|
before do
|
7
|
-
@sample =
|
7
|
+
@sample = meta("./test/fixtures/ebooks/demo1.pdf")
|
8
8
|
end
|
9
9
|
|
10
10
|
context "#meta" do
|
11
11
|
it "raises error on invalid input" do
|
12
|
-
->{
|
12
|
+
->{ meta("invalid-filename") }.must_raise RuntimeError
|
13
13
|
end
|
14
14
|
|
15
15
|
it "returns valid valid input" do
|
@@ -20,16 +20,16 @@ describe EbookRenamer do
|
|
20
20
|
|
21
21
|
context "#meta_to_hash" do
|
22
22
|
it 'returns empty hash' do
|
23
|
-
|
23
|
+
meta_to_hash(nil).must_be_empty
|
24
24
|
end
|
25
25
|
it 'returns non-empty hash' do
|
26
|
-
hash =
|
26
|
+
hash = meta_to_hash(@sample)
|
27
27
|
hash.wont_be_empty
|
28
28
|
end
|
29
29
|
|
30
30
|
describe 'invalid format' do
|
31
31
|
it 'return empty hash' do
|
32
|
-
|
32
|
+
meta_to_hash('aa bb').must_equal({})
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -44,7 +44,7 @@ describe EbookRenamer do
|
|
44
44
|
END
|
45
45
|
}
|
46
46
|
|
47
|
-
let(:result) {
|
47
|
+
let(:result) { meta_to_hash(sample) }
|
48
48
|
|
49
49
|
it "returns proper type for result" do
|
50
50
|
result.must_be_instance_of Hash
|
@@ -62,31 +62,31 @@ describe EbookRenamer do
|
|
62
62
|
|
63
63
|
context "#sanitize_filename" do
|
64
64
|
it "must be defined" do
|
65
|
-
|
65
|
+
must_respond_to :sanitize_filename
|
66
66
|
end
|
67
67
|
|
68
68
|
it "replaces multiple valid chars with one" do
|
69
|
-
|
69
|
+
sanitize_filename('Valid- -fil3_name......___ .txt').must_equal('Valid.fil3.name.txt')
|
70
70
|
end
|
71
71
|
|
72
72
|
it "replaces multiple valid chars with one" do
|
73
|
-
|
73
|
+
sanitize_filename('valid filename_.txt').must_equal('valid.filename.txt')
|
74
74
|
end
|
75
75
|
|
76
76
|
it "uses sepc_char correctly" do
|
77
|
-
|
77
|
+
sanitize_filename('valid.file name.txt','_').must_equal('valid_file_name.txt')
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
context '#which' do
|
82
82
|
describe 'valid executable' do
|
83
83
|
it 'works with valid executable' do
|
84
|
-
|
84
|
+
which('ruby').wont_be_nil
|
85
85
|
end
|
86
86
|
end
|
87
87
|
describe 'invalid executable' do
|
88
88
|
it 'works with invalid executable' do
|
89
|
-
|
89
|
+
which('@not-a-valid-executable!').must_be_nil
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
@@ -94,29 +94,29 @@ describe EbookRenamer do
|
|
94
94
|
context '#formatted_name' do
|
95
95
|
describe 'invalid parameters' do
|
96
96
|
it 'raises exception on nil arguments' do
|
97
|
-
-> {
|
97
|
+
-> { formatted_name({}, nil)}.must_raise ArgumentError
|
98
98
|
end
|
99
99
|
it 'returns nil on empty hash' do
|
100
|
-
|
100
|
+
formatted_name({}, {}).must_be_empty
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
104
|
describe 'valid parameters' do
|
105
105
|
it 'returns result based on single key' do
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
formatted_name({'title' => 'The Firm',
|
107
|
+
'author' => 'John Grisham',
|
108
|
+
'page count' => 399 },
|
109
|
+
keys: ['title']).must_equal 'The Firm'
|
110
110
|
end
|
111
111
|
|
112
112
|
it 'returns result based for multiple keys' do
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
113
|
+
formatted_name({'title' => 'The Firm',
|
114
|
+
'author' => 'John Grisham',
|
115
|
+
'page count' => '399' },
|
116
|
+
sep_char: ':',
|
117
|
+
keys: ['title',
|
118
|
+
'author',
|
119
|
+
'page count']).must_equal 'The Firm:John Grisham:399'
|
120
120
|
end
|
121
121
|
end
|
122
122
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ebook_renamer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burin Choomnuan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
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'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: minitest-spec-context
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,19 +184,15 @@ files:
|
|
170
184
|
- bin/ebook_renamer
|
171
185
|
- ebook_renamer.gemspec
|
172
186
|
- lib/ebook_renamer.rb
|
173
|
-
- lib/ebook_renamer/
|
174
|
-
- lib/ebook_renamer/
|
175
|
-
- lib/ebook_renamer/helpers.rb
|
187
|
+
- lib/ebook_renamer/core_ext/hash.rb
|
188
|
+
- lib/ebook_renamer/helper.rb
|
176
189
|
- lib/ebook_renamer/logger.rb
|
177
|
-
- lib/ebook_renamer/options.rb
|
178
190
|
- lib/ebook_renamer/version.rb
|
179
191
|
- test/fixtures/ebooks/demo1.pdf
|
180
192
|
- test/fixtures/ebooks/demo2.epub
|
181
193
|
- test/fixtures/ebooks/subdir/demo3.pdf
|
182
194
|
- test/fixtures/ebooks/subdir/demo4.epub
|
183
|
-
- test/lib/ebook_renamer/configuration_test.rb
|
184
195
|
- test/lib/ebook_renamer/helpers_test.rb
|
185
|
-
- test/lib/ebook_renamer/version_test.rb
|
186
196
|
- test/test_helper.rb
|
187
197
|
homepage: https://github.com/agilecreativity/ebook_renamer
|
188
198
|
licenses:
|
@@ -214,8 +224,6 @@ test_files:
|
|
214
224
|
- test/fixtures/ebooks/demo2.epub
|
215
225
|
- test/fixtures/ebooks/subdir/demo3.pdf
|
216
226
|
- test/fixtures/ebooks/subdir/demo4.epub
|
217
|
-
- test/lib/ebook_renamer/configuration_test.rb
|
218
227
|
- test/lib/ebook_renamer/helpers_test.rb
|
219
|
-
- test/lib/ebook_renamer/version_test.rb
|
220
228
|
- test/test_helper.rb
|
221
229
|
has_rdoc:
|
data/lib/ebook_renamer/cli.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module EbookRenamer
|
2
|
-
class CLI
|
3
|
-
|
4
|
-
attr_accessor :config
|
5
|
-
|
6
|
-
# Constructor for the class
|
7
|
-
#
|
8
|
-
# @param [Configuration] config the configuration class
|
9
|
-
def initialize(config = Configuration.new)
|
10
|
-
@config = config
|
11
|
-
end
|
12
|
-
|
13
|
-
# Rename the file from the given directory
|
14
|
-
# Using the with the argurment options as follow
|
15
|
-
# :recursive - perform the rename recursively (true|false)
|
16
|
-
# :commit - make the rename permanent (true|false)
|
17
|
-
# :exts - list of extensions to be processed default to ['epub,mobi,pdf']
|
18
|
-
#
|
19
|
-
# @param base_dir [String] base directory default to current directory
|
20
|
-
# @param args [Hash<Symbol, Object>] options argument
|
21
|
-
def rename(base_dir = Dir.pwd, args = {})
|
22
|
-
options = {
|
23
|
-
recursive: false,
|
24
|
-
commit: false,
|
25
|
-
exts: %w(epub mobi pdf).join(",")
|
26
|
-
}.merge(args)
|
27
|
-
|
28
|
-
input_files = Helpers.files(base_dir, options).sort
|
29
|
-
|
30
|
-
unless options[:commit]
|
31
|
-
puts "Changes will not be applied without the --commit option."
|
32
|
-
end
|
33
|
-
|
34
|
-
input_files.each do |file|
|
35
|
-
extension = File.extname(file)
|
36
|
-
begin
|
37
|
-
hash = Helpers.meta_to_hash(Helpers.meta(file, config.meta_binary))
|
38
|
-
formatted_name = Helpers.formatted_name(hash, sep_char: " by ")
|
39
|
-
formatted_name = "#{formatted_name}#{extension}"
|
40
|
-
new_name = "#{File.dirname(file)}/#{Helpers.sanitize_filename(formatted_name, config.sep_string)}"
|
41
|
-
puts "[#{file}] -> [#{new_name}]"
|
42
|
-
|
43
|
-
# TODO: handle this properly!
|
44
|
-
# skip if the filename is too long '228'
|
45
|
-
# see: https://github.com/rails/rails/commit/ad95a61b62e70b839567c2e91e127fc2a1acb113
|
46
|
-
max_allowed_file_size = 220
|
47
|
-
if new_name && new_name.size > max_allowed_file_size
|
48
|
-
puts "FYI: skip file name too long [#{new_name.size}] : #{new_name}"
|
49
|
-
next
|
50
|
-
end
|
51
|
-
|
52
|
-
FileUtils.mv(file,new_name) if options[:commit] && file != new_name && new_name.size < max_allowed_file_size
|
53
|
-
rescue RuntimeError => e
|
54
|
-
puts e.backtrace
|
55
|
-
next
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module EbookRenamer
|
2
|
-
class Configuration
|
3
|
-
# the separator char for each word in the file name
|
4
|
-
attr_accessor :meta_binary
|
5
|
-
|
6
|
-
# the separator char for each word in the file name
|
7
|
-
attr_accessor :sep_string
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@meta_binary = 'ebook-meta'
|
11
|
-
@sep_string = '.'
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class << self
|
16
|
-
attr_writer :configuration
|
17
|
-
|
18
|
-
def configuration
|
19
|
-
@configuration ||= Configuration.new
|
20
|
-
end
|
21
|
-
|
22
|
-
def reset
|
23
|
-
@configuration = Configuration.new
|
24
|
-
end
|
25
|
-
|
26
|
-
def configure
|
27
|
-
yield(configuration)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,175 +0,0 @@
|
|
1
|
-
require 'open3'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'shellwords'
|
4
|
-
|
5
|
-
module EbookRenamer
|
6
|
-
class Helpers
|
7
|
-
|
8
|
-
EbookMetaNotInstall = Class.new(StandardError)
|
9
|
-
|
10
|
-
class << self
|
11
|
-
|
12
|
-
# Extract meta data from the input file using the ebook-meta tool
|
13
|
-
#
|
14
|
-
# @param [String] filename the input file name
|
15
|
-
# @param [String] binary the executable for use to extract the metadata
|
16
|
-
# @return [String] result of the output from running the command
|
17
|
-
def meta(filename, binary = 'ebook-meta')
|
18
|
-
raise EbookMetaNotInstall, "Need to install ebook-meta to use this gem" if which(binary).nil?
|
19
|
-
command = [
|
20
|
-
binary,
|
21
|
-
Shellwords.escape(filename)
|
22
|
-
]
|
23
|
-
|
24
|
-
stdout_str, stderr_str, status = Open3.capture3(command.join(" "))
|
25
|
-
raise "Problem processing #{filename}" unless status.success?
|
26
|
-
stdout_str
|
27
|
-
end
|
28
|
-
|
29
|
-
# Convert the output string to hash
|
30
|
-
#
|
31
|
-
# @param [String] text output string from the 'ebook-meta' command
|
32
|
-
# @return [Hash<String,String>] hash pair for the input string
|
33
|
-
def meta_to_hash(text)
|
34
|
-
hash = {}
|
35
|
-
return hash if text.nil?
|
36
|
-
result_list = []
|
37
|
-
|
38
|
-
text.split(/\n/).each do |meta|
|
39
|
-
# split by the first ':' string
|
40
|
-
list = meta.split /^(.*?):/
|
41
|
-
|
42
|
-
# ignore the empty string element
|
43
|
-
list.delete_at(0)
|
44
|
-
|
45
|
-
unless list.empty?
|
46
|
-
list.map(&:strip!)
|
47
|
-
# downcase the first item to make it easy
|
48
|
-
result_list << [list[0].downcase, list[1]]
|
49
|
-
hash = Hash[*result_list.flatten]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
hash
|
53
|
-
end
|
54
|
-
|
55
|
-
# Clean the filename to remove the special characters
|
56
|
-
#
|
57
|
-
# @param [String] filename input file
|
58
|
-
# @param [String] sep_char separator character to use
|
59
|
-
#
|
60
|
-
# @return [String] the new file name with special characters replaced or removed.
|
61
|
-
def sanitize_filename(filename, sep_char = nil)
|
62
|
-
dot = "."
|
63
|
-
|
64
|
-
# Note exclude the '.' (dot)
|
65
|
-
filename.gsub!(/[^0-9A-Za-z\-_ ]/, dot)
|
66
|
-
|
67
|
-
# replace multiple occurrences of a given char with a dot
|
68
|
-
['-','_',' '].each do |c|
|
69
|
-
filename.gsub!(/#{Regexp.quote(c)}+/, dot)
|
70
|
-
end
|
71
|
-
|
72
|
-
# replace multiple occurrence of dot with one dot
|
73
|
-
filename.gsub!(/#{Regexp.quote(dot)}+/, dot)
|
74
|
-
|
75
|
-
if sep_char
|
76
|
-
# File.basename("demo.txt", ".*") #=> "demo"
|
77
|
-
name_only = File.basename(filename, ".*")
|
78
|
-
# File.extname("demo.txt") #=> ".txt"
|
79
|
-
ext_only = File.extname(filename)
|
80
|
-
name_only.gsub!(/#{Regexp.quote(dot)}+/, sep_char)
|
81
|
-
return "#{name_only}#{ext_only}"
|
82
|
-
end
|
83
|
-
|
84
|
-
filename.strip
|
85
|
-
end
|
86
|
-
|
87
|
-
# Cross-platform way of finding an executable in the $PATH.
|
88
|
-
#
|
89
|
-
# @param command [String] the command to look up
|
90
|
-
# @return [String, NilClass] full path to the executable file or nil if the
|
91
|
-
# executable is not valid or available.
|
92
|
-
# Example:
|
93
|
-
# which('ruby') #=> /usr/bin/ruby
|
94
|
-
# which('bad-executable') #=> nil
|
95
|
-
def which(command)
|
96
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
97
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
98
|
-
exts.each { |ext|
|
99
|
-
exe = File.join(path, "#{command}#{ext}")
|
100
|
-
return exe if File.executable? exe
|
101
|
-
}
|
102
|
-
end
|
103
|
-
return nil
|
104
|
-
end
|
105
|
-
|
106
|
-
# Return formatted file name using the metadata values
|
107
|
-
#
|
108
|
-
# @param [Hash<Symbol,String>] meta_hash output from the program 'ebook-meta' or 'exiftoo'
|
109
|
-
# @param [Hash<Symbol,String>] fields list of fields that will be used to set the name
|
110
|
-
def formatted_name(meta_hash = {}, fields = {})
|
111
|
-
if hash.nil? || fields.nil?
|
112
|
-
raise ArgumentError.new("Argument must not be nil")
|
113
|
-
end
|
114
|
-
|
115
|
-
# The keys that we get from the 'mdls' or 'exiftool'
|
116
|
-
args = {
|
117
|
-
keys: ['title',
|
118
|
-
'author(s)'],
|
119
|
-
sep_char: ' '
|
120
|
-
}.merge(fields)
|
121
|
-
|
122
|
-
keys = args[:keys]
|
123
|
-
sep_char = args[:sep_char]
|
124
|
-
|
125
|
-
# Note: only show if we have the value for title
|
126
|
-
result = []
|
127
|
-
if meta_hash.fetch('title', nil)
|
128
|
-
keys.each do |k|
|
129
|
-
value = meta_hash.fetch(k, nil)
|
130
|
-
# Note: don't add 'Author(s)' => 'Unknown' to keep the result clean
|
131
|
-
if value && value.downcase != 'unknown'
|
132
|
-
result << meta_hash[k]
|
133
|
-
end
|
134
|
-
end
|
135
|
-
return result.join(sep_char)
|
136
|
-
end
|
137
|
-
# Note: if no title we choose to return empty value for result
|
138
|
-
return ""
|
139
|
-
end
|
140
|
-
|
141
|
-
# Ensure that the values in hash are sanitized
|
142
|
-
#
|
143
|
-
# @param [Hash<Symbol,String>] hash input hash to be sanitized
|
144
|
-
# @return [Hash<Symbol,String>] original hash with values sanitized
|
145
|
-
# @see #sanitize_filename
|
146
|
-
def sanitize_values(hash = {})
|
147
|
-
hash.each do |key, value|
|
148
|
-
hash[key] = sanitize_filename(value, " ")
|
149
|
-
end
|
150
|
-
hash
|
151
|
-
end
|
152
|
-
|
153
|
-
# List files base on given options
|
154
|
-
# options:
|
155
|
-
# :recursive - process the directory recursively (default false)
|
156
|
-
# :exts - list of extensions to be search (default ['epub','mobi','pdf'])
|
157
|
-
#
|
158
|
-
# @param base_dir [String] the starting directory
|
159
|
-
# @param options [Hash<Symbol,Object>] the options to be used
|
160
|
-
# @return [List<String>] list of matching files or empty list if none are found
|
161
|
-
def files(base_dir = Dir.pwd, options = {})
|
162
|
-
args = {
|
163
|
-
recursive: false,
|
164
|
-
exts: %w(epub mobi pdf).join(',')
|
165
|
-
}.merge(options)
|
166
|
-
|
167
|
-
raise ArgumentError.new("Invalid directory #{base_dir}") unless File.directory?(base_dir)
|
168
|
-
|
169
|
-
wildcard = args[:recursive] ? '**' : ''
|
170
|
-
patterns = File.join(base_dir, wildcard, "*.{#{args[:exts]}}")
|
171
|
-
Dir.glob(patterns) || []
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
|
-
module EbookRenamer::Options
|
4
|
-
|
5
|
-
def parse_options()
|
6
|
-
options = {}
|
7
|
-
|
8
|
-
option_parser = OptionParser.new do |opts|
|
9
|
-
opts.banner = <<-END.gsub(/^\s+\|/, '')
|
10
|
-
|
|
11
|
-
| Usage: ebook_renamer [options]
|
12
|
-
|
|
13
|
-
| Examples:
|
14
|
-
|
|
15
|
-
| 1) $ebook_renamer
|
16
|
-
|
|
17
|
-
| 2) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
18
|
-
|
|
19
|
-
| 3) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
20
|
-
| --recursive
|
21
|
-
|
|
22
|
-
| 4) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
23
|
-
| --recursive
|
24
|
-
|
|
25
|
-
| 5) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
26
|
-
| --recursive
|
27
|
-
| --commit
|
28
|
-
|
|
29
|
-
| 6) $ebook_renamer --base-dir ~/Dropbox/ebooks
|
30
|
-
| --recursive
|
31
|
-
| --commit
|
32
|
-
|
|
33
|
-
| Options:
|
34
|
-
|
|
35
|
-
END
|
36
|
-
|
37
|
-
options[:base_dir] ||= Dir.pwd
|
38
|
-
opts.on('-b', '--base-dir directory', 'Starting directory [default - current directory]') do |base_dir|
|
39
|
-
options[:base_dir] = base_dir
|
40
|
-
end
|
41
|
-
|
42
|
-
options[:sep_string] ||= '.'
|
43
|
-
opts.on('-s', '--sep-string string', "Separator string [default - '.']") do |sep_string|
|
44
|
-
options[:sep_string] = sep_string
|
45
|
-
end
|
46
|
-
|
47
|
-
options[:recursive] = false
|
48
|
-
opts.on('-r', '--recursive', 'Process the files recursively [default - false]') do
|
49
|
-
options[:recursive] = true
|
50
|
-
end
|
51
|
-
|
52
|
-
options[:commit] = false
|
53
|
-
opts.on('-c', '--commit', 'Perform the actual rename [default - false]') do
|
54
|
-
options[:commit] = true
|
55
|
-
end
|
56
|
-
|
57
|
-
opts.on('-v', '--version', 'Display version number') do
|
58
|
-
puts EbookRenamer::VERSION
|
59
|
-
exit 0
|
60
|
-
end
|
61
|
-
|
62
|
-
opts.on('-h', '--help', 'Display this screen') do
|
63
|
-
puts opts
|
64
|
-
exit 0
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
option_parser.parse!
|
69
|
-
options
|
70
|
-
end
|
71
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require_relative '../../test_helper'
|
2
|
-
describe EbookRenamer do
|
3
|
-
|
4
|
-
before :each do
|
5
|
-
EbookRenamer.configure do |config|
|
6
|
-
config.meta_binary = 'ebook-meta'
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
after :each do
|
11
|
-
EbookRenamer.reset
|
12
|
-
end
|
13
|
-
|
14
|
-
it "uses the updated configuration" do
|
15
|
-
EbookRenamer.configuration.meta_binary.must_equal 'ebook-meta'
|
16
|
-
config = EbookRenamer.configure do |config|
|
17
|
-
config.meta_binary = "new-ebook-meta"
|
18
|
-
end
|
19
|
-
EbookRenamer.configuration.meta_binary.must_equal 'new-ebook-meta'
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|