A gui for youtube-dl, written in TCL/TK 8.6
requires:
Tcl/Tk 8.6 http://tcl.tk/software/tcltk/
also requires tclthread. using your package manager, i'd search:
pkg search tcl | grep thread
or
apt search tcl | grep thread
depending upon your system. to install yourself you compile and install Tcl using link above. it is included there.
youtube-dl https://github.com/ytdl-org/youtube-dl is also usually available on linux systems (but I had trouble with it there) .. i use freeBSD and it works here. you might need to compile it yourself to get a working copy on linux.
it works really well for me, when I want to play around with it.
using XFCE, and using 'focus follows mouse' means I can double click a youtube link in the title bar (highlighting it) and then use the roller-wheel click in the 'Enter YouTube address here' bar.. and move the mouse away.. and it will begin downloading.
after you watch it you can use the red Xto delete the file.
unfortunately the Play button does not work. i appear to be giving xdg-open the proper link, but it doesn't want to open it to play even tho the exact same line work in the command line. perhaps it works in linux? only used it in freeBSD
running this project requires tcl/tk 8.6 and youtube-dl.
Here is the project link : youtube-dl-gui
a fun little offshoot of this project was the desire to present this in a single file format.
it reads in a source file that is used to run the program and then reads all the source files listed within and adds them to a new file that holds all the combined files. And it had the added bonus of making it simple to remove all the comments from the single file, as well as lines with no spaces. If I was feeling truly efficient I could clean up the spaces all around to provide the smallest download possible, but that was not the goal.
this single file also had the added benefit of providing a stable version during periods of development.
I also have a love of simplicity, so the fact I write this in less than 50 lines of code made me very happy. it was even smaller but I had to start adding features like including a header (so you can launch it from the command line) and making it executable. I call it makeOneFile.tcl
#!/usr/bin/tclsh
# Marc Bookmeyer 2022
set sourceFile youtube-dl-gui.tcl
set destFile run_ytDLgui.tcl
proc openFile { path } {
set fl [open $path]
set data [split [read $fl] "\n"]
close $fl
return $data
}
proc addSource { destFl path } {
foreach line [openFile $path] {
if { [string range $line 0 6] == "source " } {
puts $destFl "###START### Source:[string range $line 7 end] ###START###"
addSource $destFl [string range $line 7 end]
puts $destFl "###END### Source:[string range $line 7 end] ###END###"
} else {
if { $line == "" || [string range [string trim $line] 0 0] == "#" } {
#comments and spaces
#puts $destFl $line
} else {
puts $destFl $line
}
}
}
}
proc addHeader { destFl path } {
set sFile [openFile $path]
puts $destFl [lindex $sFile 0]
puts $destFl [lindex $sFile 1]
}
set destFl [open $destFile w]
addHeader $destFl $sourceFile
addSource $destFl $sourceFile
close $destFl
exec chmod u+x $destFile
Using this little script above I was able to create the script below from the multiple sources. Which also means I now have a nice copy here on the block chain. So what follows is nearly 800 lines of code comprising the entire project.
#!/usr/bin/tclsh
# Marc Bookmeyer 2022
###START### Source:ytDownloader.tcl ###START###
oo::class create ytDownloader {
variable link pipe extHandler ytCmd
constructor { _link _extHandler } {
set link $_link
set extHandler $_extHandler
set ytCmd "/usr/local/bin/youtube-dl"
}
method download {} {
puts "ytDownloader>>download>>$ytCmd $link"
set pipe [open |[concat $ytCmd [list $link 2>@stderr]] r]
fileevent $pipe readable [list [self] ytReadable]
}
method ytReadable {} {
if {![eof $pipe]} {
if {[gets $pipe line] >= 0 } {
if { $extHandler != "" } {
{*}$extHandler $line
}
}
} else {
catch {close $pipe}
puts "ytDownloader pipe has closed."
if { $extHandler != "" } {
{*}$extHandler "EOF"
}
}
}
}
###END### Source:ytDownloader.tcl ###END###
###START### Source:ytDownloader-thread.tcl ###START###
package require Thread
oo::class create ytDownloader_thread {
variable ytThread ytLink ytDownloader ytParse parseResults q loopDone n
constructor { _n sourceDir downloadDir } {
set n $_n
set ytThread [thread::create]
cd $sourceDir
my initiateThread $sourceDir $downloadDir
tsv::set ytDownloader_thread$n lineReady no
}
method initiateThread {sourceDir downloadDir} {
puts "initiateThread>>sourceDir: $sourceDir downloadDir: $downloadDir"
thread::send -async $ytThread [list set sourceDir $sourceDir]
thread::send -async $ytThread [list set downloadDir $downloadDir]
thread::send -async $ytThread [list set n $n]
thread::send -async $ytThread {
cd $sourceDir
source ytDownloader.tcl
oo::class create ytDownloader_inThread {
variable q ytParse qNum n ytDownloader
constructor { } {
set q ""
set qNum 0
set n $::n
tsv::set ytDownloader_thread$n lineReady no
}
method downloadLink { link } {
set ytDownloader [ytDownloader new $link [list [self] ytResultsHandler]]
$ytDownloader download
}
method ytResultsHandler { line } {
if { $line != "" } {
lappend q $line
incr qNum
tsv::set ytDownloader_thread$n lineReady yes
}
}
method lineReady {} {
if { $qNum > 0 } {
return true
} else {
return false
}
}
method linePopped {} {
incr qNum -1
}
method linePop {} {
incr qNum -1
set returnVal [lindex $q 0]
set q [lrange $q 1 end]
return $returnVal
}
method destroyDownloader {} {
$ytDownloader destroy
}
}
proc tDownloadLink { link } {
cd $::downloadDir
set ::ytHandle [ytDownloader_inThread new]
$::ytHandle downloadLink $link
}
proc lineReady {} {
$::ytHandle lineReady
}
proc linePopped {} {
$::ytHandle linePopped
}
proc linePop {} {
$::ytHandle linePop
}
proc exitThread {} {
$::ytHandle destroyDownloader
$::ytHandle destroy
}
}
}
method downloadLink { link } {
thread::send $ytThread [list tDownloadLink $link]
}
method popResults {} {
puts "popResults>>[thread::send $ytThread lineReady]"
if { [thread::send $ytThread lineReady] } {
return [thread::send $ytThread linePop]
} else {
return ""
}
}
method exitThread {} {
thread::send $ytThread exitThread
thread::release $ytThread
}
}
###END### Source:ytDownloader-thread.tcl ###END###
###START### Source:ytProgressBars.tcl ###START###
###START### Source:progressBar.tcl ###START###
package require Tk
oo::class create progressBar {
variable w pt bar0 bar1 wd ht bg fg tl mySeed seed c percent
constructor { { _w "" } { _wd 400 } { _ht 25 } { _bg lightblue } { _fg orange } } {
set ns [info object namespace [self class]]
my eval [list namespace upvar $ns seed seed]
if {![info exists seed]} {
set seed 0
} else {
incr seed
}
set mySeed $seed
set w $_w
set wd $_wd
set ht $_ht
set bg $_bg
set fg $_fg
set tl ""
set c "$w.c$mySeed"
canvas $c \
-bg $bg \
-width $wd \
-height $ht
my drawbar
my drawtext
set pt [$c create text [expr { $wd / 2 }] [expr { $ht / 2 }]]
my setPercent
grid $c -sticky ew
grid columnconfigure $w $c -weight 1
}
method mycanvas {} {
return $c
}
method setWidth { x } {
set wd $x
my redraw
my setPercent $percent
}
method redraw {} {
$c delete $bar0 $bar1 $pt
my drawbar
my drawtext
}
method drawbar { } {
set bar0 [$c create rectangle 0 0 [expr {$wd-1}] [expr {$ht-1}] -fill $fg]
set bar1 [$c create line 1 0 1 [expr {$ht-1}]]
}
method drawtext { } {
set pt [$c create text [expr { $wd / 2 }] [expr { $ht / 2 }] -text $tl]
}
method setbar { x } {
$c moveto $bar0 [expr { -$wd+($x*.01*$wd) }] 0
}
method setText { _tl } {
set tl $_tl
$c itemconfigure $pt -text $tl
}
method setPercent { { n 0 } } {
set percent $n
my setbar $percent
}
}
###END### Source:progressBar.tcl ###END###
oo::class create ytProgressBars {
variable w seed mySeed pbVideo pbAudio frameName syncResize
constructor { { _w "." } } {
set w $_w
my createBars
}
method createBars {} {
set pbVideo [progressBar new $w]
set pbAudio [progressBar new $w]
grid columnconfigure $w [$pbVideo mycanvas] -weight 1
grid columnconfigure $w [$pbAudio mycanvas] -weight 1
}
method setPercentVideo { n } {
$pbVideo setPercent $n
}
method setPercentAudio { n } {
$pbAudio setPercent $n
}
method setWidthVideo { n } {
$pbVideo setWidth $n
}
method setWidthAudio { n } {
$pbAudio setWidth $n
}
method setTextVideo { n } {
$pbVideo setText $n
}
method setTextAudio { n } {
$pbAudio setText $n
}
}
###END### Source:ytProgressBars.tcl ###END###
###START### Source:ytEntry.tcl ###START###
oo::class create ytEntry {
variable w ytEntry frameName e g seed entryTextVars ytUnique ytGo ytRemove dlLocation
constructor { { _w "." } _seed } {
set seed $_seed
set w $_w
if {$w == "." } {
set frameName ".ytEntryFrame$seed"
} else {
set frameName "$w.ytEntryFrame$seed"
}
frame $frameName
grid $frameName -sticky ew
grid columnconfigure $w $frameName -weight 1
set ytEntry $frameName.ytEntry
set ytGo $frameName.ytGo
set ytRemove $frameName.ytRemove
set dlLocation ""
my myEntry
}
method myEntry {} {
set ::entryTextVars($seed) "Enter YouTube address here"
set e [ttk::entry $ytEntry -textvariable entryTextVars($seed) -validatecommand [list [self] entryValidate %V %P] -validate all -background lightgreen]
set g [button $ytGo -text Go -command [list [self] go]]
grid $ytEntry $ytGo -sticky ew
grid columnconfigure $frameName $ytEntry -weight 1
}
method entryText {} {
return $::entryTextVars($seed)
}
method go {} {
my entryValidate focusout $::entryTextVars($seed)
}
method show {} {
}
method removeEntry {} {
puts "deleteEntry>>seed>>$seed"
set ::ytRemove($seed) yes
}
method retry {} {
puts "deleteEntry>>seed>>$seed"
set ::ytRemove($seed) yes
}
method downloadFinished { args } {
if { $::ytRun($seed) } {
} else {
}
}
method setCancelDisabled {} {
$g configure -state disabled
}
method showGoRun {} {
puts "showGoRun>>"
set ::ytRun($seed) go
trace add variable ::ytRun($seed) write "[self] downloadFinished"
$g configure -text "Cancel" -command [list set ::ytRun($seed) true]
}
method entryValidate { validationCallReason entryString } {
if { $validationCallReason == "focusout" } {
if { $entryString == "" } {
set ::entryTextVars($seed) "Enter YouTube address here"
} else {
if { [my isLink $entryString] } {
puts "isLink>>"
set ::entryTextVars($seed) $entryString
set dlLocation $::entryDownLocation
[self] showGoRun
}
}
} elseif { $validationCallReason == "focusin" } {
if { $entryString == "Enter YouTube address here" } {
set ::entryTextVars($seed) ""
}
}
return true
}
method isLink { line } {
set returnVal false
puts "state:[$ytEntry cget -state] [string range $line 32 end] -- [string range $line 0 11]"
if { [$ytEntry cget -state] == "disabled" } {
} elseif { [string length [set ytUnique [string range $line) 32 42]]] == 11 | [string length [set ytUnique [string range $line) 17 28]]] } {
puts "entryValidate1>>$ytUnique"
set returnVal true
} elseif { [string length [set ytUnique [string range $line 0 11]]] == 11 && $ytUnique != "https://www" } {
puts "entryValidate2>>$ytUnique"
set returnVal true
}
return $returnVal
}
method focus {} {
focus $e
}
method setStateEnabled {} {
$ytEntry configure -state disabled
}
method setStateDisabled {} {
$ytEntry configure -state disabled
}
method disableCancel {} {
$g configure -state disabled
}
method showRetryEntry { } {
trace remove variable ::ytRun($seed) write "[self] downloadFinished"
$g configure -text "Retry" -command [list set ::ytRun($seed) true]
my deleteRemoveEntry
}
method showRemoveEntry {} {
puts "showRemoveEntry"
button $ytRemove -text removeEntry -command [list [self] removeEntry]
grid $ytRemove -column 0 -row 0
}
method deleteRemoveEntry {} {
destroy $ytRemove
}
method createGoEntry {} {
puts "createGoEntry"
set g [button $ytGo -text Go -command [list [self] go]]
}
method showOpenDirectory {} {
puts "showOpenDirectory"
$g configure -text "Open file location" -command [list [self] openDirectory]
}
method openDirectory {} {
puts "openDirectory"
exec xdg-open $dlLocation
}
}
###END### Source:ytEntry.tcl ###END###
###START### Source:ytPrefs.tcl ###START###
oo::class create ytPrefs {
variable w frameName downloadLocation ytLabel ytEntry ytSetDirectory prefLocation ytChooseDirectory
constructor { { _w "." } } {
set w $_w
if {$w == "." } {
set frameName ".prefsFrame"
} else {
set frameName "$w.prefsFrame"
}
set configDir [file join $::env(HOME) .config]
set prefLocation [file join $configDir "youtube-dl-gui.prefs"]
if { ! [file isdirectory $configDir] } {
file mkdir $configDir
set ::entryDownLocation $::env(HOME)
my savePrefs
} else {
my readPrefs
}
puts "ytPrefs>>$prefLocation"
set ytLabel $frameName.ytLabel
set ytEntry $frameName.ytEntry
set ytSetDirectory $frameName.ytSetDirectory
set ytChooseDirectory $frameName.ytChooseDirectory
my createFrame
my createWidgets
}
method downloadLocation {} {
return $downloadLocation
}
method readPrefs {} {
set fd9 [open $prefLocation r]
set ::entryDownLocation [lindex [split [read $fd9] "\n"] 0]
set downloadLocation $::entryDownLocation
close $fd9
}
method createFrame {} {
frame $frameName
grid $frameName -sticky ew
grid columnconfigure $w $frameName -weight 1
}
method createWidgets {} {
ttk::label $ytLabel -text "Save To:"
ttk::entry $ytEntry -textvariable entryDownLocation -validatecommand [list [self] entryValidate %V %P] -validate all -background lightgreen
button $ytChooseDirectory -text "\[\]" -command [list [self] chooseDirectory]
grid $ytLabel $ytEntry $ytChooseDirectory -sticky ew -padx 1
grid columnconfigure $frameName $ytEntry -weight 1
}
method entryValidate { validationCallReason entryString } {
if { [my setDirectory $entryString] } {
$ytEntry configure -foreground black
} else {
$ytEntry configure -foreground red
}
return true
}
method chooseDirectory {} {
set dir [tk_chooseDirectory \
-initialdir $::entryDownLocation -title "Choose a directory"]
if {$dir eq ""} {
} else {
set ::entryDownLocation $dir
set downloadLocation $dir
my savePrefs
}
}
method saveDirectory {} {
my setDirectory $::entryDownLocation
}
method setDirectory { newDirectory } {
if { [file isdirectory $newDirectory] } {
if { [catch {cd $newDirectory}] } {
return false
} else {
puts "setDirectory>>$newDirectory"
set downloadLocation $newDirectory
my savePrefs
}
} else {
return false
}
return true
}
method savePrefs {} {
puts "savePrefs>>$downloadLocation"
set fd9 [open $prefLocation w]
puts $fd9 $downloadLocation
close $fd9
}
}
###END### Source:ytPrefs.tcl ###END###
###START### Source:ytParse.tcl ###START###
oo::class create ytParse {
variable info
variable percent
variable speed
variable eta
variable total
variable total_label
variable rate
variable rate_label
variable timeFinished
variable dlCount
constructor {} {
set dlCount 0
}
method parseLine { line } {
set returnVal ""
set type [string range [scan $line {[%s}] 0 end-2]
switch $type {
download {
set returnVal [my parseDownload $line]
}
youtube {
puts $line
}
youtube:tab {
set returnVal [list youtube:tab yes]
puts $line
}
info {
set info $line
}
Merger {
set returnVal [my parseMerger $line]
}
default {
puts "d-$line"
}
}
return $returnVal
}
method parseDownload { line } {
set returnVal ""
set sc [scan $line {[download] %i.%i%% of %i.%i%s at %i.%i%s ETA %s}]
if { [lindex $sc 0] == 100 } {
if { [lindex $sc 1] == "" } {
set sc [scan $line {[download] %i%% of %i.%i%s in %s}]
puts "parseDownload>>$sc"
if { [lindex $sc 4] != "" } {
set total "[lindex $sc 1].[lindex $sc 2]"
set total_label [lindex $sc 3]
set timeFinished [lindex $sc 4]
set returnVal [list total $total total_label $total_label timeFinished $timeFinished dlCount $dlCount]
incr dlCount
}
}
} elseif { [lindex $sc 8] != "" } {
set percent "[lindex $sc 0].[lindex $sc 1]"
set total "[lindex $sc 2].[lindex $sc 3]"
set total_label [lindex $sc 4]
set rate "[lindex $sc 5].[lindex $sc 6]"
set rate_label [lindex $sc 7]
set eta [lindex $sc 8]
set returnVal [list percent $percent total $total total_label $total_label rate $rate rate_label $rate_label eta $eta dlCount $dlCount]
} elseif { [lindex [scan $line {[download] Destination: %s}] 0] != "" } {
set returnVal [list destination [string range $line 24 end] dlCount $dlCount]
} elseif { [string range $line end-27 end] == " has already been downloaded" } {
set returnVal [list alreadyDownloaded yes dlCount $dlCount]
}
return $returnVal
}
method parseMerger { line } {
set returnVal ""
set fileName [string range $line 31 end-1]
set returnVal [list fileName $fileName dlCount $dlCount]
return $returnVal
}
}
###END### Source:ytParse.tcl ###END###
###START### Source:ytFile.tcl ###START###
oo::class create ytFile {
variable w frameName ytFile ytOpenDir ytPlayFile ytDeleteFile e g seed dlLocation basePath
constructor { { _w "." } _seed } {
set seed $_seed
set w $_w
if {$w == "." } {
set frameName ".ytFileFrame$seed"
} else {
set frameName "$w.ytFileFrame$seed"
}
frame $frameName
grid $frameName -sticky ew
grid columnconfigure $w $frameName -weight 1
set ytFile $frameName.ytFile
set ytOpenDir $frameName.ytOpenDir
set ytPlayFile $frameName.ytPlayFile
set ytDeleteFile $frameName.ytDeleteFile
set dlLocation ""
set basePath ""
my ytFile
}
method ytFile {} {
ttk::label $ytFile -text "" -background lightgreen
button $ytDeleteFile -text "X" -command [list [self] deleteFile] -background red
button $ytOpenDir -text "\[\]" -command [list [self] openDirectory] -background lightblue
button $ytPlayFile -text "Play" -command [list [self] playFile] -state disabled -background lightgreen
grid $ytDeleteFile $ytFile $ytOpenDir $ytPlayFile -sticky ew -padx 2
grid columnconfigure $frameName $ytFile -weight 1
}
method setBasePath { newPath } {
set basePath $newPath
}
method setFilePath { newPath } {
$ytFile configure -text $newPath
}
method setPlayEnabled {} {
$ytPlayFile configure -state normal
}
method openDirectory {} {
puts "openDirectory>>$dlLocation>>[file dirname [$ytFile cget -text]]"
exec xdg-open [file dirname [$ytFile cget -text]]
}
method playFile {} {
set cmd "\"[file join $basePath [$ytFile cget -text]]\""
puts "playFile>>$cmd"
exec xdg-open $cmd
}
method deleteFile {} {
puts "deleteFile"
set answer [tk_messageBox -message "Really Delete?" \
-icon question -type yesno \
-detail "Select \"Yes\" to DELETE this file: [$ytFile cget -text]"]
switch -- $answer {
yes {
file delete [$ytFile cget -text]
}
no {tk_messageBox -message "I know you like this application!" \
-type ok}
}
}
}
###END### Source:ytFile.tcl ###END###
###START### Source:ytGui.tcl ###START###
oo::class create yt_gui {
variable w ytProgressBarser ytParser ytEntry ytPrefs ytFile syncResize seed frameName ytDownloader_thread dl_loop sourceDir resultsLoopAfter retrying
constructor { { _w "." } } {
set sourceDir [pwd]
set seed -1
if {$_w == "" } {
set w .
} else {
set w $_w
}
bind $w <Configure> [list [self] resize.bind %W %w %h %x %y]
set n 0
set syncResize(winX) 0
set syncResize(winY) 0
set syncResize(update) 0
set retrying no
set ytPrefs [ytPrefs new]
my newDownloader
}
method newDownloader {} {
incr seed
if {$w == "." } {
set frameName($seed) ".f$seed"
} else {
set frameName($seed) "$w.f$seed"
}
labelframe $frameName($seed) -text "Enter Youtube video link below:"
grid $frameName($seed) -sticky ew
grid columnconfigure $w $frameName($seed) -weight 1
set ytEntry($seed) [ytEntry new $frameName($seed) $seed]
set ytFile($seed) [ytFile new $frameName($seed) $seed]
set ytProgressBarser($seed) [ytProgressBars new $frameName($seed)]
set ytParser($seed) [ytParse new]
$ytEntry($seed) focus
trace add variable ::ytRun($seed) write "[self] startDownloader $seed"
trace add variable ::ytRemove($seed) write "[self] removeDownloader $seed"
puts "newDownloader>>created new \[$seed\]"
}
method startDownloader { n args } {
puts "startDownloader>>$n $args"
set ytDownloader_thread($n) [ytDownloader_thread new $n $sourceDir [$ytPrefs downloadLocation]]
$ytFile($n) setBasePath [$ytPrefs downloadLocation]
trace remove variable ::ytRun($n) write "[self] startDownloader $n"
set ::ytRun($n) true
trace add variable ::ytRun($n) write "[self] cancelDownloader $n"
$ytEntry($n) setStateDisabled
$frameName($n) configure -text "Download has begun.."
if { ! $retrying } {
my newDownloader; #create a new one for the next
} else {
set retrying no
}
$ytDownloader_thread($n) downloadLink [$ytEntry($n) entryText]
set resultsLoopAfter [after 1000 [list [self] getResultsLoop $n]]
}
method cancelDownloader { n args } {
puts "cancelDownloader>>$n $args"
$frameName($n) configure -text "Download CANCELLED"
trace remove variable ::ytRun($n) write "[self] cancelDownloader $n"
after cancel $resultsLoopAfter
$ytDownloader_thread($n) exitThread
$ytDownloader_thread($n) destroy
$ytEntry($n) showRetryEntry
$ytEntry($n) showRemoveEntry
trace add variable ::ytRun($n) write "[self] retryDownload $n"
}
method retryDownload { n args } {
trace remove variable ::ytRun($n) write "[self] retryDownload $n"
$ytEntry($n) deleteRemoveEntry
set retrying yes
$ytEntry($n) showGoRun
[self] startDownloader $n
}
method getResultsLoop { n } {
set dl_loop($n) no
[self] resultsLoop $n
}
method resultsLoop { n } {
puts "resultsLoop>>$n"
if { [set line [$ytDownloader_thread($n) popResults]] != "" } {
if { $line == "EOF" } {
puts "getResultsLoop>>DONE"
set dl_loop($n) yes
$ytEntry($n) showOpenDirectory
} else {
[self] updateGUI $n $line
}
}
if { !$dl_loop($n) } {
set resultsLoopAfter [after 100 [list [self] resultsLoop $n]]
}
}
method setProgressBarText { n } {
if { $n } {
return setTextAudio
} else {
return setTextVideo
}
}
method setProgressBarPercent { n } {
if { $n } {
return setPercentAudio
} else {
return setPercentVideo
}
}
method updateGUI { n line } {
puts "updateGUI>>$line"
set k [$ytParser($n) parseLine $line]
if { [lsearch [dict keys $k] youtube:tab] != -1 } {
} elseif { [lsearch [dict keys $k] percent] != -1 } {
$ytProgressBarser($n) [my setProgressBarText [dict get $k dlCount]] "[dict get $k percent]% of [dict get $k total][dict get $k total_label] at [dict get $k rate][dict get $k rate_label] ETA [dict get $k eta]"
$ytProgressBarser($n) [my setProgressBarPercent [dict get $k dlCount]] [dict get $k percent]
} elseif { [lsearch [dict keys $k] timeFinished] != -1 } {
puts "updateGUI>>timeFinished"
$ytProgressBarser($n) [my setProgressBarText [dict get $k dlCount]] "Finished downloading [dict get $k total][dict get $k total_label] in [dict get $k timeFinished]"
$ytProgressBarser($n) [my setProgressBarPercent [dict get $k dlCount]] 100
if { [dict get $k dlCount] } {
$ytEntry($n) showRemoveEntry
$ytFile($n) setPlayEnabled
}
} elseif { [lsearch [dict keys $k] alreadyDownloaded] != -1 } {
puts "updateGUI>>alreadyDownloaded"
$frameName($n) configure -text "Download cancelled."
$ytProgressBarser($n) [my setProgressBarText 0] "Already been downloaded"
$ytProgressBarser($n) [my setProgressBarPercent 0] 100
$ytProgressBarser($n) [my setProgressBarText 1] ""
$ytProgressBarser($n) [my setProgressBarPercent 1] 100
$ytEntry($n) showRemoveEntry
$ytEntry($n) showOpenDirectory
$ytFile($n) setPlayEnabled
} elseif { [lsearch [dict keys $k] fileName] != -1 } {
puts "fileName [pwd] [dict get $k fileName]"
} elseif { [lsearch [dict keys $k] destination] != -1 } {
$frameName($n) configure -text "[dict get $k destination]"
$ytFile($n) setFilePath [dict get $k destination]
}
}
method test1 { n } {
puts "test1>>n:$n"
set x [open ex-dl-1.txt]
while {[gets $x line]>=0} {
set k [$ytParser($n) parseLine $line]
if { [lsearch [dict keys $k] percent] != -1 } {
if { [dict get $k dlCount] == 0 } {
$ytProgressBarser($n) setPercentVideo [dict get $k percent]
puts "setPercentVideo [dict get $k percent]"
} elseif { [dict get $k dlCount] == 1 } {
$ytProgressBarser($n) setPercentAudio [dict get $k percent]
puts "setPercentAudio [dict get $k percent]"
}
} elseif { [lsearch [dict keys $k] fileName] != -1 } {
puts "fileName [pwd] [dict get $k fileName]"
} elseif { [lsearch [dict keys $k] destination] != -1 } {
$frameName($n) configure -text "[dict get $k destination]"
}
sleep 210
}
}
method removeDownloader { n args } {
puts "deleteDownloader>>seed>>$n"
$ytEntry($n) destroy
$ytProgressBarser($n) destroy
$ytParser($n) destroy
unset ytEntry($n)
unset ytProgressBarser($n)
unset ytParser($n)
destroy $frameName($n)
}
method resize.bind { W width height x y } {
puts "resize.bind>>$W>>$width>>$height>>$x>>$y"
if {"$W" eq [winfo toplevel $W]} {
if { $width == $syncResize(winX) && $height == $syncResize(winY) } {
return
} else {
set syncResize(winX) $width
set syncResize(winY) $height
[self] resize.wait
}
}
}
method resize.wait { } {
after cancel $syncResize(update)
set syncResize(update) [after 25 [list [self] resize.go]]
}
method resize.go { } {
puts "resize.go>>$syncResize(winX)"
set resizeVal [expr { $syncResize(winX) - 7 }]
foreach n [array names ytProgressBarser] {
$ytProgressBarser($n) setWidthVideo $syncResize(winX)
$ytProgressBarser($n) setWidthAudio $syncResize(winX)
}
}
}
###END### Source:ytGui.tcl ###END###
set z [yt_gui new]
Watch that first line, it tells the shell how to run the file, make sure your tclsh is located in the same place as the script has it, or simply start it using .
tclsh scriptName.tcl
.. and this will run it.
Thanks for having a look. have a great day.
namaste