rubycue 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +48 -0
- data/Rakefile +23 -0
- data/VERSION +1 -0
- data/lib/rubycue/cuesheet.rb +92 -0
- data/lib/rubycue/exceptions.rb +3 -0
- data/lib/rubycue/index.rb +108 -0
- data/lib/rubycue.rb +5 -0
- data/spec/fixtures/malformed.cue +214 -0
- data/spec/fixtures/test.cue +215 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/cuesheet_spec.rb +102 -0
- data/spec/unit/index_spec.rb +243 -0
- metadata +82 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.swp
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 Blake Smith
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= RubyCue: A library to parse cuesheet song files
|
2
|
+
|
3
|
+
RubyCue is a Ruby interface for parsing and accessing cuesheet data.
|
4
|
+
|
5
|
+
= Usage:
|
6
|
+
|
7
|
+
=== Basic usage
|
8
|
+
|
9
|
+
require 'rubycue'
|
10
|
+
|
11
|
+
cuesheet = RubyCue::Cuesheet.new(File.read("cuesheet.cue"))
|
12
|
+
cuesheet.parse!
|
13
|
+
|
14
|
+
cuesheet.songs.each do |song|
|
15
|
+
puts "#{song[:performer]} - #{song[:title]} at #{song[:index]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
=== Calculated Song Durations
|
19
|
+
|
20
|
+
RubyCue will also calculate song durations. In order to calculate the last song's duration, you must pass the optional track duration (in seconds) for the entire file.
|
21
|
+
|
22
|
+
cuesheet = RubyCue::Cuesheet.new(File.read("cuesheet.cue"), 7143)
|
23
|
+
|
24
|
+
=== Current Song Position
|
25
|
+
|
26
|
+
After a cuesheet is instantiated, you can pass a current track position, and the cuesheet will return which song is currently playing at that position:
|
27
|
+
|
28
|
+
# with seconds
|
29
|
+
cuesheet.position(4352)
|
30
|
+
=> {:index=>#<RubyCue::Index:0x101025240 @seconds=7, @minutes=71, @frames=31>, :track=>32, :performer=>"Netsky", :title=>"Iron Heart", :duration=>#<RubyCue::Index:0x10100f2d8 @seconds=55, @minutes=2, @frames=38>}
|
31
|
+
|
32
|
+
# with an array [minutes, seconds, frames]
|
33
|
+
cuesheet.position([43, 23, 45])
|
34
|
+
=> {:index=>#<RubyCue::Index:0x101027590 @seconds=27, @minutes=39, @frames=57>, :track=>19, :performer=>"Legion feat. Adam Wright", :title=>"Both Sides", :duration=>#<RubyCue::Index:0x101013130 @seconds=45, @minutes=4, @frames=13>}
|
35
|
+
|
36
|
+
=== Index objects
|
37
|
+
|
38
|
+
Index objects are a time representation of the position in a track. They are represented with fields [minutes, seconds, frames]. There are 75 frames in each second. You can access the values of the index object like so:
|
39
|
+
|
40
|
+
index = Index.new([30, 23, 73])
|
41
|
+
index.minutes => 30
|
42
|
+
index.seconds => 23
|
43
|
+
index.frames => 73
|
44
|
+
index.to_i => 1823
|
45
|
+
index.to_f => 1823.97333333333
|
46
|
+
|
47
|
+
There's other stuff you can do with them, check out the source for more in-depth usage.
|
48
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
5
|
+
t.spec_files = FileList['spec/unit/*_spec.rb']
|
6
|
+
end
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'jeweler'
|
12
|
+
Jeweler::Tasks.new do |gemspec|
|
13
|
+
gemspec.name = "rubycue"
|
14
|
+
gemspec.summary = "Ruby cuesheet track parser"
|
15
|
+
gemspec.description = "Basic ruby parser for song cuesheets"
|
16
|
+
gemspec.email = "blakesmith0@gmail.com"
|
17
|
+
gemspec.homepage = "http://github.com/blakesmith/rubycue"
|
18
|
+
gemspec.authors = ["Blake Smith"]
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
22
|
+
end
|
23
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module RubyCue
|
2
|
+
class Cuesheet
|
3
|
+
attr_reader :cuesheet, :songs, :track_duration
|
4
|
+
|
5
|
+
def initialize(cuesheet, track_duration=nil)
|
6
|
+
@cuesheet = cuesheet
|
7
|
+
@reg = {
|
8
|
+
:track => %r(TRACK (\d{1,3}) AUDIO),
|
9
|
+
:performer => %r(PERFORMER "(.*)"),
|
10
|
+
:title => %r(TITLE "(.*)"),
|
11
|
+
:index => %r(INDEX \d{1,3} (\d{1,3}):(\d{1,2}):(\d{1,2}))
|
12
|
+
}
|
13
|
+
@track_duration = RubyCue::Index.new(track_duration) if track_duration
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse!
|
17
|
+
@songs = parse_titles.map{|title| {:title => title}}
|
18
|
+
@songs.each_with_index do |song, i|
|
19
|
+
song[:performer] = parse_performers[i]
|
20
|
+
song[:track] = parse_tracks[i]
|
21
|
+
song[:index] = parse_indices[i]
|
22
|
+
end
|
23
|
+
raise RubyCue::InvalidCuesheet.new("Field amounts are not all present. Cuesheet is malformed!") unless valid?
|
24
|
+
calculate_song_durations!
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def position(value)
|
29
|
+
index = Index.new(value)
|
30
|
+
return @songs.first if index < @songs.first[:index]
|
31
|
+
@songs.each_with_index do |song, i|
|
32
|
+
return song if song == @songs.last
|
33
|
+
return song if between(song[:index], @songs[i+1][:index], index)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid?
|
38
|
+
@songs.all? do |song|
|
39
|
+
[:performer, :track, :index, :title].all? do |key|
|
40
|
+
song[key] != nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def calculate_song_durations!
|
48
|
+
@songs.each_with_index do |song, i|
|
49
|
+
if song == @songs.last
|
50
|
+
song[:duration] = (@track_duration - song[:index]) if @track_duration
|
51
|
+
return
|
52
|
+
end
|
53
|
+
song[:duration] = @songs[i+1][:index] - song[:index]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def between(a, b, position_index)
|
58
|
+
(position_index > a) && (position_index < b)
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_titles
|
62
|
+
unless @titles
|
63
|
+
@titles = cuesheet_scan(:title).map{|title| title.first}
|
64
|
+
@titles.delete_at(0)
|
65
|
+
end
|
66
|
+
@titles
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_performers
|
70
|
+
unless @performers
|
71
|
+
@performers = cuesheet_scan(:performer).map{|performer| performer.first}
|
72
|
+
@performers.delete_at(0)
|
73
|
+
end
|
74
|
+
@performers
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_tracks
|
78
|
+
@tracks ||= cuesheet_scan(:track).map{|track| track.first.to_i}
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse_indices
|
82
|
+
@indices ||= cuesheet_scan(:index).map{|index| RubyCue::Index.new([index[0].to_i, index[1].to_i, index[2].to_i])}
|
83
|
+
end
|
84
|
+
|
85
|
+
def cuesheet_scan(field)
|
86
|
+
scan = @cuesheet.scan(@reg[field])
|
87
|
+
raise InvalidCuesheet.new("No fields were found for #{field.to_s}") if scan.empty?
|
88
|
+
scan
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module RubyCue
|
2
|
+
class Index
|
3
|
+
SECONDS_PER_MINUTE = 60
|
4
|
+
FRAMES_PER_SECOND = 75
|
5
|
+
FRAMES_PER_MINUTE = FRAMES_PER_SECOND * 60
|
6
|
+
|
7
|
+
attr_reader :minutes, :seconds, :frames
|
8
|
+
|
9
|
+
def initialize(value=nil)
|
10
|
+
case value
|
11
|
+
when Array
|
12
|
+
set_from_array!(value)
|
13
|
+
when Integer
|
14
|
+
set_from_integer!(value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_f
|
19
|
+
((@minutes * SECONDS_PER_MINUTE) + (@seconds) + (@frames.to_f / FRAMES_PER_SECOND)).to_f
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_i
|
23
|
+
to_f.floor
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_a
|
27
|
+
[@minutes, @seconds, @frames]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"#{'%02d' % @minutes}:#{'%02d' % @seconds}:#{'%02d' % @frames}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def +(other)
|
35
|
+
self.class.new(carrying_addition(other))
|
36
|
+
end
|
37
|
+
|
38
|
+
def -(other)
|
39
|
+
self.class.new(carrying_subtraction(other))
|
40
|
+
end
|
41
|
+
|
42
|
+
def >(other)
|
43
|
+
self.to_f > other.to_f
|
44
|
+
end
|
45
|
+
|
46
|
+
def <(other)
|
47
|
+
self.to_f < other.to_f
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
self.to_a == other.to_a
|
52
|
+
end
|
53
|
+
|
54
|
+
def each
|
55
|
+
to_a.each {|value| yield value }
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def carrying_addition(other)
|
61
|
+
minutes, seconds, frames = *[@minutes + other.minutes,
|
62
|
+
@seconds + other.seconds, @frames + other.frames]
|
63
|
+
|
64
|
+
seconds, frames = *convert_with_rate(frames, seconds, FRAMES_PER_SECOND)
|
65
|
+
minutes, seconds = *convert_with_rate(seconds, minutes, SECONDS_PER_MINUTE)
|
66
|
+
[minutes, seconds, frames]
|
67
|
+
end
|
68
|
+
|
69
|
+
def carrying_subtraction(other)
|
70
|
+
seconds = minutes = 0
|
71
|
+
|
72
|
+
my_frames = @frames + (@seconds * FRAMES_PER_SECOND) + (@minutes * FRAMES_PER_MINUTE)
|
73
|
+
other_frames = other.frames + (other.seconds * FRAMES_PER_SECOND) + (other.minutes * FRAMES_PER_MINUTE)
|
74
|
+
frames = my_frames - other_frames
|
75
|
+
|
76
|
+
seconds, frames = *convert_with_rate(frames, seconds, FRAMES_PER_SECOND)
|
77
|
+
minutes, seconds = *convert_with_rate(seconds, minutes, SECONDS_PER_MINUTE)
|
78
|
+
[minutes, seconds, frames]
|
79
|
+
end
|
80
|
+
|
81
|
+
def convert_with_rate(from, to, rate, step=1)
|
82
|
+
while from >= rate
|
83
|
+
to += step
|
84
|
+
from -= rate
|
85
|
+
end
|
86
|
+
[to, from]
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_from_array!(array)
|
90
|
+
if array.size != 3 || array.any?{|element| !element.is_a?(Integer)}
|
91
|
+
raise ArgumentError.new("Must be initialized with an array in the format of [minutes, seconds,frames], all integers")
|
92
|
+
end
|
93
|
+
@minutes, @seconds, @frames = *array
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_from_integer!(seconds)
|
97
|
+
@minutes = 0
|
98
|
+
@frames = 0
|
99
|
+
@seconds = seconds
|
100
|
+
|
101
|
+
while @seconds >= SECONDS_PER_MINUTE
|
102
|
+
@minutes += 1
|
103
|
+
@seconds -= SECONDS_PER_MINUTE
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
data/lib/rubycue.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
PERFORMER "Netsky"
|
2
|
+
TITLE "Essential Mix (2010-10-09)"
|
3
|
+
FILE "2010-10-09 - Essential Mix - Netsky.mp3" MP3
|
4
|
+
TRACK 01 AUDIO
|
5
|
+
PERFORMER "Essential Mix"
|
6
|
+
TITLE "Intro"
|
7
|
+
INDEX 01 00:00:00
|
8
|
+
TRACK 02 AUDIO
|
9
|
+
PERFORMER "Shameboy vs. Friction, Camo & Krooked feat. Dynamite MC"
|
10
|
+
TITLE "Strobot (Netsky Remix) vs. Stand Up"
|
11
|
+
INDEX 01 01:50:07
|
12
|
+
TRACK 03 AUDIO
|
13
|
+
PERFORMER "Danny Byrd feat. I-Kay"
|
14
|
+
TITLE "Ill Behaviour"
|
15
|
+
INDEX 01 05:26:67
|
16
|
+
TRACK 04 AUDIO
|
17
|
+
PERFORMER "Die & Interface feat. William Cartwright"
|
18
|
+
TITLE "Bright Lights (Netsky Remix)"
|
19
|
+
INDEX 01 07:16:59
|
20
|
+
TRACK 05 AUDIO
|
21
|
+
PERFORMER "Nu:Tone feat. Natalie Williams"
|
22
|
+
TITLE "Shine In"
|
23
|
+
INDEX 01 10:33:72
|
24
|
+
TRACK 06 AUDIO
|
25
|
+
PERFORMER "Netsky"
|
26
|
+
TITLE "Porcelain VIP vs. I Refuse (Acapella)"
|
27
|
+
INDEX 01 12:56:64
|
28
|
+
TRACK 07 AUDIO
|
29
|
+
PERFORMER "Netsky"
|
30
|
+
TITLE "Do It Do It vs. I Refuse (Acapella)"
|
31
|
+
INDEX 01 15:52:31
|
32
|
+
TRACK 08 AUDIO
|
33
|
+
PERFORMER "Brookes Brothers"
|
34
|
+
TITLE "Beautiful"
|
35
|
+
INDEX 01 17:31:10
|
36
|
+
TRACK 09 AUDIO
|
37
|
+
PERFORMER "Muffler"
|
38
|
+
TITLE "Uplifter"
|
39
|
+
INDEX 01 20:26:47
|
40
|
+
TRACK 10 AUDIO
|
41
|
+
PERFORMER "Indivision & Livewire feat. Nelver"
|
42
|
+
TITLE "Irresistible"
|
43
|
+
INDEX 01 22:15:03
|
44
|
+
TRACK 11 AUDIO
|
45
|
+
PERFORMER "Bcee & S.P.Y."
|
46
|
+
TITLE "Is There Anybody Out There?"
|
47
|
+
INDEX 01 23:44:12
|
48
|
+
TRACK 12 AUDIO
|
49
|
+
PERFORMER "Nu:Logic vs. Brooklyn"
|
50
|
+
TITLE "Bleeper vs. With All My Heart"
|
51
|
+
INDEX 01 25:33:68
|
52
|
+
TRACK 13 AUDIO
|
53
|
+
PERFORMER "Chords"
|
54
|
+
TITLE "Radio"
|
55
|
+
INDEX 01 27:23:42
|
56
|
+
TRACK 14 AUDIO
|
57
|
+
PERFORMER "Danny Byrd feat. Netsky"
|
58
|
+
TITLE "Tonight"
|
59
|
+
INDEX 01 29:46:15
|
60
|
+
TRACK 15 AUDIO
|
61
|
+
PERFORMER "Leftfield"
|
62
|
+
TITLE "Release The Pressure (Netsky Remix)"
|
63
|
+
INDEX 01 31:24:68
|
64
|
+
TRACK 16 AUDIO
|
65
|
+
PERFORMER "Danny Byrd feat. London Elektricity"
|
66
|
+
TITLE "Failsafe"
|
67
|
+
INDEX 01 35:04:31
|
68
|
+
TRACK 17 AUDIO
|
69
|
+
PERFORMER "Netsky"
|
70
|
+
TITLE "Everyday"
|
71
|
+
INDEX 01 37:16:06
|
72
|
+
TRACK 18 AUDIO
|
73
|
+
PERFORMER "Zero 7"
|
74
|
+
TITLE "In The Waiting Line (D+B Remix)"
|
75
|
+
INDEX 01 38:21:66
|
76
|
+
TRACK 19 AUDIO
|
77
|
+
PERFORMER "Legion feat. Adam Wright"
|
78
|
+
TITLE "Both Sides"
|
79
|
+
INDEX 01 39:27:57
|
80
|
+
TRACK 20 AUDIO
|
81
|
+
PERFORMER "New Zealand Shapeshifter"
|
82
|
+
TITLE "The Touch (Netsky Remix)"
|
83
|
+
INDEX 01 44:12:70
|
84
|
+
TRACK 21 AUDIO
|
85
|
+
PERFORMER "Swedish House Mafia"
|
86
|
+
TITLE "One (Netsky Remix)"
|
87
|
+
INDEX 01 46:23:20
|
88
|
+
TRACK 22 AUDIO
|
89
|
+
PERFORMER "Netsky"
|
90
|
+
TITLE "Pirate Bay VIP"
|
91
|
+
INDEX 01 48:36:23
|
92
|
+
TRACK 23 AUDIO
|
93
|
+
PERFORMER "Danny Byrd feat. Cyantific"
|
94
|
+
TITLE "Judgement Day VIP"
|
95
|
+
INDEX 01 51:09:68
|
96
|
+
TRACK 24 AUDIO
|
97
|
+
PERFORMER "Netsky vs. Sidney Samson"
|
98
|
+
TITLE "Tomorrow's Another Dub VIP vs. Riverside (Breakage Remix)"
|
99
|
+
INDEX 01 53:21:46
|
100
|
+
TRACK 25 AUDIO
|
101
|
+
PERFORMER "The Bloody Beetroots feat. Steve Aoki"
|
102
|
+
TITLE "Warp (Dirtyphonics Remix)"
|
103
|
+
INDEX 01 55:37:44
|
104
|
+
TRACK 26 AUDIO
|
105
|
+
PERFORMER "Danny Byrd vs. Burial"
|
106
|
+
TITLE "We Can Have It All vs. Archangel (Edit)"
|
107
|
+
INDEX 01 56:05:01
|
108
|
+
TRACK 27 AUDIO
|
109
|
+
PERFORMER "DJ Fresh & Sigma vs. Netsky"
|
110
|
+
TITLE "Lassitude VIP vs. Escape"
|
111
|
+
INDEX 01 59:03:20
|
112
|
+
TRACK 28 AUDIO
|
113
|
+
PERFORMER "Commix"
|
114
|
+
TITLE "Painted Smile"
|
115
|
+
INDEX 01 63:04:52
|
116
|
+
TRACK 29 AUDIO
|
117
|
+
PERFORMER "Eastcolors"
|
118
|
+
TITLE "Go To Nowhere"
|
119
|
+
INDEX 01 66:00:20
|
120
|
+
TRACK 30 AUDIO
|
121
|
+
PERFORMER "Nu:Logic"
|
122
|
+
TITLE "Bigfoot"
|
123
|
+
INDEX 01 67:49:73
|
124
|
+
TRACK 31 AUDIO
|
125
|
+
PERFORMER "Random Movement"
|
126
|
+
TITLE "Can't Resist (S.P.Y. Remix)"
|
127
|
+
INDEX 01 69:17:50
|
128
|
+
TRACK 32 AUDIO
|
129
|
+
PERFORMER "Netsky"
|
130
|
+
TITLE "Iron Heart"
|
131
|
+
INDEX 01 71:07:31
|
132
|
+
TRACK 33 AUDIO
|
133
|
+
PERFORMER "Unicorn Kid vs. DJ Fresh & Sigma"
|
134
|
+
TITLE "Wild Life (Nu:Tone Remix) vs. Cylon"
|
135
|
+
INDEX 01 74:02:69
|
136
|
+
TRACK 34 AUDIO
|
137
|
+
PERFORMER "Agent Alvin"
|
138
|
+
TITLE "Move"
|
139
|
+
INDEX 01 76:35:15
|
140
|
+
TRACK 35 AUDIO
|
141
|
+
PERFORMER "S.P.Y."
|
142
|
+
TITLE "Go With The Flow"
|
143
|
+
INDEX 01 78:01:51
|
144
|
+
TRACK 36 AUDIO
|
145
|
+
PERFORMER "Metrik"
|
146
|
+
TITLE "T 1000"
|
147
|
+
INDEX 01 79:37:45
|
148
|
+
TRACK 37 AUDIO
|
149
|
+
PERFORMER "Culture Shock"
|
150
|
+
TITLE "Cathedral"
|
151
|
+
INDEX 01 81:21:27
|
152
|
+
TRACK 38 AUDIO
|
153
|
+
PERFORMER "Blokhe4d"
|
154
|
+
TITLE "The Way Life Used To Be"
|
155
|
+
INDEX 01 83:33:35
|
156
|
+
TRACK 39 AUDIO
|
157
|
+
PERFORMER "Hamilton"
|
158
|
+
TITLE "Soundboy"
|
159
|
+
INDEX 01 85:45:13
|
160
|
+
TRACK 40 AUDIO
|
161
|
+
PERFORMER "Squash"
|
162
|
+
TITLE "Divine"
|
163
|
+
INDEX 01 87:34:63
|
164
|
+
TRACK 41 AUDIO
|
165
|
+
PERFORMER "Above & Beyond & Gareth Emery"
|
166
|
+
TITLE "On A Good Day (J Majik & Wickaman Remix)"
|
167
|
+
INDEX 01 89:24:45
|
168
|
+
TRACK 42 AUDIO
|
169
|
+
PERFORMER "Metrik"
|
170
|
+
TITLE "Arrival (Instrumental)"
|
171
|
+
INDEX 01 91:36:16
|
172
|
+
TRACK 43 AUDIO
|
173
|
+
PERFORMER "Spy"
|
174
|
+
TITLE "By Your Side (Logistics Remix)"
|
175
|
+
INDEX 01 94:09:53
|
176
|
+
TRACK 44 AUDIO
|
177
|
+
PERFORMER "Netsky"
|
178
|
+
TITLE "Come Back Home"
|
179
|
+
INDEX 01 97:05:34
|
180
|
+
TRACK 45 AUDIO
|
181
|
+
PERFORMER "Axwell & Sebastian Ingrosso"
|
182
|
+
TITLE "Together (D+B Remix)"
|
183
|
+
INDEX 01 99:16:36
|
184
|
+
TRACK 46 AUDIO
|
185
|
+
PERFORMER "Netsky"
|
186
|
+
TITLE "Rise & Shine"
|
187
|
+
INDEX 01 101:28:54
|
188
|
+
TRACK 47 AUDIO
|
189
|
+
PERFORMER "Apex"
|
190
|
+
TITLE "String Theory"
|
191
|
+
INDEX 01 102:56:39
|
192
|
+
TRACK 48 AUDIO
|
193
|
+
PERFORMER "DJ Marky & S.P.Y."
|
194
|
+
TITLE "Touch Me"
|
195
|
+
INDEX 01 105:52:04
|
196
|
+
TRACK 49 AUDIO
|
197
|
+
PERFORMER "Subwave"
|
198
|
+
TITLE "Road Rage"
|
199
|
+
INDEX 01 107:19:56
|
200
|
+
TRACK 50 AUDIO
|
201
|
+
PERFORMER "Joe Syntax"
|
202
|
+
TITLE "Slingshot"
|
203
|
+
INDEX 01 109:53:36
|
204
|
+
TRACK 51 AUDIO
|
205
|
+
PERFORMER "Pendulum"
|
206
|
+
TITLE "Witchcraft (Netsky Remix)"
|
207
|
+
INDEX 01 110:58:14
|
208
|
+
TRACK 52 AUDIO
|
209
|
+
PERFORMER "London Elektricity"
|
210
|
+
TITLE "The Great Drum & Bass Swindle (Logistics Remix)"
|
211
|
+
INDEX 01 112:27:02
|
212
|
+
TRACK 53 AUDIO
|
213
|
+
PERFORMER "Netsky vs. Genetic Bros"
|
214
|
+
TITLE "The Lotus Symphony vs. Uplifting"
|
@@ -0,0 +1,215 @@
|
|
1
|
+
PERFORMER "Netsky"
|
2
|
+
TITLE "Essential Mix (2010-10-09)"
|
3
|
+
FILE "2010-10-09 - Essential Mix - Netsky.mp3" MP3
|
4
|
+
TRACK 01 AUDIO
|
5
|
+
PERFORMER "Essential Mix"
|
6
|
+
TITLE "Intro"
|
7
|
+
INDEX 01 00:00:00
|
8
|
+
TRACK 02 AUDIO
|
9
|
+
PERFORMER "Shameboy vs. Friction, Camo & Krooked feat. Dynamite MC"
|
10
|
+
TITLE "Strobot (Netsky Remix) vs. Stand Up"
|
11
|
+
INDEX 01 01:50:07
|
12
|
+
TRACK 03 AUDIO
|
13
|
+
PERFORMER "Danny Byrd feat. I-Kay"
|
14
|
+
TITLE "Ill Behaviour"
|
15
|
+
INDEX 01 05:26:67
|
16
|
+
TRACK 04 AUDIO
|
17
|
+
PERFORMER "Die & Interface feat. William Cartwright"
|
18
|
+
TITLE "Bright Lights (Netsky Remix)"
|
19
|
+
INDEX 01 07:16:59
|
20
|
+
TRACK 05 AUDIO
|
21
|
+
PERFORMER "Nu:Tone feat. Natalie Williams"
|
22
|
+
TITLE "Shine In"
|
23
|
+
INDEX 01 10:33:72
|
24
|
+
TRACK 06 AUDIO
|
25
|
+
PERFORMER "Netsky"
|
26
|
+
TITLE "Porcelain VIP vs. I Refuse (Acapella)"
|
27
|
+
INDEX 01 12:56:64
|
28
|
+
TRACK 07 AUDIO
|
29
|
+
PERFORMER "Netsky"
|
30
|
+
TITLE "Do It Do It vs. I Refuse (Acapella)"
|
31
|
+
INDEX 01 15:52:31
|
32
|
+
TRACK 08 AUDIO
|
33
|
+
PERFORMER "Brookes Brothers"
|
34
|
+
TITLE "Beautiful"
|
35
|
+
INDEX 01 17:31:10
|
36
|
+
TRACK 09 AUDIO
|
37
|
+
PERFORMER "Muffler"
|
38
|
+
TITLE "Uplifter"
|
39
|
+
INDEX 01 20:26:47
|
40
|
+
TRACK 10 AUDIO
|
41
|
+
PERFORMER "Indivision & Livewire feat. Nelver"
|
42
|
+
TITLE "Irresistible"
|
43
|
+
INDEX 01 22:15:03
|
44
|
+
TRACK 11 AUDIO
|
45
|
+
PERFORMER "Bcee & S.P.Y."
|
46
|
+
TITLE "Is There Anybody Out There?"
|
47
|
+
INDEX 01 23:44:12
|
48
|
+
TRACK 12 AUDIO
|
49
|
+
PERFORMER "Nu:Logic vs. Brooklyn"
|
50
|
+
TITLE "Bleeper vs. With All My Heart"
|
51
|
+
INDEX 01 25:33:68
|
52
|
+
TRACK 13 AUDIO
|
53
|
+
PERFORMER "Chords"
|
54
|
+
TITLE "Radio"
|
55
|
+
INDEX 01 27:23:42
|
56
|
+
TRACK 14 AUDIO
|
57
|
+
PERFORMER "Danny Byrd feat. Netsky"
|
58
|
+
TITLE "Tonight"
|
59
|
+
INDEX 01 29:46:15
|
60
|
+
TRACK 15 AUDIO
|
61
|
+
PERFORMER "Leftfield"
|
62
|
+
TITLE "Release The Pressure (Netsky Remix)"
|
63
|
+
INDEX 01 31:24:68
|
64
|
+
TRACK 16 AUDIO
|
65
|
+
PERFORMER "Danny Byrd feat. London Elektricity"
|
66
|
+
TITLE "Failsafe"
|
67
|
+
INDEX 01 35:04:31
|
68
|
+
TRACK 17 AUDIO
|
69
|
+
PERFORMER "Netsky"
|
70
|
+
TITLE "Everyday"
|
71
|
+
INDEX 01 37:16:06
|
72
|
+
TRACK 18 AUDIO
|
73
|
+
PERFORMER "Zero 7"
|
74
|
+
TITLE "In The Waiting Line (D+B Remix)"
|
75
|
+
INDEX 01 38:21:66
|
76
|
+
TRACK 19 AUDIO
|
77
|
+
PERFORMER "Legion feat. Adam Wright"
|
78
|
+
TITLE "Both Sides"
|
79
|
+
INDEX 01 39:27:57
|
80
|
+
TRACK 20 AUDIO
|
81
|
+
PERFORMER "New Zealand Shapeshifter"
|
82
|
+
TITLE "The Touch (Netsky Remix)"
|
83
|
+
INDEX 01 44:12:70
|
84
|
+
TRACK 21 AUDIO
|
85
|
+
PERFORMER "Swedish House Mafia"
|
86
|
+
TITLE "One (Netsky Remix)"
|
87
|
+
INDEX 01 46:23:20
|
88
|
+
TRACK 22 AUDIO
|
89
|
+
PERFORMER "Netsky"
|
90
|
+
TITLE "Pirate Bay VIP"
|
91
|
+
INDEX 01 48:36:23
|
92
|
+
TRACK 23 AUDIO
|
93
|
+
PERFORMER "Danny Byrd feat. Cyantific"
|
94
|
+
TITLE "Judgement Day VIP"
|
95
|
+
INDEX 01 51:09:68
|
96
|
+
TRACK 24 AUDIO
|
97
|
+
PERFORMER "Netsky vs. Sidney Samson"
|
98
|
+
TITLE "Tomorrow's Another Dub VIP vs. Riverside (Breakage Remix)"
|
99
|
+
INDEX 01 53:21:46
|
100
|
+
TRACK 25 AUDIO
|
101
|
+
PERFORMER "The Bloody Beetroots feat. Steve Aoki"
|
102
|
+
TITLE "Warp (Dirtyphonics Remix)"
|
103
|
+
INDEX 01 55:37:44
|
104
|
+
TRACK 26 AUDIO
|
105
|
+
PERFORMER "Danny Byrd vs. Burial"
|
106
|
+
TITLE "We Can Have It All vs. Archangel (Edit)"
|
107
|
+
INDEX 01 56:05:01
|
108
|
+
TRACK 27 AUDIO
|
109
|
+
PERFORMER "DJ Fresh & Sigma vs. Netsky"
|
110
|
+
TITLE "Lassitude VIP vs. Escape"
|
111
|
+
INDEX 01 59:03:20
|
112
|
+
TRACK 28 AUDIO
|
113
|
+
PERFORMER "Commix"
|
114
|
+
TITLE "Painted Smile"
|
115
|
+
INDEX 01 63:04:52
|
116
|
+
TRACK 29 AUDIO
|
117
|
+
PERFORMER "Eastcolors"
|
118
|
+
TITLE "Go To Nowhere"
|
119
|
+
INDEX 01 66:00:20
|
120
|
+
TRACK 30 AUDIO
|
121
|
+
PERFORMER "Nu:Logic"
|
122
|
+
TITLE "Bigfoot"
|
123
|
+
INDEX 01 67:49:73
|
124
|
+
TRACK 31 AUDIO
|
125
|
+
PERFORMER "Random Movement"
|
126
|
+
TITLE "Can't Resist (S.P.Y. Remix)"
|
127
|
+
INDEX 01 69:17:50
|
128
|
+
TRACK 32 AUDIO
|
129
|
+
PERFORMER "Netsky"
|
130
|
+
TITLE "Iron Heart"
|
131
|
+
INDEX 01 71:07:31
|
132
|
+
TRACK 33 AUDIO
|
133
|
+
PERFORMER "Unicorn Kid vs. DJ Fresh & Sigma"
|
134
|
+
TITLE "Wild Life (Nu:Tone Remix) vs. Cylon"
|
135
|
+
INDEX 01 74:02:69
|
136
|
+
TRACK 34 AUDIO
|
137
|
+
PERFORMER "Agent Alvin"
|
138
|
+
TITLE "Move"
|
139
|
+
INDEX 01 76:35:15
|
140
|
+
TRACK 35 AUDIO
|
141
|
+
PERFORMER "S.P.Y."
|
142
|
+
TITLE "Go With The Flow"
|
143
|
+
INDEX 01 78:01:51
|
144
|
+
TRACK 36 AUDIO
|
145
|
+
PERFORMER "Metrik"
|
146
|
+
TITLE "T 1000"
|
147
|
+
INDEX 01 79:37:45
|
148
|
+
TRACK 37 AUDIO
|
149
|
+
PERFORMER "Culture Shock"
|
150
|
+
TITLE "Cathedral"
|
151
|
+
INDEX 01 81:21:27
|
152
|
+
TRACK 38 AUDIO
|
153
|
+
PERFORMER "Blokhe4d"
|
154
|
+
TITLE "The Way Life Used To Be"
|
155
|
+
INDEX 01 83:33:35
|
156
|
+
TRACK 39 AUDIO
|
157
|
+
PERFORMER "Hamilton"
|
158
|
+
TITLE "Soundboy"
|
159
|
+
INDEX 01 85:45:13
|
160
|
+
TRACK 40 AUDIO
|
161
|
+
PERFORMER "Squash"
|
162
|
+
TITLE "Divine"
|
163
|
+
INDEX 01 87:34:63
|
164
|
+
TRACK 41 AUDIO
|
165
|
+
PERFORMER "Above & Beyond & Gareth Emery"
|
166
|
+
TITLE "On A Good Day (J Majik & Wickaman Remix)"
|
167
|
+
INDEX 01 89:24:45
|
168
|
+
TRACK 42 AUDIO
|
169
|
+
PERFORMER "Metrik"
|
170
|
+
TITLE "Arrival (Instrumental)"
|
171
|
+
INDEX 01 91:36:16
|
172
|
+
TRACK 43 AUDIO
|
173
|
+
PERFORMER "Spy"
|
174
|
+
TITLE "By Your Side (Logistics Remix)"
|
175
|
+
INDEX 01 94:09:53
|
176
|
+
TRACK 44 AUDIO
|
177
|
+
PERFORMER "Netsky"
|
178
|
+
TITLE "Come Back Home"
|
179
|
+
INDEX 01 97:05:34
|
180
|
+
TRACK 45 AUDIO
|
181
|
+
PERFORMER "Axwell & Sebastian Ingrosso"
|
182
|
+
TITLE "Together (D+B Remix)"
|
183
|
+
INDEX 01 99:16:36
|
184
|
+
TRACK 46 AUDIO
|
185
|
+
PERFORMER "Netsky"
|
186
|
+
TITLE "Rise & Shine"
|
187
|
+
INDEX 01 101:28:54
|
188
|
+
TRACK 47 AUDIO
|
189
|
+
PERFORMER "Apex"
|
190
|
+
TITLE "String Theory"
|
191
|
+
INDEX 01 102:56:39
|
192
|
+
TRACK 48 AUDIO
|
193
|
+
PERFORMER "DJ Marky & S.P.Y."
|
194
|
+
TITLE "Touch Me"
|
195
|
+
INDEX 01 105:52:04
|
196
|
+
TRACK 49 AUDIO
|
197
|
+
PERFORMER "Subwave"
|
198
|
+
TITLE "Road Rage"
|
199
|
+
INDEX 01 107:19:56
|
200
|
+
TRACK 50 AUDIO
|
201
|
+
PERFORMER "Joe Syntax"
|
202
|
+
TITLE "Slingshot"
|
203
|
+
INDEX 01 109:53:36
|
204
|
+
TRACK 51 AUDIO
|
205
|
+
PERFORMER "Pendulum"
|
206
|
+
TITLE "Witchcraft (Netsky Remix)"
|
207
|
+
INDEX 01 110:58:14
|
208
|
+
TRACK 52 AUDIO
|
209
|
+
PERFORMER "London Elektricity"
|
210
|
+
TITLE "The Great Drum & Bass Swindle (Logistics Remix)"
|
211
|
+
INDEX 01 112:27:02
|
212
|
+
TRACK 53 AUDIO
|
213
|
+
PERFORMER "Netsky vs. Genetic Bros"
|
214
|
+
TITLE "The Lotus Symphony vs. Uplifting"
|
215
|
+
INDEX 01 115:22:47
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "../spec_helper")
|
2
|
+
|
3
|
+
describe RubyCue::Cuesheet do
|
4
|
+
before do
|
5
|
+
@cuesheet_file = load_cuesheet("test")
|
6
|
+
@cuesheet = RubyCue::Cuesheet.new(@cuesheet_file)
|
7
|
+
@cuesheet.parse!
|
8
|
+
end
|
9
|
+
|
10
|
+
it "stores the cuesheet string" do
|
11
|
+
cuesheet = RubyCue::Cuesheet.new(@cuesheet_file)
|
12
|
+
cuesheet.cuesheet.should == @cuesheet_file
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#parse!" do
|
16
|
+
context "properly formatted cuesheet" do
|
17
|
+
it "returns true if successfully parsed" do
|
18
|
+
@cuesheet.parse!.should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
it "has the right first track" do
|
22
|
+
@cuesheet.songs.first[:title].should == "Intro"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has the right last track" do
|
26
|
+
@cuesheet.songs.last[:title].should == "The Lotus Symphony vs. Uplifting"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has the right first performer" do
|
30
|
+
@cuesheet.songs.first[:performer].should == "Essential Mix"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has the right last performer" do
|
34
|
+
@cuesheet.songs.last[:performer].should == "Netsky vs. Genetic Bros"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has the right first index" do
|
38
|
+
@cuesheet.songs.first[:index].should == [0, 0, 0]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has the right last index" do
|
42
|
+
@cuesheet.songs.last[:index].should == [115, 22, 47]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has the right first track" do
|
46
|
+
@cuesheet.songs.first[:track].should == 1
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has the right last track" do
|
50
|
+
@cuesheet.songs.last[:track].should == 53
|
51
|
+
end
|
52
|
+
|
53
|
+
it "has the right amonut of tracks" do
|
54
|
+
@cuesheet.songs.size.should == 53
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#calculate_song_duration!" do
|
58
|
+
it "properly calculates song duration at the beginning of the track" do
|
59
|
+
@cuesheet.songs.first[:duration].to_a.should == [1, 50, 07]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "properly calculates song duration in the middle of the track" do
|
63
|
+
@cuesheet.songs[20][:duration].to_a.should == [2, 13, 3]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "properly calculates song duration of the last song given the user inputs the total track length" do
|
67
|
+
cuesheet = RubyCue::Cuesheet.new(load_cuesheet('test'), 7185)
|
68
|
+
cuesheet.parse!
|
69
|
+
cuesheet.songs.last[:duration].to_a.should == [4, 22, 28]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "improperly formatted cuesheet" do
|
75
|
+
it "should raise an exception for a bogus formatted cuesheet" do
|
76
|
+
cuesheet = RubyCue::Cuesheet.new("Something bogus")
|
77
|
+
lambda { cuesheet.parse! }.should raise_error(RubyCue::InvalidCuesheet)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "raises an exception if all our fields don't find the same amount of items" do
|
81
|
+
cue = load_cuesheet('malformed')
|
82
|
+
cuesheet = RubyCue::Cuesheet.new(cue)
|
83
|
+
lambda { cuesheet.parse! }.should raise_error(RubyCue::InvalidCuesheet)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#position" do
|
89
|
+
it "returns the current song in the cuesheet based on the designated position" do
|
90
|
+
@cuesheet.position(1943).should == @cuesheet.songs[14]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "returns the first song if a negative position is passed" do
|
94
|
+
@cuesheet.position(-5).should == @cuesheet.songs[0]
|
95
|
+
end
|
96
|
+
|
97
|
+
it "returns the last song if a position greater than the last index is passed" do
|
98
|
+
@cuesheet.position(10000000).should == @cuesheet.songs.last
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "../spec_helper")
|
2
|
+
|
3
|
+
describe RubyCue::Index do
|
4
|
+
describe "init" do
|
5
|
+
it "allows empty initialization" do
|
6
|
+
lambda { RubyCue::Index.new }.should_not raise_error
|
7
|
+
end
|
8
|
+
|
9
|
+
it "initializes from an array if specified default" do
|
10
|
+
index = RubyCue::Index.new([5, 0, 75])
|
11
|
+
index.minutes.should == 5
|
12
|
+
index.seconds.should == 0
|
13
|
+
index.frames.should == 75
|
14
|
+
end
|
15
|
+
|
16
|
+
it "initializes from integer seconds less than a minute" do
|
17
|
+
index = RubyCue::Index.new(30)
|
18
|
+
index.minutes.should == 0
|
19
|
+
index.seconds.should == 30
|
20
|
+
index.frames.should == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
it "initializes from integer seconds over a minute" do
|
24
|
+
index = RubyCue::Index.new(90)
|
25
|
+
index.minutes.should == 1
|
26
|
+
index.seconds.should == 30
|
27
|
+
index.frames.should == 0
|
28
|
+
end
|
29
|
+
|
30
|
+
it "initializes from integer seconds at a minute" do
|
31
|
+
index = RubyCue::Index.new(60)
|
32
|
+
index.minutes.should == 1
|
33
|
+
index.seconds.should == 0
|
34
|
+
index.frames.should == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
it "raises an error if the array size is not size 3" do
|
38
|
+
lambda { RubyCue::Index.new([0, 0, 0, 0]) }.should raise_error(ArgumentError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises an error if not all the array elements are integers" do
|
42
|
+
lambda { RubyCue::Index.new([0, "moose", 0]) }.should raise_error(ArgumentError)
|
43
|
+
end
|
44
|
+
|
45
|
+
context "conversions" do
|
46
|
+
describe "#to_f" do
|
47
|
+
it "converts an array value under a minute" do
|
48
|
+
index = RubyCue::Index.new([0, 30, 0])
|
49
|
+
index.to_f.should == 30.0
|
50
|
+
end
|
51
|
+
|
52
|
+
it "converts an array value over a minute" do
|
53
|
+
index = RubyCue::Index.new([1, 30, 0])
|
54
|
+
index.to_f.should == 90.0
|
55
|
+
end
|
56
|
+
|
57
|
+
it "converts an array value over a minute with frames" do
|
58
|
+
index = RubyCue::Index.new([1, 30, 74])
|
59
|
+
index.to_f.should == (90 + (74 / 75.0)).to_f
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#to_s" do
|
64
|
+
it "renders the index as a string with leading zeroes" do
|
65
|
+
index = RubyCue::Index.new([1, 30, 74]).to_s.should == "01:30:74"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#to_i" do
|
70
|
+
it "converts to seconds and rounds down" do
|
71
|
+
index = RubyCue::Index.new([0, 30, 74])
|
72
|
+
index.to_i.should == 30
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#to_a" do
|
77
|
+
it "converts to an array" do
|
78
|
+
index = RubyCue::Index.new([1, 2, 3])
|
79
|
+
index.to_a.should == [1, 2, 3]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "computations" do
|
85
|
+
describe "#+" do
|
86
|
+
it "returns an object of Class Index" do
|
87
|
+
index1 = RubyCue::Index.new([0, 30, 0])
|
88
|
+
index2 = RubyCue::Index.new([0, 30, 0])
|
89
|
+
|
90
|
+
(index1 + index2).class.should == RubyCue::Index
|
91
|
+
end
|
92
|
+
|
93
|
+
it "adds two indices under a minute" do
|
94
|
+
index1 = RubyCue::Index.new([0, 30, 0])
|
95
|
+
index2 = RubyCue::Index.new([0, 30, 0])
|
96
|
+
|
97
|
+
(index1 + index2).to_a.should == [1, 0, 0]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "adds two indices over a minute" do
|
101
|
+
index1 = RubyCue::Index.new([1, 30, 0])
|
102
|
+
index2 = RubyCue::Index.new([2, 20, 0])
|
103
|
+
|
104
|
+
(index1 + index2).to_a.should == [3, 50, 0]
|
105
|
+
end
|
106
|
+
|
107
|
+
it "adds two indices with frames" do
|
108
|
+
index1 = RubyCue::Index.new([1, 30, 50])
|
109
|
+
index2 = RubyCue::Index.new([2, 20, 50])
|
110
|
+
|
111
|
+
(index1 + index2).to_a.should == [3, 51, 25]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "adds two indices with only frames" do
|
115
|
+
index1 = RubyCue::Index.new([0, 0, 50])
|
116
|
+
index2 = RubyCue::Index.new([0, 0, 25])
|
117
|
+
|
118
|
+
(index1 + index2).to_a.should == [0, 1, 0]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#-" do
|
123
|
+
it "returns an object of Class Index" do
|
124
|
+
index1 = RubyCue::Index.new([0, 30, 0])
|
125
|
+
index2 = RubyCue::Index.new([0, 30, 0])
|
126
|
+
|
127
|
+
(index1 - index2).class.should == RubyCue::Index
|
128
|
+
end
|
129
|
+
|
130
|
+
it "subtracts two indices with only frames" do
|
131
|
+
index1 = RubyCue::Index.new([0, 0, 50])
|
132
|
+
index2 = RubyCue::Index.new([0, 0, 25])
|
133
|
+
|
134
|
+
(index1 - index2).to_a.should == [0, 0, 25]
|
135
|
+
end
|
136
|
+
|
137
|
+
it "subtracts two indices with minutes" do
|
138
|
+
index1 = RubyCue::Index.new([3, 20, 50])
|
139
|
+
index2 = RubyCue::Index.new([2, 40, 25])
|
140
|
+
|
141
|
+
(index1 - index2).to_a.should == [0, 40, 25]
|
142
|
+
end
|
143
|
+
|
144
|
+
it "subtracts two indices with even minutes" do
|
145
|
+
index1 = RubyCue::Index.new([3, 0, 0])
|
146
|
+
index2 = RubyCue::Index.new([2, 0, 0])
|
147
|
+
|
148
|
+
(index1 - index2).to_a.should == [1, 0, 0]
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "#>" do
|
154
|
+
it "returns true for frames" do
|
155
|
+
index1 = RubyCue::Index.new([0, 0, 50])
|
156
|
+
index2 = RubyCue::Index.new([0, 0, 25])
|
157
|
+
|
158
|
+
(index1 > index2).should be_true
|
159
|
+
end
|
160
|
+
|
161
|
+
it "returns true for seconds" do
|
162
|
+
index1 = RubyCue::Index.new([0, 30, 50])
|
163
|
+
index2 = RubyCue::Index.new([0, 29, 25])
|
164
|
+
|
165
|
+
(index1 > index2).should be_true
|
166
|
+
end
|
167
|
+
|
168
|
+
it "returns true for minutes" do
|
169
|
+
index1 = RubyCue::Index.new([2, 30, 50])
|
170
|
+
index2 = RubyCue::Index.new([1, 29, 25])
|
171
|
+
|
172
|
+
(index1 > index2).should be_true
|
173
|
+
end
|
174
|
+
|
175
|
+
it "returns true for the same time" do
|
176
|
+
index1 = RubyCue::Index.new([1, 30, 50])
|
177
|
+
index2 = RubyCue::Index.new([1, 30, 50])
|
178
|
+
|
179
|
+
(index1 > index2).should be_false
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "#<" do
|
184
|
+
it "returns false for frames" do
|
185
|
+
index1 = RubyCue::Index.new([0, 0, 50])
|
186
|
+
index2 = RubyCue::Index.new([0, 0, 25])
|
187
|
+
|
188
|
+
(index1 < index2).should be_false
|
189
|
+
end
|
190
|
+
|
191
|
+
it "returns false for seconds" do
|
192
|
+
index1 = RubyCue::Index.new([0, 30, 50])
|
193
|
+
index2 = RubyCue::Index.new([0, 29, 25])
|
194
|
+
|
195
|
+
(index1 < index2).should be_false
|
196
|
+
end
|
197
|
+
|
198
|
+
it "returns false for minutes" do
|
199
|
+
index1 = RubyCue::Index.new([2, 30, 50])
|
200
|
+
index2 = RubyCue::Index.new([1, 29, 25])
|
201
|
+
|
202
|
+
(index1 < index2).should be_false
|
203
|
+
end
|
204
|
+
|
205
|
+
it "returns false for the same time" do
|
206
|
+
index1 = RubyCue::Index.new([1, 30, 50])
|
207
|
+
index2 = RubyCue::Index.new([1, 30, 50])
|
208
|
+
|
209
|
+
(index1 < index2).should be_false
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#==" do
|
214
|
+
it "returns true if they're the same" do
|
215
|
+
index1 = RubyCue::Index.new([1, 30, 50])
|
216
|
+
index2 = RubyCue::Index.new([1, 30, 50])
|
217
|
+
|
218
|
+
(index1 == index2).should be_true
|
219
|
+
end
|
220
|
+
|
221
|
+
it "returns false if they're not the same" do
|
222
|
+
index1 = RubyCue::Index.new([1, 30, 50])
|
223
|
+
index2 = RubyCue::Index.new([1, 30, 51])
|
224
|
+
|
225
|
+
(index1 == index2).should be_false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "#each" do
|
231
|
+
it "yields each minute, second, frame value" do
|
232
|
+
array = []
|
233
|
+
index = RubyCue::Index.new([1, 30, 45])
|
234
|
+
index.each do |value|
|
235
|
+
array << value
|
236
|
+
end
|
237
|
+
|
238
|
+
array.to_a.should == index.to_a
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubycue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Blake Smith
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-26 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Basic ruby parser for song cuesheets
|
23
|
+
email: blakesmith0@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.rdoc
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- MIT-LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
- Rakefile
|
35
|
+
- VERSION
|
36
|
+
- lib/rubycue.rb
|
37
|
+
- lib/rubycue/cuesheet.rb
|
38
|
+
- lib/rubycue/exceptions.rb
|
39
|
+
- lib/rubycue/index.rb
|
40
|
+
- spec/fixtures/malformed.cue
|
41
|
+
- spec/fixtures/test.cue
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
- spec/unit/cuesheet_spec.rb
|
44
|
+
- spec/unit/index_spec.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/blakesmith/rubycue
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --charset=UTF-8
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Ruby cuesheet track parser
|
79
|
+
test_files:
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- spec/unit/cuesheet_spec.rb
|
82
|
+
- spec/unit/index_spec.rb
|