Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add progressbar and create CLI class
- Loading branch information
Showing
43 changed files
with
42,692 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,5 @@ | |
*.gem | ||
doc/* | ||
.yardoc | ||
.rspec | ||
Gemfile.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
source "https://rubygems.org" | ||
|
||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,8 @@ | ||
#!/usr/bin/env ruby | ||
|
||
require_relative '../lib/pandata' | ||
require_relative '../lib/pandata/argv_parser' | ||
require_relative '../lib/pandata/data_formatter' | ||
require_relative '../lib/pandata/cli' | ||
|
||
options = Pandata::ArgvParser.parse(ARGV) | ||
|
||
output_file = options[:output_file] | ||
if output_file | ||
File.delete(output_file) if File.exists?(output_file) | ||
|
||
Object.send(:define_method, :write) do |string| | ||
File.open(output_file, 'a') do |file| | ||
file.puts string | ||
end | ||
end | ||
else | ||
def write(string) | ||
puts string | ||
end | ||
end | ||
|
||
if ARGV.empty? | ||
# Print command-line usage help. | ||
puts options[:opts] | ||
exit | ||
end | ||
|
||
scraper = Pandata::Scraper.get(options[:user_id]) | ||
formatter = Pandata::DataFormatter.new | ||
|
||
# If scraper is an array, a Pandora user could not be found with certainty. | ||
# In this case, scraper will contain webnames similar to options[:user_id]. | ||
if scraper.kind_of?(Array) | ||
puts "No exact match for '#{options[:user_id]}'." | ||
|
||
unless scraper.empty? | ||
puts "\nWebname results for '#{options[:user_id]}':" | ||
puts formatter.list(scraper) | ||
end | ||
|
||
exit | ||
end | ||
|
||
scraper_data = {} | ||
options[:data_to_get].each do |data_type| | ||
if /(bookmark|like)e?d_(.*)/ =~ data_type | ||
method = $1 << 's' # 'likes' or 'bookmarks' | ||
argument = $2.to_sym # :tracks, :artists, :stations or :albums | ||
scraper_data[data_type] = scraper.public_send(method, argument) | ||
else | ||
scraper_data[data_type] = scraper.public_send(data_type) | ||
end | ||
end | ||
|
||
if options[:return_as_json] | ||
require 'json' | ||
write JSON.generate(scraper_data) | ||
exit | ||
end | ||
|
||
scraper_data.each do |key, value| | ||
# Capitalize each word in the key symbol. | ||
# e.g. :liked_tracks becomes 'Liked Tracks:' | ||
title = key.to_s.split('_').map(&:capitalize).join(' ') << ':' | ||
|
||
if value.empty? | ||
output = ' ** No Data **' | ||
else | ||
output = case key | ||
when /playing_station|recent_activity/ | ||
formatter.list(value) | ||
when /liked_tracks|bookmarked_tracks/ | ||
formatter.tracks(value) | ||
when /liked_artists|bookmarked_artists|stations|liked_stations/ | ||
formatter.sort_list(value) | ||
when :liked_albums | ||
formatter.albums(value) | ||
when /following|followers/ | ||
formatter.followx(value) | ||
end | ||
end | ||
|
||
write "#{ title }\n#{ output }" | ||
begin | ||
Pandata::CLI.scrape(ARGV) | ||
rescue Pandata::PandataError | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
require 'json' | ||
require 'ruby-progressbar' | ||
require_relative '../pandata' | ||
require_relative 'argv_parser' | ||
require_relative 'data_formatter' | ||
|
||
module Pandata | ||
|
||
# Pandata command-line interface | ||
class CLI | ||
|
||
def self.scrape(argv) | ||
options = Pandata::ArgvParser.parse(argv) | ||
|
||
if argv.empty? || options[:help] | ||
puts options[:opts].to_s # Log usage information | ||
elsif options[:version] | ||
puts Pandata::Version::STRING | ||
else | ||
new(options).download_and_output | ||
end | ||
end | ||
|
||
def initialize(options) | ||
@data_to_get = options[:data_to_get] | ||
@output_file = options[:output_file] | ||
@return_as_json = options[:return_as_json] | ||
|
||
@scraper = scraper_for(options[:user_id]) | ||
@scraper.download_cb = method(:update_progress) | ||
end | ||
|
||
def update_progress(num_data) | ||
progressbar.progress += num_data | ||
end | ||
|
||
def download_and_output | ||
output_data format_data(download_data, @return_as_json) | ||
end | ||
|
||
private | ||
|
||
def progressbar | ||
@progressbar ||= ProgressBar.create( | ||
title: 'Data Downloaded', | ||
format: '%t: %c', | ||
total: nil | ||
) | ||
end | ||
|
||
def formatter | ||
@formatter ||= DataFormatter.new | ||
end | ||
|
||
def log(msg) | ||
puts msg | ||
end | ||
|
||
# Writes the data to STDOUT or a file. | ||
# @param formatted_data [String] | ||
def output_data(formatted_data) | ||
@progressbar.stop if @progressbar | ||
|
||
if @output_file | ||
File.write(@output_file, formatted_data) | ||
else | ||
log formatted_data | ||
end | ||
end | ||
|
||
# Formats data as a string list or JSON. | ||
# @param data [Hash] | ||
# @param json [Boolean] | ||
# @return [String] | ||
def format_data(data, json = false) | ||
if json | ||
JSON.generate(data) | ||
else | ||
data.map do |category, cat_data| | ||
# Capitalize each word in the category symbol. | ||
# e.g. :liked_tracks becomes 'Liked Tracks' | ||
title = category.to_s.split('_').map(&:capitalize).join(' ') | ||
|
||
output = if cat_data.empty? | ||
" ** No Data **\n" | ||
else | ||
case category | ||
when /playing_station|recent_activity/ | ||
formatter.list(cat_data) | ||
when /liked_tracks|bookmarked_tracks/ | ||
formatter.tracks(cat_data) | ||
when /liked_artists|bookmarked_artists|stations|liked_stations/ | ||
formatter.sort_list(cat_data) | ||
when :liked_albums | ||
formatter.albums(cat_data) | ||
when /following|followers/ | ||
formatter.followx(cat_data) | ||
end | ||
end | ||
|
||
"#{title}:\n#{output}" | ||
end.join | ||
end | ||
end | ||
|
||
# Downloads the user's desired data. | ||
# @return [Hash] | ||
def download_data | ||
scraper_data = {} | ||
|
||
@data_to_get.each do |data_category| | ||
if /(bookmark|like)e?d_(.*)/ =~ data_category | ||
method = $1 << 's' # 'likes' or 'bookmarks' | ||
argument = $2.to_sym # :tracks, :artists, :stations or :albums | ||
scraper_data[data_category] = @scraper.public_send(method, argument) | ||
else | ||
scraper_data[data_category] = @scraper.public_send(data_category) | ||
end | ||
end | ||
|
||
scraper_data | ||
end | ||
|
||
# Returns a scraper for the user's id. | ||
# @param user_id [String] webname or email | ||
# @return [Pandata::Scraper] | ||
def scraper_for(user_id) | ||
scraper = Pandata::Scraper.get(user_id) | ||
|
||
if scraper.kind_of?(Array) | ||
log "No exact match for '#{user_id}'." | ||
|
||
unless scraper.empty? | ||
log "\nWebname results for '#{user_id}':\n#{formatter.list(scraper)}" | ||
end | ||
|
||
raise PandataError, "Could not create a scraper for '#{user_id}'." | ||
end | ||
|
||
scraper | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.