#! /bin/sh
# the next line restarts using tclsh \
exec tclsh8.4 $0 "$@"
package require http
if {[llength $argv] != 1} {
puts "usage: $argv0 <google video URL>"
exit 0
}
set url [lindex $argv 0]
puts -nonewline "Downloading $url ..."
flush stdout
if {[catch {set urlToken [http::geturl $url]} oops]} {
puts "$oops"
exit 1
}
if {[http::status $urlToken] ne "ok"} {
puts [http::error $urlToken]
http::cleanup $urlToken
exit 1
}
set urlData [http::data $urlToken]
http::cleanup $urlToken
puts "done."
#
# Looking for ...googleplayer.swf?&videoUrl\u003d[<video URL>]&
#
puts -nonewline "Extracting encoded video URL ... "
flush stdout
if {[set googleplayerIndex [string first "googleplayer.swf" $urlData]] == -1} {
puts "failed."
puts "Error: magic string \"googleplayer.swf\" not found."
exit 1
}
if {[string range $urlData \
[expr {$googleplayerIndex + 18}] \
[expr {$googleplayerIndex + 25}]] ne "videoUrl"} {
puts "failed."
puts "Error: magic string \"videoUrl\" not found."
exit 1
}
if {[string range $urlData \
[expr {$googleplayerIndex + 26}] \
[expr {$googleplayerIndex + 31}]] ne "\\u003d"} {
puts "failed."
puts "Error: magic URL marker not found."
exit 1
}
set urlBeginIndex [expr {$googleplayerIndex + 32}]
if {[set urlEndIndex [string first "&" $urlData $urlBeginIndex]] == -1} {
puts "failed."
puts "Error: magic end of URL marker not found."
exit 1
}
incr urlEndIndex -1
set encodedVideoUrl [string range $urlData $urlBeginIndex $urlEndIndex]
if {[string first "\n" $encodedVideoUrl] != -1 || \
[string first "\"" $encodedVideoUrl] != -1} {
puts "failed."
puts "Error: video URL looks fishy."
exit 1
}
puts "done."
#
# Replace all URL-encoded characters, e.g., replace "%3D" with "="
#
puts -nonewline "Unencoding video URL ... "
flush stdout
lappend ud_map + { }
for {set i 0} {$i < 256} {incr i} {
set c [format %c $i]
set x %[format %02x $i]
if {![string match {[a-zA-Z0-9]} $c]} {
lappend ud_map $x $c
}
}
set videoUrl [string map -nocase $ud_map $encodedVideoUrl]
puts "done."
#
# At this URL, we may get the video data. Or, we might be redirected.
#
puts -nonewline "Determining file name ... "
flush stdout
if {[catch {set videoToken [http::geturl $videoUrl -validate 1]} oops]} {
puts "$oops"
exit 1
}
upvar \#0 $videoToken videoState
array set videoMeta $videoState(meta)
http::cleanup $videoToken
if {[info exists videoMeta(Location)]} {
puts -nonewline "Following redirection ... "
flush stdout
set videoUrl $videoMeta(Location)
if {[catch {set videoToken [http::geturl $videoUrl -validate 1]} oops]} {
puts "$oops"
exit 1
}
upvar \#0 $videoToken videoState
array set videoMeta $videoState(meta)
http::cleanup $videoToken
}
#
# There should be a Content-Disposition: attachment; filename=<file name> header.
#
if {![info exists videoMeta(Content-Disposition)]} {
puts "failed."
puts "Error: no Content-Disposition header found."
exit 1
}
set disposition $videoMeta(Content-Disposition)
if {[set filenameIndex [string first "filename=" $disposition]] == -1} {
puts "failed."
puts "Error: filename not found in \"$disposition\""
exit 1
}
set filenameFirst [expr {$filenameIndex + 9}]
set filename [string range $disposition $filenameFirst end]
puts "done."
#
# Download the video for real.
#
proc progressIndicator {token total current} {
set currentKb [expr {$current / 1024}]
set totalKb [expr {$total / 1024}]
puts -nonewline "\rDownloading $::filename ... $currentKb "
if {$total != 0} {
puts -nonewline "/ $totalKb "
}
}
puts -nonewline "Downloading $filename ... "
if {[catch {set output [open $filename "w"]} oops]} {
puts "failed."
puts "Error: can not open \"$filename\" for writing: $oops"
exit 1
}
if {[catch {set videoToken [http::geturl $videoUrl -channel $output -progress progressIndicator]} oops]} {
puts "$oops"
catch {close $output}
exit 1
}
if {[http::status $videoToken] ne "ok"} {
puts [http::error $videoToken]
http::cleanup $videoToken
exit 1
}
http::cleanup $videoToken
puts "done."Category File - Category Internet
