splattael-shoutcast_api 0.0.2 → 0.1.0
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/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
|