Last active
August 29, 2015 14:07
-
-
Save frosty/b6d1615dab5544fc22b0 to your computer and use it in GitHub Desktop.
iTunes Receipt Email Parser
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
class ReceiptParser | |
attr_reader :counts, :prices | |
def initialize(currency_symbol) | |
if (currency_symbol == "") then currency_symbol = "£" end | |
@currency_symbol = currency_symbol | |
@all_items = [] | |
@counts = { :ios_apps => 0, :iaps => 0 } | |
@prices = { :ios_apps => 0, :iaps => 0 } | |
end | |
def parse_email(file) | |
lines = slice_out_relevant_section(file) | |
if (lines) then | |
lines.map! { |line| | |
line.gsub!(/\Fr=\r\n/, "Free") | |
line.gsub!(/\=\r\n/, "") | |
line.gsub!(/\=C2=A3/, @currency_symbol) | |
line.gsub!(/\=A3=\r\n/, @currency_symbol) | |
line.gsub!(/\=A3/, @currency_symbol) | |
line | |
} | |
new_lines = [] | |
lines.each_with_index do |line, index| | |
if (line.end_with? @currency_symbol ) then | |
new_lines << (line + lines[index+1]) | |
end | |
if (line =~ / #{@currency_symbol}(\.|\d)+\r\n/) then | |
new_lines << (lines[index-1] + line) | |
end | |
if (line.end_with? "Free") then | |
new_lines << line | |
end | |
end | |
new_lines.select! { |line| | |
(line.include?("Seller:") || line.include?("App")) | |
} | |
new_lines.reject! { |line| | |
line.include?("Mac App") # Filter out all Mac Apps | |
} | |
# Clean up the data | |
new_lines.map! { |line| | |
line.gsub!(/^\d{1,2}\s+/, "") | |
line.gsub!(/^Q\d{4}\s+/, "") | |
line.gsub!(/\ {3,}/, "\t") | |
line.gsub!(/, Seller: /, "\t") | |
if (line.count("\t") == 2) then | |
line.gsub!(/\tFree$/, "\t\tFree") | |
line.gsub!(/\t#{@currency_symbol}/, "\t\t#{@currency_symbol}") | |
end | |
line | |
} | |
new_lines | |
end | |
end | |
def slice_out_relevant_section(file) | |
lines = File.readlines(file) | |
item_index = lines.index { |line| line =~ /^Item/ } | |
if (!item_index) then return end | |
lines.slice!(0, item_index+2) | |
line_index = lines.index { |line| line !~ /^-----------------------------------------------/ } | |
lines.slice!(0, line_index+1) | |
next_line_index = lines.index { |line| line =~ /^-----------------------------------------------/ } | |
lines.slice!(next_line_index, lines.size - next_line_index) | |
return lines | |
end | |
def price_for_part(part) | |
return 0 if (part == "") | |
return part.gsub(/#{@currency_symbol}/, "").to_f | |
end | |
def parse | |
Dir.glob("**/*.eml") do |file| | |
email_items = parse_email(file) | |
@all_items += email_items || [] | |
end | |
@all_items.each do |item| | |
parts = item.split("\t") | |
case parts[2] | |
when "" | |
@counts[:ios_apps] += 1 | |
@prices[:ios_apps] += price_for_part(parts[3]) | |
when "In-App Pu" | |
@counts[:iaps] += 1 | |
@prices[:iaps] += price_for_part(parts[3]) | |
when "In App Pu" | |
@counts[:iaps] += 1 | |
@prices[:iaps] += price_for_part(parts[3]) | |
when "App" | |
@counts[:ios_apps] += 1 | |
@prices[:ios_apps] += price_for_part(parts[3]) | |
when "iOS App" | |
@counts[:ios_apps] += 1 | |
@prices[:ios_apps] += price_for_part(parts[3]) | |
end | |
end | |
File.open("App.tsv", "w") do |file| | |
@all_items.each do |item| | |
file.write item | |
end | |
end | |
end | |
def price_for_type(item_type) | |
format_price(@prices[item_type]) | |
end | |
def format_price(price) | |
"#{@currency_symbol}#{price.round(2)}" | |
end | |
end | |
currency_symbol = [(print 'What currency symbol do you use? (default £) '), gets.rstrip][1] | |
parser = ReceiptParser.new(currency_symbol) | |
parser.parse | |
puts | |
puts "iOS Apps: #{parser.counts[:ios_apps]} (#{parser.price_for_type(:ios_apps)})" | |
puts "In-App Purchases: #{parser.counts[:iaps]} (#{parser.price_for_type(:iaps)})" | |
puts | |
puts "Total Purchases: #{parser.counts.values.inject(:+)} (#{parser.format_price(parser.prices.values.inject(:+))})" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment