391 lines
12 KiB
PHP
391 lines
12 KiB
PHP
<?
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Skim RTC Browser
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
require "togggle.php";
|
|
require "debug.php";
|
|
|
|
$db_dir = "skim";
|
|
$icon_size = 64;
|
|
$pad = 28;
|
|
|
|
?>
|
|
|
|
<html>
|
|
<head>
|
|
<style>
|
|
|
|
html { font-family: Helvetica; word-wrap: break-word; }
|
|
|
|
div.container { display: flex; flex-flow: row wrap; justify-content: center; }
|
|
div.item { width: <?=$icon_size+$pad;?>px; height: <?=$icon_size+$pad;?>px; padding: <?=$pad;?>px; }
|
|
div.item { font-size: 11px; }
|
|
div.flexfill { width: <?=$icon_size+($pad*3);?>px; height: 1px; }
|
|
|
|
div.size { color: grey; margin-top: 3px; }
|
|
|
|
img.thumb { padding: 6px; border: 1px solid gainsboro; }
|
|
img.item { float: left; margin-right: 10px; width: 32px; height: 32px; }
|
|
img { margin-bottom: 8px; }
|
|
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<?
|
|
|
|
// Functions
|
|
|
|
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];
|
|
}
|
|
|
|
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) {
|
|
$suffix = "(...).".pathinfo($filename)['extension'];
|
|
if (strlen($filename) > $max) {
|
|
$return = substr($filename, 0, ($max-strlen($suffix))).$suffix;
|
|
} else {
|
|
$return = $filename;
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
function findicon($filename) {
|
|
$ext = pathinfo($filename)['extension'];
|
|
if (!$ext) {
|
|
$good = "icons/directory.png";
|
|
} else {
|
|
$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'];
|
|
|
|
if ($db_file) {
|
|
|
|
echo "<a href='?db='>db list</a>";
|
|
echo "<hr>";
|
|
|
|
if (!is_readable($db_file)) { echo "can't read db file"; die; }
|
|
|
|
$dbo = new PDO("sqlite:".$db_file);
|
|
$dbx = new PDO("sqlite:".dirname($db_file)."/pool.sqlite3");
|
|
$dbo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
$dbx->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
|
|
// Get zpath
|
|
|
|
$zpath = $dbo->query("SELECT zpath FROM _skim")->fetch()['zpath'];
|
|
|
|
// Check for initial view
|
|
|
|
if (!$pid) {
|
|
$pid = $dbo->query("SELECT pid FROM family WHERE (rowid=2)")->fetch()['pid'];
|
|
$view = $dbo->query("SELECT * FROM _skim")->fetchAll()[0];
|
|
// hide long strings
|
|
$view['qlmanage'] = "hidden";
|
|
$view['disks'] = "hidden";
|
|
$view['diskutil'] = "hidden";
|
|
} else {
|
|
$view = $dbo->query("SELECT * FROM files WHERE (pid='".$pid."')")->fetchAll()[0];
|
|
}
|
|
|
|
// Breadcrumbs
|
|
|
|
$crumb = breadcrumbs($zpath,$view['Pathname']);
|
|
$xc = "";
|
|
|
|
foreach ($crumb as $myparts) {
|
|
if ($myparts[0] === null) {
|
|
$xc .= $myparts[1];
|
|
} else {
|
|
$xc .= "<a href='?db=".$db_file."&pid=".$myparts[0]."'>".$myparts[1]."</a> > ";
|
|
}
|
|
}
|
|
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'];
|
|
|
|
echo "<table><tr>";
|
|
|
|
echo "<td valign='top'>";
|
|
$row_a = $dbo->query("SELECT rowid, * FROM files WHERE (pid='".$pid."')")->fetchAll()[0];
|
|
|
|
if (!strpos($spotlight_status,"disabled")) {
|
|
|
|
$row_b = $dbo->query("SELECT * FROM mdls WHERE (rowid='".$row_a['rowid']."')")->fetchAll()[0];
|
|
|
|
}
|
|
|
|
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 = $dbx->query("SELECT * FROM exiftool WHERE (rowid='".$row_a['has_exif']."')")->fetchAll()[0];
|
|
}
|
|
if (isset($row_a['has_mediainfo'])) {
|
|
$row_d = $dbx->query("SELECT * FROM mediainfo WHERE (rowid='".$row_a['has_mediainfo']."')")->fetchAll()[0];
|
|
}
|
|
|
|
} else {
|
|
|
|
// fetch exif and mediainfo by slower fid
|
|
|
|
$row_c = $dbx->query("SELECT * FROM exiftool WHERE (fid='".$row_a['fid']."')")->fetchAll()[0];
|
|
$row_d = $dbx->query("SELECT * FROM mediainfo WHERE (fid='".$row_a['fid']."')")->fetchAll()[0];
|
|
|
|
}
|
|
|
|
if ($row_a['thumb_filename']) {
|
|
$width = $row_a['thumb_width'];
|
|
$height = $row_a['thumb_height'];
|
|
$realfile = dirname($db_file).$row_a['thumb_filename'];
|
|
$icon = "<img src='".$realfile."' width='".$width."' height='".$height."'>";
|
|
} else {
|
|
$icon = "<img src='".findicon($row_a['Filename'])."' width='512' height='512'>";
|
|
}
|
|
|
|
echo $icon;
|
|
|
|
echo "</td>";
|
|
|
|
echo "<td valign='top'>";
|
|
|
|
debug(array($row_a),"file");
|
|
|
|
if ($row_b) {
|
|
$parser = new plistParser();
|
|
$row_b['spotlight'] = $parser->parseString($row_b['spotlight']);
|
|
debug(array($row_b),"mdls");
|
|
}
|
|
|
|
echo "</td><td valign='top'>";
|
|
|
|
if ($row_c) {
|
|
debug(array(unserialize($row_c['tags'])),"exiftool");
|
|
}
|
|
if ($row_d) {
|
|
debug(array(json_decode(json_encode(simplexml_load_string($row_d['info'])))),"mediainfo");
|
|
}
|
|
|
|
echo "</td>";
|
|
|
|
echo "</tr></table>";
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// Dir view
|
|
|
|
} elseif (!$search) {
|
|
|
|
echo "<table><tr><td valign='top'>";
|
|
echo "<div class='container'>";
|
|
|
|
foreach ($children as $item) {
|
|
|
|
echo "<div class='item'>";
|
|
|
|
/////////////////////////
|
|
|
|
$row_a = $dbo->query("SELECT * FROM files WHERE (rowid='".$item."')")->fetchAll()[0];
|
|
$row_b = $dbo->query("SELECT * FROM mdls WHERE (rowid='".$item."')")->fetchAll()[0];
|
|
//$row_c = $dbo->query("SELECT * FROM milk WHERE (pid='".$item."')")->fetchAll()[0];
|
|
|
|
/////////////////////////
|
|
|
|
if ($row_a['thumb_filename']) {
|
|
$aspect = $row_a['thumb_width']/$row_a['thumb_height'];
|
|
if ($aspect > 1) {
|
|
$width = $icon_size;
|
|
$height = $icon_size/$aspect;
|
|
} else {
|
|
$width = $icon_size*$aspect;
|
|
$height = $icon_size;
|
|
}
|
|
$realfile = dirname($db_file).$row_a['thumb_filename'];
|
|
$icon = "<img class='thumb' src='".$realfile."' width='".$width."' height='".$height."'>";
|
|
} else {
|
|
$icon = "<img class='icon' src='".findicon($row_a['Filename'])."' width='".$icon_size."' height='".$icon_size."'>";
|
|
}
|
|
|
|
echo "\n<a href='?db=".$db_file."&pid=".$row_a['pid']."'>".$icon."</a>";
|
|
|
|
echo "<div class='title'>".htmlentities(shortlabel($row_a['Filename']))."</div>";
|
|
|
|
if ($row_a['Size']) {
|
|
echo "<div class='size'>".human_filesize($row_a['Size'])."</div>";
|
|
}
|
|
|
|
if ($row_a['Type'] == "dir" && $row_a['items']) {
|
|
echo "<div class='size'>".$row_a['items']." items</div>";
|
|
}
|
|
|
|
echo "</div>";
|
|
echo "<br>";
|
|
|
|
}
|
|
|
|
echo str_repeat("<div class='flexfill'></div>", 100);
|
|
echo "</div>";
|
|
echo "</td><td valign='top'>";
|
|
debug($view,$view['Pathname']);
|
|
echo "</td></tr></table>";
|
|
|
|
} else {
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// Search
|
|
|
|
$result = $dbo->query("SELECT * FROM files WHERE (Filename LIKE '%".$search."%')")->fetchAll();
|
|
|
|
if (count($result)) {
|
|
echo count($result)." 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 ".$search;
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// DB List
|
|
|
|
$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) {
|
|
echo "<div id='bundle'>";
|
|
$dbs = array_reverse(glob($bundle."/*.sqlite3"));
|
|
array_shift($dbs);
|
|
if ($dbs[0]) {
|
|
$dbo = new PDO("sqlite:".$dbs[0]);
|
|
$type = $dbo->query("SELECT type FROM _skim")->fetch()['type'];
|
|
echo "<img class='item' src='".$icons[$type]."'>";
|
|
}
|
|
echo "<h2>".pathinfo($bundle)['filename']."</h2>";
|
|
foreach ($dbs as $db_file) {
|
|
$dbo = new PDO("sqlite:".$db_file);
|
|
echo "<div>";
|
|
echo "<a href='?db=".$db_file."'>".pathinfo($db_file)['filename']."</a> ";
|
|
echo $dbo->query("SELECT version FROM _skim")->fetch()['version'].", ";
|
|
echo $dbo->query("SELECT passed_total FROM _skim")->fetch()['passed_total']." files, ";
|
|
echo $dbo->query("SELECT status FROM _skim")->fetch()['status'];
|
|
$spotlight_status = $dbo->query("SELECT mdutil FROM _skim")->fetch()['mdutil'];
|
|
if (strpos($spotlight_status,"disabled")) { echo " (no spotlight)"; }
|
|
echo "</div>";
|
|
}
|
|
echo "</div>";
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
echo "<hr><br>".round($time = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"],2)." seconds";
|
|
|
|
?>
|
|
|
|
</body>
|
|
</html>
|