shoutout 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +38 -30
- data/lib/shoutout.rb +1 -170
- data/lib/shoutout/headers.rb +1 -1
- data/lib/shoutout/metadata.rb +8 -3
- data/lib/shoutout/quick_access.rb +1 -1
- data/lib/shoutout/stream.rb +171 -0
- data/lib/shoutout/util.rb +1 -1
- data/lib/shoutout/version.rb +2 -2
- data/spec/shoutout/quick_access_spec.rb +5 -5
- data/spec/{shoutout_spec.rb → shoutout/stream_spec.rb} +5 -6
- metadata +10 -9
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# shoutout
|
1
|
+
# shoutout [](https://travis-ci.org/DouweM/shoutout)
|
2
2
|
|
3
3
|
A Ruby library for easily getting metadata from Shoutcast-compatible audio streaming servers.
|
4
4
|
|
@@ -19,60 +19,68 @@ gem "shoutout"
|
|
19
19
|
```ruby
|
20
20
|
require "shoutout"
|
21
21
|
|
22
|
-
|
22
|
+
# You can open a connection to the stream that will live for the duration of the block using `.open`:
|
23
|
+
Shoutout::Stream.open("http://82.201.100.5:8000/radio538") do |stream|
|
24
|
+
# Use `stream` as described below.
|
25
|
+
end
|
26
|
+
|
27
|
+
# If you want a little more control over opening and closing the connection, just use `.new`:
|
28
|
+
stream = Shoutout::Stream.new("http://82.201.100.5:8000/radio538")
|
23
29
|
|
24
|
-
#
|
25
|
-
|
30
|
+
# You can then explicitly open a connection to the stream.
|
31
|
+
# You're responsible for closing it using `#disconnect` when you're done.
|
32
|
+
stream.connect
|
26
33
|
|
27
|
-
# If you call any of the reader methods below without having
|
28
|
-
# one will be opened and closed around reading the information implicitly.
|
34
|
+
# If you call any of the reader methods below without having opened a connection using `#connect`
|
35
|
+
# or `.open`, one will be opened and closed around reading the information implicitly.
|
29
36
|
# This is convenient if you're only looking for one piece of information, but it is of course
|
30
37
|
# very inefficient if you're going to do multiple reads.
|
31
38
|
|
32
39
|
# Stream info
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
stream.name # => "RADIO538"
|
41
|
+
stream.description # => "ARE YOU IN"
|
42
|
+
stream.genre # => "Various"
|
43
|
+
stream.notice # => nil in this case, but this could very well have a value for your stream
|
44
|
+
stream.content_type # => "audio/mpeg"
|
45
|
+
stream.bitrate # => 128
|
46
|
+
stream.public? # => true
|
47
|
+
stream.audio_info # => { :samplerate => 44100, :bitrate => 128, :channels => 2 }
|
41
48
|
|
42
49
|
# Current metadata
|
43
|
-
|
50
|
+
stream.metadata # => { "StreamTitle" => "Armin van Buuren - This Is What It Feels Like", "StreamUrl" => "http://www.radio538.nl" }
|
44
51
|
|
45
52
|
# The Metadata object is a Hash that has been extended with the following features:
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
stream.metadata[:stream_title] # => "Armin van Buuren - This Is What It Feels Like"
|
54
|
+
stream.metadata[:stream_url] # => "http://www.radio538.nl"
|
55
|
+
stream.metadata.now_playing # => "Armin van Buuren - This Is What It Feels Like"
|
56
|
+
stream.metadata.website # => "http://www.radio538.nl"
|
57
|
+
stream.metadata.artist # => "Armin van Buuren"
|
58
|
+
stream.metadata.song # => "This Is What It Feels Like"
|
52
59
|
|
53
|
-
# Conveniently, `#now_playing` and `#website` are also available on the
|
54
|
-
|
55
|
-
|
60
|
+
# Conveniently, `#now_playing` and `#website` are also available on the stream object:
|
61
|
+
stream.now_playing # => "Armin van Buuren - This Is What It Feels Like"
|
62
|
+
stream.website # => "http://www.radio538.nl"
|
56
63
|
|
57
64
|
# For convenience, all of the reader methods above are also available as class methods:
|
58
|
-
Shoutout.now_playing("http://82.201.100.5:8000/radio538") # => "
|
59
|
-
# Just like the equivalent `Shoutout.new("http://82.201.100.5:8000/radio538").now_playing`,
|
65
|
+
Shoutout::Stream.now_playing("http://82.201.100.5:8000/radio538") # => "Armin van Buuren - This Is What It Feels Like"
|
66
|
+
# Just like the equivalent `Shoutout::Stream.new("http://82.201.100.5:8000/radio538").now_playing`,
|
60
67
|
# this will automatically open and close a connection around reading the information.
|
61
68
|
|
62
|
-
# You can
|
63
|
-
|
69
|
+
# You can be notified every time the metadata changes:
|
70
|
+
stream.metadata_change do |metadata|
|
64
71
|
puts "Now playing: #{metadata.song} by #{metadata.artist}"
|
72
|
+
# => Now playing: This Is What It Feels Like by Armin van Buuren
|
65
73
|
end
|
66
74
|
# Of course, this only works with an explicitly opened connection.
|
67
75
|
|
68
76
|
# If you're done setting up but want the program to keep listening for metadata, say so:
|
69
|
-
|
77
|
+
stream.listen
|
70
78
|
# Note that listening will only end when the connection is lost or the end of file is reached,
|
71
79
|
# so anything that comes after this call will only then be executed.
|
72
80
|
# This will generally be the last call in your program.
|
73
81
|
|
74
82
|
# If we don't want to wait around and listen, just let the program exit or disconnect explicitly:
|
75
|
-
|
83
|
+
stream.disconnect
|
76
84
|
```
|
77
85
|
|
78
86
|
## Examples
|
data/lib/shoutout.rb
CHANGED
@@ -6,173 +6,4 @@ require "shoutout/util"
|
|
6
6
|
require "shoutout/metadata"
|
7
7
|
require "shoutout/headers"
|
8
8
|
require "shoutout/quick_access"
|
9
|
-
|
10
|
-
class Shoutout
|
11
|
-
include QuickAccess
|
12
|
-
|
13
|
-
attr_reader :url
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def open(url)
|
17
|
-
shoutcast = new(url)
|
18
|
-
|
19
|
-
begin
|
20
|
-
shoutcast.connect
|
21
|
-
yield shoutcast
|
22
|
-
ensure
|
23
|
-
shoutcast.disconnect
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def metadata(url)
|
28
|
-
new(url).metadata
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(url)
|
33
|
-
@url = url
|
34
|
-
end
|
35
|
-
|
36
|
-
def connected?
|
37
|
-
@connected
|
38
|
-
end
|
39
|
-
|
40
|
-
def connect
|
41
|
-
return false if @connected
|
42
|
-
|
43
|
-
uri = URI.parse(@url)
|
44
|
-
@socket = TCPSocket.new(uri.host, uri.port)
|
45
|
-
@socket.puts "GET #{uri.path} HTTP/1.0"
|
46
|
-
@socket.puts "Icy-MetaData: 1"
|
47
|
-
@socket.puts
|
48
|
-
|
49
|
-
# Read status line
|
50
|
-
status_line = @socket.gets
|
51
|
-
status_code = status_line.match(/\AHTTP\/([0-9]\.[0-9]) ([0-9]{3})/)[2].to_i
|
52
|
-
|
53
|
-
@connected = true
|
54
|
-
|
55
|
-
read_headers
|
56
|
-
|
57
|
-
if status_code >= 300 && status_code < 400 && headers[:location]
|
58
|
-
disconnect
|
59
|
-
|
60
|
-
@url = URI.join(uri, headers[:location]).to_s
|
61
|
-
|
62
|
-
return connect
|
63
|
-
end
|
64
|
-
|
65
|
-
unless status_code >= 200 && status_code < 300
|
66
|
-
disconnect
|
67
|
-
|
68
|
-
return false
|
69
|
-
end
|
70
|
-
|
71
|
-
unless metadata_interval
|
72
|
-
disconnect
|
73
|
-
|
74
|
-
return false
|
75
|
-
end
|
76
|
-
|
77
|
-
@read_metadata_thread = Thread.new(&method(:read_metadata))
|
78
|
-
|
79
|
-
true
|
80
|
-
end
|
81
|
-
|
82
|
-
def disconnect
|
83
|
-
return false unless @connected
|
84
|
-
|
85
|
-
@connected = false
|
86
|
-
|
87
|
-
@socket.close if @socket && !@socket.closed?
|
88
|
-
@socket = nil
|
89
|
-
|
90
|
-
true
|
91
|
-
end
|
92
|
-
|
93
|
-
def listen
|
94
|
-
return unless @connected
|
95
|
-
|
96
|
-
@read_metadata_thread.join
|
97
|
-
@last_metadata_change_thread.join if @last_metadata_change_thread
|
98
|
-
end
|
99
|
-
|
100
|
-
def metadata
|
101
|
-
return @metadata if defined?(@metadata)
|
102
|
-
|
103
|
-
original_metadata_change_block = @metadata_change_block
|
104
|
-
|
105
|
-
received = false
|
106
|
-
metadata_change do |new_metadata|
|
107
|
-
received = true
|
108
|
-
end
|
109
|
-
|
110
|
-
already_connected = @connected
|
111
|
-
connect unless already_connected
|
112
|
-
|
113
|
-
sleep 0.015 until received
|
114
|
-
|
115
|
-
disconnect unless already_connected
|
116
|
-
|
117
|
-
metadata_change(&original_metadata_change_block) if original_metadata_change_block
|
118
|
-
|
119
|
-
@metadata
|
120
|
-
end
|
121
|
-
|
122
|
-
def metadata_change(&block)
|
123
|
-
@metadata_change_block = block
|
124
|
-
|
125
|
-
report_metadata_change(@metadata) if defined?(@metadata)
|
126
|
-
|
127
|
-
true
|
128
|
-
end
|
129
|
-
|
130
|
-
private
|
131
|
-
def read_headers
|
132
|
-
raw_headers = ""
|
133
|
-
while line = @socket.gets
|
134
|
-
break if line.chomp == ""
|
135
|
-
raw_headers << line
|
136
|
-
end
|
137
|
-
@headers = Headers.parse(raw_headers)
|
138
|
-
end
|
139
|
-
|
140
|
-
def read_metadata
|
141
|
-
while @connected
|
142
|
-
# Skip audio data
|
143
|
-
data = @socket.read(metadata_interval) || raise(EOFError)
|
144
|
-
|
145
|
-
data = @socket.read(1) || raise(EOFError)
|
146
|
-
metadata_length = data.unpack("c")[0] * 16
|
147
|
-
next if metadata_length == 0
|
148
|
-
|
149
|
-
data = @socket.read(metadata_length) || raise(EOFError)
|
150
|
-
raw_metadata = data.unpack("A*")[0]
|
151
|
-
@metadata = Metadata.parse(raw_metadata)
|
152
|
-
|
153
|
-
report_metadata_change(@metadata)
|
154
|
-
end
|
155
|
-
rescue Errno::EBADF, IOError => e
|
156
|
-
# Connection lost
|
157
|
-
disconnect
|
158
|
-
end
|
159
|
-
|
160
|
-
def report_metadata_change(metadata)
|
161
|
-
@last_metadata_change_thread = Thread.new(metadata, @last_metadata_change_thread) do |metadata, last_metadata_change_thread|
|
162
|
-
last_metadata_change_thread.join if last_metadata_change_thread
|
163
|
-
|
164
|
-
@metadata_change_block.call(metadata) if @metadata_change_block
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def headers
|
169
|
-
return @headers if defined?(@headers)
|
170
|
-
|
171
|
-
# Connected but no headers? I give up.
|
172
|
-
return [] if @connected
|
173
|
-
|
174
|
-
connect && disconnect
|
175
|
-
|
176
|
-
@headers
|
177
|
-
end
|
178
|
-
end
|
9
|
+
require "shoutout/stream"
|
data/lib/shoutout/headers.rb
CHANGED
data/lib/shoutout/metadata.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Shoutout
|
2
2
|
class Metadata < Hash
|
3
3
|
def self.parse(raw_metadata)
|
4
4
|
metadata = {}
|
@@ -51,12 +51,17 @@ class Shoutout
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def artist
|
54
|
-
|
54
|
+
artist_and_song[0]
|
55
55
|
end
|
56
56
|
|
57
57
|
def song
|
58
|
-
|
58
|
+
artist_and_song[1]
|
59
59
|
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def artist_and_song
|
63
|
+
@artist_and_song ||= now_playing.split(" - ", 2)
|
64
|
+
end
|
60
65
|
end
|
61
66
|
|
62
67
|
include QuickAccess
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Shoutout
|
2
|
+
class Stream
|
3
|
+
include QuickAccess
|
4
|
+
|
5
|
+
attr_reader :url
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def open(url)
|
9
|
+
stream = new(url)
|
10
|
+
|
11
|
+
begin
|
12
|
+
stream.connect
|
13
|
+
yield stream
|
14
|
+
ensure
|
15
|
+
stream.disconnect
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def metadata(url)
|
20
|
+
new(url).metadata
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(url)
|
25
|
+
@url = url
|
26
|
+
end
|
27
|
+
|
28
|
+
def connected?
|
29
|
+
@connected
|
30
|
+
end
|
31
|
+
|
32
|
+
def connect
|
33
|
+
return false if @connected
|
34
|
+
|
35
|
+
uri = URI.parse(@url)
|
36
|
+
@socket = TCPSocket.new(uri.host, uri.port)
|
37
|
+
@socket.puts "GET #{uri.path} HTTP/1.0"
|
38
|
+
@socket.puts "Icy-MetaData: 1"
|
39
|
+
@socket.puts
|
40
|
+
|
41
|
+
# Read status line
|
42
|
+
status_line = @socket.gets
|
43
|
+
status_code = status_line.match(/\AHTTP\/([0-9]\.[0-9]) ([0-9]{3})/)[2].to_i
|
44
|
+
|
45
|
+
@connected = true
|
46
|
+
|
47
|
+
read_headers
|
48
|
+
|
49
|
+
if status_code >= 300 && status_code < 400 && headers[:location]
|
50
|
+
disconnect
|
51
|
+
|
52
|
+
@url = URI.join(uri, headers[:location]).to_s
|
53
|
+
|
54
|
+
return connect
|
55
|
+
end
|
56
|
+
|
57
|
+
unless status_code >= 200 && status_code < 300
|
58
|
+
disconnect
|
59
|
+
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
unless metadata_interval
|
64
|
+
disconnect
|
65
|
+
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
|
69
|
+
@read_metadata_thread = Thread.new(&method(:read_metadata))
|
70
|
+
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def disconnect
|
75
|
+
return false unless @connected
|
76
|
+
|
77
|
+
@connected = false
|
78
|
+
|
79
|
+
@socket.close if @socket && !@socket.closed?
|
80
|
+
@socket = nil
|
81
|
+
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
def listen
|
86
|
+
return unless @connected
|
87
|
+
|
88
|
+
@read_metadata_thread.join
|
89
|
+
@last_metadata_change_thread.join if @last_metadata_change_thread
|
90
|
+
end
|
91
|
+
|
92
|
+
def metadata
|
93
|
+
return @metadata if defined?(@metadata)
|
94
|
+
|
95
|
+
original_metadata_change_block = @metadata_change_block
|
96
|
+
|
97
|
+
received = false
|
98
|
+
metadata_change do |new_metadata|
|
99
|
+
received = true
|
100
|
+
end
|
101
|
+
|
102
|
+
already_connected = @connected
|
103
|
+
connect unless already_connected
|
104
|
+
|
105
|
+
sleep 0.015 until received
|
106
|
+
|
107
|
+
disconnect unless already_connected
|
108
|
+
|
109
|
+
metadata_change(&original_metadata_change_block) if original_metadata_change_block
|
110
|
+
|
111
|
+
@metadata
|
112
|
+
end
|
113
|
+
|
114
|
+
def metadata_change(&block)
|
115
|
+
@metadata_change_block = block
|
116
|
+
|
117
|
+
report_metadata_change(@metadata) if defined?(@metadata)
|
118
|
+
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
def read_headers
|
124
|
+
raw_headers = ""
|
125
|
+
while line = @socket.gets
|
126
|
+
break if line.chomp == ""
|
127
|
+
raw_headers << line
|
128
|
+
end
|
129
|
+
@headers = Headers.parse(raw_headers)
|
130
|
+
end
|
131
|
+
|
132
|
+
def read_metadata
|
133
|
+
while @connected
|
134
|
+
# Skip audio data
|
135
|
+
data = @socket.read(metadata_interval) || raise(EOFError)
|
136
|
+
|
137
|
+
data = @socket.read(1) || raise(EOFError)
|
138
|
+
metadata_length = data.unpack("c")[0] * 16
|
139
|
+
next if metadata_length == 0
|
140
|
+
|
141
|
+
data = @socket.read(metadata_length) || raise(EOFError)
|
142
|
+
raw_metadata = data.unpack("A*")[0]
|
143
|
+
@metadata = Metadata.parse(raw_metadata)
|
144
|
+
|
145
|
+
report_metadata_change(@metadata)
|
146
|
+
end
|
147
|
+
rescue Errno::EBADF, IOError => e
|
148
|
+
# Connection lost
|
149
|
+
disconnect
|
150
|
+
end
|
151
|
+
|
152
|
+
def report_metadata_change(metadata)
|
153
|
+
@last_metadata_change_thread = Thread.new(metadata, @last_metadata_change_thread) do |metadata, last_metadata_change_thread|
|
154
|
+
last_metadata_change_thread.join if last_metadata_change_thread
|
155
|
+
|
156
|
+
@metadata_change_block.call(metadata) if @metadata_change_block
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def headers
|
161
|
+
return @headers if defined?(@headers)
|
162
|
+
|
163
|
+
# Connected but no headers? I give up.
|
164
|
+
return [] if @connected
|
165
|
+
|
166
|
+
connect && disconnect
|
167
|
+
|
168
|
+
@headers
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
data/lib/shoutout/util.rb
CHANGED
data/lib/shoutout/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
module Shoutout
|
2
|
+
VERSION = "0.0.2"
|
3
3
|
end
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe Shoutout::QuickAccess do
|
4
4
|
|
5
5
|
let(:url) { "http://82.201.100.5:8000/radio538" }
|
6
|
-
subject { Shoutout.new(url) }
|
6
|
+
subject { Shoutout::Stream.new(url) }
|
7
7
|
|
8
8
|
describe "#audio_info" do
|
9
9
|
|
@@ -28,15 +28,15 @@ describe Shoutout::QuickAccess do
|
|
28
28
|
describe ".name" do
|
29
29
|
|
30
30
|
it "creates a new instance" do
|
31
|
-
Shoutout.should_receive(:new).with(url).and_return(double("
|
31
|
+
Shoutout::Stream.should_receive(:new).with(url).and_return(double("stream").as_null_object)
|
32
32
|
|
33
|
-
Shoutout.name(url)
|
33
|
+
Shoutout::Stream.name(url)
|
34
34
|
end
|
35
35
|
|
36
36
|
it "calls #name on the opened connection" do
|
37
|
-
Shoutout.any_instance.should_receive(:name)
|
37
|
+
Shoutout::Stream.any_instance.should_receive(:name)
|
38
38
|
|
39
|
-
Shoutout.name(url)
|
39
|
+
Shoutout::Stream.name(url)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Shoutout do
|
4
|
-
|
3
|
+
describe Shoutout::Stream do
|
5
4
|
let(:url) { "http://82.201.100.5:8000/radio538" }
|
6
5
|
let(:uri) { URI.parse(url) }
|
7
6
|
subject! { described_class.new(url) }
|
8
|
-
let(:response_data) { File.read(File.expand_path("
|
7
|
+
let(:response_data) { File.read(File.expand_path("../../fixtures/ok_response", __FILE__)) }
|
9
8
|
let(:socket) { FakeTCPSocket.new(response_data) }
|
10
9
|
|
11
10
|
before(:each) do
|
@@ -105,7 +104,7 @@ describe Shoutout do
|
|
105
104
|
|
106
105
|
context "when the response indicates a redirect" do
|
107
106
|
|
108
|
-
let(:redirect_response_data) { File.read(File.expand_path("
|
107
|
+
let(:redirect_response_data) { File.read(File.expand_path("../../fixtures/redirect_response", __FILE__)) }
|
109
108
|
let(:redirect_socket) { FakeTCPSocket.new(redirect_response_data) }
|
110
109
|
|
111
110
|
before(:each) do
|
@@ -138,7 +137,7 @@ describe Shoutout do
|
|
138
137
|
|
139
138
|
context "when the response indicates an error" do
|
140
139
|
|
141
|
-
let(:response_data) { File.read(File.expand_path("
|
140
|
+
let(:response_data) { File.read(File.expand_path("../../fixtures/error_response", __FILE__)) }
|
142
141
|
|
143
142
|
it "closes the connection" do
|
144
143
|
subject.should_receive(:disconnect).twice.and_call_original
|
@@ -155,7 +154,7 @@ describe Shoutout do
|
|
155
154
|
|
156
155
|
context "when the response is unsupported" do
|
157
156
|
|
158
|
-
let(:response_data) { File.read(File.expand_path("
|
157
|
+
let(:response_data) { File.read(File.expand_path("../../fixtures/unsupported_response", __FILE__)) }
|
159
158
|
|
160
159
|
it "closes the connection" do
|
161
160
|
subject.should_receive(:disconnect).twice.and_call_original
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shoutout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2013-09-08 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &70322661963000 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70322661963000
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70322661962580 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70322661962580
|
36
36
|
description: A Ruby library for easily getting metadata from Shoutcast-compatible
|
37
37
|
audio streaming servers
|
38
38
|
email: douwe@selenight.nl
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/shoutout/headers.rb
|
44
44
|
- lib/shoutout/metadata.rb
|
45
45
|
- lib/shoutout/quick_access.rb
|
46
|
+
- lib/shoutout/stream.rb
|
46
47
|
- lib/shoutout/util.rb
|
47
48
|
- lib/shoutout/version.rb
|
48
49
|
- lib/shoutout.rb
|
@@ -57,8 +58,8 @@ files:
|
|
57
58
|
- spec/shoutout/headers_spec.rb
|
58
59
|
- spec/shoutout/metadata_spec.rb
|
59
60
|
- spec/shoutout/quick_access_spec.rb
|
61
|
+
- spec/shoutout/stream_spec.rb
|
60
62
|
- spec/shoutout/util_spec.rb
|
61
|
-
- spec/shoutout_spec.rb
|
62
63
|
- spec/spec_helper.rb
|
63
64
|
- spec/support/fake_tcp_socket.rb
|
64
65
|
homepage: https://github.com/DouweM/shoutout
|
@@ -76,7 +77,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
77
|
version: '0'
|
77
78
|
segments:
|
78
79
|
- 0
|
79
|
-
hash:
|
80
|
+
hash: 401984402802077394
|
80
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
82
|
none: false
|
82
83
|
requirements:
|
@@ -85,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
86
|
version: '0'
|
86
87
|
segments:
|
87
88
|
- 0
|
88
|
-
hash:
|
89
|
+
hash: 401984402802077394
|
89
90
|
requirements: []
|
90
91
|
rubyforge_project:
|
91
92
|
rubygems_version: 1.8.6
|
@@ -100,7 +101,7 @@ test_files:
|
|
100
101
|
- spec/shoutout/headers_spec.rb
|
101
102
|
- spec/shoutout/metadata_spec.rb
|
102
103
|
- spec/shoutout/quick_access_spec.rb
|
104
|
+
- spec/shoutout/stream_spec.rb
|
103
105
|
- spec/shoutout/util_spec.rb
|
104
|
-
- spec/shoutout_spec.rb
|
105
106
|
- spec/spec_helper.rb
|
106
107
|
- spec/support/fake_tcp_socket.rb
|