897 lines
27 KiB
PHP
897 lines
27 KiB
PHP
<?
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Yuba RTC Browser
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
$browser_version = "0.7.12.6";
|
|
|
|
require "togggle.php";
|
|
require "lib/ref/ref.php";
|
|
|
|
ref::config('expLvl', 1);
|
|
ref::config('validHtml', TRUE);
|
|
|
|
$db_dir = "data/skim";
|
|
$icon_size = 96;
|
|
$pad = 40;
|
|
$border_tools = array("sips","sox","ffmpeg","ql-thumbnail");
|
|
$hidefiles = array(".DS_Store");
|
|
|
|
?>
|
|
|
|
<html>
|
|
<head>
|
|
<meta charset='UTF-8'>
|
|
<style>
|
|
|
|
html { font-family: Helvetica; word-wrap: break-all; word-break: break-all; }
|
|
|
|
table.outlined tbody > tr > td > div { outline: 1px solid purple; }
|
|
table.outlined tbody > tr > td > div > div { outline: 1px solid orange; }
|
|
table.outlined tbody > tr > td > div > div > div { outline: 1px solid pink; }
|
|
table.outlined tbody > tr > td > div > div > div > div { outline: 1px solid yellow; }
|
|
table.outlined tbody > tr > td > div > div > div > div > div { outline: 1px solid red; }
|
|
|
|
table.file td { width: 33%; }
|
|
table.dir td:last-of-type { width: 22%; }
|
|
|
|
div#exectime { position: absolute; right: 8px; top: 8px; }
|
|
|
|
div.container { display: flex;
|
|
flex-flow: row wrap;
|
|
justify-content: center;
|
|
}
|
|
|
|
div.item { width: <?=$icon_size+$pad;?>px;
|
|
height: <?=$icon_size+$pad*2;?>px;
|
|
text-align: center;
|
|
}
|
|
|
|
div.item { font-size: 11px; }
|
|
|
|
div.ibox { display: table;
|
|
height: calc(100% - <?=$pad;?>px);
|
|
width: 100%;
|
|
}
|
|
|
|
div.iibox { display: table-cell;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
div.diibox { display: table-cell;
|
|
vertical-align: middle;
|
|
background: url("/icons/directory.png");
|
|
background-repeat: no-repeat;
|
|
background-size: <?=$icon_size;?>px;
|
|
background-position: center;
|
|
}
|
|
|
|
div.flexfill { width: <?=$icon_size+$pad;?>px; height: 1px; }
|
|
div.aborted { text-decoration: line-through; }
|
|
.slider, .slow_slider { position: absolute !important; top: 50px; right: 10px; width: 200px; }
|
|
.controls { position: absolute !important; top: 85px; right: 10px; width: 30px; }
|
|
form { margin-block-end: 0em !important; }
|
|
|
|
.arrow { font-size: 8px; opacity: .7; }
|
|
img.tiny { vertical-align: middle; width: 18px; height: 18px; margin: 0px 4px 0px 0px; }
|
|
|
|
.red { background-color: #ea6c60; }
|
|
.green { background-color: #9cde70; }
|
|
.blue { background-color: #6dbcf4; }
|
|
.yellow { background-color: #f8d657; }
|
|
.orange { background-color: #f1ad4e; }
|
|
.purple { background-color: #ca94e2; }
|
|
.gray { background-color: #a4a4a7; }
|
|
|
|
.tag {
|
|
height: 14px;
|
|
width: 14px;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
vertical-align: middle;
|
|
font-size: 500%;
|
|
position: relative;
|
|
display: inline-block;
|
|
margin-left: -6px;
|
|
}
|
|
|
|
div.size { color: grey; margin-top: 3px; font-size: 9px; }
|
|
|
|
img#thumb { padding: 6px;
|
|
outline: 1px solid gainsboro;
|
|
outline-offset: -7px;
|
|
border: 1px solid gainsboro;
|
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
img#item { float: left; margin-right: 10px; width: 32px; height: 32px; }
|
|
img { margin-bottom: 8px; }
|
|
|
|
div.title { padding: 0px 10px 0px 10px; }
|
|
|
|
div.fileinfo { font-size: 12px; }
|
|
div.fileinfo span.title { display: table-cell; font-weight: bold; width: 200px; }
|
|
div.fileinfo span.value { display: table-cell; }
|
|
|
|
div.dcontainer { margin: 10px; margin-bottom: 20px;}
|
|
|
|
a.hidden img { opacity: .3; }
|
|
|
|
iframe { width: 425px; height: 550px; padding: 6px; border: 1px solid black; }
|
|
|
|
div.dblist { display: none; }
|
|
|
|
</style>
|
|
|
|
<script src="/lib/ref/ref.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/4.1.5/lazysizes.min.js"></script>
|
|
|
|
<link type="text/css" rel="stylesheet" href="/lib/ref/ref.css">
|
|
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css">
|
|
|
|
<script type="text/javascript">
|
|
|
|
function wrapImg(xfactor) {
|
|
var maxWidth = 0;
|
|
var maxHeight = 0;
|
|
$('div.item').each(function() {
|
|
$(this).width((<?=$icon_size?>*xfactor)+<?=$pad;?>);
|
|
$(this).height((<?=$icon_size?>*xfactor)+<?=$pad*2;?>);
|
|
img = $(this).find('img');
|
|
swidth = $(img).data('width')*xfactor;
|
|
sheight = $(img).data('height')*xfactor;
|
|
$(img).width(swidth);
|
|
$(img).height(sheight);
|
|
fileinfo = $(this).find('div.title');
|
|
if (xfactor > 2) {
|
|
$(this).css("font-size", 16);
|
|
} else if (xfactor < .7) {
|
|
$(this).css("font-size", 9);
|
|
} else {
|
|
$(this).css("font-size", 12);
|
|
}
|
|
})
|
|
$('div.flexfill').width((<?=$icon_size?>*xfactor)+<?=$pad;?>);
|
|
}
|
|
|
|
$(function(){
|
|
|
|
$("h2").click(function(){
|
|
$(this).next('.dblist').toggle();
|
|
});
|
|
|
|
$(".toggler").click(function(){
|
|
$('.dblist').toggle();
|
|
});
|
|
|
|
$(".info").click(function(){
|
|
$('.sidebar').toggle();
|
|
});
|
|
|
|
$(".slider").slider({
|
|
step: .01,
|
|
min: .5,
|
|
max: 3,
|
|
value: 1,
|
|
slide: function(event, ui) {
|
|
wrapImg(ui.value);
|
|
},
|
|
});
|
|
|
|
$(".slow_slider").slider({
|
|
step: .25,
|
|
min: .5,
|
|
max: 3,
|
|
value: 1,
|
|
stop: function(event, ui) {
|
|
wrapImg(ui.value);
|
|
},
|
|
});
|
|
|
|
$("select").on("change", function () {
|
|
var db = $(this).val();
|
|
var href = new URL(window.location.href);
|
|
href.searchParams.set('db', db);
|
|
window.location = href;
|
|
});
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<?
|
|
|
|
// Functions
|
|
|
|
function get_gps($gps_pos) {
|
|
|
|
# convert:
|
|
# 40 deg 44' 49.36" N, 73 deg 56' 28.18" W
|
|
# to:
|
|
# 40.7470444,-073.9411611
|
|
|
|
$parts = explode(" ",str_replace(array("deg ",",","'","\""),"",$gps_pos));
|
|
|
|
$lat_deg = $parts[0];
|
|
$lat_min = $parts[1];
|
|
$lat_sec = $parts[2];
|
|
$lat_dir = $parts[3];
|
|
|
|
$lon_deg = $parts[4];
|
|
$lon_min = $parts[5];
|
|
$lon_sec = $parts[6];
|
|
$lon_dir = $parts[7];
|
|
|
|
if ($lat_dir == "N") {
|
|
$lat_sin = "+";
|
|
} else {
|
|
$lat_sin = "-";
|
|
}
|
|
|
|
if ($lon_dir == "E") {
|
|
$lon_sin = "+";
|
|
} else {
|
|
$lon_sin = "-";
|
|
}
|
|
|
|
$latitiude = $lat_sin.($lat_deg+($lat_min/60)+($lat_sec/3600));
|
|
$longitude = $lon_sin.($lon_deg+($lon_min/60)+($lon_sec/3600));
|
|
|
|
return $latitiude.",".$longitude;
|
|
|
|
}
|
|
|
|
function is_serial($string) {
|
|
return (@unserialize($string) !== false || $string == 'b:0;');
|
|
}
|
|
|
|
function human_filesize($bytes, $decimals = 2) {
|
|
$size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
|
|
$factor = floor((strlen($bytes) - 1) / 3);
|
|
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor];
|
|
}
|
|
|
|
function utf8_for_xml($string) {
|
|
return preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string);
|
|
}
|
|
|
|
class plistParser extends XMLReader {
|
|
public function parseString($string) { $this->XML($string); return $this->process(); }
|
|
private function process() {
|
|
$this->read();
|
|
if($this->nodeType !== XMLReader::DOC_TYPE || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 2); }
|
|
if(!$this->next("plist") || $this->nodeType !== XMLReader::ELEMENT || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 3); }
|
|
$plist = array(); while($this->read()) { if($this->nodeType == XMLReader::ELEMENT) { $plist[] = $this->parse_node(); } }
|
|
if(count($plist) == 1 && $plist[0]) { return $plist[0]; } else { return $plist; }
|
|
}
|
|
private function parse_node() {
|
|
if($this->nodeType !== XMLReader::ELEMENT) return;
|
|
switch($this->name) {
|
|
case 'data': return base64_decode($this->getNodeText()); break;
|
|
case 'real': return floatval($this->getNodeText()); break;
|
|
case 'string': return $this->getNodeText(); break;
|
|
case 'integer': return intval($this->getNodeText()); break;
|
|
case 'date': return $this->getNodeText(); break;
|
|
case 'true': return true; break;
|
|
case 'false': return false; break;
|
|
case 'array': return $this->parse_array(); break;
|
|
case 'dict': return $this->parse_dict(); break;
|
|
//default: throw new Exception(sprintf("Not a valid plist. %s is not a valid type", $this->name), 4);
|
|
}
|
|
}
|
|
private function parse_dict() {
|
|
$array = array(); $this->nextOfType(XMLReader::ELEMENT);
|
|
do { if($this->nodeType !== XMLReader::ELEMENT || $this->name !== "key") { if(!$this->next("key")) { return $array; } } $key = $this->getNodeText(); $this->nextOfType(XMLReader::ELEMENT); $array[$key] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
|
|
while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "dict")); return $array;
|
|
}
|
|
private function parse_array() {
|
|
$array = array(); $this->nextOfType(XMLReader::ELEMENT);
|
|
do { $array[] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
|
|
while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "array")); return $array;
|
|
}
|
|
private function getNodeText() { $string = $this->readString(); $this->nextOfType(XMLReader::END_ELEMENT); return $string; }
|
|
private function nextOfType() { $types = func_get_args(); $this->read(); while($this->nodeType && !(in_array($this->nodeType, $types))) { $this->read(); } }
|
|
private function isNodeOfTypeName($type, $name) { return $this->nodeType === $type && $this->name === $name; }
|
|
}
|
|
|
|
function breadcrumbs($zpath, $pathname) {
|
|
if (!$pathname) {
|
|
return array(array(null,basename($zpath)));
|
|
} else {
|
|
$pathname_adjusted = str_replace($zpath."/", "", $pathname);
|
|
$parts = explode("/", $pathname_adjusted);
|
|
$i = count($parts);
|
|
while ($i) {
|
|
$search_path = $zpath."/".implode("/", array_slice($parts, 0, $i));
|
|
if ($i == count($parts)) {
|
|
$result[] = array(null, basename($search_path));
|
|
} else {
|
|
$result[] = array(md5($search_path), basename($search_path));
|
|
}
|
|
$i--;
|
|
}
|
|
$result[] = array("",basename($zpath));
|
|
return array_reverse($result);
|
|
}
|
|
}
|
|
|
|
function shortlabel($filename, $max = 40) {
|
|
if (strlen($filename) > $max) {
|
|
$prefix = substr($filename, 0, floor($max*.66));
|
|
$suffix = substr($filename, -floor($max*.33));
|
|
$return = $prefix."...".$suffix;
|
|
} else {
|
|
$return = $filename;
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
function mb_shortlabel($filename, $max = 40) {
|
|
if (mb_strlen($filename, mb_detect_encoding($filename)) > $max) {
|
|
// more work is needed to figure out what is going on with non EN chars
|
|
//echo "(-) ";
|
|
$prefix = mb_substr($filename, 0, floor($max*.66), mb_detect_encoding($filename));
|
|
$suffix = mb_substr($filename, -floor($max*.33));
|
|
$return = $prefix."...".$suffix;
|
|
} else {
|
|
$return = $filename;
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
function findicon($filename) {
|
|
$ext = pathinfo($filename)['extension'];
|
|
$good = "icons/null.png";
|
|
foreach (glob("icons/*.png") as $file) {
|
|
if (pathinfo($file)['filename'] == $ext) {
|
|
$good = $file;
|
|
}
|
|
}
|
|
return $good;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
$db_file = $_GET['db'];
|
|
$pid = $_GET['pid'];
|
|
$search = $_POST['query'];
|
|
$parser = new plistParser();
|
|
|
|
if ($db_file) {
|
|
|
|
if (!is_readable($db_file)) { echo "can't read db file"; die; }
|
|
|
|
$dbo = new PDO("sqlite:".$db_file);
|
|
$dbp = new PDO("sqlite:".dirname($db_file)."/pool.sqlite3");
|
|
$dbo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
$dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
$dbp->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
$dbp->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
// Get zpath
|
|
|
|
$zpath = $dbo->query("SELECT zpath FROM _skim")->fetch()['zpath'];
|
|
$skim_version = $dbo->query("SELECT version FROM _skim")->fetch()['version'];
|
|
|
|
// Check for initial view
|
|
|
|
$view = $dbo->query("SELECT * FROM _skim")->fetch();
|
|
|
|
if (!$pid) {
|
|
$pid = $dbo->query("SELECT pid FROM family WHERE (rowid=2)")->fetch()['pid'];
|
|
// handle special strings
|
|
$view['opts'] = unserialize($view['opts']);
|
|
$view['qlmanage'] = array($view['qlmanage']);
|
|
$view['profile'] = array($view['profile']);
|
|
if ($view['details']) {
|
|
$view['details'] = unserialize($view['details']);
|
|
}
|
|
if (substr($view['disks'],0,5) == "<?xml") {
|
|
$view['disks'] = $parser->parseString(utf8_for_xml($view['disks']));
|
|
} else {
|
|
$view['disks'] = $view['disks'];
|
|
}
|
|
if (substr($view['diskutil'],0,5) == "<?xml") {
|
|
$view['diskutil'] = $parser->parseString(utf8_for_xml($view['diskutil']));
|
|
} else {
|
|
$view['diskutil'] = $view['diskutil'];
|
|
}
|
|
if ($view['vdisks']) {
|
|
$view['vdisks'] = $parser->parseString(utf8_for_xml($view['vdisks']));
|
|
}
|
|
if ($view['hdiutil']) {
|
|
$view['hdiutil'] = $parser->parseString(utf8_for_xml($view['hdiutil']));
|
|
}
|
|
$view['Type'] = "dir";
|
|
} else {
|
|
$view = $dbo->query("SELECT rowid, * FROM files WHERE (pid='".$pid."')")->fetch();
|
|
if (is_serial($view['stat'])) {
|
|
$view['stat'] = unserialize($view['stat']);
|
|
}
|
|
$dirmdls = $dbo->query("SELECT rowid, * FROM mdls WHERE (rowid='".$view['rowid']."')")->fetch();
|
|
}
|
|
|
|
// Header
|
|
|
|
echo "<a href='?db='><img class='tiny' src='icons/home.png'>Home</a> <span class='arrow'>► </span>";
|
|
$dbs = glob(pathinfo($_GET['db'],PATHINFO_DIRNAME)."/????-??-??_??-??-??.sqlite3");
|
|
rsort($dbs);
|
|
echo "<select>";
|
|
foreach ($dbs as $db) {
|
|
echo "<option value='".$db."'";;
|
|
if ($_GET['db'] == $db) {
|
|
echo " selected";
|
|
}
|
|
echo ">".basename($db)."</option>";
|
|
}
|
|
echo "</select>";
|
|
echo "<hr>";
|
|
|
|
// Breadcrumbs
|
|
|
|
$crumb = breadcrumbs($zpath,$view['Pathname']);
|
|
$xc = "";
|
|
|
|
foreach ($crumb as $myparts) {
|
|
if ($myparts[0] === null) {
|
|
if ($view['Type'] == "dir") {
|
|
$myicon = "icons/directory.png";
|
|
} else {
|
|
$myicon = "icons/null.png";
|
|
}
|
|
$xc .= "<img class='tiny' src='".$myicon."'>".$myparts[1];
|
|
} else {
|
|
$xc .= "<a href='?db=".$db_file."&pid=".$myparts[0]."'><img class='tiny' src='icons/directory.png'>".$myparts[1]."</a> <span class='arrow'>►</span> ";
|
|
}
|
|
}
|
|
if (!$search) { echo $xc; echo "<hr>"; }
|
|
|
|
// Search
|
|
|
|
echo "<form action='' method='post'><input type='text' name='query' size='50' value='".$search."'><input type='submit' value='query'></form>";
|
|
|
|
echo "<hr>";
|
|
|
|
$array = $dbo->query("SELECT children FROM family WHERE (pid='".$pid."')")->fetch()['children'];
|
|
|
|
$children = unserialize($array);
|
|
|
|
if (!$children && !$search) {
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// File view
|
|
|
|
$skim_version = $dbo->query("SELECT version FROM _skim")->fetch()['version'];
|
|
$spotlight_status = $dbo->query("SELECT mdutil FROM _skim")->fetch()['mdutil'];
|
|
|
|
$row_a = $dbo->query("SELECT rowid, * FROM files WHERE (pid='".$pid."')")->fetch();
|
|
if (!$row_a) { // this file doesn't exist in this version of the db
|
|
echo "<meta http-equiv='refresh' content='0; URL=".$_SERVER['REQUEST_URI']."&pid=' />";
|
|
}
|
|
|
|
echo "<table class='file'><tr>";
|
|
|
|
echo "<td valign='top'>";
|
|
if (is_serial($row_a['stat'])) {
|
|
$row_a['stat'] = unserialize($row_a['stat']);
|
|
}
|
|
|
|
if (!strpos($spotlight_status,"disabled")) {
|
|
|
|
$row_b = $dbo->query("SELECT * FROM mdls WHERE (rowid='".$row_a['rowid']."')")->fetch();
|
|
$row_e = @$dbo->query("SELECT * FROM milk WHERE (rowid='".$row_a['rowid']."')")->fetch();
|
|
|
|
}
|
|
|
|
if (version_compare($skim_version,"0.7.7b") > -1) {
|
|
|
|
// newer version stores rowid rather than 0 or 1 for has_exif etc
|
|
|
|
if (isset($row_a['has_exif'])) {
|
|
$row_c = $dbp->query("SELECT * FROM exiftool WHERE (rowid='".$row_a['has_exif']."')")->fetch();
|
|
}
|
|
if (isset($row_a['has_mediainfo'])) {
|
|
$row_d = $dbp->query("SELECT * FROM mediainfo WHERE (rowid='".$row_a['has_mediainfo']."')")->fetch();
|
|
}
|
|
|
|
} else {
|
|
|
|
// fetch exif and mediainfo by slower fid
|
|
|
|
$row_c = $dbp->query("SELECT * FROM exiftool WHERE (fid='".$row_a['fid']."')")->fetch();
|
|
$row_d = $dbp->query("SELECT * FROM mediainfo WHERE (fid='".$row_a['fid']."')")->fetch();
|
|
|
|
}
|
|
|
|
if ($row_a['thumb_filename']) {
|
|
$width = $row_a['thumb_width'];
|
|
$height = $row_a['thumb_height'];
|
|
$realfile = dirname($db_file).$row_a['thumb_filename'];
|
|
if (array_key_exists("thumb_tool",$row_a)) {
|
|
if (in_array($row_a['thumb_tool'], $border_tools)) {
|
|
// put a border around images that are not icons
|
|
$border = "id='thumb'";
|
|
} else {
|
|
$border = "";
|
|
}
|
|
} else {
|
|
$border = "id='thumb'";
|
|
}
|
|
$icon = "<img ".$border." src='".$realfile."' width='".$width."' height='".$height."' class='lazyload'>";
|
|
} elseif ($row_a['Type'] == "dir") {
|
|
$icon = "<img src='/icons/directory.png' width='512' height='512'>";
|
|
} else {
|
|
$icon = "<img src='".findicon($row_a['Filename'])."' width='512' height='512'>";
|
|
}
|
|
|
|
if ($row_a['contents_filename']) {
|
|
$realcfile = dirname($db_file).$row_a['contents_filename'];
|
|
$icon = "<iframe src='/handle_zip.php?file=".$realcfile."'></iframe>";
|
|
}
|
|
|
|
echo $icon;
|
|
|
|
// debug milk
|
|
|
|
if (count(@$row_e) > 1) {
|
|
echo "<div class='dcontainer'>";
|
|
foreach($row_e as $title => $val) {
|
|
if ($title == "GPS" && $val) {
|
|
if (strpos($val,"deg") != false) {
|
|
$val = get_gps($val);
|
|
}
|
|
$print = "<a href='https://www.google.com/maps?q=".$val."' target='_blank'>".$val."</a>";
|
|
} else {
|
|
$print = $val;
|
|
}
|
|
echo "<div class='fileinfo'><span class='title'>".$title."</span><span class='value'>".$print."</span></div>";
|
|
}
|
|
echo "</div>";
|
|
}
|
|
|
|
// debug file times
|
|
|
|
$fileinfo['atime (php)'] = date("F jS, Y h:i:s",$row_a['ATime']);
|
|
$fileinfo['mtime (php)'] = date("F jS, Y h:i:s",$row_a['MTime']);
|
|
$fileinfo['ctime (php)'] = date("F jS, Y h:i:s",$row_a['CTime']);
|
|
|
|
if ($row_a['stat']) {
|
|
|
|
if (is_array($row_a['stat'])) {
|
|
|
|
$fileinfo['atime (stat)'] = date("F jS, Y h:i:s",$row_a['stat']['st_atime']);
|
|
$fileinfo['mtime (stat)'] = date("F jS, Y h:i:s",$row_a['stat']['st_mtime']);
|
|
$fileinfo['ctime (stat)'] = date("F jS, Y h:i:s",$row_a['stat']['st_ctime']);
|
|
$fileinfo['btime (stat)'] = date("F jS, Y h:i:s",$row_a['stat']['st_birthtime']);
|
|
|
|
} else {
|
|
|
|
// parse old version stat
|
|
preg_match('/^Access: ([^\r\n]*)/m', $row_a['stat'], $access);
|
|
$fileinfo['atime (stat)'] = date("F jS, Y h:i:s",strtotime($access[1]));
|
|
preg_match('/^Modify: ([^\r\n]*)/m', $row_a['stat'], $modify);
|
|
$fileinfo['mtime (stat)'] = date("F jS, Y h:i:s",strtotime($modify[1]));
|
|
preg_match('/^Change: ([^\r\n]*)/m', $row_a['stat'], $change);
|
|
$fileinfo['ctime (stat)'] = date("F jS, Y h:i:s",strtotime($change[1]));
|
|
|
|
}
|
|
}
|
|
|
|
if ($row_b['spotlight']) {
|
|
$row_b['spotlight'] = $parser->parseString(utf8_for_xml($row_b['spotlight']));
|
|
$fileinfo['added (mdls)'] = date("F jS, Y h:i:s",$row_b['DateAdded']);
|
|
$fileinfo['mtime (mdls)'] = date("F jS, Y h:i:s",$row_b['ContentModificationDate']);
|
|
$fileinfo['btime (mdls)'] = date("F jS, Y h:i:s",$row_b['ContentCreationDate']);
|
|
}
|
|
|
|
ksort($fileinfo);
|
|
|
|
echo "<div class='dcontainer'>";
|
|
|
|
foreach ($fileinfo as $title => $value) {
|
|
echo "<div class='fileinfo'><span class='title'>".$title."</span><span class='value'>".$value."</span></div>";
|
|
}
|
|
|
|
echo "</div>";
|
|
|
|
if ($dbo->query("SELECT name FROM sqlite_master WHERE name='dupes'")->fetch()) {
|
|
$dupes = $dbo->query("SELECT dupes FROM dupes WHERE (fid='".$row_a['fid']."')")->fetch();
|
|
if ($dupes) {
|
|
$count = count(unserialize($dupes['dupes']));
|
|
echo "<form action='' method='post'><input type='hidden' name='query' size='50' value='".$row_a['fid']."'><input type='submit' value='show ".$count." dupes'></form>";
|
|
}
|
|
}
|
|
|
|
echo "</td>";
|
|
|
|
echo "<td valign='top'>";
|
|
|
|
r($row_a);
|
|
|
|
if ($row_b['spotlight']) {
|
|
r($row_b);
|
|
}
|
|
|
|
echo "</td><td valign='top'>";
|
|
|
|
if ($row_c) {
|
|
r(unserialize($row_c['tags']));
|
|
}
|
|
|
|
ref::config('expLvl', 2);
|
|
|
|
if ($row_d) {
|
|
|
|
if (substr($row_d['info'],0,5) == "<?xml") {
|
|
r(json_decode(json_encode(simplexml_load_string(utf8_encode($row_d['info']))))->File->track);
|
|
} else {
|
|
r(json_decode(utf8_encode($row_d['info']), true)['media']['track']);
|
|
}
|
|
}
|
|
|
|
echo "</td>";
|
|
|
|
echo "</tr></table>";
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// Dir view
|
|
|
|
} elseif (!$search) {
|
|
|
|
if (count($children) > 3000) {
|
|
echo "<div class='slow_slider'></div>";
|
|
} else {
|
|
echo "<div class='slider'></div>";
|
|
}
|
|
|
|
echo "<div class='controls'><a href='#' class='info'>info</a></div>";
|
|
|
|
//echo "<table class='dir outlined'><tr><td valign='top'>";
|
|
echo "<table class='dir'><tr><td valign='top'>";
|
|
echo "<div class='container'>";
|
|
|
|
$spotlight_status = $dbo->query("SELECT mdutil FROM _skim")->fetch()['mdutil'];
|
|
|
|
$sql = "SELECT mdls.*, files.*, milk.* FROM files ";
|
|
$sql .= "LEFT JOIN mdls ON (files.rowid = mdls.rowid) ";
|
|
$sql .= "LEFT JOIN milk ON (files.rowid = milk.rowid) ";
|
|
$sql .= "WHERE files.rowid IN (".implode(",",$children).") ";
|
|
$sql .= "ORDER BY files.Filename COLLATE NOCASE";
|
|
|
|
$rows = $dbo->query($sql)->fetchAll();
|
|
|
|
foreach ($rows as $item) {
|
|
|
|
//print_r($item);
|
|
|
|
$myname = $item['Filename'];
|
|
|
|
if (in_array($myname, $hidefiles)) { continue; }
|
|
|
|
echo "<div class='item'>";
|
|
|
|
if ($item['FSInvisible'] | substr($item['Filename'],0,1) == ".") {
|
|
$visibility = "hidden";
|
|
} else {
|
|
$visibility = "unhidden";
|
|
}
|
|
|
|
////////////////////////////////////////////////
|
|
// hack to preview mixed icon/thumb view
|
|
$opts = unserialize($dbo->query("SELECT opts FROM _skim")->fetch()['opts']);
|
|
$skipicon = array("jpg","png","JPG","jpeg","tif","tiff","DNG","dng","NEF");
|
|
if($item['icon_filename'] && !in_array($item['Extension'],$skipicon)) {
|
|
$item['thumb_filename'] = $item['icon_filename'];
|
|
$item['thumb_width'] = $opts['thumb_size'];
|
|
$item['thumb_height'] = $opts['thumb_size'];
|
|
$item['thumb_tool'] = "qltool";
|
|
}
|
|
////////////////////////////////////////////////
|
|
|
|
if ($item['thumb_filename']) {
|
|
$aspect = $item['thumb_width']/$item['thumb_height'];
|
|
if ($aspect > 1) {
|
|
$width = $icon_size;
|
|
$height = $icon_size/$aspect;
|
|
} else {
|
|
$width = $icon_size*$aspect;
|
|
$height = $icon_size;
|
|
}
|
|
if ($item['Type'] == "dir") {
|
|
$width = $width/2;
|
|
$height = $height/2;
|
|
}
|
|
$realfile = dirname($db_file).$item['thumb_filename'];
|
|
if (array_key_exists("thumb_tool",$item)) {
|
|
if (in_array($item['thumb_tool'], $border_tools) && $item['Type'] != "dir") {
|
|
// put a border around images that are not icons
|
|
$border = "id='thumb'";
|
|
} else {
|
|
$border = "";
|
|
}
|
|
} else {
|
|
$border = "id='thumb'";
|
|
}
|
|
$icon = "<img ".$border." class='lazyload' data-src='".$realfile."' width='".$width."' height='".$height."' data-width='".$width."' data-height='".$height."'>";
|
|
} elseif ($item['Type'] == "dir") {
|
|
$icon = "<img src='/icons/directory.png' width='".$icon_size."' height='".$icon_size."' data-width='".$icon_size."' data-height='".$icon_size."'>";
|
|
} else {
|
|
$icon = "<img src='".findicon($item['Filename'])."' width='".$icon_size."' height='".$icon_size."' data-width='".$icon_size."' data-height='".$icon_size."'>";
|
|
}
|
|
|
|
echo "<div class='ibox'>";
|
|
|
|
if ($item['thumb_filename'] && $item['Type'] == "dir") {
|
|
echo "<div class='diibox'>";
|
|
} else {
|
|
echo "<div class='iibox'>";
|
|
}
|
|
|
|
echo "\n<a class='".$visibility."' href='?db=".$db_file."&pid=".$item['pid']."'>".$icon."</a>";
|
|
|
|
echo "</div></div>";
|
|
|
|
echo "<div class='title'>";
|
|
|
|
if ($item['UserTags']) {
|
|
foreach (unserialize($item['UserTags']) as $tag) {
|
|
echo "<span class='tag ".$tag."'></span>";
|
|
}
|
|
echo " ";
|
|
}
|
|
|
|
echo htmlentities(mb_shortlabel($item['Filename']));
|
|
|
|
echo "</div>";
|
|
|
|
if ($item['Size']) {
|
|
echo "<div class='size'>".human_filesize($item['Size']);
|
|
if ($item['Seconds']) {
|
|
$s = $item['Seconds'];
|
|
$duration_string = sprintf("%02d:%02d:%02d", $s/3600%24, $s/60%60, $s%60);
|
|
echo " (".$duration_string.")";
|
|
} elseif ($item['Dimensions']) {
|
|
echo " (".str_replace(","," x ",$item['Dimensions']).")";
|
|
}
|
|
echo "</div>";
|
|
}
|
|
|
|
if ($item['Type'] == "dir" && $item['items']) {
|
|
echo "<div class='size'>".number_format($item['items'])." items</div>";
|
|
}
|
|
|
|
echo "</div>";
|
|
echo "<br>";
|
|
|
|
}
|
|
|
|
echo str_repeat("<div class='flexfill'></div>", 100);
|
|
echo "</div>";
|
|
echo "</td><td valign='top' class='sidebar'>";
|
|
|
|
r($view);
|
|
|
|
if ($dirmdls['spotlight']) {
|
|
$dirmdls['spotlight'] = $parser->parseString(utf8_for_xml($dirmdls['spotlight']));
|
|
r($dirmdls);
|
|
}
|
|
|
|
echo "</td></tr></table>";
|
|
|
|
} else {
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// Search
|
|
|
|
if (@$dbo->query("SELECT name FROM sqlite_master WHERE name='dupes'")->fetch() && strlen($search) == 32) {
|
|
// this is a hash search with dupes table
|
|
|
|
$dupesearch = @$dbo->query("SELECT dupes FROM dupes WHERE (fid = '".$search."')")->fetch()['dupes'];
|
|
if ($dupesearch) {
|
|
foreach (unserialize($dupesearch) as $pathname) {
|
|
echo "\n<a href='?db=".$db_file."&pid=".md5($pathname)."'>".$pathname."</a><br>";
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// this is a text search
|
|
|
|
if (strlen($search) == 32) {
|
|
$result = $dbo->query("SELECT * FROM files WHERE (fid = '".$search."')")->fetchAll();
|
|
$label = "hash";
|
|
} else {
|
|
$result = $dbo->query("SELECT * FROM files WHERE (Filename LIKE '%".$search."%')")->fetchAll();
|
|
$label = "text";
|
|
}
|
|
|
|
if (count($result)) {
|
|
echo count($result)." ".$label." results<br>";
|
|
foreach ($result as $row) {
|
|
$pathbold = str_ireplace($search,"<b>".$search."</b>",$row['Pathname']);
|
|
echo "\n<a href='?db=".$db_file."&pid=".$row['pid']."'>".$pathbold."</a><br>";
|
|
}
|
|
} else {
|
|
echo "No results for ".$label." ".$search;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// DB List
|
|
|
|
echo "<a href='#' class='toggler'>toggle all</a>";
|
|
|
|
$icons['Disk image'] = "/icons/dmg.png";
|
|
$icons['Folder'] = "/icons/directory.png";
|
|
$icons['External disk'] = "/icons/firewire.png";
|
|
$icons['Startup disk'] = "/icons/internal.png";
|
|
|
|
$bundles = glob($db_dir."/*.bundle");
|
|
|
|
foreach ($bundles as $bundle) {
|
|
$exploded = explode("_", $bundle);
|
|
$sorted_bundles[$exploded[1]] = $bundle;
|
|
}
|
|
|
|
ksort($sorted_bundles);
|
|
|
|
foreach ($sorted_bundles as $key => $bundle) {
|
|
echo "<div id='bundle'>";
|
|
$dbs = array_reverse(glob($bundle."/????-??-??_??-??-??.sqlite3"));
|
|
if ($dbs[0]) {
|
|
$dbo = new PDO("sqlite:".$dbs[0]);
|
|
$type = $dbo->query("SELECT type FROM _skim")->fetch()['type'];
|
|
echo "<img id='item' src='".$icons[$type]."'>";
|
|
}
|
|
$dbo = new PDO("sqlite:".$dbs[0]);
|
|
$info = $dbo->query("SELECT * FROM _skim")->fetch();
|
|
echo "<h2><a href='#'>".pathinfo($bundle)['filename']." (".$info['passed_total'].")</a></h2>";
|
|
echo "<div class='dblist'>";
|
|
foreach ($dbs as $db_file) {
|
|
$dbo = new PDO("sqlite:".$db_file);
|
|
$info = $dbo->query("SELECT * FROM _skim")->fetch();
|
|
if (strpos($info['status'],"completed") === 0) {
|
|
$seconds = str_replace("completed_in_","",$info['status']);
|
|
$s = (int)$seconds;
|
|
$status = sprintf("%02d:%02d:%02d:%02d", $s/86400, $s/3600%24, $s/60%60, $s%60);
|
|
echo "<div>";
|
|
} else {
|
|
echo "<div class='aborted'>";
|
|
}
|
|
echo "<a href='?db=".$db_file."'>".pathinfo($db_file)['filename']."</a> ";
|
|
echo $info['version'].", ";
|
|
echo number_format($info['passed_total'])." files, ";
|
|
if ($info['image_file']) { echo $info['image_file'].", "; }
|
|
echo $status;
|
|
if (strpos($info['mdutil'],"disabled")) { echo " (no spotlight)"; }
|
|
echo "</div>";
|
|
}
|
|
echo "</div>";
|
|
echo "</div>";
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
echo "<hr><div id='exectime'>".round($time = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"],2)." seconds</div>";
|
|
echo "<div>Skim version = ".$skim_version.", RTC Browser Version = ".$browser_version."</div>";
|
|
|
|
?>
|
|
|
|
</body>
|
|
</html>
|