#!/usr/bin/perl -w # # Foto.com Command line Image uploader # # Usage: foto.com-uploader.pl [options] [filenames]... # Options: # --email specify the email address used for identification # --password specify the associated password # --album specify the name of the album to transfer into # If no album is specified, the current date/time is used. # If "?" is used, the list of existing albums is retrieved. # --list=filename specify the file from which the list of filesi # to export should be read # --[no-]strip specify whether the path is stripped # from the filenames during the transfer # --root specify the root part to be stripped # from the filenames during the transfer # Ignored if --strip is specified. # If none of them is specified, --strip is the default. # --verbose specify whether the program shows # the progress of the transfer # --quiet specify whether the program is showing # only the names of the files that have been transferred # #END HELP # # Author: Olivier Smeesters # # This program can be freely modified and redistributed provided my name # is kept somewhere in it. # If you improve it, please send me a mail at osmeest@gmail.com . # use strict; use English; use Getopt::Long; use LWP::UserAgent; use HTTP::Cookies; use HTML::Form; use HTML::Parser; use File::Basename; use Data::Dumper; #my $login_url = 'http://be.foto.com/fr/webalbum.asp'; my $login_url = 'http://webalbum.foto.com/index.php?module=webalbum&page=login&lg=fr&cid=1'; my $email; my $pass; my $file_list; my $strip_path = 1; my $strip_root; my $verbose; my $quiet; my $album = localtime; my @images = (); sub print_help() { open HELP, `which $0` or die "Can't find myself."; ; while (1) { $_ = ; chomp $_; last if ($_ eq "#END HELP"); $_ =~ s/^#//; print "$_\n"; } close HELP; exit(0); } if (open PREFS, "$ENV{HOME}/.foto.com") { while () { if (/^\s*email\s*:\s*(.*)\s*$/) { $email = $1; } elsif (/^\s*password\s*:\s*(.*)\s*$/) { $pass = $1; } elsif (/^\s*album\s*:\s*(.*)\s*$/) { $album = $1; } elsif (/^\s*root\s*:\s*(.*)\s*$/) { $strip_root = $1; } elsif (/^\s*strip\s*:\s*(.*)\s*$/) { my $v = $1; $strip_path = (($v eq '1') or ($v eq 't') or ($v eq 'true') or ($v eq 'y') or ($v eq 'yes')); } } close PREFS; } my $optparsing = GetOptions( "email=s" => \$email, "password=s" => \$pass, "album=s" => \$album, "list=s" => \$file_list, "strip!" => \$strip_path, "root=s" => \$strip_root, "quiet" => \$quiet, "verbose" => \$verbose, "help" => sub { print_help(); }); die "File list not found." if defined $file_list and $file_list ne "-" and not -r $file_list; $strip_path = 1 if (not defined $strip_root and not defined $strip_path); $verbose = 0 if not defined $verbose; $quiet = 0 if not defined $quiet or $verbose; if (defined $file_list) { sub readList { my $fh = shift; foreach my $file (<$fh>) { chomp $file; push @images, $file if -r $file; } } if ($file_list eq "-") { readList(\*STDIN); } else { open LIST, "$file_list"; readList(\*LIST); close LIST; } } foreach my $arg (@ARGV) { push @images, $arg if -r $arg; } die "No email specified.\n" if not defined $email or $email eq ""; die "No password specified.\n" if not defined $pass; die "No image to transfer.\n" if @images < 1 && $album ne "?"; my $ua = LWP::UserAgent->new( cookie_jar => HTTP::Cookies->new()); push @{ $ua->requests_redirectable }, ('POST', 'GET'); # --- WEBALBUM HOME - LOGIN PAGE ----------------------------------------- my $login_req = HTTP::Request->new( GET => $login_url ); print STDERR "Requesting login page\n" if $verbose; my $login_page = $ua->request($login_req); die $login_page->status_line if not $login_page->is_success; my @forms = HTML::Form->parse($login_page->content, $login_req->uri); @forms = grep $_->attr("id") eq "login", @forms; die "No login form in start page found." unless @forms; my $login_form = shift @forms; $login_form->find_input("email")->value($email); $login_form->find_input("password")->value($pass); print "Sending login information\n" if $verbose; # --- USER LOGGED IN - ALBUM SELECTION PAGE ------------------------------ my $albums_page = $ua->request( $login_form->click ); die $albums_page->status_line if not $albums_page->is_success; my $albums_base = $albums_page->base; $albums_base =~ s!\?.*!!; $albums_base =~ s!\#.*!!; if ($albums_base !~ m!/$!) { $albums_base =~ s!/[^/]*$!/!; } $albums_base =~ m!http://[^/]*!; my $albums_host = $MATCH; print STDERR "Parsing albums list.\n" if $verbose; my %albums_status = ( 'state' => '' ); my %albums = (); sub albums_start($$) { my ($tag, $attr) = @_; if ($tag eq "span" && defined $attr->{'class'} && $attr->{'class'} eq "album_title") { $albums_status{'state'} = 'TITLE'; $albums_status{'title'} = ''; } elsif ($tag eq "a") { my $href = $attr->{'href'}; return unless defined $href; if ($href =~ m!^http://!) { } elsif ($href =~ m!^/!) { $href = $albums_host . $href; } else { $href = $albums_base . $href; } $href =~ s![^/]*/\.\.!!; if ($href =~ /javascript:ViewPage\('uploadmode',(\d+)\)/) { my $id = $1; my $title = $albums_status{'title'}; $title =~ s/^\s*//; $title =~ s/\s*$//; my $href="http://webalbum.foto.com/index.php?module=webalbum&page=uploadmode&albumId=$id"; $albums{ $title } = $href; } elsif ($href =~ /page=addalbum/) { $albums{ '__NEW__' } = $href; } } } sub albums_text($) { my ($text) = @_; if ($albums_status{'state'} eq 'TITLE') { $albums_status{'title'} .= (defined($albums_status{'title'}) ? " " : "") . $text; } } sub albums_end($) { my ($tag) = @_; if ($tag eq "span" && $albums_status{'state'} eq 'TITLE') { $albums_status{'state'} = ''; } } my $albums_parser = HTML::Parser->new(); $albums_parser->handler( text => \&albums_text, "text" ); $albums_parser->handler( start => \&albums_start, "tagname, attr" ); $albums_parser->handler( end => \&albums_end, "tagname" ); $albums_parser->unbroken_text(1); $albums_parser->parse( $albums_page->content ); print STDERR "Albums found: '" . join("', '", keys %albums) . "'\n" if $verbose; print "Albums found: '" . join("', '", keys %albums) . "'\n" if not $verbose and $album eq "?"; exit(0) if $album eq "?"; my $album_url = $albums{"$album"}; my $choose_uploader_page; if (not defined $album_url) { # --- NEW ALBUM - CREATE ALBUM PAGE ---------------------------------- my $create_url = $albums{'__NEW__'}; die "No create album URL found.\n" if not defined $create_url; print STDERR "New album '$album'.\n" if $verbose; print "New album '$album'.\n" if not $verbose and not $quiet; my $create_req = HTTP::Request->new( GET => $create_url ); my $create_page = $ua->request($create_req); @forms = HTML::Form->parse($create_page->content, $create_req->uri); @forms = grep $_->attr("id") eq "frm_createalbum", @forms; die "No album creation form in create page found." unless @forms; my $create_form = shift @forms; $create_form->find_input('album_name')->value($album); # --- ALBUM CREATED - UPLOAD METHOD CHOOSER PAGE---------------------- print STDERR "Creating album.\n" if $verbose; $choose_uploader_page = $ua->request( $create_form->click ); die $choose_uploader_page->status_line if not $choose_uploader_page->is_success; } else { # --- EXISTING ALBUM - UPLOAD METHOD CHOOSER PAGE -------------------- print STDERR "Existing album '$album'.\n" if $verbose; print "Existing album '$album'.\n" if not $verbose and not $quiet; my $choose_uploader_req = HTTP::Request->new( GET => $album_url ); print STDERR "Opening album.\n" if $verbose; $choose_uploader_page = $ua->request( $choose_uploader_req ); die $choose_uploader_page->status_line if not $choose_uploader_page->is_success; } # --- UPLOAD METHOD CHOOSER PAGE PARSING --------------------------------- my $http_uploader_url; my $choose_uploader_base = $choose_uploader_page->base; $choose_uploader_base =~ s!\?.*!!; $choose_uploader_base =~ s!\#.*!!; if ($choose_uploader_base !~ m!/$!) { $choose_uploader_base =~ s!/[^/]*$!/!; } $choose_uploader_base =~ m!http://[^/]*!; my $choose_uploader_host = $MATCH; sub choose_uploader_start($$) { my ($tag, $attr) = @_; if ($tag eq "a") { my $href = $attr->{'href'}; return unless defined $href; if ($href =~ m!^http://!) { } elsif ($href =~ m!^/!) { $href = $choose_uploader_host . $href; } else { $href = $choose_uploader_base . $href; } $href =~ s![^/]*/\.\.!!; if ($href =~ /page=htmlmode/) { $http_uploader_url = $href; } } } my $choose_uploader_parser = HTML::Parser->new(); $choose_uploader_parser->handler( start => \&choose_uploader_start, "tagname, attr" ); $choose_uploader_parser->parse( $choose_uploader_page->content ); die "HTTP Uploader url not found in uploader choice page.\n" if not defined $http_uploader_url; # --- HTTP UPLOAD PAGE --------------------------------------------------- print STDERR "Opening uploader.\n" if $verbose; my $http_uploader_req = HTTP::Request->new( GET => $http_uploader_url ); my $http_uploader_page = $ua->request( $http_uploader_req ); die $http_uploader_page->status_line if not $http_uploader_page->is_success; @forms = HTML::Form->parse($http_uploader_page->content, $http_uploader_req->uri); @forms = grep $_->attr("id") eq "uploadForm", @forms; die "No upload form in HTTP uploader page found." unless @forms; my $upload_form = shift @forms; my $imgcount = 0; my $imgtotal = scalar @images; while (@images > 0) { my $image = shift @images; $imgcount++; print STDERR "Transfering ($imgcount/$imgtotal) $image.\n" if $verbose; my $file_input = $upload_form->find_input('image_upload1'); my $filename = $image; if (defined $strip_path and $strip_path != 0) { $filename = basename($image); } else { $filename =~ s!^$strip_root!! if defined $strip_root; } $file_input->file($image); $file_input->filename($filename); my $upload_result_page = $ua->request( $upload_form->click ); die $upload_result_page->status_line if not $upload_result_page->is_success; print STDERR "Transfer of $image as $filename to album $album complete.\n" if $verbose; print "($imgcount/$imgtotal) " if not $quiet and not $verbose; print "$image\n" if not $verbose; }