#!/usr/bin/ruby -w

require 'optparse'
require 'ostruct'
require 'xmms'
require 'fileutils'

class Optparse

  PROGRAM = $0.sub(/^.*\//, '')
  USAGE_BANNER = "Usage: #{PROGRAM} [options]"

  def self.parse(args)
    options = OpenStruct.new
    options.append = nil
    options.copy = nil
    options.format = :pls
    options.dos = false
    options.streams = true
    options.strip = nil

    opts = OptionParser.new do |opts|
      opts.banner = USAGE_BANNER

      opts.on("-a", "--append PATH",
	      "Append leading path to file-names.") do |path|
	options.append = path
      end

      opts.on("-c", "--copy PATH",
	      "Copy files while creating playlist.") do |path|
	options.copy = path
      end

      opts.on("-d", "--dos", "Translate file paths to DOS/Windows format.") do
	options.dos = true
      end

      opts.on("-f", "--format FORMAT", [:m3u, :pls],
	      "Format for output: m3u or pls") do |format|
	options.format = format
      end

      opts.on("-n", "--no-streams", "Omit streams from playlist.") do
	options.streams = false
      end

      opts.on("-s", "--strip PATH",
	      "Strip leading path from file-names.") do |path|
	options.strip = path
      end

      opts.on_tail("-h", "--help", "Show this message.") do
	puts opts
	puts <<'EOF'

  Example: xmms2pl -a /music -c /mnt/ihp/music -df m3u -n -s /var/local/audio

  Connect to XMMS and copy files in the dynamic playlist to /mnt/ihp. In the
  process, /var/local/audio will be stripped from the source filename and
  /music will be appended to it, so that /var/local/audio/artist/song.ogg will
  be copied to /mnt/ihp/music/artist/song.ogg. The associated playlist path
  will be \music\artist\song.ogg, thanks to DOS/Windows translation. An M3U
  format playlist will be output, but any streams in the original will be
  omitted from it.

  Be aware that, if you're creating a playlist for a device like an iRiver
  jukebox, you'll need to send the output through a program like unix2dos, in
  order to get DOS/Windows-style line endings.
EOF
	exit
      end
    end

    begin
      opts.parse!(args)
      options
    rescue OptionParser::InvalidOption
      puts opts
      exit 1
    end

  end
end

options = Optparse.parse(ARGV)

# Connect to XMMS and grab play-list
#
remote = Xmms::Remote.new
playlist = remote.playlist

# Strip streams if desired (streams have a time of -1)
#
playlist.delete_if { |tune| tune[2] == -1 } if options.copy ||
					       ! options.streams
# Display file header
#
if options.format == :m3u
  puts "#EXTM3U"
else
  printf("[playlist]\nNumberOfEntries=%d\n", playlist.size)
end

# Iterate over play-list
#
count = 0
playlist.each do |tune|
  name, path, time = tune

  file = path.dup
  base = File.basename(file)

  # Strip leading path if desired
  #
  path.sub!(/^#{options.strip}/, '') unless options.strip.nil?

  src_dir = File.dirname(path)

  if options.copy
    dst_dir = File.join(options.copy, src_dir[1..-1])
    FileUtils.mkdir_p dst_dir unless File.exist? dst_dir
    FileUtils.cp file, dst_dir unless File.exist? File.join(dst_dir, base)
  end

  # Append leading path if desired
  #
  path = options.append + path unless options.append.nil?

  # Translate file-names if desired
  #
  path.tr!('/', '\\') if options.dos

  if options.format == :m3u
    printf("#EXTINF:%d,%s\n%s\n", time / 1000, name, path)
  else
    printf("File%d=%s\n", count += 1, path)
  end

end
