Even easier way to distribute code:
http://github.com
:)
> #!/usr/bin/ruby
> # LDS.org ward picture directory generator
> #
> # Dan Amelang (
d...@amelang.net) - January 2007
> # Released under the Ruby license
> #
> # Dave Smith (
da...@thesmithfam.org) - February 2008
> # Added parents, children, addresses, and phone numbers
> #
> # TODO:
> # Don't print "The ... Family" if there is only one person in the family
> # Add list of families w/out photo at the end
> # Package as an executable (report Ruby2exe bug)
> # documentation
> # GUI file chooser
> # GUI username and password entry
> # GUI progress/status widget
>
> puts "Loading libraries (so dang slow)..."
>
> trap("INT") {
> puts "Exiting"
> exit
> }
>
> require 'rubygems'
> require 'mechanize'
> require 'ftools'
> require 'pdf/writer'
>
> username = ''
> password = ''
>
> login_file = File.dirname($0) + "/wardlogin.conf"
> if File.exists?(login_file)
> puts "Reading username/password from '" + login_file + "'"
> File.open(login_file).each { |line|
> line.strip!
> if line == ''
> abort "Woops. No empty lines aloud in " + login_file
> elsif username == ''
> username = line
> elsif password == ''
> password = line
> else
> abort "Woops. wardlogin.conf should only have a user line and a password line, nothing else."
> end
> }
> else
> abort "Please create wardlogin.conf with your LDS username and password on separate lines in this directory: " + File.dirname($0)
> end
>
> # Start up our "web browser"
> agent = WWW::Mechanize.new
>
> # We'll pretend to be IE, just be on the safe side
> agent.user_agent_alias = 'Windows IE 6'
>
> # Start at the main LDS.org page
> begin
> puts "Browsing to lds.org..."
> page = agent.get('
http://lds.org/')
> rescue Exception
> abort "Unable to connect to
lds.org! Check your internet connection."
> end
>
> # Go to the login page
> puts "Browsing to the ward login page..."
> page = page.links.find {|l| l.text =~ /ward.*site/i}.click
>
> # Find the login form
> form = page.forms.find {|f|
f.name =~ /log/i}
>
> # Enter the username
> form.fields.find {|f|
f.name =~ /user/i}.value = username
>
> # Enter the password
> form.fields.find {|f|
f.name =~ /pass/i}.value = password
>
> # Try to login
> puts "Logging in as '" + username + "'..."
> page = form.submit
>
> # Check for a failed login
> if /login/i.match(page.title)
> abort "Unable to login! Incorrect username and/or password?"
> end
>
> # We're in!
>
> # Go to the membership directory page
> puts "Navigating to the membership directory..."
> page = page.links.find {|l| l.text =~ /member.*directory/i}.click
>
> # Find the link to the version of the directory with the photos
> link = page.links.find {|l| l.text =~ /photo/i}
>
> # The actual URL for the photo directory is embedded in javascript
> # in the HREF field. So we have to dig it out ourselves.
> # TODO Can we pull the base of the URI from the agent (or page)
> # instead of hard coding it?
> photo_directory_url =
> '
https://secure.lds.org' + /(\/.*\.html)/i.match(link.uri.to_s)[1]
> puts "Downloading the ward photo directory (this can take a few minutes)"
> puts " " + photo_directory_url
> page = agent.get(photo_directory_url)
>
> # Yes, this page actually has _two_ HTML title elements!
> ward_name = page.search('/html/head/title')[0].all_text.strip
> ward_name.slice!(' Membership Directory')
>
> puts "Ward name: '" + ward_name + "'"
>
> Family = Struct.new(:last_name, :parents, :children, :phone, :address, :picture)
> families = []
>
> CHILD_REGEX = /^ /
> PARENT_REGEX = /^ /
> FAMILY_QUERY = '/html/body/table/tr/td[@class=\'eventsource\']/table/tr'
>
> puts 'Searching for families...'
> results = page.search(FAMILY_QUERY)
> picture_counter = 0
> picture_file_names = []
> results.each do |family|
> name_search = family.search('tr/td/table/tr/td')
> if name_search != nil and name_search.size > 0
> last_name = name_search[0].all_text.strip
> puts "Family: " + last_name
> parents = []
> children = []
> for i in 1...name_search.size
> first_name = name_search[i].all_text.strip
> if first_name =~ CHILD_REGEX
> first_name.slice!(CHILD_REGEX)
> children << first_name
> elsif first_name =~ PARENT_REGEX
> first_name.slice!(PARENT_REGEX)
> parents << first_name
> end
> end
>
> puts " Parents: " + parents.join(', ')
> puts " Children: " + children.join(', ')
>
> img_search = family.search('img')
> picture = ''
> if img =
img_search.at('img')
> picture_url = '
https://secure.lds.org' + img['src']
> puts " Picture: " + picture_url
> picture_data = agent.get_file(picture_url)
> picture = "/tmp/ward-photo-" + picture_counter.to_s + ".jpg"
> puts " Saving picture to '" + picture + "'"
> File.open(picture, 'w') {|f| f.write(picture_data) }
> picture_counter = picture_counter + 1
> picture_file_names << picture
> else
> puts " Picture: (none)"
> end
>
> phone_search = family.search('tr/td/table/tr/td')
> phone_text = ''
> if phone_search.size >= 2 and phone_text = phone_search[1].all_text.strip
> puts " Phone: " + phone_text
> else
> puts " Phone: (none)"
> end
>
> address_search = family.search('tr/td')
> address_text = ''
> if address_search.size >= 2 and address_text = address_search[1].all_text.strip.split("\n")[0]
> puts " Address: " + address_text
> else
> address_text = ''
> puts " Address: (none)"
> end
>
> families << Family.new(last_name, parents, children, phone_text, address_text, picture)
>
> end # if we found the family's last name
>
> end # for each family
>
> puts "Generating the PDF..."
>
> class Array
> # Handy for dividing an array into fixed-size pieces (later versions of Ruby
> # have a built-in way to do this)
> def / len
> inject([]) do |ary, x|
> ary << [] if [*ary.last].nitems % len == 0
> ary.last << x
> ary
> end
> end
> end
>
> pdf = PDF::Writer.new(:orientation => :portrait)
> pdf.select_font "Times-Roman"
>
> # Insert the ward name and timestamp at the top
> pdf.text ward_name, :font_size => 30, :justification => :center
> pdf.text "\n", :font_size => 15
> pdf.text Time.now.strftime("%B %d, %Y"), :font_size => 15,
> :justification => :center
>
> pdf.font_size = 10
> pdf.start_columns 2
>
> families.each do |family|
>
> puts "Adding the '" + family.last_name + "' family to the PDF..."
>
> info_text = family.last_name
> info_text << "\n"
> info_text << family.parents.join(', ')
>
> if family.children.length > 0
> info_text << "\n"
> info_text << family.children.join(', ')
> end
>
> puts " Address: '" + family.address + "'"
> if family.address != ''
> info_text << "\n"
> info_text << family.address
> end
>
> puts " Phone: '" + family.phone + "'"
> if family.phone != ''
> info_text << "\n"
> info_text << family.phone
> end
>
> pdf.text info_text
>
> if family.picture != ''
> pdf.image(family.picture, :resize => 0.7, :pad => 1)
> end
>
> pdf.text "\n"
> end
>
> puts "Cleaning up temporary files..."
> picture_file_names.each do |file|
> File.delete(file)
> end
>
> pdf.save_as('Ward_Picture_Directory.pdf')
> puts 'Saved generated picture directory in file named "Ward_Picture_Directory.pdf"'
>
>