serienmover 0.1.2 → 0.1.3
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 +12 -11
- data/bin/serienmover +148 -131
- data/lib/serienmover/version.rb +1 -1
- metadata +3 -2
data/README.md
CHANGED
@@ -56,14 +56,15 @@ like, hold all copied files in a separate directory. This file has to be
|
|
56
56
|
executable and there are two parameters supplied:
|
57
57
|
1) the episodefile 2) the seriesname
|
58
58
|
|
59
|
-
###
|
60
|
-
Should
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
### auto_process_enable
|
60
|
+
Should `serienmover` decide automatically which action (copy/move) should be
|
61
|
+
applied on the episodes.
|
62
|
+
|
63
|
+
### auto_default_action
|
64
|
+
This is the default action, that `serienmover` will apply, when the previous
|
65
|
+
setting is true.
|
66
|
+
|
67
|
+
### auto_exceptions
|
68
|
+
A list of series that will have the opposite default action. When
|
69
|
+
`auto_default_action` is `:copy` than the default action is `:move`, and vice
|
70
|
+
versa.
|
data/bin/serienmover
CHANGED
@@ -27,14 +27,15 @@ STANDARD_CONFIG = {
|
|
27
27
|
:store_path => '',
|
28
28
|
:byte_count_for_md5 => 2048,
|
29
29
|
:post_copy_hook => '',
|
30
|
-
:
|
31
|
-
:
|
30
|
+
:auto_process_enable => false,
|
31
|
+
:auto_default_action => :copy, # or :move
|
32
|
+
:auto_exceptions => [ # Series that should have the other action
|
33
|
+
'SERIES_DOESN_NOT_EXISTS',
|
34
|
+
],
|
32
35
|
}
|
33
36
|
|
34
37
|
config = STANDARD_CONFIG.merge_with_serialized(CONFIG_FILE)
|
35
38
|
|
36
|
-
###
|
37
|
-
# option definition and handling
|
38
39
|
options = {}
|
39
40
|
OptionParser.new do |opts|
|
40
41
|
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [DIR]"
|
@@ -46,7 +47,7 @@ OptionParser.new do |opts|
|
|
46
47
|
opts.separator(" Options:")
|
47
48
|
|
48
49
|
opts.on( "-s", "--seriesdir=DIR", String,
|
49
|
-
|
50
|
+
"Directory that contains series data (multiple allowed)") do |dirs|
|
50
51
|
dirs = [ dirs ] if dirs.is_a? String
|
51
52
|
|
52
53
|
dirs.each do |d|
|
@@ -54,98 +55,106 @@ OptionParser.new do |opts|
|
|
54
55
|
config[:series_directories] << d
|
55
56
|
end
|
56
57
|
end
|
57
|
-
|
58
|
+
end
|
58
59
|
|
59
60
|
opts.on( "-i", "--ignore-seriesinfo",
|
60
|
-
|
61
|
+
"do not use the information from the infostore") do |opt|
|
61
62
|
config[:read_episode_info] = false
|
62
|
-
|
63
|
+
end
|
63
64
|
|
64
|
-
opts.on( "-n", "--
|
65
|
-
|
66
|
-
config[:
|
67
|
-
|
65
|
+
opts.on( "-n", "--no-autoprocess",
|
66
|
+
"disables auto processing") do |opt|
|
67
|
+
config[:auto_process_enable] = false
|
68
|
+
end
|
68
69
|
|
69
70
|
opts.on( "-v", "--version",
|
70
|
-
|
71
|
+
"Outputs the version number.") do |opt|
|
71
72
|
puts Serienmover::VERSION
|
72
73
|
exit
|
73
|
-
|
74
|
+
end
|
74
75
|
|
75
76
|
opts.separator("")
|
76
77
|
opts.separator(" Arguments:")
|
77
78
|
opts.separator(" DIR The path that includes the episodes")
|
78
79
|
opts.separator(" defaults to ~/Downloads")
|
79
80
|
opts.separator("")
|
80
|
-
|
81
81
|
end.parse!
|
82
82
|
|
83
|
-
###
|
84
|
-
# change into DIR
|
85
|
-
episode_directory = ARGV.pop || config[:default_directory]
|
86
83
|
|
87
|
-
|
88
|
-
Dir.exists?(episode_directory)
|
84
|
+
class Serienmover::Cmdline
|
89
85
|
|
90
|
-
|
86
|
+
def initialize(config, options)
|
87
|
+
@config = config
|
88
|
+
@options = options
|
91
89
|
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
@series_store = Serienmover::SeriesStore.new(@config[:series_directories])
|
91
|
+
@info_store = Serienrenamer::InformationStore.new(
|
92
|
+
@config[:store_path], @config[:byte_count_for_md5])
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
autoprocess_list = {}
|
94
|
+
@processable_files = []
|
95
|
+
end
|
99
96
|
|
100
|
-
|
101
|
-
|
102
|
-
autoprocess_list =
|
103
|
-
exisiting_series.merge_with_serialized(config[:auto_process_list_file])
|
104
|
-
end
|
97
|
+
def process
|
98
|
+
chdir
|
105
99
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
config[:store_path], config[:byte_count_for_md5])
|
100
|
+
Dir.new('.').to_a.sort.each do |file|
|
101
|
+
determine_target_and_action file
|
102
|
+
end
|
110
103
|
|
111
|
-
|
112
|
-
# iterate through all episode files
|
113
|
-
episode_actions = []
|
104
|
+
exit if @processable_files.empty?
|
114
105
|
|
115
|
-
|
106
|
+
exit unless should_start_with_processing?
|
116
107
|
|
117
|
-
|
118
|
-
next unless File.file? file
|
119
|
-
next unless Serienrenamer::Episode.determine_video_file(file)
|
108
|
+
puts "\nEpisodes will be processed now"
|
120
109
|
|
121
|
-
|
110
|
+
@processable_files.each do |episode|
|
111
|
+
apply_action_on_episode episode
|
112
|
+
end
|
113
|
+
end
|
122
114
|
|
123
|
-
episode = Serienrenamer::Episode.new(file)
|
124
115
|
|
125
|
-
|
126
|
-
|
127
|
-
md5 = episode.md5sum(config[:byte_count_for_md5])
|
128
|
-
series = info_store.episode_hash[md5]
|
116
|
+
def chdir
|
117
|
+
episode_directory = ARGV.pop || @config[:default_directory]
|
129
118
|
|
130
|
-
|
131
|
-
|
132
|
-
|
119
|
+
fail "'#{episode_directory}' does not exist or is not a directory" unless
|
120
|
+
Dir.exists?(episode_directory)
|
121
|
+
Dir.chdir(episode_directory)
|
133
122
|
end
|
134
123
|
|
135
|
-
targets = store.find_suitable_target(episode, options)
|
136
|
-
selected_target = nil
|
137
124
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
125
|
+
def determine_target_and_action(file)
|
126
|
+
return if file.match(/^\./)
|
127
|
+
return unless File.file? file
|
128
|
+
return unless Serienrenamer::Episode.determine_video_file(file)
|
129
|
+
|
130
|
+
puts "\n\n"
|
131
|
+
p file
|
132
|
+
|
133
|
+
episode = Serienrenamer::Episode.new(file)
|
134
|
+
|
135
|
+
# get seriesname from the informationstore which is used by
|
136
|
+
# serienrenamer to store the seriesname when it renames files
|
137
|
+
md5 = episode.md5sum(@config[:byte_count_for_md5])
|
138
|
+
series = @info_store.episode_hash[md5]
|
139
|
+
|
140
|
+
options = {}
|
141
|
+
if @config[:read_episode_info] && series && series.match(/\w+/)
|
142
|
+
options[:series] = series
|
143
|
+
end
|
144
|
+
|
145
|
+
targets = @series_store.find_suitable_target(episode, options)
|
146
|
+
selected_target = nil
|
147
|
+
|
148
|
+
###
|
149
|
+
# process the targets
|
150
|
+
case targets.size
|
151
|
+
when 0
|
152
|
+
puts "No suitable target found\n"
|
153
|
+
return
|
154
|
+
when 1
|
155
|
+
selected_target = targets[0]
|
156
|
+
else
|
147
157
|
|
148
|
-
begin
|
149
158
|
puts "Available targets:"
|
150
159
|
choose do |menu|
|
151
160
|
menu.prompt = "Choose the right target: "
|
@@ -154,90 +163,98 @@ Dir.new('.').to_a.sort.each do |file|
|
|
154
163
|
menu.choice t.series do lambda { selected_target = t }.call end
|
155
164
|
end
|
156
165
|
end
|
157
|
-
rescue Interrupt
|
158
|
-
puts ""
|
159
166
|
end
|
160
167
|
|
161
|
-
|
168
|
+
if selected_target
|
169
|
+
puts ">> '%s'" % selected_target
|
170
|
+
episode.target = selected_target
|
171
|
+
|
172
|
+
# get the choice from the autoprocess
|
173
|
+
copy = nil
|
174
|
+
if @config[:auto_process_enable]
|
162
175
|
|
163
|
-
|
164
|
-
|
165
|
-
|
176
|
+
if @config[:auto_default_action] == :copy and not
|
177
|
+
@config[:auto_exceptions].include? episode.target.series
|
178
|
+
copy = true
|
179
|
+
else
|
180
|
+
copy = false
|
181
|
+
end
|
182
|
+
end
|
166
183
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
copy = false if choice && choice.match(/[vm]/i)
|
184
|
+
###
|
185
|
+
# ask for the action (copy/move)
|
186
|
+
print "What should be done ( [c]opy (*) , [m]ove ): "
|
187
|
+
char = nil
|
172
188
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
char = nil
|
189
|
+
if copy.nil?
|
190
|
+
char = get_character
|
191
|
+
print char.chr unless char.chr.match(/\r/)
|
177
192
|
|
178
|
-
|
179
|
-
|
180
|
-
|
193
|
+
unless char.chr.match(/[kcmv\r]/i)
|
194
|
+
puts "\nwill be skipped ...\n\n"
|
195
|
+
return
|
196
|
+
end
|
197
|
+
end
|
181
198
|
|
182
|
-
|
183
|
-
|
184
|
-
|
199
|
+
if copy == true || char && char.chr.match(/[kc\r]/i)
|
200
|
+
episode.set_action(copy: true)
|
201
|
+
print " ... copy"
|
202
|
+
else
|
203
|
+
episode.set_action(move: true)
|
204
|
+
print " ... move"
|
185
205
|
end
|
186
|
-
end
|
187
206
|
|
188
|
-
|
189
|
-
episode
|
190
|
-
|
191
|
-
|
192
|
-
episode
|
193
|
-
print " ... move"
|
207
|
+
###
|
208
|
+
# save the episode and set the target as used
|
209
|
+
@series_store.set_target_to_used(episode, selected_target)
|
210
|
+
|
211
|
+
@processable_files << episode
|
194
212
|
end
|
213
|
+
end
|
195
214
|
|
196
|
-
###
|
197
|
-
# save the episode and set the target as used
|
198
|
-
store.set_target_to_used(episode, selected_target)
|
199
215
|
|
200
|
-
|
216
|
+
def apply_action_on_episode(episode)
|
217
|
+
puts "%s '%s' to '%s'" % [episode.action.capitalize, episode, episode.target]
|
218
|
+
|
219
|
+
episode.process_action
|
220
|
+
|
221
|
+
# the supplied Script is called with two parameters
|
222
|
+
# 1. the path to the episodefile
|
223
|
+
# 2. the seriesname
|
224
|
+
#
|
225
|
+
if @config[:post_copy_hook] &&
|
226
|
+
File.file?(@config[:post_copy_hook]) &&
|
227
|
+
File.executable?(@config[:post_copy_hook]) &&
|
228
|
+
episode.action.match(/copy/i)
|
229
|
+
|
230
|
+
puts "Calling Post-Copy-Hook for this episode"
|
231
|
+
cmd = '%s "%s" "%s"' %
|
232
|
+
[ @config[:post_copy_hook], episode.episodepath, episode.target ]
|
233
|
+
|
234
|
+
system(cmd) or fail "Post-Copy-Hook ends not succesfully"
|
235
|
+
end
|
201
236
|
end
|
202
237
|
|
203
|
-
puts "\n\n"
|
204
|
-
end
|
205
238
|
|
206
|
-
|
239
|
+
def should_start_with_processing?
|
207
240
|
|
208
|
-
|
209
|
-
|
210
|
-
print
|
211
|
-
char = get_character
|
212
|
-
print char.chr
|
241
|
+
print "\n\nStart processing the episodes ? [yJ]"
|
242
|
+
char = get_character
|
243
|
+
print char.chr
|
213
244
|
|
214
|
-
unless char.chr.match(/[jy\r]/i)
|
215
|
-
|
216
|
-
|
217
|
-
end
|
245
|
+
unless char.chr.match(/[jy\r]/i)
|
246
|
+
puts "\nwill exit ...\n\n"
|
247
|
+
return false
|
248
|
+
end
|
218
249
|
|
219
|
-
|
220
|
-
episode_actions.each do |episode|
|
221
|
-
puts "%s '%s' to '%s'" % [episode.action.capitalize, episode, episode.target]
|
222
|
-
|
223
|
-
episode.process_action
|
224
|
-
|
225
|
-
###
|
226
|
-
# run the Script that is supplied in config[:post_copy_hook]
|
227
|
-
# this lets you process episodes that are copied
|
228
|
-
#
|
229
|
-
# the supplied Script is called with two parameters
|
230
|
-
# 1. the path to the episodefile
|
231
|
-
# 2. the seriesname
|
232
|
-
if config[:post_copy_hook] &&
|
233
|
-
File.file?(config[:post_copy_hook]) &&
|
234
|
-
File.executable?(config[:post_copy_hook]) &&
|
235
|
-
episode.action.match(/copy/i)
|
236
|
-
|
237
|
-
puts "Calling Post-Copy-Hook for this episode"
|
238
|
-
cmd = '%s "%s" "%s"' %
|
239
|
-
[ config[:post_copy_hook], episode.episodepath, episode.target ]
|
240
|
-
|
241
|
-
system(cmd) or fail "Post-Copy-Hook ends not succesfully"
|
250
|
+
true
|
242
251
|
end
|
243
252
|
end
|
253
|
+
|
254
|
+
cmd = Serienmover::Cmdline.new(config, options)
|
255
|
+
begin
|
256
|
+
cmd.process
|
257
|
+
rescue Interrupt => e
|
258
|
+
puts
|
259
|
+
end
|
260
|
+
|
data/lib/serienmover/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serienmover
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: serienrenamer
|
@@ -82,3 +82,4 @@ test_files:
|
|
82
82
|
- spec/series_store_spec.rb
|
83
83
|
- spec/spec_helper.rb
|
84
84
|
- spec/spec_testdata.rb
|
85
|
+
has_rdoc:
|