pandata 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 41b8bbfd247c0f180d0d3db4c385a9780d67f3af
4
- data.tar.gz: 25e9aa7769864eae1bbb5c37f8157ed4905b1234
3
+ metadata.gz: b110672f1843569186fff6c0c073defe047b0932
4
+ data.tar.gz: bf753689e76d89c1b0ce7a92e1c2491f6d021392
5
5
  SHA512:
6
- metadata.gz: f498522a3bedfb5234bd1ae76a0655ca8ea2c997e44665e7920c2e2d65a664c023246cbedb08803eff016691edcd487722bc717bd70646e0bf5be76397a255f8
7
- data.tar.gz: 47cf7b5378e3bd2d9ceaa38388f24c90afc01921d409003844a9436de3045951d01060fec9d707565eb8c923eb7880b7f1593a37f9c51c5ca7d920a7c30efd91
6
+ metadata.gz: 0aa2816fa28182cf3bce1f1a813663624279095ff2de56922afa58b110b3e26faa0b661fc1a33df416d90d64c08b3e741174806521d7d65fedf03afa293bb438
7
+ data.tar.gz: 79cd4ce5b6a65d08585164040d39dd6a952cb8a5fd65ab55023ab4aaf6aaa402e063af7105eb977fd904ee12d6a90ce7bc10d388525c00070840392abac91129
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Brian Ustas
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.md ADDED
@@ -0,0 +1,84 @@
1
+ # Pandata
2
+
3
+ Pandata is a Ruby 1.9+ library for downloading a user's Pandora.com data. This data includes:
4
+
5
+ - Playing Station *
6
+ - Recent Activity *
7
+ - Stations *
8
+ - Bookmarks (artists, tracks) *
9
+ - Likes (albums, artists, stations, tracks)
10
+ - Followers
11
+ - Following
12
+
13
+ Where possible, Pandora [feeds][1] are used (indicated by an * above).
14
+
15
+ Pandata can only access **public** Pandora profiles. This option can be changed in Pandora's settings.
16
+
17
+ ## Installing
18
+
19
+ Pandata is a Ruby gem. To install, execute:
20
+
21
+ gem install pandata
22
+
23
+ This also installs a command-line tool called 'pandata'.
24
+
25
+ ## Usage
26
+
27
+ Pandata can be used as a Ruby library or command-line tool.
28
+
29
+ To identify a user, you must supply either an email address or a webname.
30
+
31
+ A **webname** is what Pandora uses to identify a user and it remains constant even if the user ties a new email address to their Pandora account.
32
+ To find your webname, go to 'My Profile' and you'll see your webname in the URL. For example:
33
+
34
+ pandora.com/profile/\<my_webname\>
35
+
36
+ ### As a Library
37
+
38
+ First, create a new Pandata scraper for a user:
39
+
40
+ require 'pandata'
41
+
42
+ # Scraper.get takes either an email or a webname.
43
+ # Returns an array of similar webnames if no match is found.
44
+ johns_scraper = Pandata::Scraper.get('john@example.com')
45
+
46
+ Next, start scraping!
47
+
48
+ # Get only liked tracks
49
+ likes = johns_scraper.likes(:tracks)
50
+
51
+ # Get all bookmarks (artists and tracks)
52
+ bookmarks = johns_scraper.bookmarks
53
+
54
+ # Get all stations
55
+ stations = johns_scraper.stations
56
+
57
+ # Get all followers
58
+ followers = johns_scraper.followers
59
+
60
+ For more information, see the documentation for Pandata::Scraper.
61
+
62
+ ### As a Command-Line Tool
63
+
64
+ All output is sorted alphabetically, duplicates are removed and tracks are grouped under their owning artist.
65
+
66
+ pandata <email|webname> [options]
67
+
68
+ **Options:**
69
+
70
+ For an up-to-date list, check out:
71
+
72
+ pandata --help
73
+
74
+ **Examples:**
75
+
76
+ pandata john@example.com --liked_tracks
77
+
78
+ # Get liked tracks, artists and bookmarked tracks + output as JSON.
79
+ pandata my_webname -lLb --json
80
+
81
+ # Get all data and output to a file.
82
+ pandata my_webname --all -o my_pandora_data.txt
83
+
84
+ [1]: http://www.pandora.com/feeds
data/lib/pandata.rb CHANGED
@@ -9,7 +9,7 @@ module Pandata
9
9
  module Version
10
10
  MAJOR = 0
11
11
  MINOR = 1
