tiegz-ruby-mtv 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README +52 -0
  3. data/Rakefile +5 -0
  4. data/TODO +4 -0
  5. data/ruby-mtv.gemspec +21 -0
  6. data/ruby-mtv.rb +283 -0
  7. 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
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/gempackagetask'
4
+
5
+
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ - Fix edge cases where no string is passed to a #find, #browse, #search, etc. method
2
+ - Add request cacheing
3
+ - Add specs (with mock requests)
4
+ - Better rdocs
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
+