If you’re like me, you may download a lot of videos at once and then be forced to ask the question, “Wait, what haven’t I watched yet?” I created lnSponge, a simple TCL script, to keep track of new files for me. It scans a given directory tree and creates symbolic links to all new files in a designated folder. It retains a copy of all the filenames so you can delete the symbolic links after you’re done watching the media and it won’t reappear on the next run.
The script takes in four arguments indicating the path of files to scan, the path to the symbolic link folder, the file to use to hold the database of filenames and the number of trackback days (e.g. ignore all new files older than n days). It produces no output if there are no new files to add, so it can easily be coupled with the Ruby Email Script
Example usage:
./lnsponge.tcl /mnt/orion/tv_shows /mnt/orion/new ~/.tvshows.list 10
Script:
#!/usr/bin/tclsh # # lnSponge - v1.0 # # A script designed to create a set of symbolic links # in one directory for all new files found in a given # directory tree. Created links are kept track of in # an index file to prevent creating duplicate links. # # Useful to keep track of new files for users who # download a lot of media. # # Sumit Khanna <sumdog@gmail.com> # http://penguindreams.org # # Free for noncommercial use # namespace eval lnSpongeVars { #only consider files that were created in the past n days variable mdays #path to meida tree variable path #path to directory with symbolic links variable newlinks #path to processed file list variable plist #file descriptor for update process variable plistchannel #tmp arry for processed files variable pfilearray } proc printUsage {} { puts "lnSponge Usage:" puts "" puts "lnsponge.tcl <media path> <new links path> <list file> <trackback days>" puts "" puts "\tmedia path - path to directories to recursivly search for new media" puts "\tnew links path - path to directory that contains links to new media" puts "\tlist file - file which contains list of processed files" puts "\ttrackback days - ignore new files that were modified more than n days ago" puts "" } #reads in command line args into lnSpongeVars namespace # make sure $argc ==4 first proc readCmdArgs {} { variable ::lnSpongeVars::mdays variable ::lnSpongeVars::path variable ::lnSpongeVars::newlinks variable ::lnSpongeVars::plist global argv set path [lindex $argv 0] set newlinks [lindex $argv 1] set plist [lindex $argv 2] set mdays [lindex $argv 3] } #ftime = UNIX time/seconds from epoch #days = number of days #return true if ftime is < days; else false proc checkDays { ftime } { variable ::lnSpongeVars::mdays #seconds per day set secdays [ expr $mdays * 24 * 60 * 60 ] if { [ expr [ clock seconds ] - $ftime ] < $secdays } { return 1 } return 0 } #initial reading of list # is read in entirety proc readPList {} { variable ::lnSpongeVars::plist variable ::lnSpongeVars::pfilearray if { [ file exists $plist ] } { set fd [open $plist "r"] while {[gets $fd line] >= 0} { array set pfilearray [list "$line" "1"] } close $fd } } #--functions for appending to processed file list proc openPFile {} { variable ::lnSpongeVars::plist variable ::lnSpongeVars::plistchannel set plistchannel [open $plist "a"] } proc addPFile { name } { variable ::lnSpongeVars::plistchannel puts $plistchannel $name } proc closePFile {} { variable ::lnSpongeVars::plistchannel close $plistchannel } #-- #recursive function for scanning # all directories from a given path # and creating links for those files # not on processed list #$rpath = base of tree to scan proc probeDirs {rpath} { variable ::lnSpongeVars::pfilearray variable ::lnSpongeVars::newlinks if {[ file isdirectory $rpath ]} { set i [glob -nocomplain -directory $rpath *] foreach sub $i { probeDirs $sub } } else { file stat $rpath finfo set ftime [ lindex [ array get finfo "ctime" ] 1 ] set btime [ checkDays $ftime ] #if it was created in the past n days if { $btime == 1 } { #if it's not all ready in processed list set basename [file tail $rpath] if {![info exists pfilearray($basename)]} { if { [ file exists "$newlinks/$basename" ] } { puts "File Exists (ignoring): $basename" } else { puts "New Link: $basename" file link -symbolic "$newlinks/$basename" $rpath } addPFile [file tail $rpath] } } } } #main entry point # functions must be called in this order if { $argc != 4 } { printUsage exit 1 } else { readCmdArgs readPList openPFile probeDirs $::lnSpongeVars::path closePFile }