12
- PATCH = 1
12
+ PATCH = 2
13
13
  BUILD = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
@@ -5,18 +5,17 @@ module Pandata
5
5
 
6
6
  # Parses command-line input.
7
7
  class ArgvParser
8
- # Prevent instances
9
8
  private_class_method :new
10
9
 
11
- # Takes an ARGV (array) argument.
12
- #
13
- # Returns a hash with:
14
- # - :opts (OptionParser object)
15
- # - :user_id (string)
16
- # - :output_file (string)
17
- # - :data_to_get (array)
18
- # - :get_all_data (boolean)
19
- # - :return_as_json (boolean)
10
+ # Parses an ARGV array for options.
11
+ # @param argv [Array] an ARGV array
12
+ # @return [Hash]
13
+ # - :opts [OptionParser]
14
+ # - :user_id [String]
15
+ # - :output_file [String]
16
+ # - :data_to_get [Array]
17
+ # - :get_all_data [Boolean]
18
+ # - :return_as_json [Boolean]
20
19
  def self.parse(argv)
21
20
  options = { data_to_get: [] }
22
21
  get_all_data = false
@@ -127,5 +126,6 @@ Options:
127
126
 
128
127
  options
129
128
  end
129
+
130
130
  end
131
131
  end
@@ -5,15 +5,8 @@ module Pandata
5
5
  # Sorts and formats Pandata::Scraper data as a string for printing.
6
6
  class DataFormatter
7
7
 
8
- # Takes an array or string and returns a string with each item on its own line.
9
- #--
10
- #
11
- # Example output:
12
- # - item1
13
- # - item2
14
- # - item3
15
- #
16
- #++
8
+ # @param data [Array, String]
9
+ # Returns a string with each array item on its own line.
17
10
  def list(data)
18
11
  data = [data] unless data.kind_of?(Array)
19
12
  str = ''
@@ -22,21 +15,25 @@ module Pandata
22
15
  end
23
16
 
24
17
  # Identical to #list but sorts alphabetically ignoring 'the'.
18
+ # @param data [Array]
25
19
  def sort_list(data)
26
20
  list custom_sort(data)
27
21
  end
28
22
 
29
- # Takes an array of hashes with :artist and :track keys.
23
+ # @param tracks [Array] array of hashes with :artist and :track keys
24
+ # Returns a string with tracks grouped under owning artist.
30
25
  def tracks(tracks)
31
26
  artists_items(tracks, :track)
32
27
  end
33
28
 
34
- # Takes an array of hashes with :artist and :album keys.
29
+ # @param albums [Array] array of hashes with :artist and :album keys
30
+ # Returns a string with albums grouped under owning artist.
35
31
  def albums(albums)
36
32
  artists_items(albums, :album)
37
33
  end
38
34
 
39
- # Takes an array of hashes with :name, :webname and :href keys.
35
+ # @param data [Array] array of hashes with :name, :webname and :href keys
36
+ # Returns a string with followers/ing sorted by webname.
40
37
  def followx(data)
41
38
  str = ''
42
39
  data.sort_by { |item| item[:webname].downcase }.each do |hash|
@@ -49,11 +46,14 @@ module Pandata
49
46
 
50
47
  private
51
48
 
52
- # Takes an array or hash.
53
49
  # Sorts alphabetically ignoring the initial 'The' when sorting strings.
54
50
  # Also case-insensitive to prevent lowercase names from being sorted last.
51
+ # @param enumerable [Array, Hash]
52
+ # @return [Array, Hash]
55
53
  def custom_sort(enumerable)
56
- sorted_array = enumerable.sort_by { |key, _| key.sub(/^the\s*/i, '').downcase }
54
+ sorted_array = enumerable.sort_by do |key, _|
55
+ key.sub(/^the\s*/i, '').downcase
56
+ end
57
57
 
58
58
  # sort_by() returns an array when called on hashes.
59
59
  if enumerable.kind_of?(Hash)
@@ -66,21 +66,9 @@ module Pandata
66
66
  end
67
67
  end
68
68
 
69
- # Takes an array of hashes with :artist and another key belonging to an
70
- # artist (e.g. :track or :album).
71
- # Returns a string with each artist name on a line with the artist's items
72
- # listed and indented below. Sorts the output, too.
73
- #--
74
- #
75
- # Example output:
76
- # - Artist1:
77
- # - item2
78
- # - item3
79
- # - Artist2:
80
- # - item1
81
- # - item1
82
- #
83
- #++
69
+ # @param data [Array] array of hashes with :artist and item_name
70
+ # @param item_name [Symbol] e.g. :track or :album
71
+ # Returns a string with items grouped under their owning artist.
84
72
  def artists_items(data, item_name)
