track_parser 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +2 -0
- data/lib/track_parser.rb +5 -0
- data/lib/track_parser/filter_pipeline.rb +21 -0
- data/lib/track_parser/filtered_parts.rb +25 -0
- data/lib/track_parser/filters/featuring_filter.rb +30 -0
- data/lib/track_parser/filters/filter_nodes_mapping.rb +12 -0
- data/lib/track_parser/filters/remix_filter.rb +41 -0
- data/lib/track_parser/nodes/artist_node.rb +14 -0
- data/lib/track_parser/nodes/artists_node.rb +31 -0
- data/lib/track_parser/nodes/base_node.rb +16 -0
- data/lib/track_parser/nodes/empty_node.rb +7 -0
- data/lib/track_parser/nodes/featuring_node.rb +22 -0
- data/lib/track_parser/nodes/name_node.rb +14 -0
- data/lib/track_parser/nodes/remix_node.rb +40 -0
- data/lib/track_parser/nodes/track_node.rb +49 -0
- data/lib/track_parser/nodes/trackname_node.rb +20 -0
- data/lib/track_parser/parser.rb +19 -0
- data/lib/track_parser/processor.rb +53 -0
- data/lib/track_parser/track.rb +49 -0
- data/lib/track_parser/version.rb +3 -0
- data/spec/parser_spec.rb +96 -0
- data/spec/spec_helper.rb +11 -0
- data/track_parser.gemspec +26 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 41f48fe39a78f9c5bc0852de5826ba1473fd487e
|
4
|
+
data.tar.gz: 303e183dc8057a76b3585ea9a048bcb04f6e9c09
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f2d9a92b145ee0172a4ab131e0542fe5847b7c47217c86a9a5f393bcdc6ebb576e1b3c6727796ddf338dcc7606fc69f807c20d4c17ae0622515cec96c5626b7c
|
7
|
+
data.tar.gz: cb4bdda3a49365c7360f62ecf4d976e42f4c71d0f78de9db2b67dbada973b63866aef0342789cbcb9d6d78e77bbc87799ade5ca4e6b5616569708f0e66b4b6df
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Alexandre Quintino
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# TrackParser
|
2
|
+
|
3
|
+
Tries to parse the name of a track (e.g. ArtistA - ABC (ArtistB remix)) and extract metadata from it (e.g. artists = ArtistA, track-name = ABC, remixer = ArtistB)
|
4
|
+
It makes a best effort to extract the metadata by passing the track through a set of rules that most tracks follow. If the track does not follow those rules, the results might not be accurate.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'track_parser'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install track_parser
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Simple
|
25
|
+
```ruby
|
26
|
+
require "track_parser"
|
27
|
+
TrackParser::Parser.do("Derek Marin - We've Been Expecting You - Hreno's Deep Pockets Dub")
|
28
|
+
=> {:artists=>["Derek Marin"], :track_name=>"We've Been Expecting You", :remixer=>"Hreno", :remix_name=>"Deep Pockets Dub"}
|
29
|
+
```
|
30
|
+
|
31
|
+
### Structured
|
32
|
+
You might know already the artists. In that case you can use:
|
33
|
+
```ruby
|
34
|
+
require "track_parser"
|
35
|
+
TrackParser::Parser.do(artists: ["Derek Marin], name: "We've Been Expecting You - Hreno's Deep Pockets Dub")
|
36
|
+
=> {:artists=>["Derek Marin"], :track_name=>"We've Been Expecting You", :remixer=>"Hreno", :remix_name=>"Deep Pockets Dub"}
|
37
|
+
```
|
38
|
+
|
39
|
+
## Non-exhaustive list of formats supported (for more check the [tests](https://github.com/alexquintino/track_parser/blob/master/spec/parser_spec.rb))
|
40
|
+
|
41
|
+
* `<artist> - <track name>`
|
42
|
+
* `<artist> - <track name> [-] (<remixer> Remix|Vocal|Dub|Mix)`
|
43
|
+
* `<artist> - <track name> (<remixer>'s <remix name>)`
|
44
|
+
* `<artist> & <artist> - <track name>`
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it ( https://github.com/alexquintino/track_parser/fork )
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/track_parser.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "filters/remix_filter"
|
2
|
+
require_relative "filters/featuring_filter"
|
3
|
+
require_relative "filtered_parts"
|
4
|
+
|
5
|
+
module TrackParser
|
6
|
+
class FilterPipeline
|
7
|
+
|
8
|
+
FILTERS = [RemixFilter, FeaturingFilter] #order matters currently
|
9
|
+
|
10
|
+
def self.filter(text)
|
11
|
+
size_last_pass = 0
|
12
|
+
filtered = nil
|
13
|
+
loop do #make several passes until nothing new is found
|
14
|
+
filtered = FILTERS.reduce(FilteredParts.new(text)) { |data, filter_class| filter_class.filter(data) }
|
15
|
+
break if filtered.parts.size == size_last_pass
|
16
|
+
size_last_pass = filtered.parts.size
|
17
|
+
end
|
18
|
+
return filtered.parts, filtered.text
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module TrackParser
|
2
|
+
class FilteredParts
|
3
|
+
|
4
|
+
def initialize(text)
|
5
|
+
@remaining = text
|
6
|
+
@parts = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def text
|
10
|
+
@remaining
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_part(type, text)
|
14
|
+
@parts << {type: type, text: text}
|
15
|
+
end
|
16
|
+
|
17
|
+
def remove_text(text)
|
18
|
+
@remaining = @remaining.gsub(text, "")
|
19
|
+
end
|
20
|
+
|
21
|
+
def parts
|
22
|
+
@parts
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module TrackParser
|
2
|
+
class FeaturingFilter
|
3
|
+
|
4
|
+
def self.filter(data)
|
5
|
+
self.new(data).filter
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
@data = data
|
10
|
+
end
|
11
|
+
|
12
|
+
def filter
|
13
|
+
if has_featuring?
|
14
|
+
featuring_text = regexp.match(@data.text)[:featuring]
|
15
|
+
@data.add_part(:featuring, featuring_text)
|
16
|
+
@data.remove_text(featuring_text) #remove featuring artists from trackname
|
17
|
+
end
|
18
|
+
return @data
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_featuring?
|
22
|
+
!!regexp.match(@data.text)
|
23
|
+
end
|
24
|
+
|
25
|
+
def regexp
|
26
|
+
/(?<featuring>\(?(#{FeaturingNode::VERSIONS_REGEXP})\s.*\)?)/i #find featuring keywords
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative '../nodes/remix_node'
|
2
|
+
require_relative '../nodes/featuring_node'
|
3
|
+
|
4
|
+
module TrackParser
|
5
|
+
class FilterNodesMapping
|
6
|
+
FILTERS_NODES_MAPPING = {remix: RemixNode, featuring: FeaturingNode}
|
7
|
+
|
8
|
+
def self.to_nodes(parts)
|
9
|
+
parts.map { |part| FILTERS_NODES_MAPPING[part[:type]].new(part[:text])}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "../nodes/remix_node"
|
2
|
+
|
3
|
+
module TrackParser
|
4
|
+
class RemixFilter
|
5
|
+
|
6
|
+
def self.filter(data)
|
7
|
+
self.new(data).filter
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data)
|
11
|
+
@data = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def filter
|
15
|
+
if has_remix?
|
16
|
+
extracted = content.select {|match| !regexp.match(match).nil?}.first #select first that matches a remix
|
17
|
+
@data.add_part(:remix, extracted)
|
18
|
+
@data.remove_text "(#{extracted})" #remove remix string from
|
19
|
+
end
|
20
|
+
return @data
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_remix?
|
24
|
+
!!regexp #find remix keywords
|
25
|
+
end
|
26
|
+
|
27
|
+
def content
|
28
|
+
text = @data.text
|
29
|
+
if text =~ /(\(|\))+/
|
30
|
+
text.scan(/\((?<content>.*?)\)/).flatten
|
31
|
+
else
|
32
|
+
[text]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def regexp
|
37
|
+
/(?<remix>.*?\b(#{RemixNode::VERSIONS_REGEXP})+)\b/i
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative 'artist_node'
|
2
|
+
require_relative 'base_node'
|
3
|
+
|
4
|
+
module TrackParser
|
5
|
+
class ArtistsNode < BaseNode
|
6
|
+
|
7
|
+
def initialize(artists)
|
8
|
+
super(:artists, artists)
|
9
|
+
end
|
10
|
+
|
11
|
+
def children
|
12
|
+
if @raw.is_a? String
|
13
|
+
if multiple?
|
14
|
+
@raw.split(regex).map { |capture| ArtistNode.new(capture) }
|
15
|
+
else
|
16
|
+
[ArtistNode.new(@raw)]
|
17
|
+
end
|
18
|
+
else
|
19
|
+
@raw.map { |artist| ArtistNode.new(artist) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def multiple?
|
24
|
+
!!regex.match(@raw)
|
25
|
+
end
|
26
|
+
|
27
|
+
def regex
|
28
|
+
/\s(?:and|&)\s/i
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ast'
|
2
|
+
require_relative 'empty_node'
|
3
|
+
|
4
|
+
module TrackParser
|
5
|
+
class BaseNode < AST::Node
|
6
|
+
|
7
|
+
def self.new(text)
|
8
|
+
return EmptyNode.new if text.nil? || (text.is_a?(String) && text.strip.empty?)
|
9
|
+
super(text)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(type, text)
|
13
|
+
super(type, [], {raw: text})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'artist_node'
|
2
|
+
require_relative 'base_node'
|
3
|
+
|
4
|
+
module TrackParser
|
5
|
+
class FeaturingNode < BaseNode
|
6
|
+
|
7
|
+
VERSIONS_REGEXP = ["feat.", "featuring", "ft."].join("|")
|
8
|
+
|
9
|
+
def initialize(artists)
|
10
|
+
super(:featuring, artists)
|
11
|
+
end
|
12
|
+
|
13
|
+
def regexp
|
14
|
+
/\(?(#{FeaturingNode::VERSIONS_REGEXP})\s(?<artist>[^\)]*)\)?/i
|
15
|
+
end
|
16
|
+
|
17
|
+
def children
|
18
|
+
artist = regexp.match(@raw)[:artist]
|
19
|
+
[ArtistsNode.new(artist)]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'base_node'
|
2
|
+
require_relative 'artists_node'
|
3
|
+
require_relative 'name_node'
|
4
|
+
|
5
|
+
module TrackParser
|
6
|
+
class RemixNode < BaseNode
|
7
|
+
|
8
|
+
VERSIONS_REGEXP = ["remix", "mix", "vocal", "dub", "rework", "edit", "version", "extended", "club", "original"].join("|")
|
9
|
+
|
10
|
+
def initialize(remix)
|
11
|
+
raw = remix.gsub(/(\(|\))/, "") # remove parantheses
|
12
|
+
super(:remix, raw)
|
13
|
+
end
|
14
|
+
|
15
|
+
def children
|
16
|
+
if has_remix_name?
|
17
|
+
nodes = @raw.split(/(?:'|´)s/)
|
18
|
+
[ArtistsNode.new(nodes[0]), NameNode.new(nodes[1])]
|
19
|
+
else
|
20
|
+
[ArtistsNode.new(remixer), NameNode.new(remix_version)]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_remix_name?
|
25
|
+
@raw.include?("'s") || @raw.include?("´s")
|
26
|
+
end
|
27
|
+
|
28
|
+
def remixer
|
29
|
+
without_version.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def remix_version(remix = @raw)
|
33
|
+
remix.scan(/(#{VERSIONS_REGEXP})\b/i).flatten.join(" ")
|
34
|
+
end
|
35
|
+
|
36
|
+
def without_version(part = @raw)
|
37
|
+
part.gsub(remix_version, "")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'base_node'
|
2
|
+
require_relative 'artists_node'
|
3
|
+
require_relative 'trackname_node'
|
4
|
+
require_relative 'remix_node'
|
5
|
+
|
6
|
+
module TrackParser
|
7
|
+
class TrackNode < BaseNode
|
8
|
+
|
9
|
+
def initialize(track)
|
10
|
+
raw = replace_parentheses(track)
|
11
|
+
super(:track, raw)
|
12
|
+
end
|
13
|
+
|
14
|
+
def children
|
15
|
+
if track_sections.size == 1
|
16
|
+
raise UnparseableTrack.new("Don't know how to parse a track without \"-\". Track was:#{@raw}")
|
17
|
+
else
|
18
|
+
nodes = track_sections[2..-1].map do |track_section|
|
19
|
+
parts = FilterPipeline.filter(track_section).first
|
20
|
+
FilterNodesMapping.to_nodes(parts)
|
21
|
+
end
|
22
|
+
[ArtistsNode.new(track_sections[0]), TracknameNode.new(track_sections[1])] + nodes.flatten
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def replace_parentheses(text)
|
27
|
+
if text.is_a? String
|
28
|
+
text.gsub("[","(").gsub("]",")")
|
29
|
+
else
|
30
|
+
text[:name] = replace_parentheses(text[:name])
|
31
|
+
text
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def track_sections
|
36
|
+
if @raw.is_a? String
|
37
|
+
split_sections(@raw)
|
38
|
+
else
|
39
|
+
[@raw[:artists]] + split_sections(@raw[:name])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def split_sections(text)
|
44
|
+
text.split(" - ").map(&:strip)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class UnparseableTrack < StandardError; end
|
49
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'base_node'
|
2
|
+
require_relative 'name_node'
|
3
|
+
require_relative 'remix_node'
|
4
|
+
require_relative 'featuring_node'
|
5
|
+
require_relative '../filter_pipeline'
|
6
|
+
require_relative '../filters/filter_nodes_mapping'
|
7
|
+
|
8
|
+
module TrackParser
|
9
|
+
class TracknameNode < BaseNode
|
10
|
+
|
11
|
+
def initialize(trackname)
|
12
|
+
super(:trackname, trackname)
|
13
|
+
end
|
14
|
+
|
15
|
+
def children
|
16
|
+
parts, remaining_text = FilterPipeline.filter(@raw)
|
17
|
+
[NameNode.new(remaining_text)] + FilterNodesMapping.to_nodes(parts)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "nodes/track_node"
|
2
|
+
require_relative "processor"
|
3
|
+
|
4
|
+
module TrackParser
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
def self.do(track)
|
8
|
+
self.new(track).parse
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(track)
|
12
|
+
@track = TrackNode.new(track)
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
Processor.new.process(@track)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "ast"
|
2
|
+
require_relative "track"
|
3
|
+
|
4
|
+
module TrackParser
|
5
|
+
class Processor < AST::Processor
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@track = Track.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_track(node)
|
12
|
+
hash = process_all(node).reduce({}) { |mem, h| mem.merge(h) }
|
13
|
+
@track.add_artists(hash[:artists])
|
14
|
+
@track
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_trackname(node)
|
18
|
+
hash = process_all(node).reduce({}) { |mem, h| mem.merge(h) }
|
19
|
+
@track.add_name(hash[:name])
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_artists(node)
|
24
|
+
artists = process_all(node)
|
25
|
+
{ artists: artists }
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_artist(node)
|
29
|
+
node.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_name(node)
|
33
|
+
{ name: node.name }
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_remix(node)
|
37
|
+
hash = process_all(node).reduce({}) { |mem, h| mem.merge(h) }
|
38
|
+
@track.add_remixer(hash[:artists])
|
39
|
+
@track.add_remix_name(hash[:name])
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_featuring(node)
|
44
|
+
artists = process_all(node).first
|
45
|
+
@track.add_featuring(artists[:artists])
|
46
|
+
{}
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_empty(node)
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module TrackParser
|
2
|
+
class Track
|
3
|
+
|
4
|
+
attr_accessor :artists, :name, :remixer, :remix_name, :featuring
|
5
|
+
|
6
|
+
def initialize(hash = {})
|
7
|
+
@artists = hash[:artists]
|
8
|
+
@name = hash[:name]
|
9
|
+
@remixer = hash[:remixer]
|
10
|
+
@remix_name = hash[:remix_name]
|
11
|
+
@featuring = hash[:featuring]
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_artists(artists)
|
15
|
+
@artists = artists
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_remixer(remixer)
|
19
|
+
return if remixer.nil?
|
20
|
+
if @remixer.nil?
|
21
|
+
@remixer = remixer
|
22
|
+
else
|
23
|
+
@remixer.concat(remixer)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_remix_name(remix_name)
|
28
|
+
return if remix_name.nil?
|
29
|
+
if @remix_name.nil?
|
30
|
+
@remix_name = remix_name
|
31
|
+
else
|
32
|
+
@remix_name += " " + remix_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_name(name)
|
37
|
+
@name = name
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_featuring(featured_artists)
|
41
|
+
@featuring = featured_artists
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"artists='#{@artists}' name='#{@name}' remixer='#{@remixer}' remix_name='#{@remix_name}' featuring='#{featuring}'"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
describe TrackParser::Parser do
|
2
|
+
|
3
|
+
tracks = {
|
4
|
+
"SIS - Orgsa" =>
|
5
|
+
{ artists: ["SIS"], name: "Orgsa", remixer: nil, remix_name: nil},
|
6
|
+
"Roy Davis Jr - About Love (Pezzner Remix)" =>
|
7
|
+
{ artists: ["Roy Davis Jr"], name: "About Love", remixer: ["Pezzner"], remix_name: "Remix" },
|
8
|
+
"Julien Perez & Octavio Camino - Parada Maya" =>
|
9
|
+
{ artists: ["Julien Perez", "Octavio Camino"], name: "Parada Maya", remixer: nil, remix_name: nil},
|
10
|
+
"Kollektiv Turmstrasse - Ordinary (Lake People's Circle Motive Remix)" =>
|
11
|
+
{ artists: ["Kollektiv Turmstrasse"], name: "Ordinary", remixer: ["Lake People"], remix_name: "Circle Motive Remix" },
|
12
|
+
"Derek Marin - We've Been Expecting You - Hreno´s Deep Pockets Dub" =>
|
13
|
+
{ artists: ["Derek Marin"], name: "We've Been Expecting You", remixer: ["Hreno"], remix_name: "Deep Pockets Dub" },
|
14
|
+
"Umek & Uto Karem - Crossing the Lines - Original Mix" =>
|
15
|
+
{ artists: ["Umek", "Uto Karem"], name: "Crossing the Lines", remixer: nil, remix_name: "Original Mix" },
|
16
|
+
"Noir & Fraser Owen - &U - Mendo and Danny Serrano Remix" =>
|
17
|
+
{ artists: ["Noir", "Fraser Owen"], name: "&U", remixer: ["Mendo", "Danny Serrano"], remix_name: "Remix"},
|
18
|
+
"Plastikman - Spastik - Dubfire Rework" =>
|
19
|
+
{ artists: ["Plastikman"], name: "Spastik", remixer: ["Dubfire"], remix_name: "Rework" },
|
20
|
+
"Alex Under - El Encuentro - Richie Hawtin Edit" =>
|
21
|
+
{ artists: ['Alex Under'], name: 'El Encuentro', remixer: ["Richie Hawtin"], remix_name: "Edit" },
|
22
|
+
"Gorge - Erotic Soul feat. The Writers Poet - Original Mix" =>
|
23
|
+
{ artists: ["Gorge"], name: "Erotic Soul", featuring: ["The Writers Poet"], remixer: nil, remix_name: "Original Mix"},
|
24
|
+
"John Talabot & Pional - Destiny (Feat. Pional)" =>
|
25
|
+
{ artists: ["John Talabot", "Pional"], name: "Destiny", featuring: ["Pional"], remixer: nil, remix_name: nil},
|
26
|
+
"Ornette - Crazy - Nôze Remix - Extended Club Version" =>
|
27
|
+
{ artists: ["Ornette"], name: "Crazy", remixer: ["Nôze"], remix_name: "Remix Extended Club Version" },
|
28
|
+
"2 Guys in Venice & Spiller & Digitalism - Encore - Spiller & 2 Guys In Venice Remix" =>
|
29
|
+
{ artists: ["2 Guys in Venice", "Spiller", "Digitalism"], name: "Encore", remixer: ["Spiller", "2 Guys In Venice"], remix_name: "Remix" },
|
30
|
+
"Subb-an - Take You Back (ft. Beckford)" =>
|
31
|
+
{ artists: ["Subb-an"], name: "Take You Back", featuring: ["Beckford"] },
|
32
|
+
"Aki Bergen & Pezzner & Terry Grant - Tarareando - Vocal Mix" =>
|
33
|
+
{ artists: ["Aki Bergen", "Pezzner", "Terry Grant"], name: "Tarareando", remixer: nil, remix_name: "Vocal Mix" },
|
34
|
+
"Jay Haze & Laila Tov - I Wait For You - Original" =>
|
35
|
+
{ artists: ["Jay Haze", "Laila Tov"], name: "I Wait For You", remixer: nil, remix_name: "Original"},
|
36
|
+
"DJ T. - City Life - feat. Cari Golden [Maceo Plex Remix]" =>
|
37
|
+
{ artists: ["DJ T."], name: "City Life", remixer: ["Maceo Plex"], remix_name: "Remix", featuring: ["Cari Golden"]},
|
38
|
+
"Fritz Kalkbrenner - Right in the Dark - Henrik Schwarz Remix - Chopstick & Johnjon Edit" =>
|
39
|
+
{ artists: ["Fritz Kalkbrenner"], name: "Right in the Dark", remixer: ["Henrik Schwarz", "Chopstick", "Johnjon"], remix_name: "Remix Edit"}
|
40
|
+
}
|
41
|
+
|
42
|
+
tracks_structured = [
|
43
|
+
{track: { artists: ["Sailor & I"], name: "Tough Love - Aril Brikha Remix" }, result:
|
44
|
+
{ artists: ["Sailor & I"], name: "Tough Love", remixer: ["Aril Brikha"], remix_name: "Remix"}}
|
45
|
+
]
|
46
|
+
|
47
|
+
let(:parsed_track) { TrackParser::Parser.do(track) }
|
48
|
+
|
49
|
+
tracks.keys.each do |track|
|
50
|
+
context "#{track}" do
|
51
|
+
let(:track) { track }
|
52
|
+
|
53
|
+
it "returns the artist correctly" do
|
54
|
+
expect(parsed_track.artists).to eq(tracks[track][:artists])
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns the track name correctly" do
|
58
|
+
expect(parsed_track.name).to eq(tracks[track][:name])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "returns the remixer correctly" do
|
62
|
+
expect(parsed_track.remixer).to eq(tracks[track][:remixer])
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns the remix name correctly" do
|
66
|
+
expect(parsed_track.remix_name).to eq(tracks[track][:remix_name])
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns the featured artists correctly" do
|
70
|
+
expect(parsed_track.featuring).to eq(tracks[track][:featuring])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "invalid track" do
|
76
|
+
let(:track) { "Invalid Track" }
|
77
|
+
|
78
|
+
it "throws an exception when the track doesn't have \"-\"" do
|
79
|
+
expect{TrackParser::Parser.do(track)}.to raise_error(TrackParser::UnparseableTrack)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "Hash as input" do
|
84
|
+
let(:track) { tracks_structured.first[:track] }
|
85
|
+
let(:result) { tracks_structured.first[:result]}
|
86
|
+
|
87
|
+
it "returns all the correct info" do
|
88
|
+
expect(parsed_track.artists).to eq(result[:artists])
|
89
|
+
expect(parsed_track.name).to eq(result[:name])
|
90
|
+
expect(parsed_track.remixer).to eq(result[:remixer])
|
91
|
+
expect(parsed_track.remix_name).to eq(result[:remix_name])
|
92
|
+
expect(parsed_track.featuring).to eq(result[:featuring])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'track_parser/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "track_parser"
|
8
|
+
spec.version = TrackParser::VERSION
|
9
|
+
spec.authors = ["Alexandre Quintino"]
|
10
|
+
spec.email = ["amsquintino@gmail.com"]
|
11
|
+
spec.summary = %q{Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix)) and extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer = ArtistB)}
|
12
|
+
spec.description = %q{Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix)) and extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer = ArtistB)}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "pry"
|
25
|
+
spec.add_runtime_dependency "ast"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: track_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexandre Quintino
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ast
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix))
|
84
|
+
and extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer =
|
85
|
+
ArtistB)
|
86
|
+
email:
|
87
|
+
- amsquintino@gmail.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rspec"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- lib/track_parser.rb
|
99
|
+
- lib/track_parser/filter_pipeline.rb
|
100
|
+
- lib/track_parser/filtered_parts.rb
|
101
|
+
- lib/track_parser/filters/featuring_filter.rb
|
102
|
+
- lib/track_parser/filters/filter_nodes_mapping.rb
|
103
|
+
- lib/track_parser/filters/remix_filter.rb
|
104
|
+
- lib/track_parser/nodes/artist_node.rb
|
105
|
+
- lib/track_parser/nodes/artists_node.rb
|
106
|
+
- lib/track_parser/nodes/base_node.rb
|
107
|
+
- lib/track_parser/nodes/empty_node.rb
|
108
|
+
- lib/track_parser/nodes/featuring_node.rb
|
109
|
+
- lib/track_parser/nodes/name_node.rb
|
110
|
+
- lib/track_parser/nodes/remix_node.rb
|
111
|
+
- lib/track_parser/nodes/track_node.rb
|
112
|
+
- lib/track_parser/nodes/trackname_node.rb
|
113
|
+
- lib/track_parser/parser.rb
|
114
|
+
- lib/track_parser/processor.rb
|
115
|
+
- lib/track_parser/track.rb
|
116
|
+
- lib/track_parser/version.rb
|
117
|
+
- spec/parser_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
- track_parser.gemspec
|
120
|
+
homepage: ''
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
metadata: {}
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options: []
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 2.4.5
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Tries to parse the name of a track (eg. ArtistA - ABC (ArtistB remix)) and
|
144
|
+
extract metadata from it (eg. artists = ArtistA, track-name = ABC, remixer = ArtistB)
|
145
|
+
test_files:
|
146
|
+
- spec/parser_spec.rb
|
147
|
+
- spec/spec_helper.rb
|