filter_rename 1.0.0

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.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # FilterRename
2
+
3
+ FilterRename is a CLI tool created to rename a bunch of files at once applying a cascade of
4
+ self-explainatory options called _filters_, in order to substitute all the other shell commands
5
+ (like _sed_, _awk_, _trim_, ... ) and personal shell script to achieve that goal safely and
6
+ in comfortable manner.
7
+
8
+ To simplify the whole process through a command line, the full filename is logically organized
9
+ in _targets_ like:
10
+
11
+ <path>/<folder>/<name><ext>
12
+
13
+ Considering the file `/home/fabio/Documents/Ruby/filter_rename/Gemfile.lock` we have:
14
+
15
+ - path: */home/fabio/Documents/Ruby*
16
+ - folder: *filter_rename*
17
+ - name: *Gemfile*
18
+ - ext: *.lock*
19
+
20
+ The chain of filters will be applied to the current _target_ which can be selected using the *--select*
21
+ option, the default target is _name_.
22
+
23
+ ## Installation
24
+
25
+ Install it yourself as:
26
+
27
+ $ gem install filter_rename
28
+
29
+ ## Usage
30
+
31
+ The main concept about FilterRename is the _target_ manipulation with a chain of _filters_
32
+ executed one by one as they appear in the argument's list.
33
+
34
+ There are three main operations:
35
+ * _preview_: show the results without make any change (default);
36
+ * _dry-run_: executes a simulation warning when a conflict is raised;
37
+ * _apply_: confirm the changes and rename the files unless the destination file exists.
38
+
39
+ Having the files:
40
+
41
+ home
42
+ fabio
43
+ Documents
44
+ Photos
45
+ Vacations
46
+ image_portofino_1.jpg
47
+ image_portofino_2.jpg
48
+ image_portofino_3.jpg
49
+ ...
50
+
51
+ to replace _underscores_ with _spaces_ and _capitalize_ each word let's execute:
52
+
53
+ filter_rename /home/fabio/Documents/Photos/Vacations/*.jpg --spacify '_' --capitalize --apply
54
+
55
+ and the result will be:
56
+
57
+ home
58
+ fabio
59
+ Documents
60
+ Photos
61
+ Vacations
62
+ Image Portofino 1.jpg
63
+ Image Portofino 2.jpg
64
+ Image Portofino 3.jpg
65
+ ...
66
+
67
+
68
+ ## Get help
69
+
70
+ Where to start
71
+
72
+ $ filter_rename --help
73
+
74
+ More help
75
+
76
+ - The wiki page: https://github.com/fabiomux/filter_rename/wiki
77
+
78
+
79
+ ## Contributing
80
+
81
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fabio_mux/filter_rename. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
82
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "filter_rename"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/filter_rename ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'filter_rename/cli'
4
+
5
+ FilterRename::CLI.start
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'filter_rename/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "filter_rename"
8
+ spec.version = FilterRename::VERSION
9
+ spec.authors = ["Fabio Mucciante"]
10
+ spec.email = ["fabio.mucciante@gmail.com"]
11
+
12
+ spec.summary = %q{Rename filenames through a chain of filter.}
13
+ spec.description = %q{Rename filenames applying a cascade of commands called filters in specified portion of it called targets.}
14
+ spec.homepage = "https://github.com/fabiomux/filter_rename"
15
+ spec.license = "GPL-3.0"
16
+
17
+ spec.metadata = {
18
+ "bug_tracker_uri" => "https://github.com/fabiomux/filter_rename/issues",
19
+ #"changelog_uri" => "",
20
+ "documentation_uri" => "https://www.rubydoc.info/gems/filter_rename/#{spec.version}",
21
+ "homepage_uri" => "https://github.com/fabiomux/filter_rename",
22
+ #"mailing_list_uri" => "",
23
+ "source_code_uri" => "https://github.com/fabiomux/filter_rename",
24
+ "wiki_uri" => "https://github.com/fabiomux/filter_rename/wiki"
25
+ }
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
+ f.match(%r{^(test|spec|features)/})
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_development_dependency "bundler", "~> 2.0"
35
+ spec.add_development_dependency "rake", "~> 13.0"
36
+ spec.add_development_dependency "rspec", "~> 3.0"
37
+
38
+ spec.add_runtime_dependency "mp3info"
39
+ spec.add_runtime_dependency "mimemagic"
40
+ spec.add_runtime_dependency "differ"
41
+ spec.add_runtime_dependency "exiv2"
42
+ spec.add_runtime_dependency "fastimage"
43
+ spec.add_runtime_dependency "pdf-reader"
44
+ end
@@ -0,0 +1,137 @@
1
+ require 'fileutils'
2
+ require 'filter_rename/version'
3
+ require 'filter_rename/config'
4
+ require 'filter_rename/filter_base'
5
+ require 'filter_rename/filters'
6
+ require 'filter_rename/filter_pipe'
7
+ require 'filter_rename/filename'
8
+ require 'filter_rename/filename_factory'
9
+ require 'filter_rename/utils'
10
+
11
+ module FilterRename
12
+
13
+ class Builder
14
+
15
+ def initialize(options)
16
+ @cfg = Config.new(options.global)
17
+ @filters = FilterList.new(options.filters)
18
+ @files = options.files
19
+ @show_macro = options.show_macro
20
+ end
21
+
22
+ def preview
23
+ raise MissingFiles if @files.empty?
24
+
25
+ @filters.expand_macros!(@cfg.macro)
26
+
27
+ Messages.label "Preview:"
28
+
29
+ @files.each do |src|
30
+ fp = FilterPipe.new(src, @filters, @cfg).apply
31
+ Messages.diff(fp)
32
+ end
33
+ end
34
+
35
+ def apply
36
+ raise MissingFiles if @files.empty?
37
+
38
+ @filters.expand_macros!(@cfg.macro)
39
+
40
+ Messages.label "Apply:"
41
+ @files.each do |src|
42
+
43
+ fp = FilterPipe.new(src, @filters, @cfg).apply
44
+
45
+ if fp.changed?
46
+ old_data = fp.rename!
47
+
48
+ if old_data[:full_filename]
49
+ Messages.renamed!(old_data, fp.dest)
50
+ Messages.changed_tags(fp, old_data, false) if fp.source.class.has_writable_tags
51
+ else
52
+ Messages.changed_tags(fp, old_data)
53
+ end
54
+
55
+ else
56
+ Messages.skipping(fp)
57
+ end
58
+ end
59
+ end
60
+
61
+ def globals
62
+ Messages.label 'Global configurations:'
63
+ Messages.config_list @cfg.global
64
+ end
65
+
66
+ def configs
67
+ Messages.label 'Filter\'s configurations:'
68
+ Messages.config_list @cfg.filter
69
+ end
70
+
71
+ def words
72
+ Messages.label 'Groups and subgroups of words available for translation:'
73
+ Messages.config_multilist @cfg.words
74
+ end
75
+
76
+ def dry_run
77
+ raise MissingFiles if @files.empty?
78
+
79
+ @filters.expand_macros!(@cfg.macro)
80
+ cache = []
81
+
82
+ Messages.label "Dry Run:"
83
+ @files.each do |src|
84
+
85
+ fp = FilterPipe.new(src, @filters, @cfg).apply
86
+
87
+ if fp.unchanged?
88
+ Messages.skipping(fp)
89
+ elsif (cache.include?(fp.dest.full_filename) || fp.dest.exists?)
90
+ if fp.source.full_filename == fp.dest.full_filename
91
+ Messages.changed_tags(fp)
92
+ else
93
+ Messages.file_exists(fp)
94
+ end
95
+ else
96
+ Messages.renamed(fp)
97
+ Messages.changed_tags(fp, {}, false) if fp.source.class.has_writable_tags
98
+ cache << fp.dest.full_filename
99
+ end
100
+ end
101
+ end
102
+
103
+ def targets
104
+ raise MissingFiles if @files.empty?
105
+
106
+ Messages.label 'Targets:'
107
+ @files.each do |src|
108
+
109
+ fname = FilenameFactory.create(src, @cfg.global)
110
+
111
+ Messages.multi fname.full_filename
112
+ Messages.send(@cfg.global.targets == :short ? :short_targets : :long_targets, fname)
113
+ end
114
+ end
115
+
116
+ def macros
117
+ Messages.label 'Macros:'
118
+ Messages.list @cfg.macro.get_macros
119
+ end
120
+
121
+ def show_macro
122
+ Messages.label "Macro: #{@show_macro}"
123
+ macro = @cfg.macro.get_macro(@show_macro)
124
+ if macro.class == Array
125
+ macro.each do |k|
126
+ Messages.item k.keys.first.to_s + ': ' + k.values.first.map { |x| '"' + x.to_s.green + '"' }.join(',')
127
+ end
128
+ elsif macro.class == Hash
129
+ macro.each do |k, v|
130
+ Messages.item k.to_s + ': ' + v.map { |x| '"' + x.to_s.green + '"' }.join(', ')
131
+ end
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+ end
@@ -0,0 +1,165 @@
1
+ ---
2
+ :global:
3
+ :hash_type: :none
4
+ :date_format: '%Y-%m-%d'
5
+ :counter_length: 3
6
+ :counter_start: 0
7
+ :targets: :short
8
+ :pdf_metadata: false
9
+ :image_metadata: false
10
+ :filter:
11
+ :lang: :en
12
+ :word_separator: " "
13
+ :target: :name
14
+ :ignore_case: true
15
+ :grep: '.*'
16
+ :grep_on: :source
17
+ :grep_exclude: false
18
+ # full_filename, :full_path, :filename, <target>
19
+ :grep_target: :full_filename
20
+ :words:
21
+ :shortcut:
22
+ :short: ['Vol', 'Num']
23
+ :long: ['Volume', 'Number']
24
+ :general:
25
+ :en: ['Hello']
26
+ :it: ['Ciao']
27
+ :fr: ['Salut']
28
+ :es: ['Hola']
29
+ :pt: ['Olá']
30
+ :short_months:
31
+ :en: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
32
+ :it: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
33
+ :fr: ['Janv', 'Févr', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil', 'Août|Aout', 'Sept', 'Oct', 'Nov', 'Déc|Dec']
34
+ :es: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic']
35
+ :pt: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
36
+ :de: ['Jan', 'Feb', 'Mär|Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
37
+ :hr: ['Sij', 'Vel', 'Ožu|Ozu', 'Tra', 'Svi', 'Lip', 'Srp', 'Kol', 'Ruj', 'Lis', 'Stu', 'Pro']
38
+ :long_months:
39
+ :en: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
40
+ :it: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre']
41
+ :fr: ['Janvier', 'Février|Fevrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août|Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre|Decembre']
42
+ :es: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']
43
+ :pt: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro']
44
+ :de: ['Januar[^y]', 'Februar[^y]', 'März|Marz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']
45
+ :hr: ['Siječanj|Sijecanj', 'Veljača|Veljaca', 'Ožujak|Ozujak', 'Travanj', 'Svibanj', 'Lipanj', 'Srpanj', 'Kolovoz', 'Rujan', 'Listopad', 'Studeni', 'Prosinac']
46
+ :short_days:
47
+ :en: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
48
+ :it: ['Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom']
49
+ :fr: ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim']
50
+ :es: ['Lun', 'Mar', 'Mié|Mie', 'Jue', 'Vie', 'Sáb|Sab', 'Dom']
51
+ :pt: ['Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb|Sab', 'Dom']
52
+ :de: ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
53
+ :hr: ['Pon', 'Uto', 'Sri', 'čet|cet', 'Pet', 'Sub', 'Ned']
54
+ :long_days:
55
+ :en: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
56
+ :it: ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato', 'Domenica']
57
+ :fr: ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche']
58
+ :es: ['Lunes', 'Martes', 'Miércoles|Miercoles', 'Jueves', 'Viernes', 'Sábado|Sabado', 'Domingo']
59
+ :pt: ['Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado|Sabado', 'Domingo']
60
+ :de: ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag']
61
+ :hr: ['Ponedjeljak', 'Utorak', 'Srijeda', 'četvrtak|Cetvrtak', 'Petak', 'Subota', 'Nedjelja']
62
+
63
+ :macro:
64
+ humanize:
65
+ -
66
+ :spacify:
67
+ - '_'
68
+ - "\\."
69
+ -
70
+ :squeeze:
71
+ - ' '
72
+ -
73
+ :translate_words:
74
+ - :long_months
75
+ - :it
76
+ - :en
77
+ -
78
+ :translate_words:
79
+ - :long_months
80
+ - :es
81
+ - :en
82
+ -
83
+ :translate_words:
84
+ - :long_months
85
+ - :fr
86
+ - :en
87
+ -
88
+ :translate_words:
89
+ - :long_months
90
+ - :de
91
+ - :en
92
+ -
93
+ :translate_words:
94
+ - :long_months
95
+ - :hr
96
+ - :en
97
+ -
98
+ :translate_words:
99
+ - :long_months
100
+ - :pt
101
+ - :en
102
+ -
103
+ :replace_date:
104
+ - '<B> <Y>'
105
+ - '<Y>-<m>'
106
+ -
107
+ :replace:
108
+ - ' ,[ ]*'
109
+ - ', '
110
+ -
111
+ :replace:
112
+ - '([a-z]) - ([0-9])'
113
+ - '\1 \2'
114
+ append_issue:
115
+ :move_to:
116
+ - '(Issue|Volume) ([0-9]+)'
117
+ - 'tmp'
118
+ :template:
119
+ - '<name> #<tmp>'
120
+ :delete:
121
+ - ' #$'
122
+ :squeeze:
123
+ - ' '
124
+ file_to_id3:
125
+ -
126
+ :copy_to:
127
+ - "([^-]+) -"
128
+ - "artist"
129
+ -
130
+ :copy_to:
131
+ - "- ([^-]+)"
132
+ - "title"
133
+ id3_to_file:
134
+ :template:
135
+ - "<artist> - <title>"
136
+ remove_id3_comments:
137
+ :select:
138
+ - "comments"
139
+ :set:
140
+ - ''
141
+ camels_to_words:
142
+ -
143
+ :config:
144
+ - ignore_case:false
145
+ -
146
+ :replace:
147
+ - "([A-Z])([a-z!']+)"
148
+ - " \\1\\2 "
149
+ -
150
+ :replace:
151
+ - '\( +'
152
+ - '('
153
+ -
154
+ :replace:
155
+ - ' +\)'
156
+ - ')'
157
+ -
158
+ :squeeze:
159
+ - " "
160
+ -
161
+ :trim: []
162
+ remove_dash_separator:
163
+ :replace:
164
+ - '([a-z]) - ([0-9])'
165
+ - '\1 \2'