359 lines
9.1 KiB
Plaintext
Executable File
359 lines
9.1 KiB
Plaintext
Executable File
#!/mod/bin/jimsh
|
|
######
|
|
# FlexView - Generate directory tree in jqGrid JSON format
|
|
# Author: MymsMan, 2015/16
|
|
######
|
|
|
|
|
|
package require cgi
|
|
source /mod/webif/lib/setup
|
|
require ts.class pretty_size system.class settings.class escape browse.class \
|
|
plugin epg.class classdump
|
|
|
|
set dustbin [system dustbin 1]
|
|
set root [system mediaroot]
|
|
set nicesplice [system pkginst nicesplice]
|
|
set model [system model]
|
|
set dlnaok [system dlnastatus]
|
|
|
|
set ignore {.nts .thm .hmi}
|
|
set include {.ts .avi .mpg .mpeg .wmv .mkv .mp3 .mp4 .mov .hmt .m4v .m4a}
|
|
|
|
# logging options
|
|
if {[lindex $argv 0] eq "-d"} {
|
|
set argv [lrange $argv 1 end]
|
|
set loglevel 2
|
|
} else {
|
|
# Use same logging option as auto log
|
|
set settings [settings]
|
|
set loglevel [$settings _nval_setting "autolog"]
|
|
}
|
|
|
|
|
|
proc log {msg {level 2}} {
|
|
if {$level > $::loglevel} return
|
|
system plog flexview $msg
|
|
}
|
|
######
|
|
# Common JSON code.
|
|
# Author: Martin Wink, 2014.
|
|
######
|
|
|
|
#
|
|
# Initialize a map from control characters to JSON escaped characters.
|
|
# Initially all non-null control characters to \u00xx sequences.
|
|
for {set i 1} {$i < 32} {incr i} {
|
|
set json_escape_map([format %c $i]) \\u[format %04x $i]
|
|
}
|
|
# Then overwrite certain well known control characters with shorter versions.
|
|
set json_escape_map([format %c 8]) \\b; # backspace
|
|
set json_escape_map([format %c 9]) \\t; # tab
|
|
set json_escape_map([format %c 10]) \\n; # lf
|
|
set json_escape_map([format %c 12]) \\f; # ff
|
|
set json_escape_map([format %c 13]) \\r; # cr
|
|
# Other special sequences
|
|
set json_escape_map(\") {\"}
|
|
set json_escape_map(\\) {\\}
|
|
set json_escape_map(/) {\/}
|
|
|
|
#
|
|
# Escape a string for inclusion in JSON output.
|
|
#
|
|
proc escape_json_string { in } {
|
|
return [string map $::json_escape_map $in]
|
|
}
|
|
###### end Common JSON code.
|
|
|
|
set lbrc "\{"
|
|
set rbrc "\}"
|
|
set lbrk "\["
|
|
set rbrk "\]"
|
|
set quot "\""
|
|
set nul ""
|
|
set comma ","
|
|
|
|
# id's are used as html id so shouldn't contain space, dot etc to avoid confusing jquery
|
|
# convert most specials to -
|
|
for {set i 1} {$i < 48} {incr i} {
|
|
set id_escape_map([format %c $i]) {-}
|
|
}
|
|
for {set i 58} {$i < 65} {incr i} {
|
|
set id_escape_map([format %c $i]) {-}
|
|
}
|
|
for {set i 91} {$i < 95} {incr i} {
|
|
set id_escape_map([format %c $i]) {-}
|
|
}
|
|
for {set i 123} {$i < 128} {incr i} {
|
|
set id_escape_map([format %c $i]) {-}
|
|
}
|
|
|
|
proc idQstring {str} {
|
|
# Return quoted and escaped id string
|
|
global quot
|
|
return "$quot[string map $::id_escape_map $str]$quot"
|
|
}
|
|
|
|
proc Qstring {str} {
|
|
# Return quoted and escaped string
|
|
global quot
|
|
return "$quot[escape_json_string $str]$quot"
|
|
}
|
|
|
|
proc json-key {key value {sep ","}} {
|
|
global quot
|
|
set jkey "$sep $quot$key$quot: $value"
|
|
return $jkey
|
|
}
|
|
|
|
proc p1l {str} {
|
|
puts -nonewline $str
|
|
}
|
|
|
|
proc pnl {str} {
|
|
puts $str
|
|
}
|
|
|
|
proc genDirList {dir ddir {depth 0} {expand 0} {i 0} {mode "children"}} {
|
|
global lbrc rbrc lbrk rbrk quot nul comma
|
|
|
|
if {[catch {set dsize [exec /mod/bin/busybox/du -s "$dir/"]} msg]} {
|
|
puts "Error, $dir, $msg"
|
|
return
|
|
}
|
|
lassign $dsize dsize
|
|
set psize [pretty_size $($dsize * 1024)]
|
|
|
|
|
|
|
|
set alist {}
|
|
set dlist {}
|
|
set flist {}
|
|
foreach entry [lsort [readdir -nocomplain $dir]] {
|
|
if {[string index $entry 0] eq "."} {
|
|
lappend alist $entry
|
|
continue
|
|
}
|
|
if {[file isdirectory "$dir/$entry"]} {
|
|
lappend dlist $entry
|
|
if {$depth <= 0} {
|
|
# quit if not loading
|
|
break
|
|
}
|
|
} else {
|
|
lappend flist $entry
|
|
}
|
|
}
|
|
|
|
set ssep $nul
|
|
if {$mode eq "parent"} {
|
|
# Basic fields for all directories
|
|
p1l [json-key title [Qstring $ddir] $lbrc]
|
|
set ssep $comma
|
|
|
|
p1l [json-key id [idQstring $dir] ]
|
|
p1l [json-key dir [Qstring $dir] ]
|
|
p1l [json-key level $i]
|
|
if {$i} {
|
|
p1l [json-key parent [idQstring [file dirname $dir]] ]
|
|
} else {
|
|
p1l [json-key parent null ]
|
|
}
|
|
p1l [json-key listloaded 0]
|
|
p1l [json-key opt [Qstring dopt] ]
|
|
p1l [json-key dsize $dsize ]
|
|
p1l [json-key psize [Qstring $psize] ]
|
|
|
|
# If subdirectories exist show whether node expanded or not
|
|
if {[llength $dlist]} {
|
|
p1l [json-key isLeaf false ]
|
|
if {$expand >0} {
|
|
p1l [json-key expanded true ]
|
|
} else {
|
|
p1l [json-key expanded false ]
|
|
}
|
|
} else {
|
|
p1l [json-key isLeaf true ]
|
|
}
|
|
|
|
# For each hidden file (dir attribute) create a flag (and content?) column
|
|
foreach attr $alist {
|
|
p1l [json-key [string range $attr 1 end] 1]
|
|
}
|
|
|
|
|
|
pnl "$rbrc"
|
|
}
|
|
|
|
# Recurse into subdirectories if they are to be expanded
|
|
if {[llength $dlist] && $depth > 0} {
|
|
incr depth -1
|
|
incr expand -1
|
|
incr i
|
|
|
|
foreach subd $dlist {
|
|
p1l $ssep
|
|
genDirList "$dir/$subd" $subd $depth $expand $i parent
|
|
set ssep $comma
|
|
}
|
|
|
|
# if {[llength $flist]} {
|
|
# p1l "$ssep [json-key title [Qstring -Files-] $lbrc]"
|
|
# pnl "[json-key folder false $comma] $rbrc"
|
|
# }
|
|
}
|
|
|
|
}
|
|
|
|
proc genFileDetails {dir file} {
|
|
global lbrc rbrc lbrk rbrk quot nul comma dinuse
|
|
|
|
set ext [string tolower [file extension $file]]
|
|
set base [file rootname $file]
|
|
|
|
set fsize [file size "$dir/$file"]
|
|
set psize [pretty_size $fsize]
|
|
|
|
# Basic attributes for all file types
|
|
p1l [json-key id [idQstring "$dir/$file"] $lbrc ]
|
|
p1l [json-key fname [Qstring $file] ]
|
|
p1l [json-key dir [Qstring "$dir"] ]
|
|
p1l [json-key sel false]
|
|
p1l [json-key showrow true]
|
|
p1l [json-key fsize $fsize ]
|
|
p1l [json-key psize [Qstring $psize] ]
|
|
|
|
if {$ext eq ".ts"} {
|
|
set omenu opt
|
|
set type ts
|
|
} else {
|
|
set omenu oopt
|
|
set type gen
|
|
}
|
|
|
|
p1l [json-key ftype [Qstring $type] ]
|
|
pnl [json-key opt [Qstring $omenu] ]
|
|
|
|
if {[file exists "$dir/$base.hmt"]} {
|
|
# Generate hmt related attributes
|
|
# Use HMT utility rather than TS class so we can handle orphaned HMT (and write less code)
|
|
set line [exec hmt -p "$dir/$file"]
|
|
set vars [split $line "\t"]
|
|
|
|
set vnames {title synopsis definition channel_num channel_name
|
|
start end flags_list guidance bookmarks schedstart scheddur
|
|
genre resume status seriesnum episodenum episodetot}
|
|
|
|
set ix 0
|
|
foreach vn $vnames {
|
|
p1l [json-key $vn [Qstring [lindex $vars $ix]] ]
|
|
set $vn [lindex $vars $ix]
|
|
incr ix
|
|
}
|
|
|
|
if {[string is integer -strict $end]} {
|
|
# calc duration
|
|
set duration $($end-$start)
|
|
p1l [json-key duration $duration ]
|
|
}
|
|
|
|
if {$flags_list != ""} {
|
|
# Individual Flag entries
|
|
set flags [split [string range $flags_list 0 end-1] ,]
|
|
foreach flag $flags {
|
|
if {$flag in {HD SD {Unlimited Copies}}} {continue}
|
|
p1l [json-key $flag 1]
|
|
}
|
|
# Need to special case Decrypt since it is the absence of ODE flag
|
|
if {"ODEncrypted" ni $flags} {p1l [json-key Decrypted 1]}
|
|
}
|
|
}
|
|
|
|
|
|
if {[file exists "$dir/$base.thm"]} {
|
|
# Generate thumbnail related attributes
|
|
p1l [json-key thmok 1]
|
|
}
|
|
|
|
# Possibly use SQL call to retrieve all DLNA for directory?
|
|
set dlnaIndex [system dlnaurl [file normalize $dir/$file]]
|
|
if {$dlnaIndex != ""} {
|
|
p1l [json-key dlna 1]
|
|
p1l [json-key dlnaIndex [Qstring $dlnaIndex] ]
|
|
}
|
|
|
|
# Check for file inuse
|
|
if {$file in $dinuse} {
|
|
p1l [json-key inuse 1]
|
|
}
|
|
|
|
pnl "$rbrc"
|
|
|
|
}
|
|
|
|
proc genFileList {dirlist } {
|
|
global lbrc rbrc lbrk rbrk quot nul comma dinuse
|
|
set ssep " "
|
|
set dirl [split $dirlist {,}]
|
|
|
|
foreach dir $dirl {
|
|
set alist {}
|
|
set dlist {}
|
|
set flist {}
|
|
set dinuse [system dirinuse $dir]
|
|
|
|
foreach entry [lsort [readdir -nocomplain $dir]] {
|
|
if {[string index $entry 0] eq "."} {
|
|
lappend alist $entry
|
|
continue
|
|
}
|
|
if {[file isdirectory "$dir/$entry"]} {
|
|
lappend dlist $entry
|
|
} else {
|
|
set ext [string tolower [file extension $entry]]
|
|
if {$ext ni $::include} { continue }
|
|
set base [file rootname $entry]
|
|
if {$ext eq ".hmt"} {
|
|
if {[file exists "$dir/$base.ts"]} { continue }
|
|
}
|
|
lappend flist $entry
|
|
}
|
|
}
|
|
|
|
|
|
if {[llength $flist]} {
|
|
|
|
foreach file $flist {
|
|
p1l $ssep
|
|
genFileDetails $dir $file
|
|
set ssep $comma
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
httpheader "application/json"
|
|
|
|
set dir [cgi_get dir "/media"]
|
|
set dir [cgi_get dir $root]
|
|
set level [cgi_get n_level 0]
|
|
set mode [cgi_get mode "parent"]
|
|
set mode [cgi_get mode "filelist"]
|
|
|
|
pnl "[json-key rows $lbrk $lbrc]"
|
|
|
|
set start [clock milliseconds]
|
|
if {$mode == "filelist"} {
|
|
genFileList $dir
|
|
} else {
|
|
genDirList $dir [file tail $dir] 1 1 $level $mode
|
|
}
|
|
set end [clock milliseconds]
|
|
set elapse $(double($end-$start)/1000.0)
|
|
log "$mode | $elapse | $dir" 0
|
|
|
|
pnl "$rbrk $rbrc"
|
|
|