#!/mod/bin/jimsh

source /mod/webif/lib/setup
require lock system.class ts.class tdelete

set testing 0

proc dsc {} {
	lassign [system diskspace] x x perc
	if {$perc > 90} {
		puts "Insufficient disk space ($perc%), terminating."
		exit
	}
}

dsc

if {![acquire_lock webif_auto]} {
	puts "Cannot acquire exclusive lock, terminating."
	exit
}

set tmp "/mod/tmp/webif_auto"
if {![file exists $tmp]} {
	if {[catch {file mkdir $tmp} msg]} {
		puts "Cannot create temporary directory - $tmp ($msg)"
		exit
	}
} elseif {![file isdirectory $tmp]} {
	puts "Cannot create temporary directory - $tmp (file exists)"
	exit
}

# Clean-up the temporary directory
foreach file [readdir -nocomplain $tmp] { tdelete "$tmp/$file" }

if {[system pkginst undelete]} {
	set dustbin "[system dustbin]"
} else {
	set dustbin ""
}

proc bindir {file binroot} {
	set dir [file dirname $file]
	regsub "^[system mediaroot]" $dir $binroot ndir
	if {$dir eq $ndir} { set ndir $binroot }
	system mkdir_p $ndir
	return $ndir
}

proc dedup {dir} {
	if {$::testing} {
		puts "DEDUP: \[$dir]"
	} else {
		puts [exec /mod/webif/html/dedup/dedup -yes $dir]
		exec /mod/webif/html/dedup/dedup -yes $dir
	}
}

proc do_shrink {ts} {
	global tmp dustbin tsgroup

	set file [file rootname [$ts get file]]
	if {[catch {
		set perc [exec /mod/bin/stripts -aq $file]
	    } msg]} {
		puts "          Error: $msg"
		return
	}
	if {[string match {*%} $perc]} {
		set perc [string range $perc 0 end-1]
	} else {
		set perc 0
	}

	if {$perc == 0} {
		#puts "          Already shrunk."
		return
	}
	puts "  SHRINK: $file"
	puts "          Estimate $perc% saving."
	puts "          Shrinking..."
	if {[catch {
		puts [exec nice -n 19 /mod/bin/stripts -q $file $tmp/shrunk]
	    } msg]} {
		puts "Error during shrink: $msg"
		return
	}

	# The following steps are structured to minimise the risk of
	# things being left in an inconsistent state if the system goes
	# into standby. Renames within the same filesystem are very
	# quick so the risk is small, but even so...

	# Move the shrunken version back to the local directory.
	foreach f [glob "$tmp/shrunk.*"] {
		set ext [file extension $f]
		file rename $f "${file}_shrunk${ext}"
	}

	# Move the old recording to the bin if undelete is installed.
	if {$dustbin ne ""} {
		$ts move [bindir $file "$dustbin/webif_autoshrink"] 1 1
	} else {
		# Delete otherwise.
		if {[$ts delete]} {
			puts "Successfully deleted $file."
		} else {
			puts "Problem deleting $file, [$ts get error]"
			return
		}
	}

	# Finally, rename the shrunken recording again.
	foreach ext $tsgroup {
		set f "${file}_shrunk.$ext"
		if {[file exists $f]} {
			file rename $f "${file}.$ext"
		}
	}
}

