tiegz-ruby-mtv 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/MIT-LICENSE +20 -0
- data/README +52 -0
- data/Rakefile +5 -0
- data/TODO +4 -0
- data/ruby-mtv.gemspec +21 -0
- data/ruby-mtv.rb +283 -0
- metadata +67 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Tieg Zaharia
|
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.
|
data/README
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
ruby-mtv
|
2
|
+
by Tieg Zaharia
|
3
|
+
http://github.com/tiegz/ruby-mtv
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
This is a Ruby library for the MTV api. Right now it has classes for Artists and Videos, although
|
8
|
+
there is much to be done, spec'd and/or tested!
|
9
|
+
|
10
|
+
== REQUIREMENTS:
|
11
|
+
|
12
|
+
* git (http://git.or.cz) tested with 1.5.3.4
|
13
|
+
|
14
|
+
== INSTALL:
|
15
|
+
|
16
|
+
$ gem sources -a http://gems.github.com/ (you only need to do this once)
|
17
|
+
$ gem install tiegz-ruby-mtv
|
18
|
+
|
19
|
+
== USAGE:
|
20
|
+
|
21
|
+
Require the gem...
|
22
|
+
|
23
|
+
require 'tiegz-ruby-mtv'
|
24
|
+
|
25
|
+
To find an artist,
|
26
|
+
|
27
|
+
artist = MTV::Artist.search('dinosaur jr').first
|
28
|
+
# => #<MTV::Artist name: "Dinosaur Jr.", uid: "dinosaur_jr", uri: "http://api.mtvnservices.com/1/artist/dinosaur_jr/">
|
29
|
+
|
30
|
+
To find related artists,
|
31
|
+
|
32
|
+
artist.related
|
33
|
+
# => [#<MTV::Artist name: "Afghan Whigs", uid: "afghan_whigs", uri: "http://api.mtvnservices.com/1/artist/afghan_whigs/">,
|
34
|
+
#<MTV::Artist name: "The Breeders", uid: "breeders", uri: "http://api.mtvnservices.com/1/artist/breeders/">, ... ]
|
35
|
+
|
36
|
+
To find a video,
|
37
|
+
|
38
|
+
video = MTV::Video.search('dinosaur jr').first
|
39
|
+
# => #<MTV::Video title: "Been There All the Time", uid: "hznHivqrbHHDAXBAZ", artist_name: "Dinosaur Jr.",
|
40
|
+
uri: "http://api.mtvnservices.com/1/video/hznHivqrbHHDAXB...",
|
41
|
+
artist_uri: "http://api.mtvnservices.com/1/artist/dinosaur_jr/">
|
42
|
+
v.artist
|
43
|
+
# => #<MTV::Artist name: "Dinosaur Jr.", uid: "dinosaur_jr", uri: "http://api.mtvnservices.com/1/artist/dinosaur_jr/">
|
44
|
+
|
45
|
+
To find all videos for an artist,
|
46
|
+
|
47
|
+
artist.videos
|
48
|
+
# => [#<MTV::Video title: ["Been There All the Time"], uid: "hznHivqrbHHDAXBAZ", artist_name: ["Dinosaur Jr."] ...>, ... ]
|
49
|
+
|
50
|
+
== RELEVANT LINKS
|
51
|
+
|
52
|
+
MTVN api docs: http://developer.mtvnservices.com/docs
|
data/Rakefile
ADDED
data/TODO
ADDED
data/ruby-mtv.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "ruby-mtv"
|
3
|
+
s.version = "1.0"
|
4
|
+
s.date = "2008-09-16"
|
5
|
+
s.summary = "Ruby wrapper library for MTV api"
|
6
|
+
s.email = "tiegzaharia@gmail.com"
|
7
|
+
s.homepage = "http://github.com/tiegz/ruby-mtv"
|
8
|
+
s.description = "ruby-mtv is a Ruby library for accessing Artist and Video objects through the MTVN api."
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Tieg Zaharia"]
|
11
|
+
s.files = ["MIT-LICENSE",
|
12
|
+
"Rakefile",
|
13
|
+
"README",
|
14
|
+
"ruby-mtv.gemspec",
|
15
|
+
"ruby-mtv.rb",
|
16
|
+
"TODO"]
|
17
|
+
s.test_files = []
|
18
|
+
s.rdoc_options = ["--main", "README"]
|
19
|
+
s.extra_rdoc_files = ["README"]
|
20
|
+
s.add_dependency("active-support", ["> 2.0.2"])
|
21
|
+
end
|
data/ruby-mtv.rb
ADDED
@@ -0,0 +1,283 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
module MTV
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :base_url, :host, :protocol, :debug
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
self.host = "api.mtvnservices.com/1"
|
15
|
+
self.protocol = "http"
|
16
|
+
self.base_url = "#{protocol}://#{host}"
|
17
|
+
self.debug = true if ENV['DEBUG']
|
18
|
+
|
19
|
+
class Base
|
20
|
+
def initialize(values={})
|
21
|
+
values.each { |k, v| send "#{k}=", v }
|
22
|
+
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def request path
|
26
|
+
url = URI.escape "#{MTV.base_url}/#{path}"
|
27
|
+
response = nil
|
28
|
+
seconds = Benchmark.realtime { response = open url }
|
29
|
+
puts " \e[4;36;1mREQUEST (#{sprintf("%f", seconds)})\e[0m \e[0;1m#{url}\e[0m" if MTV.debug
|
30
|
+
response.is_a?(String) ? response : response.read
|
31
|
+
rescue OpenURI::HTTPError => e
|
32
|
+
puts " \e[4;36;1mREQUEST (404)\e[0m \e[0;1m#{url}\e[0m" if MTV.debug
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
# assuming that the uid for the artist is downcase and no spaces, this tries to match better
|
38
|
+
def string_to_uid(str)
|
39
|
+
str.downcase.underscore.gsub(" ", "_")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Copied from ActiveRecord::Base
|
44
|
+
def attribute_for_inspect(attr_name)
|
45
|
+
value = send(attr_name)
|
46
|
+
|
47
|
+
if value.is_a?(String) && value.length > 50
|
48
|
+
"#{value[0..50]}...".inspect
|
49
|
+
elsif value.is_a?(Date) || value.is_a?(Time)
|
50
|
+
%("#{value.to_s(:db)}")
|
51
|
+
else
|
52
|
+
value.inspect
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# This class represents a musical artist in MTV's database.
|
58
|
+
class Artist < Base
|
59
|
+
attr_accessor :name, :uid, :uri, :links, :updated
|
60
|
+
|
61
|
+
def initialize(values={})
|
62
|
+
super(values)
|
63
|
+
self.uid = uri.gsub(MTV.base_url + "/artist", '').delete '/' unless @uid
|
64
|
+
end
|
65
|
+
|
66
|
+
def inspect
|
67
|
+
attrs = [:name, :uid, :uri].map { |name| "#{name}: #{attribute_for_inspect(name)}" }.compact.join(", ")
|
68
|
+
"#<#{self.class} #{attrs}>"
|
69
|
+
end
|
70
|
+
|
71
|
+
# artist = MTV::Artist.search('In Flames')[2]
|
72
|
+
# MTV::Artist.browse => I Am Ghost, IB3, INXS, Ice Cube, ...
|
73
|
+
def browse
|
74
|
+
@browse ||= Artist.browse(uid.first)
|
75
|
+
end
|
76
|
+
|
77
|
+
# artist = MTV::Artist.search 'Frank Zappa'
|
78
|
+
# MTV::Artist.browse => Amon Amarth, Amorphis, Arch Enemy, Arcturus, Borknagar, ...
|
79
|
+
def related
|
80
|
+
@related ||= Artist.related(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
# artist = MTV::Artist.find('beck')
|
84
|
+
# MTV::Artist.videos => ...
|
85
|
+
def videos
|
86
|
+
@videos ||= Video.from_artist(self)
|
87
|
+
end
|
88
|
+
|
89
|
+
class << self
|
90
|
+
# MTV::Artist.browse 'x' => X, X-Clan, The X-Ecutioners, Xiren, Xscape, Xtreme, Xzibit
|
91
|
+
def browse(letter='a')
|
92
|
+
response = request "artist/browse/#{letter.to_s.first}/"
|
93
|
+
raise Error, "That artist not found!" if response.nil? || response.empty?
|
94
|
+
parse_many response
|
95
|
+
end
|
96
|
+
|
97
|
+
# MTV::Artist.find 'beck'
|
98
|
+
# MTV::Artist.find 'meGADeath'
|
99
|
+
def find(name, options={})
|
100
|
+
return name if name.is_a? Artist
|
101
|
+
|
102
|
+
options.symbolize_keys!
|
103
|
+
name = string_to_uid(options[:name] || name)
|
104
|
+
|
105
|
+
response = request "artist/#{name}/"
|
106
|
+
raise Error, "That artist not found!" if response.nil? || response.empty?
|
107
|
+
parse_one response
|
108
|
+
end
|
109
|
+
|
110
|
+
# MTV::Artist.related 'qtip'
|
111
|
+
# MTV::Artist.related MTV::Artist.find('qtip')
|
112
|
+
def related(artist)
|
113
|
+
artist = find(artist)
|
114
|
+
response = request "artist/#{artist.uid}/related/"
|
115
|
+
raise Error, "That artist not found!" if response.nil? || response.empty?
|
116
|
+
parse_many response
|
117
|
+
end
|
118
|
+
|
119
|
+
# MTV::Artist.search 'beck', :max_results => 1, :start_index => 1
|
120
|
+
def search(term=nil, options={})
|
121
|
+
options.symbolize_keys!
|
122
|
+
params = {}
|
123
|
+
params[:'max-results'] = options[:max_results] || 1
|
124
|
+
params[:'start-index'] = options[:start_index]
|
125
|
+
term = options[:term] || term
|
126
|
+
params.reject! { |k,v| !v }
|
127
|
+
response = request "artist/search?#{term.to_query('term')}&#{params.to_param}"
|
128
|
+
raise Error, "That artist not found!" if response.nil? || response.empty?
|
129
|
+
parse_many response
|
130
|
+
end
|
131
|
+
|
132
|
+
def videos(artist)
|
133
|
+
MTV::Video.from_artist(artist)
|
134
|
+
end
|
135
|
+
|
136
|
+
protected
|
137
|
+
def parse_many(body)
|
138
|
+
entries = XmlSimple.xml_in(body)['entry']
|
139
|
+
raise Error, "That artist not found!" if entries.nil?
|
140
|
+
entries = [entries] unless entries.is_a? Array
|
141
|
+
entries.map { |entry|
|
142
|
+
instantiate entry
|
143
|
+
}.reject { |artist| MTV::Artist.name.nil? || MTV::Artist.name.empty? }
|
144
|
+
end
|
145
|
+
|
146
|
+
def parse_one(body)
|
147
|
+
entry = XmlSimple.xml_in(body)
|
148
|
+
raise Error, "That artist not found!" if entry['author'].first['name'].nil? || entry['author'].first['name'].empty?
|
149
|
+
instantiate entry
|
150
|
+
end
|
151
|
+
|
152
|
+
def instantiate(entry={})
|
153
|
+
Artist.new(:name => entry['author'].first['name'].to_s,
|
154
|
+
:uri => entry['author'].first['uri'].to_s,
|
155
|
+
:links => entry['link'].map { |link| link['href'].to_s },
|
156
|
+
:updated => entry['updated'].to_s.to_datetime)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# This class represents a music video in MTV's database.
|
162
|
+
class Video < Base
|
163
|
+
attr_accessor :artist, :artist_name, :artist_uri, :category, :content, :credit,
|
164
|
+
:media_player_url, :media_thumbnails, :media_title, :media_description,
|
165
|
+
:media_keywords, :media_duration, :media_expression, :media_url, :media_type,
|
166
|
+
:media_credits, :media_category, :media_medium,
|
167
|
+
:title, :published, :uid, :updated, :uri, :vid
|
168
|
+
|
169
|
+
def initialize(values={})
|
170
|
+
super(values)
|
171
|
+
self.uid = uri.gsub(MTV.base_url + "/video", '').delete '/' unless @uid
|
172
|
+
self.vid = media_url.split(':').last
|
173
|
+
end
|
174
|
+
|
175
|
+
def artist
|
176
|
+
@artist ||= Artist.find(artist_uri.gsub(MTV.base_url + "/artist", '').delete('/'))
|
177
|
+
end
|
178
|
+
|
179
|
+
def inspect
|
180
|
+
attrs = [:title, :uid, :artist_name, :uri, :artist_uri].map { |name| "#{name}: #{attribute_for_inspect(name)}" }.compact.join(", ")
|
181
|
+
"#<#{self.class} #{attrs}>"
|
182
|
+
end
|
183
|
+
|
184
|
+
def thumbnails=(val)
|
185
|
+
@thumbnails = (val.is_a?(Array) ? val : [val]).map { |t| Thumbnail.new(t['url'], t['width'], t['height']) unless t.nil? }
|
186
|
+
end
|
187
|
+
|
188
|
+
class << self
|
189
|
+
# MTV::Video.find '1234abcd'
|
190
|
+
def find(uid, options={})
|
191
|
+
return uid if uid.is_a? Artist
|
192
|
+
|
193
|
+
options.symbolize_keys!
|
194
|
+
uid = options[:uid] || uid
|
195
|
+
|
196
|
+
response = request "video/#{uid}/"
|
197
|
+
raise Error, "That video not found!" if response.nil? || response.empty?
|
198
|
+
parse_one response
|
199
|
+
end
|
200
|
+
|
201
|
+
# MTV::Video.from_artist(Artist.find('beck'))
|
202
|
+
# MTV::Video.from_artist('beck')
|
203
|
+
def from_artist(artist)
|
204
|
+
artist_uid = artist.is_a?(Artist) ? artist.uid : string_to_uid(artist)
|
205
|
+
|
206
|
+
response = request "artist/#{artist_uid}/videos"
|
207
|
+
raise Error, "No videos found!" if response.nil? || response.empty?
|
208
|
+
parse_many response
|
209
|
+
end
|
210
|
+
|
211
|
+
# http://api.mtvnservices.com/1/video/search/[parameters]
|
212
|
+
# MTV::Video.search 'the golden age', :max_results => 1, :start_index => 1
|
213
|
+
def search(term=nil, options={})
|
214
|
+
options.symbolize_keys!
|
215
|
+
params = { :'max-results' => (options[:max_results] || 1),
|
216
|
+
:'start-index' => options[:start_index] }.reject { |k,v| v.nil? || v.to_s.empty? }.to_param
|
217
|
+
params = "&#{params}" unless params.empty?
|
218
|
+
term = (options[:term] || term).to_query('term')
|
219
|
+
|
220
|
+
response = request "video/search?#{term}#{params}"
|
221
|
+
raise Error, "No videos not found!" if response.nil? || response.empty?
|
222
|
+
parse_many response
|
223
|
+
end
|
224
|
+
|
225
|
+
protected
|
226
|
+
def parse_many(body)
|
227
|
+
body = hack_media_enclosures(body)
|
228
|
+
entries = XmlSimple.xml_in(body)['entry']
|
229
|
+
entries = [entries] unless entries.is_a? Array
|
230
|
+
entries.reject! { |entry| entry.nil? }
|
231
|
+
entries.map { |entry|
|
232
|
+
instantiate entry
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
236
|
+
def parse_one(body)
|
237
|
+
body = hack_media_enclosures(body)
|
238
|
+
entry = XmlSimple.xml_in(body)
|
239
|
+
raise Error, "That artist not found!" if entry['author']['name'].nil? || entry['author']['name'].empty?
|
240
|
+
instantiate entry
|
241
|
+
end
|
242
|
+
|
243
|
+
# HACK because XmlSimple doesn't seem to handle enclosures, we'll replace colons with hyphens
|
244
|
+
# TODO write a better regexp for that hack :\
|
245
|
+
def hack_media_enclosures(body)
|
246
|
+
body.gsub("<media:", "<media_").gsub("</media:", "</media_")
|
247
|
+
end
|
248
|
+
|
249
|
+
def instantiate(entry={})
|
250
|
+
Video.new(:title => entry['title'],
|
251
|
+
:artist_uri => entry['author'].first['uri'],
|
252
|
+
:artist_name => entry['author'].first['name'],
|
253
|
+
:published => entry['published'],
|
254
|
+
:content => entry['content'], # Artist Name, Video Title, and Record Label
|
255
|
+
:uri => entry['link'].select { |link| link['rel'] == 'self' }.first['href'],
|
256
|
+
:updated => (entry['updated'].to_datetime rescue nil),
|
257
|
+
:media_category => entry['media_category'], # governing agreement
|
258
|
+
:media_credits => entry['media_credit'].map { |credit| "#{credit['content'] || 'N/A'} (#{credit['role']})}" }.join(', '),
|
259
|
+
:media_description => entry['media_description'],
|
260
|
+
:media_duration => entry['media_content'].first['duration'],
|
261
|
+
:media_expression => entry['media_content'].first['expression'],
|
262
|
+
:media_keywords => entry['media_keywords'],
|
263
|
+
:media_medium => entry['media_content'].first['medium'],
|
264
|
+
:media_player_url => entry['media_player'].first['url'],
|
265
|
+
:media_thumbnails => entry['media_thumbnail'],
|
266
|
+
:media_title => entry['media_title'],
|
267
|
+
:media_type => entry['media_content'].first['type'],
|
268
|
+
:media_url => entry['media_content'].first['url'])
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
class Thumbnail
|
274
|
+
attr_accessor :url, :width, :height
|
275
|
+
def initialize(url, width, height)
|
276
|
+
self.url = url
|
277
|
+
self.width = width
|
278
|
+
self.height = height
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tiegz-ruby-mtv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "1.0"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tieg Zaharia
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-09-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: active-support
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.0.2
|
23
|
+
version:
|
24
|
+
description: ruby-mtv is a Ruby library for accessing Artist and Video objects through the MTVN api.
|
25
|
+
email: tiegzaharia@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README
|
32
|
+
files:
|
33
|
+
- MIT-LICENSE
|
34
|
+
- Rakefile
|
35
|
+
- README
|
36
|
+
- ruby-mtv.gemspec
|
37
|
+
- ruby-mtv.rb
|
38
|
+
- TODO
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/tiegz/ruby-mtv
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --main
|
44
|
+
- README
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Ruby wrapper library for MTV api
|
66
|
+
test_files: []
|
67
|
+
|