85
73
  artists_items = {}
86
74
 
@@ -2,11 +2,9 @@ require 'json'
2
2
  require 'open-uri'
3
3
 
4
4
  module Pandata
5
- # Custom Pandata error
6
- class PandataError < StandardError
7
- end
5
+ class PandataError < StandardError; end
8
6
 
9
- # Retrieves data from Pandora and handles errors.
7
+ # Retrieves data from Pandora.com and handles errors.
10
8
  class Downloader
11
9
  # A GitHub Gist that contains an updated cookie allowing access to 'login-only' visible data.
12
10
  CONFIG_URL = 'https://gist.github.com/ustasb/596f1ee96d03463fde77/raw/pandata_config.json'
@@ -17,13 +15,14 @@ module Pandata
17
15
 
18
16
  # Gets a Pandora cookie and returns a Downloader instance.
19
17
  def initialize
20
- # If we already have a cookie, don't get another.
21
18
  unless Downloader.cookie
22
19
  Downloader.cookie = get_cookie
23
20
  end
24
21
  end
25
22
 
26
- # Downloads a page and returns its content as a string.
23
+ # Downloads and reads a page from a URL.
24
+ # @param url [String]
25
+ # @return [String] contents of page
27
26
  def read_page(url)
28
27
  download(url, Downloader.cookie).read
29
28
  end
@@ -31,6 +30,9 @@ module Pandata
31
30
  private
32
31
 
33
32
  # Downloads a page and handles errors.
33
+ # @param url [String]
34
+ # @param cookie [String]
35
+ # @return [File]
34
36
  def download(url, cookie = '')
35
37
  escaped_url = URI.escape(url)
36
38
 
@@ -5,7 +5,9 @@ module Pandata
5
5
  # Parses HTML/XML pages from Pandora for relevant data.
6
6
  class Parser
7
7
 
8
- # Returns an array of webnames.
8
+ # Get the webnames from a user ID search.
9
+ # @param html [String]
10
+ # @return [Array] array of webnames
9
11
  def get_webnames_from_search(html)
10
12
  user_links = Nokogiri::HTML(html).css('.user_name a')
11
13
  webnames = []
@@ -17,8 +19,9 @@ module Pandata
17
19
  webnames
18
20
  end
19
21
 
20
- # Returns the query parameters necessary to get the next page of data
21
- # from Pandora.
22
+ # Get the query parameters necessary to get the next page of data from Pandora.
23
+ # @param html [String]
24
+ # @return [Hash, False]
22
25
  def get_next_data_indices(html)
23
26
  show_more = Nokogiri::HTML(html).css('.show_more')[0]
24
27
 
@@ -36,7 +39,8 @@ module Pandata
36
39
  end
37
40
  end
38
41
 
39
- # Returns an array of recent activities.
42
+ # @param xml [String]
43
+ # Returns an array of recent activity names.
40
44
  def get_recent_activity(xml)
41
45
  activity_names = []
42
46
 
@@ -47,6 +51,7 @@ module Pandata
47
51
  activity_names
48
52
  end
49
53
 
54
+ # @param xml [String]
50
55
  # Returns an array of station names.
51
56
  def get_stations(xml)
52
57
  stations = []
@@ -58,7 +63,8 @@ module Pandata
58
63
  stations
59
64
  end
60
65
 
61
- # Returns the currently playing station name.
66
+ # @param xml [String]
67
+ # @return [String]
62
68
  def get_playing_station(xml)
63
69
  station = ''
64
70
 
@@ -70,6 +76,7 @@ module Pandata
70
76
  station
71
77
  end
72
78
 
79
+ # @param xml [String]
73
80
  # Returns an array of hashes with :artist and :track keys.
74
81
  def get_bookmarked_tracks(xml)
75
82
  tracks = []
@@ -82,6 +89,7 @@ module Pandata
82
89
  tracks
83
90
  end
84
91
 
92
+ # @param xml [String]
85
93
  # Returns an array of artist names.
86
94
  def get_bookmarked_artists(xml)
87
95
  artists = []
@@ -93,6 +101,7 @@ module Pandata
93
101
  artists
94
102
  end
95
103
 
104
+ # @param html [String]
96
105
  # Returns an array of hashes with :artist and :track keys.
97
106
  def get_liked_tracks(html)
98
107
  tracks = []