proc do_decrypt {ts} {
	global tmp dustbin

	set file [$ts get file]
	set rfile [file rootname $file]
	set bfile [file tail $file]

	if {![$ts flag "ODEncrypted"]} {
		#puts "          Already decrypted."
		return
	}

	lassign [$ts dlnaloc] url
	if {$url eq ""} {
		#puts "          Not yet indexed."
		return
	}

	puts "  DECRYPT: $rfile"
	puts "  DLNA: $url"
	exec wget -O "$tmp/$bfile" $url

	if {[file size $file] != [file size "$tmp/$bfile"]} {
		puts "        File size mismatch."
		return
	}

	# Move the encrypted file out of the way.
	file rename $file "$rfile.encrypted"
	# Move the decrypted copy into place.
	file rename "$tmp/$bfile" $file
	# Patch the HMT - quickest way to get back to a playable file.
	exec /mod/bin/hmt -encrypted "$rfile.hmt"

	puts "  Removing/binning old copy."
	# Move the old recording to the bin if undelete is installed.
	if {$dustbin ne ""} {
		set bin [bindir $file "$dustbin/webif_autodecrypt"]
		set tail [file tail $rfile]
		file rename "$rfile.encrypted" "$bin/$tail.ts"
		foreach ext {nts hmt thm} {
			if {[file exists "$rfile.$ext"]} {
				file copy $rfile.$ext "$bin/$tail.$ext"
				if {$ext eq "hmt"} {
					# Patch the binned HMT back
					exec /mod/bin/hmt +encrypted \
					    "$bin/$tail.hmt"
				}
			}
		}
	} else {
		tdelete "$rfile.encrypted"
	}
	puts "  Done."
}

proc do_mpg {ts} {
	global tmp tsgroup

	set file [file rootname [$ts get file]]

	if {[file exists $file.mpg]} {
		# Already done.
		return
	}

	if {[$ts flag "ODEncrypted"]} {
		#puts "          Not decrypted."
		return
	}

	if {[$ts get definition] eq "HD"} {
		# Cannot extract a useful MP3 from a HD recording.
		return
	}

	puts "     MPG: $file"
	puts "          Converting..."
	if {[catch {
		puts [exec nice -n 19 /mod/bin/ffmpeg -y -benchmark -v 0 \
		    -i $file.ts \
		    -map 0:0 -map 0:1 \
		    -vcodec copy -acodec copy $tmp/mpg.mpg]
	    } msg]} {
		puts "Error during mpg extract: $msg"
		return
	}

	# Move the MPG into the local directory
	file rename $tmp/mpg.mpg $file.mpg
}

proc entries {dir callback} {
	foreach entry [readdir -nocomplain $dir] {
		dsc
		if {![string match {*.ts} $entry} continue
		if {[catch {set ts [ts fetch "$dir/$entry"]}]} continue
		if {$ts == 0} continue
		if {[system inuse [file rootname "$dir/$entry"]]} {
			puts "$entry - in use\n"
			continue
		}
		$callback $ts
	}
}

proc shrink {dir} {
	puts "SHRINK: \[$dir]"
	if {!$::testing} { entries $dir do_shrink }
}

proc decrypt {dir} {
	puts "DECRYPT: \[$dir]"
	if {!$::testing} { entries $dir do_decrypt }
}

proc mpg {dir} {
	puts "MPG: \[$dir]"
	if {!$::testing} { entries $dir do_mpg }
}

proc scan {dir attr {force 0}} {{indent 0}} {
	global dustbin

	incr indent 2

	if {$::testing} { puts "[string repeat " " $indent]\[$dir]" }

	#if {[string match {\[*} $dir]} continue
	if {$dir eq $::dustbin} {
		puts "Dustbin, skipping."
		return
	}

	dsc

	# Recursion
	if {[file exists "$dir/.auto${attr}r"]} {
		if {$::testing} { puts "[string repeat " " $indent]  (R)" }
		set force 1
	}

	if {$force || [file exists "$dir/.auto$attr"]} { $attr $dir }

	foreach entry [readdir -nocomplain $dir] {
		if {[file isdirectory "$dir/$entry"]} {
			scan "$dir/$entry" $attr $force
		}
	}

	incr indent -2
}

set root [system mediaroot]

if {[llength $argv] > 0} {
	foreach arg $argv { scan $root $arg }
} else {
	foreach arg {dedup decrypt shrink mpg} {
		scan $root $arg
	}
}

release_lock webif_auto