showfeature 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.
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +10 -0
- data/LICENSE +22 -0
- data/README.md +20 -0
- data/lib/showfeature/exception.rb +7 -0
- data/lib/showfeature/processor.rb +90 -0
- data/lib/showfeature/version.rb +3 -0
- data/lib/showfeature.rb +7 -0
- data/showfeature.gemspec +15 -0
- data/spec/showfeature_spec.rb +136 -0
- metadata +58 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Allan Seymour
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
|
4
|
+
obtaining a copy of this software and associated documentation
|
|
5
|
+
files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use,
|
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the
|
|
9
|
+
Software is furnished to do so, subject to the following
|
|
10
|
+
conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be
|
|
13
|
+
included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## ShowFeature ##
|
|
2
|
+
|
|
3
|
+
A library to find distinguishable features in a tv show filename as it
|
|
4
|
+
was downloaded
|
|
5
|
+
(e.g. [name].S[season]E[episode].hdtv-[team].avi)
|
|
6
|
+
|
|
7
|
+
# Usage
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
require 'showfeature'
|
|
11
|
+
sf = ShowFeature::Processor.new('foo.125.x264-bar.mkv')
|
|
12
|
+
sf.parse
|
|
13
|
+
puts sf.to_hsh
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Author :** Allan Seymour
|
|
17
|
+
**Version :** 0.1.0
|
|
18
|
+
**Release Date :** December 04, 2012
|
|
19
|
+
**Copyright :** MIT License
|
|
20
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..')
|
|
2
|
+
require 'showfeature'
|
|
3
|
+
require 'mime/types'
|
|
4
|
+
|
|
5
|
+
module ShowFeature
|
|
6
|
+
|
|
7
|
+
# The main processor class is in charge of the parsing of tv show filename
|
|
8
|
+
class Processor
|
|
9
|
+
|
|
10
|
+
attr_reader :id, :name, :team, :episode, :season, :raw_name, :parsed
|
|
11
|
+
|
|
12
|
+
# Pattern used for the parsing process
|
|
13
|
+
PATTERN = /(^[\w\.\(\)]+)\.(\d{3}|s?\d{1,2}[ex]?\d{2})\..*-(.*)\.[\d\w]{3}$/i
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Creates a new Processor instance for +raw_name+ parsing
|
|
17
|
+
#
|
|
18
|
+
# An ArgumentError is raised if +raw_name+'s mime type does not
|
|
19
|
+
# match the type of a video file
|
|
20
|
+
def initialize(raw_name)
|
|
21
|
+
raise ShowFeature::ArgumentError, 'argument does not match a video file type' unless
|
|
22
|
+
ShowFeature::Processor.video_file_type? raw_name
|
|
23
|
+
@raw_name = raw_name
|
|
24
|
+
@parsed = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Parses the tv show filename looking for relevant element
|
|
29
|
+
def parse
|
|
30
|
+
proc = Proc.new do |position, proc|
|
|
31
|
+
tmp = @raw_name[PATTERN,position]
|
|
32
|
+
tmp.nil? ? nil : proc.call(tmp)
|
|
33
|
+
end
|
|
34
|
+
@name = proc.call(1, lambda{|x| x.downcase.tr_s('.',' ')})
|
|
35
|
+
@season = proc.call(2, lambda{|x| "%02d" % x[/(\d+).?(\d{2}$)/,1].to_i})
|
|
36
|
+
@episode = proc.call(2, lambda{|x| "%02d" % x[/(\d+).?(\d{2}$)/,2].to_i})
|
|
37
|
+
@team = proc.call(3, lambda{|x| x.downcase})
|
|
38
|
+
@parsed = true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# Checks if the tv show filename has already been parsed
|
|
43
|
+
def parsed?
|
|
44
|
+
@parsed
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
# Returns hash filled with all parsed element
|
|
49
|
+
def to_hsh
|
|
50
|
+
hash = Hash.new
|
|
51
|
+
hash.merge!( { :name =>@name,
|
|
52
|
+
:season => @season,
|
|
53
|
+
:episode => @episode,
|
|
54
|
+
:team => @team } ) unless [@name,@season,@episode, @team].all? {|x| x.eql?nil}
|
|
55
|
+
hash
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# Checks if +str+'s mime type matches a video file type
|
|
60
|
+
def self.video_file_type?(str)
|
|
61
|
+
MIME::Types.of(str).any? do |x| x.to_s =~/^video/ end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# Checks if the mime type of the current processed show matches a video file type
|
|
66
|
+
def video_file_type?
|
|
67
|
+
MIME::Types.of(@raw_name).any? do |x| x.to_s =~/^video/ end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def replace(arg)
|
|
72
|
+
raise ShowFeature::TypeError, 'argument must be of type String or Hash' unless
|
|
73
|
+
[String, Hash].any?{|type| arg.kind_of? type}
|
|
74
|
+
raise ShowFeature::NotParsedError, 'showfeature cannot complete replace if show is not parsed' unless parsed?
|
|
75
|
+
if arg.kind_of? String
|
|
76
|
+
@raw_name = arg if ShowFeature::Processor.video_file_type?(arg)
|
|
77
|
+
else
|
|
78
|
+
hash = {
|
|
79
|
+
:name =>@name,
|
|
80
|
+
:season => @season,
|
|
81
|
+
:episode => @episode,
|
|
82
|
+
:team => @team }.merge(arg) {|k,v1,v2| k.eql?(:episode) ? "%02d"%v2 : v2}
|
|
83
|
+
hash.each do |key, value|
|
|
84
|
+
@raw_name.sub! self.send("#{key}").gsub(' ','.'), value
|
|
85
|
+
instance_variable_set("@#{key}", value)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/showfeature.rb
ADDED
data/showfeature.gemspec
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require File.expand_path('../lib/showfeature/version', __FILE__)
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "showfeature"
|
|
5
|
+
spec.version= ShowFeature::VERSION
|
|
6
|
+
spec.summary = 'This library allows to find the relevant features in a tv show filename (e.g. [name].S[season]E[episode].hdtv-[team].avi)'
|
|
7
|
+
spec.description = "This library allows to find the relevant features in a tv show filename (e.g. [name].S[season]E[episode].hdtv-[team].avi)"
|
|
8
|
+
spec.homepage = "https://github.com/stonebanks/showfeature/"
|
|
9
|
+
spec.author = "Allan Seymour"
|
|
10
|
+
spec.email = "banks.the.megalithic.stone@gmail.com"
|
|
11
|
+
spec.require_paths = ['lib']
|
|
12
|
+
spec.files = `git ls-files`.split("\n")
|
|
13
|
+
spec.required_ruby_version = '>= 1.9.1'
|
|
14
|
+
spec.test_files = `git ls-files -- spec `.split("\n")
|
|
15
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
|
2
|
+
|
|
3
|
+
require 'minitest/spec'
|
|
4
|
+
require 'minitest/autorun'
|
|
5
|
+
require 'showfeature'
|
|
6
|
+
require 'erb'
|
|
7
|
+
|
|
8
|
+
Output = Struct.new(:name, :episode, :season, :team, :raw_name)
|
|
9
|
+
|
|
10
|
+
def create_a_show
|
|
11
|
+
t = ([('a'..'z'),(0..9)].map{|i| i.to_a}).flatten
|
|
12
|
+
r = (Array.new(t)<<['(',')','.']).flatten
|
|
13
|
+
output = Output.new
|
|
14
|
+
output.name = (0..30).map{r.sample}.join
|
|
15
|
+
output.team = (0..4).map {t.sample}.join
|
|
16
|
+
nb = ERB.new (['s<%="%02d"%output.season %>e<%="%02d"%output.episode%>',
|
|
17
|
+
'<%="%01d"%output.season %><%="%02d"%output.episode%>',
|
|
18
|
+
'<%="%02d"%output.season %>x<%="%02d"%output.episode%>',
|
|
19
|
+
'<%="%01d"%output.season %>X<%="%02d"%output.episode%>'].sample)
|
|
20
|
+
output.season = (1..99).map{|s| s}.sample.to_s
|
|
21
|
+
output.episode = (1..99).map{|s| s}.sample.to_s
|
|
22
|
+
output.raw_name = output.name+"."+ nb.result(binding) + ".hdtv-"+output.team+[".avi",".mp4",".mkv"].sample
|
|
23
|
+
output
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe ShowFeature::Processor do
|
|
27
|
+
before do
|
|
28
|
+
@output = create_a_show
|
|
29
|
+
@show = @output.raw_name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "can be created with a string argument" do
|
|
33
|
+
ShowFeature::Processor.new(@show).raw_name.must_equal @show
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "must raised an ArgumentError if mime type does not match a video file type" do
|
|
37
|
+
result = lambda{ ShowFeature::Processor.new('show')}
|
|
38
|
+
result.must_raise ShowFeature::ArgumentError
|
|
39
|
+
error = result.call rescue $!
|
|
40
|
+
error.message.must_equal 'argument does not match a video file type'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
describe "when asked to be hashed" do
|
|
45
|
+
before do
|
|
46
|
+
@sf = ShowFeature::Processor.new(@show)
|
|
47
|
+
end
|
|
48
|
+
it "must return an hash" do
|
|
49
|
+
@sf.parse
|
|
50
|
+
@sf.to_hsh.must_be_instance_of Hash
|
|
51
|
+
end
|
|
52
|
+
it "must filled the hash correctly " do
|
|
53
|
+
@sf.parse
|
|
54
|
+
@sf.to_hsh.must_equal({ :name => @output.name.gsub('.', ' '),
|
|
55
|
+
:season => @output.season,
|
|
56
|
+
:episode => @output.episode,
|
|
57
|
+
:team => @output.team })
|
|
58
|
+
end
|
|
59
|
+
it "must return an empty hash if showfeature is not parsed yet" do
|
|
60
|
+
@sf.to_hsh.must_be_empty
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "when asked to parse the show name" do
|
|
65
|
+
before do
|
|
66
|
+
@sf = ShowFeature::Processor.new(@show)
|
|
67
|
+
@sf.parse
|
|
68
|
+
end
|
|
69
|
+
it "must retrieve the element" do
|
|
70
|
+
assert_block do
|
|
71
|
+
[:name, :episode, :team, :raw_name].
|
|
72
|
+
all? {|stuff|
|
|
73
|
+
@output.send(stuff).eql? @sf.send(stuff).gsub(' ','.')
|
|
74
|
+
}
|
|
75
|
+
@output.season.to_i.must_equal @sf.season.to_i
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe "when asked if parsed" do
|
|
81
|
+
before do
|
|
82
|
+
@sf = ShowFeature::Processor.new(@show)
|
|
83
|
+
end
|
|
84
|
+
it "must return true if parsed" do
|
|
85
|
+
@sf.parsed?.wont_equal true
|
|
86
|
+
@sf.parse
|
|
87
|
+
@sf.parsed?.must_equal true
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe "when asked to replace an element" do
|
|
92
|
+
before do
|
|
93
|
+
@sf = ShowFeature::Processor.new(@show)
|
|
94
|
+
end
|
|
95
|
+
it "must replace raw_name by default when a string is passed" do
|
|
96
|
+
@sf.parse
|
|
97
|
+
@sf.replace("foo.s01e01.hdtv-bar.mp4")
|
|
98
|
+
@sf.raw_name.must_equal "foo.s01e01.hdtv-bar.mp4"
|
|
99
|
+
end
|
|
100
|
+
it "must replace the wanted attributes" do
|
|
101
|
+
@sf.parse
|
|
102
|
+
@sf.replace(name: "foo", season: '01', episode: 1, team: "bar")
|
|
103
|
+
@sf.raw_name.must_match /foo.*01.?01.*bar/
|
|
104
|
+
end
|
|
105
|
+
it "must raised if not parsed yet" do
|
|
106
|
+
result = lambda{ @sf.replace(:name => "foo")}
|
|
107
|
+
result.must_raise ShowFeature::NotParsedError
|
|
108
|
+
error = result.call rescue $!
|
|
109
|
+
error.message.must_equal 'showfeature cannot complete replace if show is not parsed'
|
|
110
|
+
end
|
|
111
|
+
it "must raised if the given argument is not of type String or Hash" do
|
|
112
|
+
result = lambda{ @sf.replace([])}
|
|
113
|
+
result.must_raise ShowFeature::TypeError
|
|
114
|
+
error = result.call rescue $!
|
|
115
|
+
error.message.must_equal 'argument must be of type String or Hash'
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "wont do anything if argument has not a video filename when a String is passed" do
|
|
119
|
+
@sf.parse
|
|
120
|
+
@sf.replace 'foo'
|
|
121
|
+
@sf.raw_name.must_equal @output.raw_name
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe "when asked if it is a video file" do
|
|
126
|
+
before do
|
|
127
|
+
@sf = ShowFeature::Processor.new(@show)
|
|
128
|
+
end
|
|
129
|
+
it "must be true or false" do
|
|
130
|
+
assert_block do
|
|
131
|
+
[TrueClass,FalseClass].any? {|elt| @sf.video_file_type?.instance_of? elt}
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: showfeature
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Allan Seymour
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: This library allows to find the relevant features in a tv show filename
|
|
15
|
+
(e.g. [name].S[season]E[episode].hdtv-[team].avi)
|
|
16
|
+
email: banks.the.megalithic.stone@gmail.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- .gitignore
|
|
22
|
+
- Gemfile
|
|
23
|
+
- Gemfile.lock
|
|
24
|
+
- LICENSE
|
|
25
|
+
- README.md
|
|
26
|
+
- lib/showfeature.rb
|
|
27
|
+
- lib/showfeature/exception.rb
|
|
28
|
+
- lib/showfeature/processor.rb
|
|
29
|
+
- lib/showfeature/version.rb
|
|
30
|
+
- showfeature.gemspec
|
|
31
|
+
- spec/showfeature_spec.rb
|
|
32
|
+
homepage: https://github.com/stonebanks/showfeature/
|
|
33
|
+
licenses: []
|
|
34
|
+
post_install_message:
|
|
35
|
+
rdoc_options: []
|
|
36
|
+
require_paths:
|
|
37
|
+
- lib
|
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ! '>='
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: 1.9.1
|
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
|
+
none: false
|
|
46
|
+
requirements:
|
|
47
|
+
- - ! '>='
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '0'
|
|
50
|
+
requirements: []
|
|
51
|
+
rubyforge_project:
|
|
52
|
+
rubygems_version: 1.8.23
|
|
53
|
+
signing_key:
|
|
54
|
+
specification_version: 3
|
|
55
|
+
summary: This library allows to find the relevant features in a tv show filename (e.g.
|
|
56
|
+
[name].S[season]E[episode].hdtv-[team].avi)
|
|
57
|
+
test_files:
|
|
58
|
+
- spec/showfeature_spec.rb
|