@@ -104,16 +113,19 @@ module Pandata
104
113
  tracks
105
114
  end
106
115
 
116
+ # @param html [String]
107
117
  # Returns an array of artist names.
108
118
  def get_liked_artists(html)
109
119
  get_infobox_titles(html)
110
120
  end
111
121
 
122
+ # @param html [String]
112
123
  # Returns an array of station names.
113
124
  def get_liked_stations(html)
114
125
  get_infobox_titles(html)
115
126
  end
116
127
 
128
+ # @param html [String]
117
129
  # Returns an array of hashes with :artist and :album keys.
118
130
  def get_liked_albums(html)
119
131
  albums = []
@@ -125,11 +137,13 @@ module Pandata
125
137
  albums
126
138
  end
127
139
 
140
+ # @param html [String]
128
141
  # Returns an array of hashes with :name, :webname and :href keys.
129
142
  def get_following(html)
130
143
  get_followx_users(html)
131
144
  end
132
145
 
146
+ # @param html [String]
133
147
  # Returns an array of hashes with :name, :webname and :href keys.
134
148
  def get_followers(html)
135
149
  get_followx_users(html)
@@ -138,6 +152,7 @@ module Pandata
138
152
  private
139
153
 
140
154
  # Loops over each 'item' tag and yields the title and description.
155
+ # @param xml [String]
141
156
  def xml_each_item(xml)
142
157
  Nokogiri::XML(xml).css('item').each do |item|
143
158
  title = item.at_css('title').text
@@ -147,6 +162,7 @@ module Pandata
147
162
  end
148
163
 
149
164
  # Loops over each .infobox container and yields the title and subtitle.
165
+ # @param html [String]
150
166
  def infobox_each_link(html)
151
167
  Nokogiri::HTML(html).css('.infobox').each do |infobox|
152
168
  infobox_body = infobox.css('.infobox-body')
@@ -159,6 +175,7 @@ module Pandata
159
175
  end
160
176
  end
161
177
 
178
+ # @param html [String]
162
179
  # Returns an array of titles from #infobox_each_link.
163
180
  def get_infobox_titles(html)
164
181
  titles = []
@@ -166,8 +183,9 @@ module Pandata
166
183
  titles
167
184
  end
168
185
 
169
- # Loops over each .follow_section container and returns a hash with
170
- # :name, :webname and :href keys.
186
+ # Loops over each .follow_section container.
187
+ # @param html [String]
188
+ # @return [Hash] with keys :name, :webname and :href
171
189
  def get_followx_users(html)
172
190
  users = []
173
191
 
@@ -12,10 +12,11 @@ module Pandata
12
12
  # the user ties a new email address to their Pandora account.
13
13
  attr_reader :webname
14
14
 
15
- # Takes either an email or a webname string.
16
- # Returns either:
17
- # - a new scraper object for the supplied user ID.
18
- # - an array of similar webnames because a matching Pandora user could not be found.
15
+ # If possible, get a Scraper instance for the user_id otherwise return
16
+ # an array of similar webnames.
17
+ # @param user_id [String] email or webname
18
+ # @return [Scraper] a scraper object for the supplied user ID
19
+ # @return [Array] array of similar webnames
19
20
  def self.get(user_id)
20
21
  search_url = DATA_FEED_URLS[:user_search] % { searchString: user_id }
21
22
  html = Downloader.new.read_page(search_url)
@@ -38,27 +39,29 @@ module Pandata
38
39
  @webname = webname
39
40
  end
40
41
 
41
- # Returns an array of the user's recent activity.
42
+ # Get the user's recent activity.
43
+ # @return [Array] array of activity names
42
44
  def recent_activity
43
45
  scrape_for(:recent_activity, :get_recent_activity)
44
46
  end
45
47
 
46
- # Returns the user's currently playing station.
48
+ # Get the user's playing station.
49
+ # @return [String]
47
50
  def playing_station
48
51
  scrape_for(:playing_station, :get_playing_station).first
49
52
  end
50
53
 
51
- # Returns an array of the user's stations.
54
+ # Get the user's stations.
55
+ # @return [Array] array of station names
52
56
  def stations
53
57
  scrape_for(:stations, :get_stations)
54
58
  end
55
59
 
