sindex 0.1.1 → 0.1.2
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/.autotest +3 -0
- data/bin/sindex +79 -19
- data/lib/sindex/series_index.rb +31 -0
- data/lib/sindex/version.rb +1 -1
- data/test/test_helper.rb +1 -0
- data/test/test_series_index.rb +45 -0
- data/test/test_testdata.rb +115 -0
- metadata +7 -4
data/.autotest
ADDED
data/bin/sindex
CHANGED
|
@@ -34,12 +34,16 @@ STANDARD_CONFIG = {
|
|
|
34
34
|
|
|
35
35
|
config = STANDARD_CONFIG.merge_with_serialized(CONFIG_FILE)
|
|
36
36
|
|
|
37
|
-
options = {
|
|
37
|
+
options = {
|
|
38
|
+
:language => :de,
|
|
39
|
+
}
|
|
38
40
|
OptionParser.new do |opts|
|
|
39
|
-
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [DIR]"
|
|
41
|
+
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] [DIR]"
|
|
40
42
|
|
|
41
43
|
opts.separator("")
|
|
42
|
-
opts.separator("Tool that manages an index with all your watched episodes")
|
|
44
|
+
opts.separator("Tool that manages an index with all your watched episodes.")
|
|
45
|
+
opts.separator("The default action without any arguments adds new episodes")
|
|
46
|
+
opts.separator("to the index.")
|
|
43
47
|
opts.separator("")
|
|
44
48
|
opts.separator(" Options:")
|
|
45
49
|
|
|
@@ -48,12 +52,42 @@ OptionParser.new do |opts|
|
|
|
48
52
|
exit
|
|
49
53
|
end
|
|
50
54
|
|
|
55
|
+
opts.on( "-i", "--indexfile STRING", String,
|
|
56
|
+
"Path to the index that holds the index") do |opt|
|
|
57
|
+
|
|
58
|
+
config[:index_file] = opt
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
opts.on( "-b", "--buildindex STRING", String,
|
|
62
|
+
"Build an index by reading the series/episodes from the supplied directory") do |opt|
|
|
63
|
+
|
|
64
|
+
raise ArgumentError, "supplied directory does not exist" unless
|
|
65
|
+
File.directory? opt
|
|
66
|
+
options[:build_index_from_dir] = opt
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
opts.on( "-l", "--language STRING", String,
|
|
70
|
+
"language in which the episodes in the directory are, choices: (de,en,fr)") do |opt|
|
|
71
|
+
|
|
72
|
+
raise ArgumentError, "Supplied Language not supported, choices:(de,en,fr)" unless
|
|
73
|
+
opt.match(/^(de|en|fr)$/)
|
|
74
|
+
options[:language] = opt.to_sym
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
opts.separator("")
|
|
51
78
|
opts.separator(" Arguments:")
|
|
52
79
|
opts.separator(" DIR The path that includes the episodes")
|
|
53
80
|
opts.separator(" defaults to ~/Downloads")
|
|
54
81
|
opts.separator("")
|
|
55
82
|
end.parse!
|
|
56
83
|
|
|
84
|
+
# change episode directory if a different directory is supplied
|
|
85
|
+
if directory = ARGV.pop
|
|
86
|
+
raise ArgumentError, "supplied directory does not exist" unless
|
|
87
|
+
File.directory? directory
|
|
88
|
+
config[:episode_directory] = directory
|
|
89
|
+
end
|
|
90
|
+
|
|
57
91
|
|
|
58
92
|
class Cmdline
|
|
59
93
|
include HighLine::SystemExtensions
|
|
@@ -62,19 +96,30 @@ class Cmdline
|
|
|
62
96
|
@config = config
|
|
63
97
|
@options = options
|
|
64
98
|
|
|
65
|
-
@series_index = Sindex::SeriesIndex.new(index_file: @config[:index_file])
|
|
66
99
|
@processed_episodes = {}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def build_up_index
|
|
103
|
+
@series_index = Sindex::SeriesIndex.new
|
|
104
|
+
@series_index.build_up_index_from_directory(
|
|
105
|
+
@options[:build_index_from_dir], @options[:language])
|
|
67
106
|
|
|
107
|
+
@series_index.dump_index_to_file(@config[:index_file])
|
|
68
108
|
end
|
|
69
109
|
|
|
70
|
-
# mark episodes as watched
|
|
71
110
|
def mark_as_watched
|
|
111
|
+
call_pre_processing_hook
|
|
112
|
+
|
|
113
|
+
@series_index = Sindex::SeriesIndex.new(index_file: @config[:index_file])
|
|
72
114
|
|
|
73
115
|
@info_store = Serienrenamer::InformationStore.new(
|
|
74
116
|
@config[:information_store_path], @config[:byte_count_for_md5])
|
|
75
117
|
|
|
76
118
|
# process all episodes
|
|
77
119
|
Dir.chdir(@config[:episode_directory])
|
|
120
|
+
|
|
121
|
+
added_episodes=false
|
|
122
|
+
|
|
78
123
|
for filename in Dir.entries('.').sort do
|
|
79
124
|
|
|
80
125
|
next if filename.match(/^\./)
|
|
@@ -109,8 +154,12 @@ class Cmdline
|
|
|
109
154
|
@series_index.add_episode_to_index(series_name, filename, language)
|
|
110
155
|
@processed_episodes[filename] = series_name
|
|
111
156
|
puts "Added '#{filename}' to index"
|
|
157
|
+
|
|
158
|
+
added_episodes=true
|
|
112
159
|
end
|
|
113
160
|
|
|
161
|
+
exit unless added_episodes
|
|
162
|
+
|
|
114
163
|
if agree("\nShould I write the new index? ", true)
|
|
115
164
|
@series_index.dump_index_to_file(@config[:index_file])
|
|
116
165
|
puts "New Index version has been written\n"
|
|
@@ -123,6 +172,8 @@ class Cmdline
|
|
|
123
172
|
system(cmd) or fail("Episode-Hook failed")
|
|
124
173
|
end
|
|
125
174
|
end
|
|
175
|
+
|
|
176
|
+
call_post_processing_hook
|
|
126
177
|
else
|
|
127
178
|
puts "the index was not changed"
|
|
128
179
|
exit
|
|
@@ -134,6 +185,22 @@ class Cmdline
|
|
|
134
185
|
#############################################################################
|
|
135
186
|
private
|
|
136
187
|
|
|
188
|
+
def call_pre_processing_hook
|
|
189
|
+
# calling the pre-processing hook to allow a git pull or something else
|
|
190
|
+
# in a Script
|
|
191
|
+
if @config[:pre_processing_hook] and @config[:pre_processing_hook].match(/\w+/)
|
|
192
|
+
system(@config[:pre_processing_hook]) or fail("Pre-Processing-Hook failed")
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def call_post_processing_hook
|
|
197
|
+
# calling the post-processing hook to allow a git commit/push or something
|
|
198
|
+
# else in a Script
|
|
199
|
+
if @config[:post_processing_hook] and @config[:post_processing_hook].match(/\w+/)
|
|
200
|
+
system(@config[:post_processing_hook]) or fail("Post-Processing-Hook failed")
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
137
204
|
def determine_episode_language(seriesname, filename)
|
|
138
205
|
series = @series_index.series_data[seriesname]
|
|
139
206
|
|
|
@@ -155,10 +222,8 @@ class Cmdline
|
|
|
155
222
|
end
|
|
156
223
|
return language
|
|
157
224
|
end
|
|
158
|
-
|
|
159
225
|
end
|
|
160
226
|
|
|
161
|
-
|
|
162
227
|
def determine_series_name_for_episode(filename)
|
|
163
228
|
sum = md5sum(filename)
|
|
164
229
|
if not @info_store.episode_hash[sum].nil?
|
|
@@ -194,7 +259,6 @@ class Cmdline
|
|
|
194
259
|
end
|
|
195
260
|
end
|
|
196
261
|
|
|
197
|
-
|
|
198
262
|
# Private: Generates a md5sum for the number of bytes for the supplied file
|
|
199
263
|
#
|
|
200
264
|
# Returns filename
|
|
@@ -209,21 +273,17 @@ class Cmdline
|
|
|
209
273
|
end
|
|
210
274
|
end
|
|
211
275
|
|
|
212
|
-
|
|
213
|
-
#
|
|
214
|
-
if config[:pre_processing_hook] and config[:pre_processing_hook].match(/\w+/)
|
|
215
|
-
system(config[:pre_processing_hook]) or fail("Pre-Processing-Hook failed")
|
|
216
|
-
end
|
|
276
|
+
##########################
|
|
277
|
+
# Do the actual processing
|
|
217
278
|
|
|
218
279
|
cmd = Cmdline.new(config, options)
|
|
219
280
|
begin
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if config[:post_processing_hook] and config[:post_processing_hook].match(/\w+/)
|
|
225
|
-
system(config[:post_processing_hook]) or fail("Post-Processing-Hook failed")
|
|
281
|
+
if options[:build_index_from_dir]
|
|
282
|
+
cmd.build_up_index
|
|
283
|
+
else
|
|
284
|
+
cmd.mark_as_watched
|
|
226
285
|
end
|
|
286
|
+
|
|
227
287
|
rescue Interrupt => e
|
|
228
288
|
puts
|
|
229
289
|
end
|
data/lib/sindex/series_index.rb
CHANGED
|
@@ -65,6 +65,37 @@ module Sindex
|
|
|
65
65
|
false
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
# Public: Builds up an index from a directory full of series
|
|
69
|
+
#
|
|
70
|
+
# :directory - path to the directory that holds the series
|
|
71
|
+
# :language - the language symbol which the episodes in the directory have
|
|
72
|
+
#
|
|
73
|
+
def build_up_index_from_directory(directory, language=:de)
|
|
74
|
+
raise ArgumentError, "you have not supplied an existing directory" unless
|
|
75
|
+
File.directory? directory
|
|
76
|
+
|
|
77
|
+
Dir.chdir(directory)
|
|
78
|
+
|
|
79
|
+
Dir['*'].sort.each do |directory|
|
|
80
|
+
next unless File.directory? directory
|
|
81
|
+
|
|
82
|
+
series = Series.new
|
|
83
|
+
|
|
84
|
+
Dir["#{directory}/**/*"].sort.each do |episode|
|
|
85
|
+
next unless File.file? episode
|
|
86
|
+
basename_episode = File.basename(episode)
|
|
87
|
+
|
|
88
|
+
next unless SeriesIndex.extract_episode_identifier(basename_episode)
|
|
89
|
+
next unless basename_episode.match(/\.(mkv|mov|avi|flv|mp4|mpg|wmv)$/)
|
|
90
|
+
|
|
91
|
+
series.add_episode(basename_episode, language)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
@series_data[directory] = series
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
68
99
|
# Public: Dumps the in-memory version of the index back to a xml file
|
|
69
100
|
#
|
|
70
101
|
# :filename - path to file in which the index should be dumped
|
data/lib/sindex/version.rb
CHANGED
data/test/test_helper.rb
CHANGED
data/test/test_series_index.rb
CHANGED
|
@@ -114,3 +114,48 @@ class TestIndex < Test::Unit::TestCase
|
|
|
114
114
|
"Shameless.US.S01E09.German"), true
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
|
+
|
|
118
|
+
class TestIndexParsedFromDir < Test::Unit::TestCase
|
|
119
|
+
def setup
|
|
120
|
+
TestData.create
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def teardown
|
|
124
|
+
TestData.clean
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_that_an_error_is_raised_if_the_directory_does_not_exist
|
|
128
|
+
index = Sindex::SeriesIndex.new()
|
|
129
|
+
assert_raise ArgumentError do
|
|
130
|
+
index.build_up_index_from_directory('/this/should/not/exist')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_that_the_index_holds_the_right_number_of_series
|
|
135
|
+
index = Sindex::SeriesIndex.new()
|
|
136
|
+
index.build_up_index_from_directory(TestData::SERIES_STORAGE_DIR)
|
|
137
|
+
assert_equal index.empty?, false
|
|
138
|
+
assert_equal 7, index.series_data.length
|
|
139
|
+
assert_equal true, index.is_series_in_index?("The Big Bang Theory")
|
|
140
|
+
assert_equal true, index.is_series_in_index?("Criminal Minds")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_that_episodes_from_directory_are_in_index
|
|
144
|
+
index = Sindex::SeriesIndex.new()
|
|
145
|
+
index.build_up_index_from_directory(TestData::SERIES_STORAGE_DIR)
|
|
146
|
+
|
|
147
|
+
assert_equal true, index.episode_existing?("Criminal Minds", "S01E01")
|
|
148
|
+
assert_equal false, index.episode_existing?("Criminal Minds", "S01E04")
|
|
149
|
+
|
|
150
|
+
assert_equal true, index.episode_existing?("Chuck", "S01E01")
|
|
151
|
+
assert_equal false, index.episode_existing?("Chuck", "S01E31")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def test_that_episodes_are_in_index_in_the_supplied_language
|
|
155
|
+
index = Sindex::SeriesIndex.new()
|
|
156
|
+
index.build_up_index_from_directory(TestData::SERIES_STORAGE_DIR, :en)
|
|
157
|
+
|
|
158
|
+
assert_equal true, index.episode_existing?("Criminal Minds", "S01E01", :en)
|
|
159
|
+
assert_equal false, index.episode_existing?("Criminal Minds", "S01E04", :en)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper.rb")
|
|
2
|
+
|
|
3
|
+
class TestData
|
|
4
|
+
|
|
5
|
+
TESTFILE_DIRECTORY = File.join(File.dirname(__FILE__), 'tmp')
|
|
6
|
+
SERIES_STORAGE_DIR = File.join(TESTFILE_DIRECTORY, 'series')
|
|
7
|
+
|
|
8
|
+
EPISODES = {
|
|
9
|
+
:chuck => { :filename => "S04E11 - Pilot.avi",
|
|
10
|
+
:series => "Chuck",
|
|
11
|
+
:data => { :from => '1_1', :to => '4_10' }
|
|
12
|
+
},
|
|
13
|
+
:tbbt => { :filename => "S05E06 - Pilot.avi",
|
|
14
|
+
:series => "The Big Bang Theory",
|
|
15
|
+
:data => { :from => '1_1', :to => '5_9',
|
|
16
|
+
:exclude => ['5_5', '5_6', '5_7', '5_8', ] }
|
|
17
|
+
},
|
|
18
|
+
:crmi => { :filename => "S01E04 - Pilot.avi",
|
|
19
|
+
:series => "Criminal Minds",
|
|
20
|
+
:data => { :from => '1_1', :to => '1_3' }
|
|
21
|
+
},
|
|
22
|
+
:seap => { :filename => "S01E04 - Pilot.avi",
|
|
23
|
+
:series => "Sea Patrol",
|
|
24
|
+
:data => { :from => '1_1', :to => '1_3' }
|
|
25
|
+
},
|
|
26
|
+
:drhou => { :filename => "S05E01 - First Episode.avi",
|
|
27
|
+
:series => "Dr House",
|
|
28
|
+
:data => { :from => '1_1', :to => '4_20' }
|
|
29
|
+
},
|
|
30
|
+
:spook => { :filename => "S10E01 - First Episode.avi",
|
|
31
|
+
:series => "Spooks",
|
|
32
|
+
:data => { :from => '1_1', :to => '9_20' }
|
|
33
|
+
},
|
|
34
|
+
:numbe => { :filename => "S04E31 - High Episode.avi",
|
|
35
|
+
:series => "Numb3rs",
|
|
36
|
+
:data => { :from => '1_1', :to => '4_30' }
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# create test data
|
|
41
|
+
def self.create
|
|
42
|
+
_create_directories
|
|
43
|
+
EPISODES.each do |key,value|
|
|
44
|
+
create_series(value[:series], value[:data])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# remove files
|
|
49
|
+
def self.clean
|
|
50
|
+
remove_series_dir
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
|
|
55
|
+
# this method creates a directory structure for a given
|
|
56
|
+
# series with the opportunity to exclude some episodes
|
|
57
|
+
def create_series(seriesname, options={})
|
|
58
|
+
default = { :from => '1_0', :to => '1_0',
|
|
59
|
+
:max => 30, :exclude => [] }
|
|
60
|
+
options = default.merge(options)
|
|
61
|
+
|
|
62
|
+
series_dir = File.join(SERIES_STORAGE_DIR, seriesname)
|
|
63
|
+
_create_dir(series_dir)
|
|
64
|
+
|
|
65
|
+
from = _split_entry(options[:from])
|
|
66
|
+
to = _split_entry(options[:to])
|
|
67
|
+
|
|
68
|
+
for season in from[0]..to[0]
|
|
69
|
+
|
|
70
|
+
season_dir = File.join(series_dir, "Staffel %02d" % season)
|
|
71
|
+
_create_dir(season_dir)
|
|
72
|
+
|
|
73
|
+
episodes = (season == to[0]) ? to[1] : options[:max]
|
|
74
|
+
|
|
75
|
+
for episode in 1..episodes.to_i
|
|
76
|
+
|
|
77
|
+
# check for excludes
|
|
78
|
+
definition = "%d_%d" % [ season, episode ]
|
|
79
|
+
next if options[:exclude].include? definition
|
|
80
|
+
|
|
81
|
+
# build and create file
|
|
82
|
+
file = "S%02dE%02d - Episode %02d.mkv" % [ season, episode,episode ]
|
|
83
|
+
episode_file = File.join(season_dir, file)
|
|
84
|
+
_create_file(episode_file)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# remove testfile directory
|
|
91
|
+
def remove_series_dir
|
|
92
|
+
if File.directory?(SERIES_STORAGE_DIR)
|
|
93
|
+
FileUtils.remove_dir(SERIES_STORAGE_DIR)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def _split_entry(definition)
|
|
98
|
+
definition.split(/_/)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def _create_directories
|
|
102
|
+
_create_dir TESTFILE_DIRECTORY
|
|
103
|
+
_create_dir SERIES_STORAGE_DIR
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def _create_dir(dir)
|
|
107
|
+
FileUtils.mkdir(dir) unless File.directory?(dir)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def _create_file(file)
|
|
111
|
+
FileUtils.touch(file) unless File.file?(file)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sindex
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
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-11-
|
|
12
|
+
date: 2012-11-16 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: nokogiri
|
|
@@ -100,6 +100,7 @@ executables:
|
|
|
100
100
|
extensions: []
|
|
101
101
|
extra_rdoc_files: []
|
|
102
102
|
files:
|
|
103
|
+
- .autotest
|
|
103
104
|
- .gitignore
|
|
104
105
|
- .travis.yml
|
|
105
106
|
- Gemfile
|
|
@@ -117,6 +118,7 @@ files:
|
|
|
117
118
|
- test/seriesindex_example.xml
|
|
118
119
|
- test/test_helper.rb
|
|
119
120
|
- test/test_series_index.rb
|
|
121
|
+
- test/test_testdata.rb
|
|
120
122
|
homepage: https://github.com/pboehm/sindex
|
|
121
123
|
licenses: []
|
|
122
124
|
post_install_message:
|
|
@@ -131,7 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
131
133
|
version: '0'
|
|
132
134
|
segments:
|
|
133
135
|
- 0
|
|
134
|
-
hash: -
|
|
136
|
+
hash: -4573183238350985480
|
|
135
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
138
|
none: false
|
|
137
139
|
requirements:
|
|
@@ -140,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
140
142
|
version: '0'
|
|
141
143
|
segments:
|
|
142
144
|
- 0
|
|
143
|
-
hash: -
|
|
145
|
+
hash: -4573183238350985480
|
|
144
146
|
requirements: []
|
|
145
147
|
rubyforge_project:
|
|
146
148
|
rubygems_version: 1.8.24
|
|
@@ -151,3 +153,4 @@ test_files:
|
|
|
151
153
|
- test/seriesindex_example.xml
|
|
152
154
|
- test/test_helper.rb
|
|
153
155
|
- test/test_series_index.rb
|
|
156
|
+
- test/test_testdata.rb
|