# Mon Aug 28 21:54:36 CDT 2006 wliao
# track listings doesn't seem to work well with
# stream urls, and I don't have an videos

package require tcom

namespace eval itunesm3u {
    ## enumeration variables from itunes
    # itunes com interface holder
    # !!!not the actual items!!!
    # only does the local playlists (not cd, not ipods, etc)
    variable itunes
    array set itunes [list ref "" sources "" playlists "" \
      tracks "" playlist_id "" path ""]

    # array of lists
    # the key is the playlist id,
    # and the value will be a duple: name of playlist, and number of tracks
    # XXX list of dicts?
    variable pl

    # array of lists
    # playlist_id and tr should be synched
    # the key is the track id
    # values will be length of track (seconds), name of track, path (in native form)
    # (match m3u syntax...which is backwards of pls :/)
    variable tr

    # some playlists don't really matter
    # XXX let user add to list like a mask?
    variable non_pl [list]
}


### given a playlist, export to a file for winamp to use

proc itunesm3u::playlist_list {} {
    # populates the internal database (pl)
    # of tracks and track count

    variable itunes
    variable pl

    # now iterate through all the playlists,
    # and gather them into a list
    set playlists_count [$itunes(playlists) Count]

    for {set i 1} {$i <= $playlists_count} {incr i} {
        set p [$itunes(playlists) Item $i]
        set t [$p Tracks]
        set pl($i) [list [$p Name] [$t Count]]
        unset p
        unset t
    }
}

proc itunesm3u::track_list {} {
    # given a playlist id, list the tracks 
    # takes 1 playlist id (as found by [playlist_list])
    # the tracks will be a quad: track id, name of track, length of track, path
    # the ordering will be as defined by playlist: always start at 1
    variable itunes
    variable pl
    variable tr

    set id $itunes(playlist_id)

    if {! [info exist pl($id)]} {
        error "track id $id does not exist"
    }

    set itunes(tracks) [[$itunes(playlists) Item $id] Tracks]
    set count [$itunes(tracks) Count]
    
    for {set i 1} {$i <= $count} {incr i} {
        set t [$itunes(tracks) Item $i]
        set tr($i) [list [$t Duration] [$t Name] [$t Location]]
        unset t
    }
}

proc itunesm3u::export {{form m3u}} {
    variable itunes
    variable tr

    if {[file exist $itunes(path)]} {
        error "file exists alrady at $itunes(path)"
    }

    switch -- $form {
        m3u {
            set output "#EXTM3U"
            foreach l [lsort -integer [array names tr]] {
                append output [format "#EXTINF:%d,%s\n%s\n" \
                  [lindex $tr($l) 0] [lindex $tr($l) 1] [lindex $tr($l) 2]]
            }
        }
        pls {
            set output "\[playlist\]\n"
            foreach l [lsort -integer [array names tr]] {
                append output [format "File%d=%s\n" $l [lindex $tr($l) 2]]
                #append output [format "Title%d=%s\n" $l [lindex $tr($l) 1]]
                #append output [format "Length%d=%d\n" $l [lindex $tr($l) 0]]
            }
            append output [format "NumberOfEntries=%d\nVersion=2" \
              [llength [array names tr]]]
        }
        default {
            error "unknown file format: $form"
        }
    }

    set fh [open $itunes(path) w]
    puts -nonewline $fh $output
    close $fh
}

proc itunesm3u::init {} {
    variable itunes
    variable pl
    variable tr
    
    catch {
        unset itunes(ref)
        unset itunes(playlists)
        unset itunes(sources)
        unset itunes(tracks)
        unset pl
        unset tr
    }

    set itunes(ref) [::tcom::ref createobject "iTunes.Application"]
    # XXX necessary to keep Sources?
    set itunes(sources) [$itunes(ref) Sources]
    set itunes(playlists) [[$itunes(sources) Item 1] Playlists]
    set itunes(tracks) ""
    set itunes(playlist_id) 0

    array set pl [list]
    array set tr [list]

}

proc itunesm3u::usage {} {
    return "list | export id path ? m3u | pls ? | tracks id"
}

proc myperror {msg {ret 1}} {
    puts stderr $msg
    exit $ret
}

proc itunesm3u::main {ac av} {
    variable itunes
    variable pl
    variable tr

    if {$ac == 0} {

        puts stderr [usage]

    } else {

        init

        # loop and process av
        set i 0
        while {$i < $ac} {
            switch -- [lindex $av $i] {
                list {
                    playlist_list
                    foreach p [lsort -integer [array names pl]] {
                        puts "$p - $pl($p)"
                    }
                }
                export {
                    set id [lindex $av [incr i]]
                    set path [lindex $av [incr i]]
                    set format [lindex $av [incr i]]

                    if {[string match "" $format]} {
                        set format m3u
                    } else {
                        set format [lindex $av $i]
                    }

                    if {[string match "" $id] || [string match "" $path]} {
                        myperror "export: need id and path\n[usage]"
                    }

                    set itunes(playlist_id) $id
                    set itunes(path) $path
                    playlist_list
                    track_list
                    puts "writing [lindex $pl($id) 0] to $path"
                    export $format
                }
                tracks {
                    set id [lindex $av [incr i]]
                    if {[string match "" $id]} {
                        myperror "tracks: need id\n[usage]"
                    }
                    playlist_list
                    set itunes(playlist_id) $id
                    puts "list tracks in [lindex $pl($id) 0]"
                    track_list
                    foreach t [lsort -integer [array names tr]] {
                        puts "$t - $tr($t)"
                    }
                }
                default {
                    myperror "unknown playlist command: [usage]"
                }
            }
            incr i
        }
    }
}

if {$tcl_interactive != 1} {
    itunesm3u::main $::argc $::argv
}

