basuco 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.textile +318 -0
- data/Rakefile +1 -0
- data/basuco.gemspec +23 -0
- data/examples/artist.rb +20 -0
- data/examples/artist_links.rb +38 -0
- data/lib/basuco.rb +30 -0
- data/lib/basuco/api.rb +26 -0
- data/lib/basuco/attribute.rb +67 -0
- data/lib/basuco/collection.rb +7 -0
- data/lib/basuco/property.rb +91 -0
- data/lib/basuco/request.rb +86 -0
- data/lib/basuco/resource.rb +215 -0
- data/lib/basuco/search.rb +100 -0
- data/lib/basuco/topic.rb +192 -0
- data/lib/basuco/trans.rb +36 -0
- data/lib/basuco/type.rb +53 -0
- data/lib/basuco/util.rb +17 -0
- data/lib/basuco/version.rb +3 -0
- data/lib/basuco/view.rb +54 -0
- data/rails/init.rb +2 -0
- data/stats.sh +30 -0
- data/tasks/ken.rb +4 -0
- data/tasks/spec.rb +25 -0
- data/test/fixtures/music_artist.json +103 -0
- data/test/fixtures/the_police.json +937 -0
- data/test/fixtures/the_police_topic.json +751 -0
- data/test/integration/ken_test.rb +75 -0
- data/test/test_helper.rb +59 -0
- data/test/unit/attribute_test.rb +49 -0
- data/test/unit/property_test.rb +27 -0
- data/test/unit/resource_test.rb +58 -0
- data/test/unit/session_test.rb +44 -0
- data/test/unit/topic_test.rb +92 -0
- data/test/unit/type_test.rb +35 -0
- data/test/unit/view_test.rb +48 -0
- metadata +94 -0
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
test_log
|
2
|
+
pkg
|
3
|
+
pkg/*
|
4
|
+
*/pkg/*
|
5
|
+
bundle
|
6
|
+
bundle/*
|
7
|
+
doc
|
8
|
+
*.log
|
9
|
+
log
|
10
|
+
!log*.rb
|
11
|
+
*/log
|
12
|
+
log/*
|
13
|
+
*/log/*
|
14
|
+
coverage
|
15
|
+
*/coverage
|
16
|
+
lib/dm-more.rb
|
17
|
+
*.db
|
18
|
+
nbproject
|
19
|
+
.DS_Store
|
20
|
+
rspec_report.html
|
21
|
+
*.swp
|
22
|
+
_Yardoc
|
23
|
+
*/ri
|
24
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Michael Aufreiter
|
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.textile
ADDED
@@ -0,0 +1,318 @@
|
|
1
|
+
h1. Basuco (In Dev)
|
2
|
+
|
3
|
+
h2. Introduction
|
4
|
+
|
5
|
+
Basuco is a rails3 update in the form of a gem for the original Ken plugin.
|
6
|
+
|
7
|
+
It provides simple syntax to interact with the freebase api, and wraps responses in handy ruby objects.
|
8
|
+
|
9
|
+
h2. Installation
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
<code>
|
13
|
+
$ gem install basuco
|
14
|
+
</code>
|
15
|
+
</pre>
|
16
|
+
|
17
|
+
|
18
|
+
h2. Getting started
|
19
|
+
|
20
|
+
The first place to get started with Freebase is of course, Freebase. Try out their Browser at
|
21
|
+
"http://www.freebase.com":http://www.freebase.com.
|
22
|
+
|
23
|
+
The Freebase Database can be thought of as a huge graph of interconnected nodes that represent
|
24
|
+
knowledge (in a much more structured way than wikipedia does).
|
25
|
+
That graph can be viewed at a higher level through an object-oriented lens which leads to easier interaction.
|
26
|
+
To understand the fundamental Metaweb Architecture please read the official
|
27
|
+
"MQL Reference guide":http://download.freebase.com/MQLReferenceGuide.pdf (with focus on Chapter 2)
|
28
|
+
provided by Freebase.
|
29
|
+
|
30
|
+
In addition, you can learn a lot by employing the Freebase "Query Editor":http://www.freebase.com/tools/queryeditor/.
|
31
|
+
|
32
|
+
With no registration you get 100K API calls per 24 hours, and more is available along with writing through registration.
|
33
|
+
|
34
|
+
h3. Fetching a Resource
|
35
|
+
|
36
|
+
Interaction with freebase occurs in three major ways.
|
37
|
+
|
38
|
+
First and most obvious is searching which will return collections built of resources, in turn built of properties.
|
39
|
+
<pre><code>x = Basuco::Search.new</code></pre>
|
40
|
+
Second is trans. The trans section is used for getting large chunks of text and images with their guid's.
|
41
|
+
<pre><code>x = Basuco::Trans.new</code></pre>
|
42
|
+
Lastly comes the Api for non-functional methods like logging in or checking the status of the api.
|
43
|
+
<pre><code>x = Basuco::Api.new</code></pre>
|
44
|
+
|
45
|
+
Lets start with an example:
|
46
|
+
|
47
|
+
<pre>
|
48
|
+
<code>
|
49
|
+
x = Basuco::Search.new
|
50
|
+
x.get('/en/new_order')
|
51
|
+
# => <Resource id="/en/new_order" name="New Order">
|
52
|
+
</code>
|
53
|
+
</pre>
|
54
|
+
|
55
|
+
h3. Inspecting the Types
|
56
|
+
|
57
|
+
Every Resource can have multiple types.
|
58
|
+
|
59
|
+
<pre>
|
60
|
+
<code>
|
61
|
+
resource.types
|
62
|
+
# => [ #<Type id="/film/music_contributor" name="Film music contributor">, #<Type id="/music/artist" name="Musical Artist">,
|
63
|
+
#<Type id="/common/topic" name="Topic">, #<Type id="/music/musical_group" name="Musical Group">,
|
64
|
+
#<Type id="/broadcast/artist" name="Broadcast Artist">, #<Type id="/music/group_member" name="Musical Group Member"> ]
|
65
|
+
</code>
|
66
|
+
</pre>
|
67
|
+
|
68
|
+
We can see that New Order is a member of Music Artist, Film Music Contributor, Broadcast Artist and other types.
|
69
|
+
|
70
|
+
h3. Inspecting a Type's properties
|
71
|
+
|
72
|
+
A type defines a set of properties to describe a Resource.
|
73
|
+
|
74
|
+
<pre>
|
75
|
+
<code>
|
76
|
+
resource.types.each do |type|
|
77
|
+
type.properties # => e.g. [ #<Property id="/music/musical_group/member"> ]
|
78
|
+
end
|
79
|
+
</code>
|
80
|
+
</pre>
|
81
|
+
|
82
|
+
We get sets of Properties for each Type. The Type Musical Group has just one Property @/music/musical_group/member@
|
83
|
+
named Members Of Musical Group.
|
84
|
+
|
85
|
+
h3. Listing all Attributes
|
86
|
+
|
87
|
+
After inspecting a Resource's Types and Properties we now know what we could know. But actually we don't know nothing :)
|
88
|
+
So it's time to ask for the values of properties, the so called _Attributes_.
|
89
|
+
|
90
|
+
~Note: In Ken's terminology we differ between _Properties_ and concrete Property instances, the _Attributes_, while
|
91
|
+
Freebase itself doesn't.~
|
92
|
+
|
93
|
+
<pre>
|
94
|
+
<code>
|
95
|
+
resource.attributes.each do |att|
|
96
|
+
att # => e.g. #<Attribute property="/music/artist/album">
|
97
|
+
att.property.name # => e.g. "Albums"
|
98
|
+
|
99
|
+
att.values
|
100
|
+
# e.g. => [ #<Resource id="/guid/9202a8c04000641f8000000002fa2556" name="Ceremony">,
|
101
|
+
#<Resource id="/guid/9202a8c04000641f8000000002fa24d5" name="Procession">,
|
102
|
+
#<Resource id="/guid/9202a8c04000641f8000000002fa20d3" name="Everything's Gone Green">, ... ]
|
103
|
+
# e.g. => ["1980"]
|
104
|
+
end
|
105
|
+
|
106
|
+
# alternatively you can access them directly
|
107
|
+
resource.attribute('/music/artist/album') # => #<Attribute property="/music/artist/album">
|
108
|
+
</code>
|
109
|
+
</pre>
|
110
|
+
|
111
|
+
Attributes are slightly more complicated to handle compared to Types and Properties.
|
112
|
+
|
113
|
+
There are four kinds of Attributes.
|
114
|
+
* Unique Value Type
|
115
|
+
* Unique Object Type
|
116
|
+
* Non-unique Value Type
|
117
|
+
* Non-unique Object
|
118
|
+
|
119
|
+
In order to be able to use unique and non-unique Attributes in the same manner we always wrap the value of an Attribute
|
120
|
+
in a Collection, no matter if there's one value or there are many.
|
121
|
+
|
122
|
+
h3. Group Attributes by their Type using Views
|
123
|
+
|
124
|
+
<pre>
|
125
|
+
<code>
|
126
|
+
resource.views.each do |view|
|
127
|
+
view # => e.g. #<View type="/music/artist">
|
128
|
+
view.type # => e.g #<Type id="/music/artist" name="Musical Artist">
|
129
|
+
view.attributes
|
130
|
+
# => [#<Attribute property="/music/artist/home_page">, #<Attribute property="/music/artist/genre">,
|
131
|
+
#<Attribute property="/music/artist/active_start">, #<Attribute property="/music/artist/similar_artist">,
|
132
|
+
#<Attribute property="/music/artist/album">, #<Attribute property="/music/artist/label">,
|
133
|
+
#<Attribute property="/music/artist/track">, #<Attribute property="/music/artist/origin">]
|
134
|
+
|
135
|
+
view.attributes.each do |att|
|
136
|
+
att.values
|
137
|
+
# e.g. => [ #<Resource id="/en/alternative_dance" name="Alternative dance">,
|
138
|
+
#<Resource id="/en/synthpop" name="Synthpop">,
|
139
|
+
#<Resource id="/en/house_music" name="House music">,
|
140
|
+
#<Resource id="/en/post-punk" name="Post-punk"> ]
|
141
|
+
# e.g. => ["1980"]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
</code>
|
145
|
+
</pre>
|
146
|
+
|
147
|
+
h3. Fetching multiple Resources using a query
|
148
|
+
|
149
|
+
As of now you can ask for multiple Resources by specifying a query.
|
150
|
+
|
151
|
+
<pre>
|
152
|
+
<code>
|
153
|
+
resources = Ken.all(:name => "Apple", :type => "/music/album")
|
154
|
+
# => [#<Resource id="/guid/9202a8c04000641f80000000031dae7c" name="Apple">,
|
155
|
+
#<Resource id="/guid/9202a8c04000641f8000000007ce31ec" name="Apple">]
|
156
|
+
</code>
|
157
|
+
</pre>
|
158
|
+
|
159
|
+
Keep in mind that only the top level of the query is mapped to a Collection of Resource Objects.
|
160
|
+
So asking for values in a nested level does not make sense. Use nested statements just for
|
161
|
+
lowering the top level result.
|
162
|
+
|
163
|
+
However you can instead navigate the normal way to figure out that values.
|
164
|
+
_But won't that require another query to triggered? Certainly._
|
165
|
+
|
166
|
+
Let's look at a nested query:
|
167
|
+
|
168
|
+
<pre>
|
169
|
+
<code>
|
170
|
+
query = {
|
171
|
+
:directed_by => "George Lucas",
|
172
|
+
:starring => [
|
173
|
+
{
|
174
|
+
:actor => "Harrison Ford"
|
175
|
+
}
|
176
|
+
],
|
177
|
+
:type => "/film/film"
|
178
|
+
}
|
179
|
+
|
180
|
+
resources = Ken.all(query)
|
181
|
+
# => [#<Resource id="/en/star_wars_episode_iv_a_new_hope" name="Star Wars Episode IV: A New Hope">,
|
182
|
+
#<Resource id="/en/american_graffiti" name="American Graffiti">,
|
183
|
+
#<Resource id="/en/the_star_wars_holiday_special" name="The Star Wars Holiday Special">]
|
184
|
+
</code>
|
185
|
+
</pre>
|
186
|
+
|
187
|
+
h3. Access properties attributes directly
|
188
|
+
|
189
|
+
Ken is primarily designed for inspecting resources in a generic way, what's ideal for domain independent browsing applications.
|
190
|
+
However, there are legitimate situations where you already know what you want to access.
|
191
|
+
|
192
|
+
That's why I now added direct Property/Attribute access, but only on a Type/View level:
|
193
|
+
|
194
|
+
<pre>
|
195
|
+
<code>
|
196
|
+
resource = Ken.get('/en/new_order')
|
197
|
+
type = resource.types[1] # => #<Type id="/music/artist" name="Musical Artist">
|
198
|
+
# because we know _/music/artist_ has a _genre_ property we can access that directly
|
199
|
+
type.genre # => #<Property id="/music/artist/genre" expected_type="/music/genre" unique="false" object_type="true">
|
200
|
+
</code>
|
201
|
+
</pre>
|
202
|
+
|
203
|
+
The same works for views:
|
204
|
+
|
205
|
+
<pre>
|
206
|
+
<code>
|
207
|
+
resource = Ken.get('/en/new_order')
|
208
|
+
view = resource.views[1] # => #<View type="/music/artist">
|
209
|
+
# because we know _/music/artist_ has a _genre_ property we can access attribute directly as well
|
210
|
+
view.genre # => #<Attribute property="/music/artist/genre">
|
211
|
+
</code>
|
212
|
+
</pre>
|
213
|
+
|
214
|
+
If you rather want to query based on Types and access Properties/Attributes directly you can consider using
|
215
|
+
Chris "Eppsteins Freebase Library":http://github.com/chriseppstein/freebase/tree/master as an alternative.
|
216
|
+
|
217
|
+
|
218
|
+
h3. Low Level API
|
219
|
+
|
220
|
+
Sometimes you may want to do specific queries instead of inspecting Resources as a whole.
|
221
|
+
In such a case you would want to use Ken's low level API.
|
222
|
+
|
223
|
+
_mqlread_ works like the regular _mqlread service_, except that you are able to pass Ruby hashes instead of JSON.
|
224
|
+
And you don't have to deal with HTTP, parameter encoding and parsing JSON.
|
225
|
+
|
226
|
+
<pre>
|
227
|
+
<code>
|
228
|
+
artists = Ken.session.mqlread([{
|
229
|
+
:type => "/music/artist",
|
230
|
+
:id => nil,
|
231
|
+
:"/common/topic/webpage" => [{:uri => nil}],
|
232
|
+
:home_page => [{:uri => nil}],
|
233
|
+
:limit => 2
|
234
|
+
}])
|
235
|
+
|
236
|
+
# => [
|
237
|
+
{"type"=>"/music/artist", "home_page"=>[{"uri"=>"http://www.massiveattack.co.uk/"}], "id"=>"/en/massive_attack", "/common/topic/webpage"=>[{"uri"=>"http://musicmoz.org/Bands_and_Artists/M/Massive_Attack/"}, {"uri"=>"http://www.discogs.com/artist/Massive+Attack"}, {"uri"=>"http://www.massiveattackarea.com/"}, {"uri"=>"http://www.massiveattack.co.uk/"}, {"uri"=>"http://www.massiveattack.com/"}]},
|
238
|
+
{"type"=>"/music/artist", "home_page"=>[{"uri"=>"http://www.apartment26.com/"}], "id"=>"/en/apartment_26", "/common/topic/webpage"=>[{"uri"=>"http://www.discogs.com/artist/Apartment+26"}, {"uri"=>"http://musicmoz.org/Bands_and_Artists/A/Apartment_26/"}, {"uri"=>"http://www.apartment26.com/"}]}
|
239
|
+
]
|
240
|
+
</code>
|
241
|
+
</pre>
|
242
|
+
|
243
|
+
|
244
|
+
h3. Topic API
|
245
|
+
|
246
|
+
Please first have a look at the official "Topic HTTP API documentation":http://www.freebase.com/docs/topic_api .
|
247
|
+
|
248
|
+
The API provides general meta-data such as name, description, links and images for a given topic,
|
249
|
+
as well as all properties directly related to that topic in the graph.
|
250
|
+
The API wraps a series of MQL queries that are needed to get this data, which otherwise must be performed separately.
|
251
|
+
So for gaining common interest information about a specific topic the Topic API is a way faster alternative to mqlread.
|
252
|
+
|
253
|
+
The latest update of Ken provides an easy way to access Freebase Topics using Ruby.
|
254
|
+
As usual Ken wraps the JSON result of the web service to convenient Ruby Objects.
|
255
|
+
|
256
|
+
For now Ken only returns simple properties. Support for so called mediator properties (aka 'CVT') will be added later.
|
257
|
+
To be honest, I just don't know how to wrap them appropriately using the existing Ken object model. Any API ideas are welcome, btw! ;)
|
258
|
+
However, in the meanwhile you can access CVT's by using the plain JSON result returned by the low level Ken.session.topic method.
|
259
|
+
|
260
|
+
|
261
|
+
The API for Topics is quite the same as for Resources.
|
262
|
+
|
263
|
+
<pre>
|
264
|
+
<code>
|
265
|
+
t = Ken::Topic.get("/en/new_order")
|
266
|
+
# => <Topic id="/en/new_order" name="New Order">
|
267
|
+
|
268
|
+
t.types
|
269
|
+
# => [ #<Type id="/music/artist" name="Musical Artist">, #<Type id="/music/musical_group" name="Musical Group">, ... ]
|
270
|
+
|
271
|
+
t.views
|
272
|
+
# => [ #<View type="/music/artist">, #<View type="/music/musical_group">, ... ]
|
273
|
+
|
274
|
+
t.properties
|
275
|
+
# => [ #<Property id="/music/artist/similar_artist" expected_type="/music/artist">, ... ]
|
276
|
+
|
277
|
+
t.attributes
|
278
|
+
# => [ #<Attribute property="/music/artist/similar_artist">, #<Attribute property="/music/artist/album">, ... ]
|
279
|
+
|
280
|
+
</code>
|
281
|
+
</pre>
|
282
|
+
|
283
|
+
Additionally you can access some general meta-data, most importantly the topic's description which otherwise would need an additional request to the raw service.
|
284
|
+
|
285
|
+
<pre>
|
286
|
+
<code>
|
287
|
+
|
288
|
+
t.name # => "New Order"
|
289
|
+
t.description # => "New Order were an English musical group formed in 1980 by Bernard Sumner ... "
|
290
|
+
t.aliases # => [ "NewOrder", "Englandneworder" ]
|
291
|
+
t.webpages # => [ {"url"=>"http://en.wikipedia.org/wiki/index.html?curid=22146", "text"=>"Wikipedia"}, ... ]
|
292
|
+
t.url # => "http://www.freebase.com/view/en/new_order"
|
293
|
+
t.thumbnail => "http://api.freebase.com/api/trans/image_thumb/en/new_order"
|
294
|
+
|
295
|
+
</code>
|
296
|
+
</pre>
|
297
|
+
|
298
|
+
|
299
|
+
h2. Project Status
|
300
|
+
|
301
|
+
h3. Features
|
302
|
+
|
303
|
+
* Fetching of single Resources
|
304
|
+
* Fetching of multiple Resources by specifying a query
|
305
|
+
* Accessing Properties/Attributes directly (on a type/view level)
|
306
|
+
* Type inspection
|
307
|
+
* Attribute inspection
|
308
|
+
* Low Level API (mqlread)
|
309
|
+
* Rails and Merb support
|
310
|
+
* Views on Resources to group Attributes based on the Resource's types
|
311
|
+
* Accessing Topics using the new Freebase Topic API
|
312
|
+
|
313
|
+
h3. Roadmap
|
314
|
+
|
315
|
+
# More tests
|
316
|
+
# Write-Support
|
317
|
+
|
318
|
+
Initial thoughts, obviously not up-to-date and not conforming to the current version, are available at "http://wiki.github.com/michael/ken":http://wiki.github.com/michael/ken.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/basuco.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "basuco/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "basuco"
|
7
|
+
s.version = Basuco::VERSION
|
8
|
+
s.authors = ["Caleb Bron"]
|
9
|
+
s.email = [""]
|
10
|
+
s.homepage = "https://github.com/cbron/basuco"
|
11
|
+
s.summary = %q{Freebase Gem}
|
12
|
+
s.description = %q{Transfer information from freebase.com through ruby.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "basuco"
|
15
|
+
|
16
|
+
s.add_development_dependency "rspec"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
end
|
data/examples/artist.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
|
5
|
+
require EXAMPLES_ROOT.parent + 'lib/basuco'
|
6
|
+
|
7
|
+
session = Basuco::Search.new
|
8
|
+
|
9
|
+
resource = session.get('/en/tiesto') #basically everything starts with /en/
|
10
|
+
|
11
|
+
resource.views.each do |view|
|
12
|
+
puts view
|
13
|
+
puts "="*20
|
14
|
+
view.attributes.each do |a|
|
15
|
+
puts a.property
|
16
|
+
puts "-"*20
|
17
|
+
puts a
|
18
|
+
puts # newline
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
# displays all links related to music/artists
|
5
|
+
# low level api through Ken.session.mqlread is used here
|
6
|
+
|
7
|
+
EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
|
8
|
+
require EXAMPLES_ROOT.parent + 'lib/ken'
|
9
|
+
|
10
|
+
Ken::Session.new('http://www.freebase.com', 'ma', '*****')
|
11
|
+
|
12
|
+
puts "collecting artist links... this might take a while..."
|
13
|
+
|
14
|
+
artist_links = []
|
15
|
+
|
16
|
+
# execute query
|
17
|
+
artists = Ken.session.mqlread([{
|
18
|
+
:type => "/music/artist",
|
19
|
+
:id => nil,
|
20
|
+
:"/common/topic/webpage" => [{:uri => nil}],
|
21
|
+
:home_page => [{:uri => nil}]
|
22
|
+
}], :cursor => true)
|
23
|
+
|
24
|
+
# collect artist links
|
25
|
+
artists.each do |artist|
|
26
|
+
artist["/common/topic/webpage"].each do |webpage|
|
27
|
+
artist_links << webpage["uri"] unless artist_links.include?(webpage["uri"])
|
28
|
+
end
|
29
|
+
|
30
|
+
artist["home_page"].each do |homepage|
|
31
|
+
artist_links << homepage["uri"] unless artist_links.include?(homepage["uri"])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# print artist links
|
36
|
+
artist_links.each do |link|
|
37
|
+
puts link
|
38
|
+
end
|