shoutout 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/DouweM/shoutout.png?branch=master)](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
|