#!/usr/bin/env ruby

# This script is a front-end to pdftk.  With no options, it
# displays the metadata for the specified PDF files.  Or you
# can use the -a, -t, and -k options to change the
# Author, Title, and Keywords metadata fields.

$VERBOSE = true

require 'getoptlong'

$author = nil
$title = nil
$do_backup = false
$display = true
$strip_xmp = false
$keywords = nil

def usage
  puts "usage: metadata [-a \"author\"] [-t \"title\"] [-k \"keywords\"] [-b] [-x] pdffile"
  puts "  -a  set author"
  puts "  -t  set title"
  puts "  -k  set keywords"
  puts "  -b  make backup file"
  puts "  -x  strip XMP metadata"
  exit 1
end

def parse_args
  opts = GetoptLong.new(
    [ '-a', '--author',   GetoptLong::REQUIRED_ARGUMENT ],
    [ '-t', '--title',    GetoptLong::REQUIRED_ARGUMENT ],
    [ '-k', '--keywords', GetoptLong::REQUIRED_ARGUMENT ],
    [ '-b', '--backup',   GetoptLong::NO_ARGUMENT ],
    [ '-x', '--xmp',      GetoptLong::NO_ARGUMENT ]
  )

  opts.each do |opt, arg|
    case opt
    when '-a'
      $author = arg
      $display = false
    when '-t'
      $title = arg
      $display = false
    when '-k'
      $keywords = arg
      $display = false
    when '-b'
      $do_backup = true
    when '-x'
      $strip_xmp = true
      $display = false
    end
  end

end

def display_metadata(pdf)
  key = nil
  puts "#{pdf}:"
  IO.popen("pdftk '#{pdf}' dump_data", "r") do |pipe|
    pipe.each do |line|
      line.chomp
      if line =~ /^InfoKey: (.*)$/
	key = $1
      elsif line =~ /^InfoValue: (.*)$/
	printf("  %-16s %s\n", key, $1)
      end
    end
  end
end

def change_metadata(old, new)
  puts "Updating metadata"
  IO.popen("pdftk '#{old}' update_info - output #{new}", "w") do |pipe|
    if $author
      pipe.puts("InfoKey: Author")
      pipe.puts("InfoValue: #{$author}")
    end
    if $title
      pipe.puts "InfoKey: Title"
      pipe.puts "InfoValue: #{$title}"
    end
    if $keywords
      pipe.puts "InfoKey: Keywords"
      pipe.puts "InfoValue: #{$keywords}"
    end
  end
end

def copy_without_xmp(old, new)
  puts "Stripping XMP metadata"
  system("pdftk #{old} cat output #{new}\n")
end

def make_backup(pdf)
  if $do_backup
    backup = "#{pdf}.bak"
    File.delete(backup) if File.exist?(backup)
    File.rename(pdf, backup)
    puts "#{pdf} modified, original in #{backup}"
  else
    File.delete(pdf)
    puts "#{pdf} modified, no backup made"
  end
end

def process_files
  if ARGV.length == 0
    puts "no pdf files specified"
    usage
  end

  ARGV.each do |pdf|
    if $display
      display_metadata(pdf)
    else
      # Modify metadata.
      newfile = "#{pdf}.new"
      newfile2 = "#{pdf}.new2"

      if File.exist?(newfile)
	puts "#{newfile} already exists, won't overwrite"
      else
	if $strip_xmp
	  copy_without_xmp(pdf, newfile2)
	  change_metadata(newfile2, newfile)
	  if File.exist?(newfile2)
	    File.delete(newfile2)
	  end
	else
	  change_metadata(pdf, newfile)
	end

	if File.exist?(newfile)
	  make_backup(pdf)
	  File.rename(newfile, pdf)
	else
	  puts "An error occured; #{pdf} is unchanged"
	end
      end
    end
  end
end

def main
  parse_args
  process_files
end

main
