#!/bin/sh # -*- tcl -*- \ exec wish8.4 "$0" "$@" ### Copyright (C) 2003 Robert Fenk # # Author: Robert Fenk # X-URL: http://www.robf.de/Hacking/TclTk.html # X-RCS: $Id: mp3man.tk,v 1.8 2004/05/24 15:27:03 fenk Exp $ # # The currently valid contact email-address can be found on my homepage, but I # will not make it available anywhere else. # # $Log: mp3man.tk,v $ # Revision 1.8 2004/05/24 15:27:03 fenk # - Added support for an external player (xmms) # - More progress information # - better help # - usability enhancements # # Files: xtools/mp3man.tk # # Revision 1.7 2004/01/27 11:51:11 fenk # - enhanced progress report # - use wish8.4 # - also allow navigation on the player, by selecting dirs # # Revision 1.6 2003/08/22 17:16:12 fenk # - Fixed some docs # - Added RELOAD # # Files: mp3man.tk # # Revision 1.5 2003/08/08 22:00:22 fenk # - enhanced config dialog (editing the file is not necessary any more) # - removed all mtool code (use the right kernel instead) # - use id3.tcl instead of external id3tool (thus also on Win$ tags are seen) # - a note on fixing reorg problems # # Revision 1.4 2003/07/14 22:50:24 fenk # - Added a configuration dialog. # - MS-Windows: Docs and modified some code parts, i.e. who cares for mounting? # # Revision 1.3 2003/07/13 21:23:57 fenk # Fixed proc name for move. # # Revision 1.2 2003/07/07 22:39:42 fenk # Added a sorting button and predefined osrt orders. # # Revision 1.1 2003/07/07 09:22:55 fenk # First Version of this nifty tool. # # ### Comments: The idea of mp3man.tk is stolen from its windows equivalent # which can be found at http://oliver-frietsch.de/reorganize/ (thanks to # Oliver for pointing me to the trick), but I do not care for Windows at all # in order to get this running, so I made this little Tcl/TK script which is # doing even somemore things for you, i.e. it eases coping mp3s to the player, # deleting files from the player and reorganizing the play order on the # player. # # To run it you need Tcl/Tk version >= 8.3 and optionally id3.tcl! When first # starting mp3man a config file in the users home directory is created. The # configure dialog allows you to adjust the paths to your (mounted) player and # MP3 library. # # I have the AIPTEK MP3-310, but it is equivalents, e.g. Jamba! U-100, George # and other players should also work well. # ### Linux # You need atleast kernel version >= 2.4.21 (in my case) in order to mount the # player properly, otherwise tracks written to the player get lost. The # mtools are a workaround to this, but I dropped mp3man-support for them. # # For mounting the player add something like the following to your /etc/fstab # /dev/sda1 /mnt/mp3 vfat dirsync,sync,user,rw,noauto,noexec 0 0 # and do something like: # modprobe usbcore # modprobe usb-uhci # modprobe usb-storage # mount /mnt/mp3 # where /dev/sda1 might be different if you have other SCSI devices, i.e. it # might be /dev/sdb1 ... # # When using the mtools you probably want to have something like the following # in your ~/.mtoolsrc: # drive m: # file="/dev/sda1" # sync # filter # mtools_skip_check=1 # ### MS-Windows # Get the Tcl/Tk windows binaries and install them on your system. # Then create a shortcut to "wish.exe" and add the full path to mp3man.tk, # e.g. something like the following # "C:\Programs\TclTk-8.4.1\bin\wish.exe C:\tmp\mp3man.tk" # This should enable you to start mp3man with a simple double click on the # shortcut. # ### How does the reorganizing work? # Reorganization is nothing but moving files on the player. All files get # moved t a new subdir and then get moved back to the root dir of the player # in the desired order. YES there are cases where this does NOT work! In # fact the play order is determined by the order as MP3s will occur in the # directory data structure of the FAT. If you notice anomalies, then move all # files /directories from the player to your disk, then it should be empty!!! # Now first move back the "settings.dat" file and then the "voice" directory. # ### ToDo # - Add more documentation on bindings and the like # ### License # This code is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 1, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ############################################################################## proc formatTags {file {format {listformat}}} { global files upvar $format listformat set s $listformat upvar count count while {[regexp -indices {%([0-9]*)([%a-z])} $s range width tag]} { switch -exact -- [eval string range {$s} $tag] { c {set t "count"} t {set t "Song Title"} a {set t "Artist"} l {set t "Album"} y {set t "Year"} n {set t "Track"} g {set t "Genre"} f {set t "file"} r {set t "random"; set files($file,random) "[expr rand()]-$file"} } # parray files if {[info exists files($file,$t)]} { set s [eval string replace {$s} $range {[format "%[eval string range {$s} $width]s" $files($file,$t)]}] } else { set s [eval string replace {$s} $range] } } return $s } ############################################################################## # wrappers for MTool resp. direct access proc mmd {dir} { file mkdir $dir } proc mdir {pattern} { return [glob -nocomplain $pattern] } proc mrd {dir} { file delete $dir } proc mdel {files} { eval file delete -force $files } proc mmove {from to} { file rename $from $to } proc mcopy {from to} { message [format "Transfering .../%s/%s" \ [file tail [file dirname $from]] \ [file tail $from]] # we could do this easier with "file copy" but then we would no have any # progress to be displayed. set in [open $from "r"] set out [open [file join $to [file tail $from]] "w"] fconfigure $in -translation {binary binary} fconfigure $out -translation {binary binary} set size [file size $from] set now 0 global message set junksize 100000 set oldp {} while {![eof $in]} { set buf [read $in $junksize] puts -nonewline $out $buf incr now $junksize set newp [expr int(100.0 * $now / $size)] if {$oldp != $newp} { set oldp $newp progress [format "Transfered \[%2d%%\]" $newp] } } close $out close $in clearProgress } ############################################################################### # This performs the actual resorting proc Player_save {} { global tmpdir files tracks changes mmd $tmpdir foreach t $tracks { if {![info exists files($t)]} {continue} set f $files($t) mmove $f $tmpdir/$f puts "mmove $f $tmpdir/$f" } set count 0 foreach t $tracks { if {![info exists files($t)]} {continue} set f $files($t) set t $f regsub {"^plp\[0-9\]+-"} $t "" t set t [format "plp%03d-$f" $count] mmove $tmpdir/$f $t puts "mmove $tmpdir/$f $t" incr count } # keep the dir to maintain its position # mrd $tmpdir Player_updateView set changes "" } proc Player_move {dir} { global tracks changes set ts $tracks if {$dir < 0} { set pos [lsort -integer -increasing [.tracks.list curselection]] } else { set pos [lsort -integer -decreasing [.tracks.list curselection]] } set end [llength $tracks] set first 1 foreach t $pos { set p [expr $t + $dir] if {$p < 0 || $p >= $end} break if {$first} { .tracks.list selection clear 0 end set first 0 } set v [lindex $ts $t] set ts [lreplace $ts $t $t] set ts [linsert $ts $p $v] .tracks.list selection set $p set changes "There are unsaved changes!" } catch { .tracks.list see $p .tracks.list activate $p } set tracks $ts } proc Player_delete {} { global tracks files set ts $tracks set pos [lsort -integer -decreasing [.tracks.list curselection]] if {[llength $pos] == 0} return foreach t $pos { if {![file isdirectory [lindex $tracks $t]]} { lappend dfiles $files([lindex $tracks $t]) set ts [lreplace $ts $t $t] } } set tracks $ts if {[info exists dfiles]} { mdel $dfiles } } proc Player_reload {} { global mp3lib doreload reload .tracks.list selection set 0 end update Player_delete set basedir $mp3lib set doreload 1 # make stop button .reload configure -text "Stop Reload" -command { .reload configure -text "Stoping Reload" set doreload 0 update } .reload configure -foreground red ################# catch { for {set i 0} {$doreload && $i < $reload} {incr i} { set mp3lib $basedir while {$doreload} { Lib_updateView update set pos [expr 1+ int(rand() * ([.mp3lib.list size] - 1))] .mp3lib.list selection clear 0 end .mp3lib.list selection set $pos .mp3lib.list see $pos set item [file join $mp3lib [.mp3lib.list get $pos]] if {[file isdirectory $item]} { Lib_selectItem $pos } else { if {[file isfile $item] && [file extension $item] == ".mp3"} { Lib_addItems break } else { incr i -1 break } } } } } errmsg if {[info exists errmsg]} {puts $errmsg} set mp3lib $basedir Lib_updateView set doreload 0 .reload configure -text "Reload" -command {Player_reload} .reload configure -foreground black } proc Player_sort {by} { global tracks files foreach t $tracks { if {![info exists files($t)]} {continue} set neworder([formatTags $files($t) by]-$files($t)) $t } set tracks {../} global sortorder foreach t [lsort -dict $sortorder [array names neworder]] { lappend tracks $neworder($t) } global changes set changes "There are unsaved changes!" } proc Player_updateView {} { global mp3dir tracks files id3lib if {[catch {cd $mp3dir} errmsg]} { set answer [tk_dialog .error "$errmsg" \ "ERROR: $errmsg" error 0 "Ignore" "Quit"] if {$answer == 1} exit } set count 0 set width 0 set tracks {../} foreach d [lsort -dict [mdir *]] { if {[file isdirectory $d]} { lappend tracks "$d/" } } catch {unset files} set files(list) [mdir *.mp3] foreach f $files(list) { set files($f,file) $f incr count if {$id3lib && [string tolower [file extension $f]] == ".mp3"} { set tags [id3Tag::id3V2Get $f] if {$tags == ""} { set tags [id3Tag::id3V1Get $f] } foreach {t d v} $tags { switch -- $t { TIT2 {set t "Song Title"} TPE1 {set t "Artist"} TALB {set t "Album"} TYER {set t "Year"} TRCK {set t "Track"} TCON {set t "Genre"} default {set t ""} } if {$t != ""} { # puts "$f<$t=$v>" set files($f,$t) $v } } set files($f,count) $count global listformat set v [formatTags $f] if {[string length $v] > $width} { set width [string length $v] } } else { continue set v [format "%03d %s" $count [file tail $f]] } lappend tracks $v set files($v) $f } .tracks.list configure -height $count -width $width catch { global message mp3dir freemem set df [exec df -h $mp3dir] set df [lindex [split $df "\n"] 1] set freemem [lindex $df 3] message "[lindex $df 1] total player-memory, [lindex $df 2] ([lindex $df 4]) used and [lindex $df 3] free!" } global mp3dirsel if {[info exists mp3dirsel($mp3dir)]} { .tracks.list activate $mp3dirsel($mp3dir) .tracks.list see $mp3dirsel($mp3dir) } } proc Player_selectItem {pos} { set s [.tracks.list get $pos] global mp3lib mp3dir mp3dirsel set newdir [file normalize [file join $mp3dir $s]] if {[file isdirectory $newdir]} { set mp3dirsel($mp3dir) [.tracks.list index active] set mp3dir $newdir Player_updateView return -code break } } proc Lib_updateView {} { global mp3lib mp3files mp3libsel set mp3files {../} foreach f [lsort -dict [glob -directory $mp3lib -nocomplain *]] { if {[file isdirectory $f]} { lappend mp3files "[file tail $f]/" } elseif {[file extension $f] == ".mp3"} { lappend mp3files [file tail $f] } } if {[info exists mp3libsel($mp3lib)]} { .mp3lib.list activate $mp3libsel($mp3lib) .mp3lib.list see $mp3libsel($mp3lib) } } proc Lib_selectItem {pos} { set s [.mp3lib.list get $pos] global mp3lib mp3dir mp3libsel set mp3libsel($mp3lib) [.mp3lib.list index active] if {$s == ".."} { set mp3lib [file normalize [file dirname $mp3lib]] Lib_updateView return -code break } set p [file join $mp3lib $s] if {[file isdirectory $p]} { set mp3lib [file normalize $p] Lib_updateView return -code break } else { global message foreach m [.mp3lib.list curselection] { set s [.mp3lib.list get $m] set p [file join $mp3lib $s] mcopy $p $mp3dir } Player_updateView } } proc Lib_addItems {{mp3s {}}} { global mp3lib mp3dir if {$mp3s == ""} { set sel [.mp3lib.list curselection] foreach s $sel { lappend mp3s [file join $mp3lib [.mp3lib.list get $s]] } } global message foreach m $mp3s { if {[file tail $m] != ".." && [file isdirectory $m]} { Lib_addItems [lsort -dict [glob -directory $m *]] continue } mcopy $m $mp3dir } Player_updateView } ############################################################################### set player {} proc player {action {files {}}} { global mp3player player foreach p $player { catch {exec kill -9 $p} } set player {} switch $action { start { set player [eval exec $mp3player $files &] message "Playing with $mp3player \[pid=$player\]" foreach f $files { message "\t$f" } } stop { } } } proc Lib_player {} { global mp3lib if {[catch { foreach i [.mp3lib.list curselection] { lappend pl [file join $mp3lib [.mp3lib.list get $i]] } player start $pl } err]} { message $err error } } proc Player_player {} { global mp3dir files if {[catch { foreach i [.tracks.list curselection] { lappend pl [file join $mp3dir $files([.tracks.list get $i])] } player start $pl } err]} { message $err error } } ############################################################################### set config "~/.mp3manrc" set configend 0 set configvarslist {} foreach {v d} { {listformat} " LISTFORMAT will be used to display the tracks on the player. It is a string containing a set of the following formatting characters: t = Title, a = Artist, l = aLbum, y = Year, g = Genre n = trackNumber, c = count, f = filename, R = Random number. Width and padding might be specified as for the format or printf commands. " {sortbyalist} " SORTBYALIST is a list of sort criteria, where the first one is the default order when clicking on the Sort-Button. The list items are pairs of labels and LISTFORMAT expressions and files will be sorted according to their lexical order with respect to their label defined by the LISTFORMAT. " {sortorder} " SORTORDER contains additional options for the sorting process, e.g. decreasing or increasing or another option of lsort. Common options, i.e. increasing or decreasing order can be chosen by right clicking on the Sort-button! " {mp3dir} " MP3DIR is the path to the mount point of the player. On startup and quitting we will mount and unmount the device attached to this path in the /etc/fstab! If you require a special actions for mounting and unmounting, modify the MOUNT and UMOUNT variables! " {mountpoint} " MOUNTPOINT is the path to the mount point as given to mount and umount. " {mount} " MOUNT is the command executed to mount your player on MP3DIR. You might write a shell script loading USB modules and the like if a simple mount operation is not sufficient. " {umount} " UMOUNT is the command executed to unmount your player. NEVER remove the player if it has not been unmounted properly!!! " {mp3lib} " MP3LIB is the path to a directory containing your collection of MP3s on your hard-disk. " {tmpdir} " TMPDIR is the directory on the player which is created during reorganization, i.e. when rearranging the play-order. " {reload} " RELOAD is the maximum number of files that are reloaded. " {mp3player} " MP3PLAYER is the program used to play MP3s. " } { set configvardocs($v) $d lappend configvarslist $v } proc configVarDoc {var} { global configvardocs foreach l [split $configvardocs($var) "\n"] { lappend docs "\# $l" } upvar \#0 $var v puts $var lappend docs "set $var {$v}" join $docs "\n" } proc configEditDir {var} { upvar $var dir set newdir [tk_chooseDirectory -initialdir $dir -parent .config \ -title "Select a directory for $var!" -mustexist 1] if {$newdir != ""} { set dir $newdir } } proc configEditCmd {var} { upvar $var cmd set newcmd [tk_getOpenFile -initialfile $cmd -parent .config \ -initialdir [file dirname $cmd] \ -title "Select a program for ${var}ing!"] if {$newcmd != ""} { set cmd $newcmd } } proc configEdit {{update 0} {x 0} {y 0}} { global configend configvardocs configvarslist if {$configend == -1} { wm deiconify .config return } set configend -1 catch {destroy .config} toplevel .config wm title .config "mp3man configuration" wm geometry .config +$x+$y foreach c $configvarslist { frame .config.$c label .config.$c.label -text "$c:" -width 10 -anchor e bind .config.$c.label ".config.missingdocs configure -text {[string trim $configvardocs($c)]}" entry .config.$c.entry -textvariable $c -width 40 pack .config.$c.label -side left pack .config.$c.entry -side left -fill x -expand 1 pack .config.$c -fill x switch -- $c { "mp3lib" - "mountpoint" - "mp3dir" { button .config.$c.choose -text "Choose" -command "configEditDir $c" pack .config.$c.choose -side left } "mount" - "umount" { button .config.$c.choose -text "Choose" -command "configEditCmd $c" pack .config.$c.choose -side left } } } label .config.missingdocs -text "To get the documentation for a variable click on its name!" pack .config.missingdocs -fill x -expand 1 -pady 0 frame .config.buttons -border 4 button .config.buttons.close -text "Save and Close" -command { configSave destroy .config set configend 1 } button .config.buttons.cancel -text "Cancel" -command { destroy .config set configend 0 } pack .config.buttons.close .config.buttons.cancel -side left -padx 10 pack .config.buttons tkwait variable configend if {$update} {Player_updateView} } proc configSave {} { global config configvarslist set fd [open $config "w"] puts $fd "# This is the config file of mp3man.tk\n" foreach v $configvarslist { puts $fd [configVarDoc $v] } close $fd } proc configLoad {} { global config uplevel \#0 source $config } proc clearProgress {} { foreach {s e} [.message.text tag ranges "progress"] { .message.text delete $s $e } } proc message {text {tags {}}} { clearProgress if {$tags != ""} { .message.text insert end "$text\n" $tags } else { .message.text insert end "$text\n" } .message.text see end } proc progress {text} { clearProgress .message.text insert end "$text\n" "progress" .message.text see end update } proc listboxSelect {W x y} { if {[winfo exists $W]} { if {[info command tk::ListboxBeginSelect] != ""} { tk::ListboxBeginSelect $W [$W index @$x,$y] } else { tkListboxBeginSelect $W [$W index @$x,$y] } } } proc help {} { destroy .helper toplevel .helper global version wm title .helper "Help - mp3man $version" text .helper.text -wrap word -height 26 -width 80 \ -yscrollcommand {.helper.scrollbar set} .helper.text insert end \ {The left window is your disk and the right side your player. Generic bindings are: select a range select all quit save and quit update the view save changes reload player

