splattael-shoutcast_api 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +3 -0
- data/README.rdoc +2 -5
- data/Rakefile +13 -2
- data/bin/shoutcast_search +26 -0
- data/lib/delegator.rb +36 -0
- data/lib/shoutcast_api.rb +48 -56
- data/shoutcast_api.gemspec +6 -4
- data/test/test_basic.rb +9 -0
- data/test/test_delegator.rb +27 -0
- data/test/test_fetcher.rb +39 -1
- data/test/test_xml.rb +31 -20
- metadata +10 -4
data/Manifest
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
Rakefile
|
2
|
+
bin/shoutcast_search
|
3
|
+
lib/delegator.rb
|
2
4
|
lib/shoutcast_api.rb
|
3
5
|
README.rdoc
|
4
6
|
Manifest
|
@@ -9,4 +11,5 @@ test/fixtures/genrelist.plain
|
|
9
11
|
test/fixtures/search_death.plain
|
10
12
|
test/fixtures/empty.plain
|
11
13
|
test/test_basic.rb
|
14
|
+
test/test_delegator.rb
|
12
15
|
shoutcast_api.gemspec
|
data/README.rdoc
CHANGED
@@ -8,7 +8,7 @@ Uses httparty and roxml for fetch and parsing data from http://yp.shoutcast.com/
|
|
8
8
|
require 'shoutcast_api'
|
9
9
|
|
10
10
|
# Stations
|
11
|
-
Shoutcast.search(:name => "Chronix").
|
11
|
+
Shoutcast.search(:name => "Chronix").each do |station|
|
12
12
|
p station
|
13
13
|
puts station.tunein
|
14
14
|
end
|
@@ -17,7 +17,6 @@ Uses httparty and roxml for fetch and parsing data from http://yp.shoutcast.com/
|
|
17
17
|
|
18
18
|
# Genres
|
19
19
|
Shoutcast.genres # => all genres
|
20
|
-
Shoutcast.genres /op/ # => genres which match "op"
|
21
20
|
|
22
21
|
== Command line
|
23
22
|
|
@@ -28,7 +27,5 @@ Uses httparty and roxml for fetch and parsing data from http://yp.shoutcast.com/
|
|
28
27
|
|
29
28
|
== TODO
|
30
29
|
|
31
|
-
* Tests!
|
32
30
|
* Docs!
|
33
|
-
* command line options transformations
|
34
|
-
* handle empty responses like search(:search => "")
|
31
|
+
* command line options transformations
|
data/Rakefile
CHANGED
@@ -6,12 +6,23 @@ desc 'Default: run unit tests.'
|
|
6
6
|
task :default => :test
|
7
7
|
|
8
8
|
require 'echoe'
|
9
|
-
|
10
9
|
Echoe.new('shoutcast_api') do |gem|
|
11
|
-
gem.version = '0.0
|
10
|
+
gem.version = '0.1.0'
|
12
11
|
gem.author = 'Peter Suschlik'
|
13
12
|
gem.summary = 'Simple Shoutcast.com API.'
|
14
13
|
gem.email = 'peter-scapi@suschlik.de'
|
15
14
|
gem.url = %q{http://github.com/splattael/shoutcast_api}
|
16
15
|
gem.runtime_dependencies = [ "httparty ~>0.4", "roxml ~>2.5" ]
|
16
|
+
gem.ignore_pattern = ["tags"]
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Tag files for vim"
|
20
|
+
task :ctags do
|
21
|
+
dirs = $LOAD_PATH.select {|path| File.directory?(path) }
|
22
|
+
system "ctags -R #{dirs.join(" ")}"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Find whitespace at line ends"
|
26
|
+
task :eol do
|
27
|
+
system "grep -nrE ' +$' *"
|
17
28
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'shoutcast_api'
|
6
|
+
|
7
|
+
if ARGV.size > 0
|
8
|
+
options = ARGV.inject({}) do |hash, arg|
|
9
|
+
key, value = arg.split(/=/)
|
10
|
+
hash[key.intern] = value
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
# TODO do more transformations
|
14
|
+
# br -> bitrate
|
15
|
+
# ct -> current_title
|
16
|
+
# can ROXML help us?
|
17
|
+
options[:search] = options.delete(:name) if options[:name]
|
18
|
+
|
19
|
+
puts Shoutcast::Station.header
|
20
|
+
Shoutcast.search(options).sort.reverse.each do |station|
|
21
|
+
puts station
|
22
|
+
end
|
23
|
+
else
|
24
|
+
puts "Genres: ", Shoutcast.genres.map { |g| g.name }.join(", ")
|
25
|
+
end
|
26
|
+
|
data/lib/delegator.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Shoutcast
|
2
|
+
|
3
|
+
# Delegates methods via Forwardable.
|
4
|
+
module Delegator
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
# Delegates all methods defined +klass+ to +object+.
|
11
|
+
#
|
12
|
+
# === Usage
|
13
|
+
# class ArrayMimic < SomeInheritance
|
14
|
+
#
|
15
|
+
# delegate_all :@array, Array
|
16
|
+
#
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# array = ArrayMimic.new
|
20
|
+
# array.push 1, 2, 3
|
21
|
+
# array.each do |item|
|
22
|
+
# p item
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
def delegate_all(object, klass)
|
26
|
+
class_eval <<-EVAL
|
27
|
+
extend Forwardable
|
28
|
+
|
29
|
+
def_delegators :#{object}, *(#{klass}.instance_methods - instance_methods)
|
30
|
+
EVAL
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/shoutcast_api.rb
CHANGED
@@ -2,46 +2,58 @@ require 'httparty'
|
|
2
2
|
require 'roxml'
|
3
3
|
require 'forwardable'
|
4
4
|
|
5
|
+
require 'delegator'
|
6
|
+
|
5
7
|
module Shoutcast
|
6
8
|
extend Forwardable
|
7
9
|
extend self
|
8
10
|
|
9
|
-
def_delegators :Fetcher, :
|
11
|
+
def_delegators :Fetcher, :genres, :search
|
10
12
|
|
11
13
|
class Fetcher
|
12
14
|
include HTTParty
|
13
|
-
base_uri
|
15
|
+
base_uri "http://yp.shoutcast.com"
|
14
16
|
format :plain
|
15
17
|
|
16
|
-
def self.genres
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def self.genres
|
19
|
+
fetch do |xml|
|
20
|
+
Genrelist.from_xml xml
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
22
24
|
def self.search(options={})
|
23
|
-
|
25
|
+
fetch(options) do |xml|
|
26
|
+
Stationlist.from_xml xml
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
27
31
|
|
28
|
-
def self.fetch(options={})
|
29
|
-
options.update(:nocache => Time.now.to_f)
|
30
|
-
get(
|
32
|
+
def self.fetch(options={}, &block)
|
33
|
+
options.update(:nocache => Time.now.to_f) if options
|
34
|
+
data = get("/sbin/newxml.phtml", :query => options).body
|
35
|
+
|
36
|
+
block.call(data) unless data.empty?
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
40
|
# XML
|
35
41
|
|
36
|
-
|
37
|
-
|
42
|
+
module Xml
|
43
|
+
def self.included(base)
|
44
|
+
base.send(:include, ROXML)
|
45
|
+
base.extend ClassMethods
|
46
|
+
end
|
38
47
|
|
39
|
-
|
40
|
-
|
48
|
+
module ClassMethods
|
49
|
+
def trim
|
50
|
+
proc { |v| v.to_s.strip.squeeze(" ") }
|
51
|
+
end
|
41
52
|
end
|
42
53
|
end
|
43
54
|
|
44
|
-
class Station
|
55
|
+
class Station
|
56
|
+
include Xml
|
45
57
|
# <station
|
46
58
|
# id="423873"
|
47
59
|
# name="www.deathmetal.at"
|
@@ -79,26 +91,36 @@ module Shoutcast
|
|
79
91
|
end
|
80
92
|
end
|
81
93
|
|
82
|
-
class Stationlist
|
94
|
+
class Stationlist
|
95
|
+
include Xml
|
96
|
+
include Delegator
|
97
|
+
|
98
|
+
delegate_all :@stations, Array
|
99
|
+
|
83
100
|
# <tunein base="/sbin/tunein-station.pls"/>
|
84
101
|
# <station... /> <station .../>
|
85
|
-
BASE_URL = "http://yp.shoutcast.com"
|
86
102
|
|
87
103
|
xml_reader :tunein_base_path, :from => '@base', :in => 'tunein'
|
88
|
-
|
104
|
+
xml_attr :stations, :as => [ Station ]
|
105
|
+
|
106
|
+
class << self
|
107
|
+
attr_accessor :base_uri
|
108
|
+
end
|
109
|
+
self.base_uri = Fetcher.base_uri
|
89
110
|
|
90
111
|
def tunein(station)
|
91
|
-
"#{
|
112
|
+
"#{self.class.base_uri}#{tunein_base_path}?id=#{station.id}"
|
92
113
|
end
|
93
114
|
|
94
115
|
private
|
95
116
|
|
96
117
|
def after_parse
|
97
|
-
|
118
|
+
each { |station| station.tunein = tunein(station) }
|
98
119
|
end
|
99
120
|
end
|
100
121
|
|
101
|
-
class Genre
|
122
|
+
class Genre
|
123
|
+
include Xml
|
102
124
|
# <genre name="24h"/>
|
103
125
|
xml_reader :name, :from => :attr
|
104
126
|
|
@@ -107,44 +129,14 @@ module Shoutcast
|
|
107
129
|
end
|
108
130
|
end
|
109
131
|
|
110
|
-
class Genrelist
|
111
|
-
|
112
|
-
|
113
|
-
def filter(option=nil)
|
114
|
-
case option
|
115
|
-
when String
|
116
|
-
genres.select { |genre| genre.name == option }
|
117
|
-
when Regexp
|
118
|
-
genres.select { |genre| genre.name =~ option }
|
119
|
-
else
|
120
|
-
genres
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
132
|
+
class Genrelist
|
133
|
+
include Xml
|
134
|
+
include Delegator
|
124
135
|
|
125
|
-
|
136
|
+
delegate_all :@genres, Array
|
126
137
|
|
127
|
-
|
128
|
-
require 'pp'
|
138
|
+
xml_attr :genres, :as => [ Genre ]
|
129
139
|
|
130
|
-
if ARGV.size > 0
|
131
|
-
options = ARGV.inject({}) do |hash, arg|
|
132
|
-
key, value = arg.split(/=/)
|
133
|
-
hash[key.intern] = value
|
134
|
-
hash
|
135
|
-
end
|
136
|
-
# TODO do more transformations
|
137
|
-
# br -> bitrate
|
138
|
-
# ct -> current_title
|
139
|
-
# can ROXML help us?
|
140
|
-
options[:search] = options.delete(:name) if options[:name]
|
141
|
-
|
142
|
-
puts Shoutcast::Station.header
|
143
|
-
Shoutcast.search(options).stations.sort.reverse.each do |station|
|
144
|
-
puts station
|
145
|
-
end
|
146
|
-
else
|
147
|
-
pp Shoutcast.genres
|
148
140
|
end
|
149
141
|
|
150
142
|
end
|
data/shoutcast_api.gemspec
CHANGED
@@ -2,15 +2,17 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{shoutcast_api}
|
5
|
-
s.version = "0.0
|
5
|
+
s.version = "0.1.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Peter Suschlik"]
|
9
9
|
s.date = %q{2009-05-14}
|
10
|
+
s.default_executable = %q{shoutcast_search}
|
10
11
|
s.description = %q{Simple Shoutcast.com API.}
|
11
12
|
s.email = %q{peter-scapi@suschlik.de}
|
12
|
-
s.
|
13
|
-
s.
|
13
|
+
s.executables = ["shoutcast_search"]
|
14
|
+
s.extra_rdoc_files = ["bin/shoutcast_search", "lib/delegator.rb", "lib/shoutcast_api.rb", "README.rdoc"]
|
15
|
+
s.files = ["Rakefile", "bin/shoutcast_search", "lib/delegator.rb", "lib/shoutcast_api.rb", "README.rdoc", "Manifest", "test/test_xml.rb", "test/helper.rb", "test/test_fetcher.rb", "test/fixtures/genrelist.plain", "test/fixtures/search_death.plain", "test/fixtures/empty.plain", "test/test_basic.rb", "test/test_delegator.rb", "shoutcast_api.gemspec"]
|
14
16
|
s.has_rdoc = true
|
15
17
|
s.homepage = %q{http://github.com/splattael/shoutcast_api}
|
16
18
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Shoutcast_api", "--main", "README.rdoc"]
|
@@ -18,7 +20,7 @@ Gem::Specification.new do |s|
|
|
18
20
|
s.rubyforge_project = %q{shoutcast_api}
|
19
21
|
s.rubygems_version = %q{1.3.1}
|
20
22
|
s.summary = %q{Simple Shoutcast.com API.}
|
21
|
-
s.test_files = ["test/test_xml.rb", "test/test_fetcher.rb", "test/test_basic.rb"]
|
23
|
+
s.test_files = ["test/test_xml.rb", "test/test_fetcher.rb", "test/test_basic.rb", "test/test_delegator.rb"]
|
22
24
|
|
23
25
|
if s.respond_to? :specification_version then
|
24
26
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/test/test_basic.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'helper')
|
2
2
|
|
3
|
+
class ShoutcastTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_delegators
|
6
|
+
assert_respond_to Shoutcast, :genres
|
7
|
+
assert_respond_to Shoutcast, :search
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
3
12
|
class ExtensionsTest < Test::Unit::TestCase
|
4
13
|
|
5
14
|
def test_file_fixture
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class ArrayMimic
|
4
|
+
include Shoutcast::Delegator
|
5
|
+
|
6
|
+
delegate_all :@array, Array
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@array = []
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class DelegatorTest < Test::Unit::TestCase
|
15
|
+
|
16
|
+
def test_method_delegation
|
17
|
+
ary = ArrayMimic.new
|
18
|
+
ary.push 1, 2, 3
|
19
|
+
|
20
|
+
assert_equal 3, ary.size
|
21
|
+
assert_equal 1, ary.first
|
22
|
+
assert_equal 3, ary.last
|
23
|
+
assert_respond_to ary, :each
|
24
|
+
assert_equal [].methods.sort, ary.methods.sort
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/test/test_fetcher.rb
CHANGED
@@ -1,3 +1,41 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'helper')
|
2
2
|
|
3
|
-
|
3
|
+
class FetcherTest < Test::Unit::TestCase
|
4
|
+
include Shoutcast
|
5
|
+
|
6
|
+
def test_base_uri
|
7
|
+
assert_equal "http://yp.shoutcast.com", Stationlist.base_uri
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_genres_list
|
11
|
+
stub_http_response_with("genrelist.plain")
|
12
|
+
|
13
|
+
list = Fetcher.genres
|
14
|
+
# DRY test/text_xml.rb GenrelistTest
|
15
|
+
assert_instance_of Genrelist, list
|
16
|
+
assert_instance_of Genre, list.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_genres_empty_response
|
20
|
+
stub_http_response_with("empty.plain")
|
21
|
+
|
22
|
+
assert_nil Fetcher.genres
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_search_with_invalid_option
|
26
|
+
stub_http_response_with("search_death.plain")
|
27
|
+
|
28
|
+
list = Fetcher.search
|
29
|
+
# DRY test/text_xml.rb StationlistTest
|
30
|
+
assert_instance_of Stationlist, list
|
31
|
+
assert_equal "/sbin/tunein-station.pls", list.tunein_base_path
|
32
|
+
assert_instance_of Station, list.first
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_search_empty_response
|
36
|
+
stub_http_response_with("empty.plain")
|
37
|
+
|
38
|
+
assert_nil Fetcher.genres
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/test/test_xml.rb
CHANGED
@@ -64,6 +64,7 @@ class StationTest < Test::Unit::TestCase
|
|
64
64
|
|
65
65
|
end
|
66
66
|
|
67
|
+
|
67
68
|
class StationlistTest < Test::Unit::TestCase
|
68
69
|
include Shoutcast
|
69
70
|
|
@@ -74,19 +75,22 @@ class StationlistTest < Test::Unit::TestCase
|
|
74
75
|
def test_attributes
|
75
76
|
assert_instance_of Stationlist, @list
|
76
77
|
assert_equal "/sbin/tunein-station.pls", @list.tunein_base_path
|
77
|
-
|
78
|
-
|
79
|
-
|
78
|
+
assert_equal 49, @list.size
|
79
|
+
assert_instance_of Station, @list.first
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_base_uri
|
83
|
+
assert_equal "http://yp.shoutcast.com", Stationlist.base_uri
|
80
84
|
end
|
81
85
|
|
82
86
|
def test_tunein
|
83
|
-
station = @list.
|
87
|
+
station = @list.first
|
84
88
|
|
85
89
|
assert_equal "http://yp.shoutcast.com/sbin/tunein-station.pls?id=#{station.id}", @list.tunein(station)
|
86
90
|
end
|
87
91
|
|
88
92
|
def test_tunein_propagtion_after_parse
|
89
|
-
station = @list.
|
93
|
+
station = @list.first
|
90
94
|
|
91
95
|
assert_equal @list.tunein(station), station.tunein
|
92
96
|
end
|
@@ -101,28 +105,35 @@ class GenrelistTest < Test::Unit::TestCase
|
|
101
105
|
@list = Genrelist.from_xml file_fixture("genrelist.plain")
|
102
106
|
end
|
103
107
|
|
104
|
-
def
|
108
|
+
def test_array_mimic
|
105
109
|
assert_instance_of Genrelist, @list
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
def test_filter
|
112
|
-
assert_equal @list.genres, @list.filter
|
113
|
-
|
114
|
-
assert_equal 1, @list.filter("Rock").size
|
115
|
-
assert_equal "Rock", @list.filter("Rock").first.name
|
116
|
-
|
117
|
-
assert_equal 13, @list.filter(/op/).size
|
118
|
-
assert_equal "Autopilot", @list.filter(/op/).first.name
|
110
|
+
assert_equal 434, @list.size
|
111
|
+
assert_instance_of Genre, @list.first
|
112
|
+
assert_respond_to @list, :each
|
113
|
+
assert_raise(NoMethodError) { @list.nothing_found }
|
119
114
|
end
|
120
115
|
|
121
116
|
def test_genre_name
|
122
|
-
sorted = @list.
|
117
|
+
sorted = @list.sort
|
123
118
|
|
124
119
|
assert_equal "24h", sorted.first.name
|
125
120
|
assert_equal "Zouk", sorted.last.name
|
126
121
|
end
|
127
122
|
|
128
123
|
end
|
124
|
+
|
125
|
+
|
126
|
+
class MyClass
|
127
|
+
include Shoutcast::Xml
|
128
|
+
end
|
129
|
+
|
130
|
+
class XmlTest < Test::Unit::TestCase
|
131
|
+
|
132
|
+
def test_trim
|
133
|
+
assert_respond_to MyClass, :trim
|
134
|
+
|
135
|
+
string = " test mee "
|
136
|
+
assert_equal "test mee", MyClass.trim.call(string)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: splattael-shoutcast_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Suschlik
|
@@ -10,7 +10,7 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
|
12
12
|
date: 2009-05-14 00:00:00 -07:00
|
13
|
-
default_executable:
|
13
|
+
default_executable: shoutcast_search
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
@@ -34,15 +34,19 @@ dependencies:
|
|
34
34
|
version:
|
35
35
|
description: Simple Shoutcast.com API.
|
36
36
|
email: peter-scapi@suschlik.de
|
37
|
-
executables:
|
38
|
-
|
37
|
+
executables:
|
38
|
+
- shoutcast_search
|
39
39
|
extensions: []
|
40
40
|
|
41
41
|
extra_rdoc_files:
|
42
|
+
- bin/shoutcast_search
|
43
|
+
- lib/delegator.rb
|
42
44
|
- lib/shoutcast_api.rb
|
43
45
|
- README.rdoc
|
44
46
|
files:
|
45
47
|
- Rakefile
|
48
|
+
- bin/shoutcast_search
|
49
|
+
- lib/delegator.rb
|
46
50
|
- lib/shoutcast_api.rb
|
47
51
|
- README.rdoc
|
48
52
|
- Manifest
|
@@ -53,6 +57,7 @@ files:
|
|
53
57
|
- test/fixtures/search_death.plain
|
54
58
|
- test/fixtures/empty.plain
|
55
59
|
- test/test_basic.rb
|
60
|
+
- test/test_delegator.rb
|
56
61
|
- shoutcast_api.gemspec
|
57
62
|
has_rdoc: true
|
58
63
|
homepage: http://github.com/splattael/shoutcast_api
|
@@ -89,3 +94,4 @@ test_files:
|
|
89
94
|
- test/test_xml.rb
|
90
95
|
- test/test_fetcher.rb
|
91
96
|
- test/test_basic.rb
|
97
|
+
- test/test_delegator.rb
|