ebook_renamer 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|