start mp3player on current track focus other side goto parent directory Right side bindings are: select a track move selcted tracks drag the selected tracks moves tracks delete selected files Save: Save changes in sorting order. Sort: After making changes to the sort order you need to save them, this will move the files around and prepend a prefix to them ensuring the correct order. Right click on the sort button to change the sorting preferences. Reload: Deletes all MP3s from your player and copies randomly selected ones from your MP3LIB and subdirs. The right side allows you to copy mp3 to your player, bindings are: / copy file/directory to player } scrollbar .helper.scrollbar -command {.helper.text yview} pack .helper.scrollbar -side right -expand 1 -fill y pack .helper.text -fill both -expand 1 bind .helper.text {destroy %W} } proc init {} { global init if {[info exists init]} return set init 1 global version set version {$Revision: 1.8 $} regexp {[0-9]+\.([0-9]+)} $version junk version set version "v$version (c) 2003-2004 Robert Widhopf-Fenk" wm title . "mp3man $version" wm withdraw . # source your source again in order to rapidly prototype ... bind . { source $argv0 puts "Resourced!!!" } set count 0 set width 0 global config listformat sortbyalist sortorder mp3dir mount umount mp3lib \ mountpoint tmpdir drive id3lib reload mp3player set listformat {%03c %02n %a - %l: %t} set sortbyalist {{"Album/Track" "%l/%n"} {"Artist/Album/Track" "%a/%l/%n"} {"Album/Artist/Album/Track" "%l/%a/%l/%n"}} set sortorder "-increasing" set mp3dir "/mnt/mp3" set mp3lib "~/Music" set tmpdir "reorg" set reload 25 set mountpoint $mp3dir set mp3player "xmms -p -e" if {![file exists $config]} { global tcl_platform env if {$tcl_platform(platform) == "windows"} { set mount "" set umount "" if {![info exists env(HOME)] && [info exists env(USERPROFILE)]} { set env(HOME) $env(USERPROFILE) } } else { set mount "/bin/mount" set umount "/bin/umount" } if {!$id3lib} { global id3tcl tk_dialog .note "mp3man Notice" "Consider installing the id3.tcl library (from snackAmp) in order to view tag information!\n Unfortunately it was not found at $id3tcl.\n Download it from the same site where you found mp3man.tcl and save it in the same directory as mp3man.tcl!" warning 0 OK } ########################################################################### configEdit ########################################################################### } else { configLoad } if {$id3lib == 0 && ![regexp {%f} $listformat]} { set listformat "%03c %f" tk_dialog .note "mp3man Notice" "The listformat has been reset to <$listformat> due to missing id3 support! Please get id3.tcl and save it in the same directory as mp3man.tk!" warning 0 OK } while {$mount != "" && [catch {eval exec $mount $mountpoint} errmsg]} { set answer [tk_dialog .error "mp3man Error during mounting" \ "ERROR: $errmsg" error 0 "Mount Again" "Ignore" "Quit"] if {$answer == 1} break if {$answer == 2} exit } if {[catch {cd $mp3dir} errmsg]} { set answer [tk_dialog .error "$errmsg" \ "ERROR: $errmsg" error 0 "Ignore" "Quit"] if {$answer == 1} exit } #---------------------------------------------------------------------------- frame .buttons button .quit -text "Quit" -command quit button .saveexit -text "Save & Quit" -command {Player_save; quit} button .save -text "Save" -command Player_save button .sort -text "Sort" -command {Player_sort $sortby} # button .update -text "Update" -command Player_updateView button .delete -text "Delete" -command Player_delete button .reload -text "Reload" -command {Player_reload} button .configure -text "Configuration" -command { configEdit 1 [winfo rootx .] [winfo rooty .] } button .help -text "Help" -command {help} label .changes -textvariable changes -foreground red pack .quit .saveexit .save .sort .delete .reload \ -side left -in .buttons pack .changes .configure .help -side right -fill x -in .buttons pack .buttons -fill x global sortby sortbyalist menu .sortbymenu -tearoff 1 set sortby [lindex [lindex $sortbyalist 0] 1] .sortbymenu add radiobutton -variable sortby -label "Shuffle" -value "%r" .sortbymenu add separator .sortbymenu add checkbutton -variable sortorder -label Reverse \ -offvalue {-increasing} -onvalue {-decreasing} foreach {ls} $sortbyalist { foreach {l s} $ls {} .sortbymenu add radiobutton -variable sortby -label $l -value $s } bind .sort {.sortbymenu post %X %Y; focus .sortbymenu} #---------------------------------------------------------------------------- if {[info command "panedwindow"] != ""} { panedwindow .vpane -orient vertical panedwindow .hpane -orient horizontal } #---------------------------------------------------------------------------- set mp3files ".." frame .mp3lib -borderwidth 4 -relief ridge frame .mp3lib.cwd label .mp3lib.cwd.label -text "mp3lib=" label .mp3lib.cwd.mp3lib -textvariable mp3lib pack .mp3lib.cwd.label .mp3lib.cwd.mp3lib -side left listbox .mp3lib.list -listvariable mp3files -selectmode extended \ -highlightthickness 3 -yscrollcommand {.mp3lib.scrollbar set} \ -width 40 -height 30 scrollbar .mp3lib.scrollbar -command {.mp3lib.list yview} pack .mp3lib.cwd -side top -fill x pack .mp3lib.scrollbar -side right -fill y pack .mp3lib.list -expand 1 -fill both bind .mp3lib.list {focus %W; Lib_selectItem @%x,%y} bind .mp3lib.list {focus %W; listboxSelect %W %x %y Lib_addItems } bind .mp3lib.list {Lib_selectItem active} bind .mp3lib.list {Lib_selectItem 0} bind .mp3lib.list {Lib_addItems} bind .mp3lib.list {.mp3lib.list selection set 1 end} bind .mp3lib.list {focus .tracks.list;break} bind .mp3lib.list

{Lib_player; break} bind .mp3lib.list {Lib_player; break} #---------------------------------------------------------------------------- frame .tracks -borderwidth 4 -relief ridge frame .tracks.label label .tracks.label.label -text "mp3dir=" label .tracks.label.mp3dir -textvariable mp3dir button .tracks.label.mkdir -text mkdir -command { set newdir [tk_getSaveFile -initialdir $mp3dir \ -title "Select a new directory fro creation!"] file mkdir $newdir } pack .tracks.label.label .tracks.label.mp3dir -side left listbox .tracks.list -selectmode extended -listvariable tracks \ -highlightthickness 3 -yscrollcommand {.tracks.scrollbar set} \ -width 50 -height 30 scrollbar .tracks.scrollbar -command {.tracks.list yview} pack .tracks.label -side top -fill x pack .tracks.scrollbar -side right -fill y pack .tracks.list -expand 1 -fill both #---------------------------------------------------------------------------- frame .message text .message.text -yscrollcommand {.message.scrollbar set} -height 5 \ -wrap word scrollbar .message.scrollbar -command {.message.text yview} pack .message.scrollbar -fill y -side right pack .message.text -fill both -expand 1 #---------------------------------------------------------------------------- if {[info command "panedwindow"] != ""} { # update .hpane add .mp3lib .tracks -width 300 .vpane add .hpane .message # pack .hpane -expand 1 -fill both pack .vpane -expand 1 -fill both # pack .message -fill x -side bottom } else { pack .message -fill x -side bottom pack .mp3lib -side left -expand 1 -fill both pack .tracks -expand 1 -fill both -side left } global tcl_platform if {$tcl_platform(platform) == "windows"} { bind .tracks.list { if {%D < 0} {Player_move +1} else {Player_move -1} } } else { bind .tracks.list {Player_move -1} bind .tracks.list {Player_move +1} } bind .tracks.list {quit} bind .tracks.list {Player_save; quit} bind .tracks.list {Player_updateView} bind .tracks.list {Player_reload} bind .tracks.list {Player_sort} bind .tracks.list {Player_save} bind .tracks.list {Player_delete} bind .tracks.list {Player_selectItem 0} bind .tracks.list {Player_move -1; break} bind .tracks.list {Player_move +1; break} bind .tracks.list {focus .mp3lib.list;break} bind .tracks.list {focus %W; Player_selectItem @%x,%y} bind .tracks.list {Player_selectItem active} bind .tracks.list {.tracks.list selection set 1 end} bind .tracks.list

{Player_player; break} bind .tracks.list {Player_player; break} bind .tracks.list { focus %W; set dragstart [.tracks.list index @%x,%y] set draglist [array get files] } bind .tracks.list { set dragnow [.tracks.list index @%x,%y] if {$dragnow == $dragstart && %y < 0} { .tracks.list yview scroll -1 u set dragnow [.tracks.list index @%x,%y] } else { array get files $draglist Player_move [expr $dragnow - $dragstart] .tracks.list see $dragnow } set dragstart $dragnow } #---------------------------------------------------------------------------- Player_updateView Lib_updateView focus .tracks.list wm deiconify . message "To the left you may select files for addition and\nto the right you can organize the files on your player" } proc quit {} { global mp3dir umount mountpoint env cd $env(HOME) if {$umount != "" && [catch {eval exec $umount $mountpoint} errmsg]} { tk_dialog .error "mp3man Error during unmounting" "$errmsg" error 0 OK } player stop exit } ############################################################################### # now try to load id3.tcl from snackAmp and hackhackhackhackhackhackhackhack # to get the loading work as expected namespace eval snack { proc sound {args} { } } catch { while {1} { set argv0 [file readlink $argv0] } } set id3tcl [file join [file dirname $argv0] "id3.tcl"] if {[file exist $id3tcl]} { source $id3tcl set id3lib 1 } { set id3lib 0 } ############################################################################### init