flexview/webif/plugin/flexview/genJSON.jim

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"