pandata 0.1.1 → 0.1.2

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.
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: