phtools 0.1.3 → 0.2.4
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/exe/phls +36 -0
- data/lib/pharrange.rb +13 -0
- data/lib/phbackup.rb +13 -0
- data/lib/phclname.rb +13 -0
- data/lib/phevent.rb +13 -0
- data/lib/phfixdate.rb +13 -0
- data/lib/phfixfmd.rb +13 -0
- data/lib/phls.rb +45 -0
- data/lib/phmtags.rb +13 -0
- data/lib/phrename.rb +13 -0
- data/lib/phtagset.rb +13 -0
- data/lib/phtools/error.rb +33 -0
- data/lib/phtools/ph_file.rb +226 -0
- data/lib/phtools/runner.rb +83 -0
- data/lib/phtools/utils/os.rb +25 -0
- data/lib/phtools/utils/os_unix.rb +15 -0
- data/lib/phtools/utils/os_win.rb +17 -0
- data/lib/phtools/utils/ruby_version.rb +13 -0
- data/lib/phtools/version.rb +1 -1
- data/lib/phtools.rb +27 -2
- data/phtools.gemspec +1 -1
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2b4a9e0f8e817daa66178993aa0d7338cc4640f
|
4
|
+
data.tar.gz: d5ebce5d0aa61183a4e018ae04c2d59b20673980
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb219b0a0dca4df74ce3ac11af40ce59893076a6c8c0c353d14e4951c97233aad4da2f50fb0cde74c26042aca13dc14fccc4ce60fad66c1d03ea2f1cf39960c6
|
7
|
+
data.tar.gz: 702e6dd55560a82cc537589a830c610f17c90be5f03ff4c2c6347b364f8f0ca31af867e9722bf63332da4b90fdb959d13031c657586857625bcf8b3bc5659684
|
data/exe/phls
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
module PhTools
|
6
|
+
tool_name = File.basename(__FILE__)
|
7
|
+
require "#{tool_name}"
|
8
|
+
|
9
|
+
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
10
|
+
usage = <<DOCOPT
|
11
|
+
***************************************************
|
12
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
13
|
+
***************************************************
|
14
|
+
#{tool_name} scans given directories and
|
15
|
+
generates list of files to standard output.
|
16
|
+
In short it acts like a smart 'ls' command (or 'dir' in Windows).
|
17
|
+
It is a good starting point for all other phtools to be used with pipes.
|
18
|
+
phtools friendly files: #{file_type * ','}
|
19
|
+
|
20
|
+
Example: #{tool_name} -r abc |ftclname => recursively scans 'abc' dir and
|
21
|
+
sends all found phtools friendly files to ftclname command.
|
22
|
+
|
23
|
+
Usage:
|
24
|
+
#{tool_name} [-D] [-r] [DIR_OR_FILE...]
|
25
|
+
#{tool_name} -h | --help
|
26
|
+
#{tool_name} -v | --version
|
27
|
+
|
28
|
+
Options:
|
29
|
+
-D --debug Turn on debugging (verbose) mode
|
30
|
+
-r --recursive Recursively scan directories
|
31
|
+
-h --help Show this screen.
|
32
|
+
-v --version Show version.
|
33
|
+
DOCOPT
|
34
|
+
|
35
|
+
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
36
|
+
end
|
data/lib/pharrange.rb
ADDED
data/lib/phbackup.rb
ADDED
data/lib/phclname.rb
ADDED
data/lib/phevent.rb
ADDED
data/lib/phfixdate.rb
ADDED
data/lib/phfixfmd.rb
ADDED
data/lib/phls.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
require 'phtools/runner'
|
6
|
+
|
7
|
+
module PhTools
|
8
|
+
# list generation
|
9
|
+
class Phls < Runner
|
10
|
+
def self.about
|
11
|
+
%Q{generates list of phtools friendly files}
|
12
|
+
end
|
13
|
+
|
14
|
+
def run!
|
15
|
+
@options_cli['DIR_OR_FILE'] = ['.'] if @options_cli['DIR_OR_FILE'].empty?
|
16
|
+
@options_cli['DIR_OR_FILE'].each do |item|
|
17
|
+
if File.exist?(item)
|
18
|
+
File.directory?(item) ? output_dir(item) : output_file(item)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
rescue SignalException
|
23
|
+
PhTools.puts_error 'EXIT on user interrupt Ctrl-C'
|
24
|
+
exit 1
|
25
|
+
rescue => e
|
26
|
+
PhTools.puts_error "FATAL: #{e.message}", e
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def output_dir(item)
|
33
|
+
fmask = File.join(item, @options_cli['--recursive'] ? '**' : '',
|
34
|
+
"{#{@file_type.map { |i| "*.#{i}" } * ','}}")
|
35
|
+
files_to_process = Dir.glob(fmask, File::FNM_CASEFOLD |
|
36
|
+
File::FNM_DOTMATCH)
|
37
|
+
files_to_process.each { |f| output_file(f) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def output_file(file)
|
41
|
+
@os.output(File.join(File.dirname(file), File.basename(file))) if
|
42
|
+
@file_type.include?(File.extname(file).slice(1..-1).downcase)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/phmtags.rb
ADDED
data/lib/phrename.rb
ADDED
data/lib/phtagset.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
require 'nesty'
|
6
|
+
|
7
|
+
# Foto tools
|
8
|
+
module PhTools
|
9
|
+
@debug = false
|
10
|
+
def self.debug=(val)
|
11
|
+
@debug = val
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.debug
|
15
|
+
@debug
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.puts_error(msg, e = nil)
|
19
|
+
prefix = File.basename($PROGRAM_NAME, '.rb')
|
20
|
+
STDERR.puts "#{prefix}: #{msg}"
|
21
|
+
if @debug && !e.nil?
|
22
|
+
if e.respond_to?(:cause) && !e.cause.nil?
|
23
|
+
STDERR.puts "#{prefix}: CAUSE: #{e.cause} - #{e.cause.message}"
|
24
|
+
end
|
25
|
+
e.backtrace.each do |b|
|
26
|
+
STDERR.puts "#{prefix}: BACKTRACE: #{b}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Error < Nesty::NestedStandardError; end
|
32
|
+
class ExiftoolTagger < Error; end
|
33
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
require 'phtools/error'
|
6
|
+
require 'date'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
# Foto tools
|
10
|
+
module PhTools
|
11
|
+
# media type constants
|
12
|
+
FILE_TYPE_IMAGE_NORMAL = %w{jpg jpeg tif tiff png}
|
13
|
+
FILE_TYPE_IMAGE_RAW = %w{orf arw dng}
|
14
|
+
FILE_TYPE_IMAGE = FILE_TYPE_IMAGE_NORMAL + FILE_TYPE_IMAGE_RAW
|
15
|
+
FILE_TYPE_VIDEO = %w{avi mp4 mpg mts dv mov mkv m2t m2ts}
|
16
|
+
FILE_TYPE_AUDIO = %w{wav}
|
17
|
+
|
18
|
+
# phtools file name operations
|
19
|
+
class FTFile
|
20
|
+
include Comparable
|
21
|
+
|
22
|
+
# filename constants
|
23
|
+
NICKNAME_MIN_SIZE = 3
|
24
|
+
NICKNAME_MAX_SIZE = 6
|
25
|
+
NICKNAME_SIZE = 3 # should be in range of MIN and MAX
|
26
|
+
ZERO_DATE = DateTime.new(0)
|
27
|
+
|
28
|
+
def self.validate_file!(filename, file_type)
|
29
|
+
fail PhTools::Error, 'does not exist' unless
|
30
|
+
filename && File.exist?(filename)
|
31
|
+
fail PhTools::Error, 'not a file' if File.directory?(filename)
|
32
|
+
fail PhTools::Error, 'no permission to write' unless
|
33
|
+
File.writable_real?(filename)
|
34
|
+
fail PhTools::Error, 'unsupported type' unless
|
35
|
+
file_type.include?(File.extname(filename).slice(1..-1).downcase)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.validate_author(author)
|
39
|
+
case
|
40
|
+
when author.size != NICKNAME_SIZE
|
41
|
+
return [false, "'#{author}' wrong author size, should be #{NICKNAME_SIZE} chars long"]
|
42
|
+
when /[-_\s]/.match(author)
|
43
|
+
return [false, "'#{author}' author should not contain spaces [_- ]"]
|
44
|
+
when /[\d]/.match(author)
|
45
|
+
return [false, "'#{author}' author should not contain digits"]
|
46
|
+
when /[\W]/.match(author)
|
47
|
+
return [false, "'#{author}' author should contain only ASCII chars"]
|
48
|
+
end
|
49
|
+
[true, '']
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_reader :filename, :dirname, :extname, :basename, :basename_part,
|
53
|
+
:basename_clean, :date_time, :author
|
54
|
+
|
55
|
+
def initialize(filename)
|
56
|
+
set_state(filename)
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"#{@filename}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def <=>(other)
|
64
|
+
@filename <=> other.filename
|
65
|
+
end
|
66
|
+
|
67
|
+
def basename_standard(basename_clean: @basename_clean,
|
68
|
+
date_time: @date_time,
|
69
|
+
author: @author)
|
70
|
+
%Q{#{date_time.strftime('%Y%m%d-%H%M%S')}_#{(author.upcase + "XXXXXX")[0, NICKNAME_SIZE]} #{basename_clean}}
|
71
|
+
end
|
72
|
+
|
73
|
+
def basename_is_standard?
|
74
|
+
@basename == basename_standard
|
75
|
+
end
|
76
|
+
|
77
|
+
def standardize(dirname: @dirname, basename_clean: @basename_clean,
|
78
|
+
extname: @extname, date_time: @date_time,
|
79
|
+
author: @author)
|
80
|
+
File.join(dirname,
|
81
|
+
basename_standard(basename_clean: basename_clean,
|
82
|
+
date_time: date_time,
|
83
|
+
author: author) + extname)
|
84
|
+
end
|
85
|
+
|
86
|
+
def standardize!(dirname: @dirname, basename_clean: @basename_clean,
|
87
|
+
extname: @extname, date_time: @date_time,
|
88
|
+
author: @author)
|
89
|
+
|
90
|
+
filename = standardize(dirname: dirname, basename_clean: basename_clean,
|
91
|
+
extname: extname, date_time: date_time,
|
92
|
+
author: author)
|
93
|
+
set_state(filename)
|
94
|
+
filename
|
95
|
+
end
|
96
|
+
|
97
|
+
def cleanse(dirname: @dirname, basename_clean: @basename_clean,
|
98
|
+
extname: @extname)
|
99
|
+
File.join(dirname, basename_clean + extname)
|
100
|
+
end
|
101
|
+
|
102
|
+
def cleanse!(dirname: @dirname, basename_clean: @basename_clean,
|
103
|
+
extname: @extname)
|
104
|
+
filename = cleanse(dirname: dirname, basename_clean: basename_clean,
|
105
|
+
extname: extname)
|
106
|
+
set_state(filename)
|
107
|
+
filename
|
108
|
+
end
|
109
|
+
|
110
|
+
def dirname=(dirname = @dirname)
|
111
|
+
@dirname = dirname
|
112
|
+
@filename = File.join(@dirname, @basename + @extname)
|
113
|
+
end
|
114
|
+
|
115
|
+
def date_time_ok?
|
116
|
+
@date_time != ZERO_DATE
|
117
|
+
end
|
118
|
+
|
119
|
+
def date_time_to_time
|
120
|
+
Time.new(@date_time.year, @date_time.month, @date_time.day,
|
121
|
+
@date_time.hour, @date_time.min, @date_time.sec)
|
122
|
+
# no use of @date_time.zone - assuming file's timezone always
|
123
|
+
# equals to photografer's computer timezone
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def set_state(filename)
|
129
|
+
@dirname = File.dirname(filename)
|
130
|
+
@extname = File.extname(filename)
|
131
|
+
@basename = File.basename(filename, @extname)
|
132
|
+
@filename = File.join(@dirname, @basename + @extname)
|
133
|
+
parse_basename
|
134
|
+
@basename_clean = @basename_part[:clean]
|
135
|
+
@date_time = reveal_date_time
|
136
|
+
@author = @basename_part[:author] || ''
|
137
|
+
end
|
138
|
+
|
139
|
+
def reveal_date_time
|
140
|
+
date = @basename_part[:date]
|
141
|
+
time = @basename_part[:time]
|
142
|
+
strptime_template = ''
|
143
|
+
strptime_string = ''
|
144
|
+
case date.size
|
145
|
+
when 4 # expecting Year e.g.2001
|
146
|
+
strptime_template += '%Y'
|
147
|
+
strptime_string += date
|
148
|
+
when 8 # expecting YYmmdd e.g.20010101
|
149
|
+
strptime_template += '%Y%m%d'
|
150
|
+
strptime_string += date
|
151
|
+
end
|
152
|
+
case time.size
|
153
|
+
when 4 # expecting HHMM e.g. 1025
|
154
|
+
strptime_template += '%H%M'
|
155
|
+
strptime_string += time
|
156
|
+
when 6 # expecting YHHMMSS e.g.102559
|
157
|
+
strptime_template += '%H%M%S'
|
158
|
+
strptime_string += time
|
159
|
+
end
|
160
|
+
|
161
|
+
return ZERO_DATE if strptime_string.empty?
|
162
|
+
DateTime.strptime(strptime_string, strptime_template)
|
163
|
+
|
164
|
+
rescue ArgumentError
|
165
|
+
return ZERO_DATE
|
166
|
+
end
|
167
|
+
|
168
|
+
def parse_basename
|
169
|
+
default = { prefix: '', clean: '', date: '',
|
170
|
+
time: '', author: '', id: '', flags: '' }
|
171
|
+
case @basename
|
172
|
+
# check YYYYmmdd-HHMMSS_AUT[ID]{FLAGS}cleanname
|
173
|
+
when /^(?<prefix>(?<date>\d{8})-(?<time>\d{6})_(?<author>\w{#{NICKNAME_MIN_SIZE},#{NICKNAME_MAX_SIZE}})\[(?<id>.*)\]\{(?<flags>.*)\})(?<clean>.*)/
|
174
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
175
|
+
clean: Regexp.last_match(:clean),
|
176
|
+
date: Regexp.last_match(:date),
|
177
|
+
time: Regexp.last_match(:time),
|
178
|
+
author: Regexp.last_match(:author),
|
179
|
+
id: Regexp.last_match(:id),
|
180
|
+
flags: Regexp.last_match(:flags))
|
181
|
+
|
182
|
+
# check YYYYmmdd-HHMMSS_AUT[ID]cleanname
|
183
|
+
when /^(?<prefix>(?<date>\d{8})-(?<time>\d{6})_(?<author>\w{#{NICKNAME_MIN_SIZE},#{NICKNAME_MAX_SIZE}})\[(?<id>.*)\])(?<clean>.*)/
|
184
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
185
|
+
clean: Regexp.last_match(:clean),
|
186
|
+
date: Regexp.last_match(:date),
|
187
|
+
time: Regexp.last_match(:time),
|
188
|
+
author: Regexp.last_match(:author),
|
189
|
+
id: Regexp.last_match(:id))
|
190
|
+
# STANDARD template
|
191
|
+
# check YYYYmmdd-HHMMSS_AUT cleanname
|
192
|
+
when /^(?<prefix>(?<date>\d{8})-(?<time>\d{6})_(?<author>\w{#{NICKNAME_MIN_SIZE},#{NICKNAME_MAX_SIZE}})[-\s_])(?<clean>.*)/
|
193
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
194
|
+
clean: Regexp.last_match(:clean),
|
195
|
+
date: Regexp.last_match(:date),
|
196
|
+
time: Regexp.last_match(:time),
|
197
|
+
author: Regexp.last_match(:author))
|
198
|
+
# check if name = YYYYmmdd-HHMM_AAA_name
|
199
|
+
when /^(?<prefix>(?<date>\d{8})-(?<time>\d{4})[-\s_](?<author>\w{#{NICKNAME_MIN_SIZE},#{NICKNAME_MAX_SIZE}})[-\s_])(?<clean>.*)/
|
200
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
201
|
+
clean: Regexp.last_match(:clean),
|
202
|
+
date: Regexp.last_match(:date),
|
203
|
+
time: Regexp.last_match(:time),
|
204
|
+
author: Regexp.last_match(:author))
|
205
|
+
# check if name = YYYYmmdd-HHMM_name
|
206
|
+
when /^(?<prefix>(?<date>\d{8})-(?<time>\d{4})[-\s_])(?<clean>.*)/
|
207
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
208
|
+
clean: Regexp.last_match(:clean),
|
209
|
+
date: Regexp.last_match(:date),
|
210
|
+
time: Regexp.last_match(:time))
|
211
|
+
# check if name = YYYYmmdd_name
|
212
|
+
when /^(?<prefix>(?<date>\d{8})[-\s_])(?<clean>.*)/
|
213
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
214
|
+
clean: Regexp.last_match(:clean),
|
215
|
+
date: Regexp.last_match(:date))
|
216
|
+
# check if name = YYYY_name
|
217
|
+
when /^(?<prefix>(?<date>\d{4})[-\s_])(?<clean>.*)/
|
218
|
+
@basename_part = default.merge(prefix: Regexp.last_match(:prefix),
|
219
|
+
clean: Regexp.last_match(:clean),
|
220
|
+
date: Regexp.last_match(:date))
|
221
|
+
else
|
222
|
+
@basename_part = default.merge(clean: @basename)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
require 'phtools/version'
|
6
|
+
require 'phtools/utils/ruby_version.rb'
|
7
|
+
require 'phtools/utils/os_win.rb'
|
8
|
+
require 'phtools/utils/os_unix.rb'
|
9
|
+
require 'phtools/error.rb'
|
10
|
+
require 'phtools/ph_file.rb'
|
11
|
+
require 'docopt'
|
12
|
+
|
13
|
+
# Foto Tools
|
14
|
+
module PhTools
|
15
|
+
# Main class processing input stream
|
16
|
+
class Runner
|
17
|
+
def initialize(usage, file_type = [])
|
18
|
+
case Utils.os
|
19
|
+
when :windows
|
20
|
+
# workaround for win32
|
21
|
+
ARGV.map! { |a| a.encode('utf-8', 'filesystem') }
|
22
|
+
@os = Utils::OSWin.new
|
23
|
+
else
|
24
|
+
@os = Utils::OSUnix.new
|
25
|
+
end
|
26
|
+
@tool_name = File.basename($PROGRAM_NAME)
|
27
|
+
@options_cli = Docopt.docopt(usage, version: "v#{PhTools::VERSION}")
|
28
|
+
@file_type = file_type
|
29
|
+
PhTools.debug = true if @options_cli['--debug']
|
30
|
+
PhTools.puts_error "OPTIONS = #{@options_cli}" if PhTools.debug
|
31
|
+
|
32
|
+
validate_options
|
33
|
+
|
34
|
+
rescue Docopt::Exit => e
|
35
|
+
STDERR.puts e.message
|
36
|
+
exit 0
|
37
|
+
rescue => e
|
38
|
+
PhTools.puts_error "FATAL: #{e.message}", e
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def run!
|
43
|
+
return if STDIN.tty?
|
44
|
+
ARGV.clear
|
45
|
+
process_before
|
46
|
+
|
47
|
+
ARGF.each_line do |line|
|
48
|
+
filename = line.chomp
|
49
|
+
begin
|
50
|
+
FTFile.validate_file!(filename, @file_type)
|
51
|
+
ftfile = FTFile.new(filename)
|
52
|
+
@os.output process_file(ftfile)
|
53
|
+
rescue PhTools::Error => e
|
54
|
+
PhTools.puts_error "ERROR: '#{filename}' - #{e.message}", e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
process_after
|
59
|
+
|
60
|
+
rescue SignalException
|
61
|
+
PhTools.puts_error 'EXIT on user interrupt Ctrl-C'
|
62
|
+
exit 1
|
63
|
+
rescue => e
|
64
|
+
PhTools.puts_error "FATAL: #{e.message}", e
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def validate_options
|
71
|
+
end
|
72
|
+
|
73
|
+
def process_before
|
74
|
+
end
|
75
|
+
|
76
|
+
def process_file(file)
|
77
|
+
file
|
78
|
+
end
|
79
|
+
|
80
|
+
def process_after
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
# foto tools
|
8
|
+
module Utils
|
9
|
+
# determine OS
|
10
|
+
def self.os(os_string = RbConfig::CONFIG['host_os'])
|
11
|
+
case os_string
|
12
|
+
when /darwin/i then :macosx
|
13
|
+
when /linux/i then :linux
|
14
|
+
when /mswin|mingw|w32/i then :windows
|
15
|
+
else :unknown
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# OS specific output implementation
|
20
|
+
class OS
|
21
|
+
def output(message)
|
22
|
+
STDOUT.puts prepare(message)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
require 'phtools/utils/os'
|
6
|
+
|
7
|
+
module Utils
|
8
|
+
# OS platfor related logic
|
9
|
+
class OSWin < OS
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def prepare(message)
|
14
|
+
message.to_s.gsub(/#{"/"}/, '\\')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# (c) ANB Andrew Bizyaev
|
4
|
+
|
5
|
+
RUBY_VERSION_WANTED = '2.0.0'
|
6
|
+
|
7
|
+
begin
|
8
|
+
fail "Ruby version must be >= #{RUBY_VERSION_WANTED}" if
|
9
|
+
RUBY_VERSION < RUBY_VERSION_WANTED
|
10
|
+
rescue => e
|
11
|
+
STDERR.puts e.message
|
12
|
+
exit 1
|
13
|
+
end
|
data/lib/phtools/version.rb
CHANGED
data/lib/phtools.rb
CHANGED
@@ -1,10 +1,35 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# encoding: UTF-8
|
3
3
|
# (c) ANB Andrew Bizyaev
|
4
|
-
require
|
4
|
+
require 'phtools/version'
|
5
|
+
require 'pharrange'
|
6
|
+
require 'phbackup'
|
7
|
+
require 'phclname'
|
8
|
+
require 'phevent'
|
9
|
+
require 'phfixdate'
|
10
|
+
require 'phfixfmd'
|
11
|
+
require 'phls'
|
12
|
+
require 'phmtags'
|
13
|
+
require 'phrename'
|
14
|
+
require 'phtagset'
|
5
15
|
|
6
16
|
module PhTools
|
7
17
|
def self.about
|
8
|
-
|
18
|
+
about = <<TEXT
|
19
|
+
phtools v#{VERSION} is a bundle of small CLI tools for arranging, renaming, tagging
|
20
|
+
of the photo and video files. Helps to keep your photo-video assets in order.
|
21
|
+
Please run phtools in a terminal via CLI commands:
|
22
|
+
pharrange\t(#{Phrename::about}),
|
23
|
+
phbackup\t(#{Phbackup::about}),
|
24
|
+
phclname\t(#{Phclname::about}),
|
25
|
+
phevent\t(#{Phevent::about}),
|
26
|
+
phfixdate\t(#{Phfixdate::about}),
|
27
|
+
phfixmd\t(#{Phfixfmd::about}),
|
28
|
+
phls\t(#{Phls::about}),
|
29
|
+
phmtags\t(#{Phmtags::about}),
|
30
|
+
phrename \t(#{Phrename::about}),
|
31
|
+
phtagset\t(#{Phtagset::about}).
|
32
|
+
For more information run these commands with -h option.
|
33
|
+
TEXT
|
9
34
|
end
|
10
35
|
end
|
data/phtools.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency 'rspec', '~> 2.9'
|
32
32
|
spec.add_development_dependency 'rspec-its', '~> 1.0'
|
33
33
|
spec.add_development_dependency 'cucumber', '~> 1.3'
|
34
|
-
spec.add_development_dependency 'aruba', '~> 0.
|
34
|
+
spec.add_development_dependency 'aruba', '~> 0.14'
|
35
35
|
spec.add_development_dependency 'fuubar'
|
36
36
|
spec.add_development_dependency 'rubocop'
|
37
37
|
spec.add_development_dependency 'pry'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phtools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Bizyaev
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.
|
89
|
+
version: '0.14'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.
|
96
|
+
version: '0.14'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: fuubar
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +211,7 @@ description: A bundle of small CLI tools for arranging, renaming, tagging of the
|
|
211
211
|
email:
|
212
212
|
- andrew.bizyaev@gmail.com
|
213
213
|
executables:
|
214
|
+
- phls
|
214
215
|
- phtools
|
215
216
|
extensions: []
|
216
217
|
extra_rdoc_files: []
|
@@ -226,8 +227,26 @@ files:
|
|
226
227
|
- bin/console
|
227
228
|
- bin/setup
|
228
229
|
- bin/stmux
|
230
|
+
- exe/phls
|
229
231
|
- exe/phtools
|
232
|
+
- lib/pharrange.rb
|
233
|
+
- lib/phbackup.rb
|
234
|
+
- lib/phclname.rb
|
235
|
+
- lib/phevent.rb
|
236
|
+
- lib/phfixdate.rb
|
237
|
+
- lib/phfixfmd.rb
|
238
|
+
- lib/phls.rb
|
239
|
+
- lib/phmtags.rb
|
240
|
+
- lib/phrename.rb
|
241
|
+
- lib/phtagset.rb
|
230
242
|
- lib/phtools.rb
|
243
|
+
- lib/phtools/error.rb
|
244
|
+
- lib/phtools/ph_file.rb
|
245
|
+
- lib/phtools/runner.rb
|
246
|
+
- lib/phtools/utils/os.rb
|
247
|
+
- lib/phtools/utils/os_unix.rb
|
248
|
+
- lib/phtools/utils/os_win.rb
|
249
|
+
- lib/phtools/utils/ruby_version.rb
|
231
250
|
- lib/phtools/version.rb
|
232
251
|
- phtools.gemspec
|
233
252
|
homepage: https://github.com/AndrewBiz/phtools.git
|