56
- # Returns a user's bookmarked data.
57
- #
58
- # Bookmark types:
59
- # - :artists - Returns an array of artist names.
60
- # - :tracks - Returns an array of hashes with :artist and :track keys.
61
- # - :all - Returns a hash with all bookmarked data.
60
+ # Get the user's bookmarked data.
61
+ # @param bookmark_type [Symbol]
62
+ # - :artists - returns an array of artist names
63
+ # - :tracks - returns an array of hashes with :artist and :track keys
64
+ # - :all - returns a hash with all bookmarked data
62
65
  def bookmarks(bookmark_type = :all)
63
66
  case bookmark_type
64
67
  when :tracks
@@ -71,14 +74,13 @@ module Pandata
71
74
  end
72
75
  end
73
76
 
74
- # Returns a user's liked data. (The results from giving a 'thumbs up.')
75
- #
76
- # Like types:
77
- # - :artists - Returns an array of artist names.
78
- # - :albums - Returns an array of album names.
79
- # - :stations - Returns an array of station names.
80
- # - :tracks - Returns an array of hashes with :artist and :track keys.
81
- # - :all - Returns a hash with all liked data.
77
+ # Get the user's liked data. (The results from giving a 'thumbs up.')
78
+ # @param like_type [Symbol]
79
+ # - :artists - returns an array of artist names
80
+ # - :albums - returns an array of hashes with :artist and :album keys
81
+ # - :stations - returns an array of station names
82
+ # - :tracks - returns an array of hashes with :artist and :track keys
83
+ # - :all - returns a hash with all liked data
82
84
  def likes(like_type = :all)
83
85
  case like_type
84
86
  when :tracks
@@ -97,17 +99,17 @@ module Pandata
97
99
  end
98
100
  end
99
101
 
100
- # Returns the *public* users being followed by the user.
101
- #
102
- # Returns an array of hashes with keys:
103
- # - :name - Profile name
104
- # - :webname - Unique Pandora ID
105
- # - :href - URL to online Pandora profile.
102
+ # Get the *public* users being followed by the user.
103
+ # @return [Array] array of hashes with keys:
104
+ # - :name - profile name
105
+ # - :webname - unique Pandora ID
106
+ # - :href - URL to online Pandora profile
106
107
  def following
107
108
  scrape_for(:following, :get_following)
108
109
  end
109
110
 
110
- # Returns the user's followers in a format identical to #following.
111
+ # Get the user's *public* followers.
112
+ # @return [Array] identical to #following
111
113
  def followers
112
114
  scrape_for(:followers, :get_followers)
113
115
  end
@@ -116,6 +118,9 @@ module Pandata
116
118
 
117
119
  # Downloads all data for a given type, calls the supplied Pandata::Parser
118
120
  # method and removes any duplicates.
121
+ # @param data_type [Symbol]
122
+ # @param parser_method [Symbol] method to be sent to the Parser instance
123
+ # @return [Array]
119
124
  def scrape_for(data_type, parser_method)
120
125
  results = []
121
126
 
@@ -139,6 +144,7 @@ module Pandata
139
144
  # Downloads all data given a starting URL. Some Pandora feeds only return
140
145
  # 5 - 10 items per page but contain a link to the next set of data. Threads
141
146
  # cannot be used because page A be must visited to know how to obtain page B.
147
+ # @param url [String]
142
148
  def download_all_data(url)
143
149
  next_data_indices = {}
144
150
 
@@ -150,6 +156,8 @@ module Pandata
150
156
  end
151
157
 
152
158
  # Grabs a URL from DATA_FEED_URLS and formats it appropriately.
159
+ # @param data_name [Symbol]
160
+ # @param next_data_indices [Symbol] query parameters to get the next set of data
153
161
  def get_url(data_name, next_data_indices = {})
154
162
  next_data_indices = {
155
163
  nextStartIndex: 0,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pandata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Ustas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-11 00:00:00.000000000 Z
11
+ date: 2013-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -38,13 +38,29 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.12.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.5
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.5
41
55
  description: A library and tool for downloading Pandora.com data (likes, bookmarks,
42
56
  stations, etc.)
43
57
  email: brianustas@gmail.com
44
58
  executables:
45
59
  - pandata
46
60
  extensions: []
47
- extra_rdoc_files: []
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.md
48
64
  files:
49
65
  - lib/pandata/argv_parser.rb
50
66
  - lib/pandata/data_formatter.rb
@@ -53,6 +69,8 @@ files:
53
69
  - lib/pandata/parser.rb
54
70
  - lib/pandata/scraper.rb
55
71
  - lib/pandata.rb
72
+ - LICENSE
73
+ - README.md
56
74
  - bin/pandata
57
75
  homepage: https://github.com/ustasb/pandata
58
76
  licenses: