484 lines
16 KiB
Plaintext
Executable File
484 lines
16 KiB
Plaintext
Executable File
#!/mod/bin/jimsh
|
|
# Retrieve recording via dlna (using curl) whilst recording is still in progress and write it to stdout for use in pipelines
|
|
|
|
source /mod/webif/lib/setup
|
|
require lock system.class ts.class settings.class rsv.class
|
|
set loglevel 0
|
|
set status 0
|
|
catch {
|
|
# Use same logging option as auto log
|
|
set settings [settings]
|
|
set loglevel [$settings _nval_setting "autolog"]
|
|
set status [$settings _nval_setting "chaseget_status" ]
|
|
}
|
|
|
|
if {[lindex $argv 0] eq "-d"} {
|
|
set argv [lrange $argv 1 end]
|
|
set loglevel 2
|
|
}
|
|
|
|
|
|
proc log {msg {level 2}} {
|
|
if {$level > $::loglevel} return
|
|
system plog $::logfile "CG([pid])- $msg"
|
|
#puts $::logfd "[\
|
|
# clock format [clock seconds] -format "%d/%m/%Y %H:%M:%S"\
|
|
# ] CG([pid])- $msg"
|
|
#flush $::logfd
|
|
}
|
|
|
|
proc help_text {} {
|
|
puts "chaseget - Retrieve recording via dlna (using curl) whilst recording is still in progress and write it to stdout for use in pipelines"
|
|
puts ""
|
|
puts "chaseget -d options = Detailed debug output"
|
|
puts "chaseget recording.ts start_offset logfile = Retrieve recording"
|
|
puts "chaseget -standby ignoreTerminals logfile = Check whether safe to put system back into standby (ignoreTerminals 0=No 1=Yes)"
|
|
puts "chaseget -help = This help text"
|
|
puts "Author MymsMan see http://hummy.tv/forum/forums/hd-hdr-fox-t2-customised-firmware.28/ for more information"
|
|
}
|
|
|
|
set file [lindex $argv 0]
|
|
set fs [lindex $argv 1]
|
|
if {$fs eq ""} {set fs 0}
|
|
set logfile [lindex $argv 2]
|
|
if {$logfile eq ""} {set logfile "chaseget"}
|
|
#set logfd [open $logfile "a+"]
|
|
set ::awfile "/mod/etc/chaseget_awakened"
|
|
|
|
|
|
|
|
proc getfile {file {fs 0}} {
|
|
set ts [ts fetch $file]
|
|
log "ChaseGet $file" 0
|
|
|
|
set fl [glob -nocomplain "/mod/tmp/*-inp.ts" ]
|
|
log "orphan file list $fl" 2
|
|
foreach f $fl {
|
|
if {[file mtime $f]+3600 < [clock seconds]} {
|
|
if {[safe_delete $file chaseget/orphans]} {
|
|
log "$f safe deleted" 0
|
|
} else {
|
|
log "$f safe_delete failed" 0
|
|
}
|
|
}
|
|
}
|
|
|
|
set blksize $(256*1024)
|
|
# extract recording info & calculate
|
|
# - full recording size when complete
|
|
# - remaining recording time and retrieval rate
|
|
set stime [$ts get start]
|
|
set etime [$ts get end]
|
|
log "Recording start: [clock format $stime -format "%H:%M:%S"] end: [clock format $etime -format "%H:%M:%S"]"
|
|
|
|
set csize [file size "$file"]
|
|
set dlnaretry 0
|
|
set dlnaalert 0
|
|
set bname [file rootname [file tail $file]]
|
|
set iname "$bname-inp"
|
|
set ipath "/mod/tmp"
|
|
set ifile "$ipath/$iname.ts"
|
|
file delete -force "$ipath/$iname.ts"
|
|
catch {file link -hard "$ipath/$iname.ts" "[file normalize [file rootname $file].ts]"}
|
|
file delete -force "$ipath/$iname.hmt"
|
|
catch {file link -hard "$ipath/$iname.hmt" "[file normalize [file rootname $file].hmt]"}
|
|
|
|
# Is file already indexed
|
|
lassign [$ts dlnaloc "127.0.0.1"] fileurl
|
|
|
|
while {$csize > $fs} {
|
|
if {[system dlnastatus]} {
|
|
set dlnaok 1
|
|
set dlnaretry 0
|
|
set dlnaalert 0
|
|
#log "DLNA Server is running." 2
|
|
} else {
|
|
set dlnaok 0
|
|
incr dlnaretry
|
|
log "DLNA Server is NOT running." 0
|
|
# Attempt to turn box fully on using IR package
|
|
if {[system instandby]} {
|
|
awake_from_standy
|
|
}
|
|
# Check file sharing enabled
|
|
if {![system param DMS_START_ON]} {
|
|
log "Content Sharing Disabled" 0
|
|
if {!$dlnaalert} {
|
|
set dlnaalert 1
|
|
system notify "ChaseGet: Contents sharing disabled, Enable via Humax Settings menu"
|
|
}
|
|
}
|
|
if {$dlnaretry >10} {
|
|
log "DLNA Server is still NOT running. Giving up" 0
|
|
return "DLNA Server is still NOT running. Giving up"
|
|
}
|
|
sleep 60
|
|
continue
|
|
}
|
|
set ctime [clock seconds]
|
|
set elapsed $($ctime-$stime)
|
|
set durn $($etime-$stime)
|
|
set remain $($etime-$ctime)
|
|
log "duration: $durn elapsed: $elapsed remaining: $remain" 2
|
|
if {$remain > 0} {
|
|
# Now using time slicing rather than throttling
|
|
# set totsize $($csize*$durn/$elapsed)
|
|
# set recrate $($csize/$elapsed)
|
|
# set drate $(($totsize-$fs)/($remain))
|
|
# log "est total size: $totsize recording rate: $recrate download rate limit: $drate"
|
|
# set lrate "--limit-rate $($drate*1)"
|
|
# sleep 10
|
|
set lrate ""
|
|
} else { set lrate ""}
|
|
|
|
set retrct 0
|
|
set url $fileurl
|
|
if {$url ne ""} {
|
|
log " $file - has been indexed."
|
|
set helper 0
|
|
} else {
|
|
log " $file - Not yet indexed, trying helper."
|
|
if {[catch {
|
|
lassign [system dlnahelper [file normalize $ifile]] url
|
|
} msg]} {
|
|
log " $ifile - $msg"
|
|
system dlnahelper -release
|
|
}
|
|
if {$url eq ""} {
|
|
log " $file - Can't use helper. retry"
|
|
# system dlnahelper -release
|
|
if {$remain > 30} {sleep 15} else {sleep 5}
|
|
continue
|
|
}
|
|
set helper 1
|
|
}
|
|
log "Start at offset $fs cur recording size: $csize DLNA: $url" 2
|
|
|
|
if {!$::status} {
|
|
# show sctive on webif status display
|
|
set statustok [system startop -multiple chaseget $file]
|
|
}
|
|
|
|
if {[catch -break -eval -signal -- {
|
|
set input [open "|curl -C $fs $lrate $url 2> /dev/null "]
|
|
} msg opts]} {
|
|
log "Open caught: $msg $opts" 1
|
|
break
|
|
}
|
|
log "Curl pid [pid $input]" 2
|
|
while {1} {
|
|
if {[catch -break -eval -signal -- {
|
|
set block [read $input $blksize]
|
|
puts -nonewline $block
|
|
flush stdout
|
|
} msg opts]} {
|
|
log "caught: $msg $opts" 0
|
|
# set ps [exec ps -Af]
|
|
# log $ps
|
|
break
|
|
}
|
|
incr fs [string bytelength $block]
|
|
incr retrct [string bytelength $block]
|
|
if {[eof $input]} {
|
|
log "EOF detected Files Size $fs Retrieved $retrct" 2
|
|
break
|
|
}
|
|
}
|
|
close $input
|
|
# Short sleep to allow pipeline to drain and for more data to accumulate on input
|
|
# Helper lock still held so parallel recording doesn't start getting and overload CPU
|
|
sleep 3
|
|
# Release the helper lock once finished.
|
|
if {$helper} { system dlnahelper -release }
|
|
|
|
if {!$::status} {
|
|
# not active for status
|
|
system endop $statustok
|
|
}
|
|
|
|
if {$retrct==0} {
|
|
log "No data returned" 1
|
|
break
|
|
}
|
|
set ctime [clock seconds]
|
|
set remain $($etime-$ctime)
|
|
if {$remain > 60} {
|
|
# Sleep if not close to recording end to allow other recordings a chance to get in and for more data to accumulate
|
|
log "snoozzzing" 2
|
|
sleep 30
|
|
} else {
|
|
sleep 3
|
|
}
|
|
set csize [file size "$file"]
|
|
}
|
|
|
|
# remove alias
|
|
file delete -force "$ipath/$iname.ts"
|
|
file delete -force "$ipath/$iname.hmt"
|
|
|
|
if {[file size $file] >$fs } {
|
|
log " Failed to retrieve entire file $([file size $file] -$fs) bytes missing" 0
|
|
log " Attempt to recreate failure message" 1
|
|
set curlout ""; set msg ""; set opts ""
|
|
catch {set curlout [exec curl -C $fs $url > /dev/null]} msg opts
|
|
log "Curl message: $msg" 0
|
|
log "Curl error: $opts" 1
|
|
log "Curl output: $curlout" 1
|
|
return -code error $msg
|
|
}
|
|
|
|
log "ChaseGet end $file Size $fs bytes" 0
|
|
#log "-----------------------------------------------" 2
|
|
return $fs
|
|
}
|
|
|
|
# Check whether now is within time range, time formats hh:mm
|
|
proc inTimeRange {start end} {
|
|
set now [clock format [clock seconds] -format "%H:%M"]
|
|
log "Now $now Range $start - $end" 2
|
|
if {$start eq $end} {return 0}
|
|
if {$start <= $end} {
|
|
# start and stop times are in the same day
|
|
if {$now >= $start && $now <= $end} {
|
|
# current time is between start and stop
|
|
return 1
|
|
}
|
|
} else {
|
|
# start and stop times are in different days
|
|
if {$now >= $start || $now <= $end} {
|
|
# current time is between start and stop
|
|
return 1
|
|
}
|
|
}
|
|
# outside range
|
|
return 0
|
|
}
|
|
|
|
proc awake_from_standy {} {
|
|
# Usee zero intead of Power for wakeup. less risk
|
|
catch {exec ir ZERO}
|
|
log "System power on attempted" 0
|
|
set settings [settings]
|
|
set mute [$settings _nval_setting "chaseget_mute" ]
|
|
set standby_start [$settings _tval_setting "chaseget_standby_start1"]
|
|
set standby_end [$settings _tval_setting "chaseget_standby_end1"]
|
|
|
|
if {$mute && ![inTimeRange "$standby_start" "$standby_end"]} {
|
|
sleep 2
|
|
# Mute in case it comes on in middle of night and to provoke button push by passive viewer
|
|
catch {exec ir MUTE}
|
|
log "Sound mute attempted" 1
|
|
}
|
|
catch {exec touch $::awfile}
|
|
#[settings new] _nval_setting "chaseget_awakened" [clock seconds]
|
|
}
|
|
|
|
proc awakened_by_chaseget {} {
|
|
#set settings [settings]
|
|
#set ::awakened [$settings _nval_setting "chaseget_awakened"]
|
|
if {[file exists $::awfile]} {
|
|
set ::awakened [file mtime $::awfile]
|
|
log "Awakened by ChaseGet at [clock format $::awakened -format %T]" 2
|
|
return 1
|
|
} else {
|
|
set ::awakened 0
|
|
return 0
|
|
}
|
|
}
|
|
|
|
proc clear_awakened_status {} {
|
|
# [settings new] _nval_setting "chaseget_awakened" 0
|
|
file delete $::awfile
|
|
set ::awakened 0
|
|
}
|
|
|
|
proc standby_check {{ignoreTerm 1}} {
|
|
# Quit quietly if nothing to do
|
|
set settings [settings]
|
|
set standby_start [$settings _tval_setting "chaseget_standby_start1"]
|
|
set standby_end [$settings _tval_setting "chaseget_standby_end1"]
|
|
#set lastboot $([clock seconds] - round([system uptime]))
|
|
#log "Last boot time [clock format $lastboot -format %T]" 2
|
|
|
|
if {[inTimeRange "$standby_start" "$standby_end"]} {
|
|
log "Standby check disabled - quit" 2
|
|
exit
|
|
}
|
|
|
|
if {![awakened_by_chaseget]} {
|
|
log "Not awakened by chaseget - quit" 2
|
|
exit
|
|
}
|
|
|
|
log "ChaseGet - standby_check starting" 1
|
|
|
|
if {[system instandby]} {
|
|
log "System in standby - quit" 1
|
|
clear_awakened_status
|
|
exit
|
|
}
|
|
|
|
|
|
# foreach {process in detectads, auto, ...} {
|
|
# # process list should probably be in a config file to allow easy update
|
|
# # what others?
|
|
# if {process active} { exit }
|
|
# }
|
|
|
|
# open and read configuration file
|
|
set cf "/mod/etc/chaseget.conf"
|
|
|
|
if {![catch {set fp [open $cf r]}]} {
|
|
set clist [split [read $fp] "\n"]
|
|
} else {
|
|
set clist {}
|
|
}
|
|
|
|
# Check if proces in list is active
|
|
foreach process $clist {
|
|
if {![string length $process]} continue
|
|
log "Checking entry: $process" 2
|
|
set status [catch {exec pgrep -x $process} ]
|
|
if {$status == 0} {
|
|
log "Active process $process - quit" 1
|
|
return 0
|
|
}
|
|
}
|
|
|
|
# # can putty/telnet users be detected ?
|
|
set termct [exec ls /dev/pts | wc -l]
|
|
log "Pseudo terminals: $termct" 2
|
|
if {!$ignoreTerm && $termct > 0 } {
|
|
log "Active terminals $termct - quit" 1
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# if { last boot time > chaseget awakened time} {
|
|
# Clear awakend by chaseget status
|
|
# exit
|
|
# }
|
|
|
|
# Ideally should be: set lastboot [system lastboottime]
|
|
#set lastboot [file mtime "/tmp/if-up"]
|
|
set lastboot $([clock seconds] - round([system uptime]))
|
|
log "Last boot time [clock format $lastboot -format %T]" 2
|
|
if {$lastboot > $::awakened} {
|
|
log "Boot time [clock format $lastboot -format %T] > Awakened time [clock format $::awakened -format %T] - quit" 1
|
|
clear_awakened_status
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# if { any .ts in use (except recording) } { exit }
|
|
#
|
|
|
|
set ret {}
|
|
# Get a list of unique in-use .ts files
|
|
if {[catch {set data [exec /mod/webif/lib/bin/lsof -Fns | grep {\.ts} | sort -u ]} msg]} {
|
|
set ret {}
|
|
} else {
|
|
set flist ""
|
|
foreach line [split $data "\n"] {
|
|
set file [string range $line 1 end]
|
|
if {[file tail $file] eq "0.ts"} continue
|
|
|
|
set csize [file size "$file"]
|
|
log "In use $file size $csize" 2
|
|
lappend flist [list $file $csize]
|
|
}
|
|
sleep 2
|
|
# Check for files size change over last few seconds - indicates recording in progress
|
|
foreach line $flist {
|
|
lassign $line file csize
|
|
set nsize [file size "$file"]
|
|
log "In use $file size $csize -> $nsize" 2
|
|
if {$csize == $nsize} {
|
|
log "In use $file not recording -quit" 1
|
|
return
|
|
} else { log "In use $file is recording OK" 2 }
|
|
}
|
|
}
|
|
|
|
#
|
|
# # Need check for within a reminder period?
|
|
|
|
set now [clock seconds]
|
|
set events [rsv list tbl_reservation \
|
|
" where ersvtype = 2 and nsttime < $now and nsttime + nduration > $now "]
|
|
if {[llength $events]} {
|
|
foreach event $events {
|
|
log [concat \
|
|
"Reminder '[$event name]' " \
|
|
"on [$event channel_name] at " \
|
|
"[clock format [$event get nsttime] -format {%H:%M}]" \
|
|
" duration [clock format [$event get nduration] -format {%H:%M}]" \
|
|
] 2
|
|
}
|
|
log "Current reminders= [llength $events] - quit" 1
|
|
return 0
|
|
} else {log "No reminders found" 2}
|
|
|
|
|
|
# if {idle time < now - chaseget awakened time} {
|
|
# # Buttons pressed since woken
|
|
# if {last button != 'power'} {
|
|
# Clear awakend by chaseget status
|
|
# exit
|
|
# }
|
|
# }
|
|
|
|
set idletime [system idletime]
|
|
set now [clock seconds]
|
|
if {$idletime < $now - $::awakened} {
|
|
set lastir 0
|
|
if {[file readable /tmp/.lastir]} {
|
|
set lastir [file read /tmp/.lastir -nonewline]
|
|
}
|
|
# Buttons pressed since woken
|
|
log "Remote Buttons pressed (last button $lastir) - quit" 1
|
|
clear_awakened_status
|
|
return 0
|
|
}
|
|
|
|
|
|
# # No current activity since awakened
|
|
#
|
|
# ir power
|
|
# Clear awakend by chaseget status
|
|
|
|
# Check system hasn't re-entered standby of it its own accord whilst we werent looking
|
|
if {[system instandby]} {
|
|
log "System in standby - quit" 1
|
|
clear_awakened_status
|
|
exit
|
|
}
|
|
|
|
|
|
log "System power Off attempted, ChaseGet power On was at [clock format $::awakened -format %T] " 0
|
|
clear_awakened_status
|
|
catch {exec ir POWER}
|
|
|
|
}
|
|
|
|
|
|
switch -- $file {
|
|
|
|
"-standby" {
|
|
standby_check $fs
|
|
}
|
|
|
|
"--help" -
|
|
"-help" -
|
|
"--h" -
|
|
"-h" -
|
|
"" {
|
|
help_text
|
|
}
|
|
|
|
default {
|
|
getfile $file $fs
|
|
}
|
|
}
|
|
exit
|