torganiser 0.0.5 → 0.1.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.
- checksums.yaml +4 -4
- data/Rakefile +10 -5
- data/bin/torganiser +28 -18
- data/lib/torganiser.rb +11 -8
- data/lib/torganiser/arranger.rb +18 -12
- data/lib/torganiser/episode_file.rb +3 -42
- data/lib/torganiser/file_query.rb +5 -9
- data/lib/torganiser/match_one.rb +12 -0
- data/lib/torganiser/matcher.rb +63 -0
- data/lib/torganiser/runner.rb +5 -12
- data/lib/torganiser/scanner.rb +4 -6
- data/lib/torganiser/series.rb +1 -5
- data/lib/torganiser/version.rb +2 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/torganiser/arranger_spec.rb +26 -9
- data/spec/torganiser/episode_file_spec.rb +46 -105
- data/spec/torganiser/file_query_spec.rb +28 -28
- data/spec/torganiser/match_one_spec.rb +10 -0
- data/spec/torganiser/matcher_spec.rb +142 -0
- data/spec/torganiser/runner_spec.rb +13 -49
- data/spec/torganiser/scanner_spec.rb +34 -35
- data/spec/torganiser/series_spec.rb +5 -6
- data/torganiser.gemspec +19 -18
- metadata +22 -2
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Main module
|
4
|
+
module Torganiser
|
5
|
+
describe Matcher do
|
6
|
+
|
7
|
+
let(:result) { Matcher.match(file) }
|
8
|
+
|
9
|
+
context 'matching an informative filename' do
|
10
|
+
|
11
|
+
let(:file) { 'Hello.S02E01.mp4' }
|
12
|
+
|
13
|
+
it 'matches season number' do
|
14
|
+
expect(result[:season]).to eq '02'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'matches episode number' do
|
18
|
+
expect(result[:episode]).to eq '01'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'matches series name' do
|
22
|
+
expect(result[:name]).to eq 'Hello'
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'that does not contain year information' do
|
26
|
+
|
27
|
+
it 'matches a nil year' do
|
28
|
+
expect(result[:year]).to be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'that contains year information' do
|
34
|
+
|
35
|
+
let(:file) { 'Hello.2008.S02E01.mp4' }
|
36
|
+
|
37
|
+
it 'matches year' do
|
38
|
+
expect(result[:year]).to eq '2008'
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'that is a double episode' do
|
44
|
+
|
45
|
+
let(:file) { 'file/path/Hello.2008.S02E01E02.mp4' }
|
46
|
+
|
47
|
+
it 'matches season number' do
|
48
|
+
expect(result[:season]).to eq '02'
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'matches first episode number' do
|
52
|
+
expect(result[:episode]).to eq '01'
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'in short format' do
|
58
|
+
let(:file) { 'Hello.2014.302.hdtv-lol.mp4' }
|
59
|
+
|
60
|
+
it 'matches season number' do
|
61
|
+
expect(result[:season]).to eq '3'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'matches episode number' do
|
65
|
+
expect(result[:episode]).to eq '02'
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with an "x"' do
|
69
|
+
let(:file) { 'Hello.2014.4x07.hdtv-lol.mp4' }
|
70
|
+
|
71
|
+
it 'matches season number' do
|
72
|
+
expect(result[:season]).to eq '4'
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'matches episode number' do
|
76
|
+
expect(result[:episode]).to eq '07'
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'surrounded in square brackets' do
|
82
|
+
let(:file) { 'file/path/Wootle [3x08] Some title here.avi' }
|
83
|
+
|
84
|
+
it 'matches season number' do
|
85
|
+
expect(result[:season]).to eq '3'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'matches episode number' do
|
89
|
+
expect(result[:episode]).to eq '08'
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'that is dash-separated' do
|
97
|
+
let(:file) { "Wiffle's Berry - S01E12-the title.avi" }
|
98
|
+
|
99
|
+
it 'matches series name' do
|
100
|
+
expect(result[:name]).to eq "Wiffle's Berry -"
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'matches season number' do
|
104
|
+
expect(result[:season]).to eq '01'
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'matches episode number' do
|
108
|
+
expect(result[:episode]).to eq '12'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'that is a special' do
|
113
|
+
|
114
|
+
context 'that is has no season' do
|
115
|
+
let(:file) { 'Hello.2014.s00.hdtv-lol.mp4' }
|
116
|
+
it 'matches season number as zero' do
|
117
|
+
expect(result[:season]).to eq '0'
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'matches episode number as nil' do
|
121
|
+
expect(result[:episode]).to be_nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'with a season specified' do
|
126
|
+
let(:file) { 'file/path/Hello.2014.s01.special.hdtv-lol.mp4' }
|
127
|
+
|
128
|
+
it 'matches season number' do
|
129
|
+
expect(result[:season]).to eq '01'
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'matches episode number as nil' do
|
133
|
+
expect(result[:episode]).to be_nil
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
@@ -1,81 +1,45 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
# Main module
|
3
4
|
module Torganiser
|
4
|
-
|
5
5
|
describe Runner do
|
6
6
|
|
7
|
-
context
|
8
|
-
|
9
|
-
let(:collection) { double("collection") }
|
10
|
-
let(:files) { double("files") }
|
11
|
-
let(:extensions) { double("extensions") }
|
12
|
-
let(:ignored) { [] }
|
7
|
+
context 'when initialised with a scanner and arranger' do
|
13
8
|
|
14
9
|
subject do
|
15
10
|
Runner.new(
|
16
|
-
|
17
|
-
files: files, extensions: extensions,
|
18
|
-
ignored: ignored, dry_run: true
|
11
|
+
scanner: scanner, arranger: arranger
|
19
12
|
)
|
20
13
|
end
|
21
14
|
|
22
|
-
let(:
|
23
|
-
instance_double(
|
15
|
+
let(:arranger) do
|
16
|
+
instance_double('Torganiser::Arranger', arrange: nil)
|
24
17
|
end
|
25
18
|
|
26
|
-
|
27
|
-
|
19
|
+
let(:scanner) do
|
20
|
+
instance_double('Torganiser::Scanner', each: nil)
|
28
21
|
end
|
29
22
|
|
30
|
-
describe
|
31
|
-
|
32
|
-
it "is created for the files, extensions, and ignored as regex" do
|
33
|
-
expect(Scanner).to receive(:new).with(
|
34
|
-
files, extensions, anything
|
35
|
-
)
|
36
|
-
subject.run
|
37
|
-
end
|
38
|
-
|
39
|
-
let(:ignored) { ["ignored", ".*stuff.*"] }
|
40
|
-
|
41
|
-
it "is given the list of files to ignore converted to regex" do
|
42
|
-
expect(Scanner).to receive(:new).with(
|
43
|
-
anything, anything, [/ignored/, /.*stuff.*/]
|
44
|
-
)
|
45
|
-
subject.run
|
46
|
-
end
|
23
|
+
describe 'the scanner' do
|
47
24
|
|
48
|
-
it
|
25
|
+
it 'is used to retrieve episode files' do
|
49
26
|
expect(scanner).to receive(:each)
|
50
27
|
subject.run
|
51
28
|
end
|
52
29
|
|
53
30
|
end
|
54
31
|
|
55
|
-
context
|
32
|
+
context 'if any episode files are found' do
|
56
33
|
|
57
|
-
let(:episode_file) { instance_double(
|
34
|
+
let(:episode_file) { instance_double('Torganiser::EpisodeFile') }
|
58
35
|
|
59
36
|
before do
|
60
37
|
allow(scanner).to receive(:each).and_yield episode_file
|
61
38
|
end
|
62
39
|
|
63
|
-
describe
|
64
|
-
|
65
|
-
let(:arranger) do
|
66
|
-
instance_double("Torganiser::Arranger", arrange: nil)
|
67
|
-
end
|
68
|
-
|
69
|
-
before do
|
70
|
-
allow(Arranger).to receive(:new).and_return arranger
|
71
|
-
end
|
72
|
-
|
73
|
-
it "is created for the collection, and dry run status" do
|
74
|
-
expect(Arranger).to receive(:new).with(collection, dry_run: true)
|
75
|
-
subject.run
|
76
|
-
end
|
40
|
+
describe 'the arranger' do
|
77
41
|
|
78
|
-
it
|
42
|
+
it 'is used to arrange episode files found by the scanner' do
|
79
43
|
expect(arranger).to receive(:arrange).with(episode_file)
|
80
44
|
subject.run
|
81
45
|
end
|
@@ -1,24 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
# Main module
|
3
4
|
module Torganiser
|
4
|
-
|
5
5
|
describe Scanner do
|
6
6
|
|
7
|
-
context
|
7
|
+
context 'when initialised with an array of files' do
|
8
8
|
|
9
|
-
let(:files) { [
|
9
|
+
let(:files) { ['/tmp/file1', '/tmp/dir1', '/tmp/file2', '/tmp/dir2'] }
|
10
10
|
|
11
|
-
let(:extensions) { double(
|
11
|
+
let(:extensions) { double('extensions') }
|
12
12
|
|
13
13
|
let(:ignored_patterns) { [] }
|
14
14
|
|
15
15
|
subject { Scanner.new(files, extensions, ignored_patterns) }
|
16
16
|
|
17
|
-
let(:query_pattern) { double(
|
17
|
+
let(:query_pattern) { double('query pattern') }
|
18
18
|
|
19
19
|
let(:file_query) do
|
20
20
|
instance_double(
|
21
|
-
|
21
|
+
'Torganiser::FileQuery',
|
22
22
|
pattern: query_pattern,
|
23
23
|
add_directory: nil,
|
24
24
|
add_extension: nil,
|
@@ -27,7 +27,7 @@ module Torganiser
|
|
27
27
|
end
|
28
28
|
|
29
29
|
let(:query_results) do
|
30
|
-
[
|
30
|
+
['/tmp/dir1', '/tmp/dir1/file3', '/tmp/dir2', '/tmp/dir2/file4']
|
31
31
|
end
|
32
32
|
|
33
33
|
before do
|
@@ -36,40 +36,40 @@ module Torganiser
|
|
36
36
|
allow(Dir).to receive(:[]).and_return query_results
|
37
37
|
end
|
38
38
|
|
39
|
-
describe
|
40
|
-
it
|
41
|
-
expect(file_query).to receive(:add_directory).with(
|
42
|
-
expect(file_query).to receive(:add_directory).with(
|
39
|
+
describe 'a file query' do
|
40
|
+
it 'is created for any non-ordinary files' do
|
41
|
+
expect(file_query).to receive(:add_directory).with('/tmp/dir1')
|
42
|
+
expect(file_query).to receive(:add_directory).with('/tmp/dir2')
|
43
43
|
subject
|
44
44
|
end
|
45
45
|
|
46
|
-
it
|
46
|
+
it 'is given any extensions' do
|
47
47
|
expect(file_query).to receive(:add_extension).with extensions
|
48
48
|
subject
|
49
49
|
end
|
50
50
|
|
51
|
-
context
|
51
|
+
context 'when enumerating' do
|
52
52
|
|
53
|
-
context
|
54
|
-
it
|
53
|
+
context 'when given some directories' do
|
54
|
+
it 'is used do a directory search' do
|
55
55
|
expect(Dir).to receive(:[]).with query_pattern
|
56
56
|
subject.each { |_| }
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
context
|
60
|
+
context 'when empty' do
|
61
61
|
|
62
|
-
let(:files) { [
|
62
|
+
let(:files) { ['/tmp/file1''/tmp/file2'] }
|
63
63
|
|
64
64
|
let(:file_query) do
|
65
65
|
instance_double(
|
66
|
-
|
66
|
+
'Torganiser::FileQuery',
|
67
67
|
add_extension: nil,
|
68
68
|
empty?: true
|
69
69
|
)
|
70
70
|
end
|
71
71
|
|
72
|
-
it
|
72
|
+
it 'is not used' do
|
73
73
|
expect(Dir).not_to receive(:[]).with query_pattern
|
74
74
|
subject.each { |_| }
|
75
75
|
end
|
@@ -78,38 +78,37 @@ module Torganiser
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
it
|
81
|
+
it 'enumerates the ordinary files, and files found in the directories' do
|
82
82
|
expect { |block| subject.each(&block) }.to yield_successive_args(
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
'/tmp/file1',
|
84
|
+
'/tmp/file2',
|
85
|
+
'/tmp/dir1/file3',
|
86
|
+
'/tmp/dir2/file4'
|
87
87
|
)
|
88
88
|
end
|
89
89
|
|
90
|
-
context
|
90
|
+
context 'if any files match any of the ignore patterns' do
|
91
91
|
let(:ignored_patterns) { [/ignoreme/, /alsoignorethis$/] }
|
92
92
|
|
93
93
|
let(:query_results) do
|
94
94
|
[
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
'/tmp/dir2/file5.alsoignorethis',
|
96
|
+
'/tmp/dir1', '/tmp/dir2/file5.ignoreme',
|
97
|
+
'/tmp/dir1/file3', '/tmp/dir2',
|
98
|
+
'/tmp/dir2/file4'
|
99
99
|
]
|
100
100
|
end
|
101
101
|
|
102
|
-
it
|
102
|
+
it 'does not include the ignored files' do
|
103
103
|
expect { |block| subject.each(&block) }.to yield_successive_args(
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
104
|
+
'/tmp/file1',
|
105
|
+
'/tmp/file2',
|
106
|
+
'/tmp/dir1/file3',
|
107
|
+
'/tmp/dir2/file4'
|
108
108
|
)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
|
113
112
|
end
|
114
113
|
end
|
115
114
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
# Main module
|
3
4
|
module Torganiser
|
4
|
-
|
5
5
|
describe Series do
|
6
6
|
|
7
|
-
context
|
7
|
+
context 'when initialized with a name' do
|
8
8
|
|
9
|
-
subject { Series.new(
|
9
|
+
subject { Series.new('Pear Tree') }
|
10
10
|
|
11
11
|
it 'has a display name' do
|
12
12
|
expect(subject.display_name).to eq 'Pear Tree'
|
13
13
|
end
|
14
14
|
|
15
|
-
context
|
15
|
+
context 'and year' do
|
16
16
|
|
17
|
-
subject { Series.new(
|
17
|
+
subject { Series.new('Pear Tree', year: 2009) }
|
18
18
|
|
19
19
|
it 'has a display name that includes year' do
|
20
20
|
expect(subject.display_name).to eq 'Pear Tree (2009)'
|
@@ -25,5 +25,4 @@ module Torganiser
|
|
25
25
|
end
|
26
26
|
|
27
27
|
end
|
28
|
-
|
29
28
|
end
|
data/torganiser.gemspec
CHANGED
@@ -4,29 +4,30 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'torganiser/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'torganiser'
|
8
8
|
spec.version = Torganiser::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
9
|
+
spec.authors = ['']
|
10
|
+
spec.email = ['']
|
11
|
+
spec.summary = 'Organises episode files according to filename.'
|
12
|
+
spec.description = 'Organises episode files according to filename.'
|
13
|
+
spec.homepage = 'https://github.com/sergei-matheson/torganiser'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files`.split(
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'clamp'
|
22
22
|
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'reek'
|
26
|
+
spec.add_development_dependency 'rubocop'
|
27
|
+
spec.add_development_dependency 'rspec'
|
28
|
+
spec.add_development_dependency 'simplecov'
|
29
|
+
spec.add_development_dependency 'cane'
|
29
30
|
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
31
|
+
spec.add_development_dependency 'pry'
|
32
|
+
spec.add_development_dependency 'codeclimate-test-reporter'
|
32
33
|
end
|