This commit is contained in:
2018-09-16 15:22:15 -07:00
parent 34de0a92c9
commit 01d7489c05
3 changed files with 502 additions and 112 deletions

267
Yuba.php
View File

@@ -3,7 +3,7 @@
// Yuba // Yuba
// // // //
////////////////////////////////////////// //////////////////////////////////////////
$version = "0.7.7"; $version = "0.7.9";
ini_set('memory_limit', '4096M'); ini_set('memory_limit', '4096M');
date_default_timezone_set("America/Los_Angeles"); date_default_timezone_set("America/Los_Angeles");
@@ -14,8 +14,8 @@ date_default_timezone_set("America/Los_Angeles");
require("functions.php"); require("functions.php");
require("filetypes.php"); require("filetypes.php");
$wopt_noprofile = 1; $wopt_noprofile = 0;
$wopt_steps = 9; $wopt_steps = 10;
$wopt_currstep = 1; $wopt_currstep = 1;
$p = unserialize(file_get_contents("prefs.php")); $p = unserialize(file_get_contents("prefs.php"));
@@ -32,7 +32,7 @@ if (!is_dir($zpath) | !is_dir($bdest)) { echo "Filepath error"; die; }
// Check for bundle // Check for bundle
if ($zpath == "/") { $blabel = "root"; } else { $blabel = preg_replace("/[^A-Za-z0-9\.]/", "_", basename($zpath)); } if ($zpath == "/") { $blabel = "root"; } else { $blabel = preg_replace("/[^A-Za-z0-9\.]/", "_", basename($zpath)); }
if (is_writable($zpath)) { echo "Warning: source is writeable\n"; } if (is_writable($zpath)) { echo "Warning: source is writeable"; }
$bpath = chop($bdest,"/")."/".substr(crc32($zpath),0,3)."_".$blabel.".bundle"; $bpath = chop($bdest,"/")."/".substr(crc32($zpath),0,3)."_".$blabel.".bundle";
if (!is_dir($bpath)) { mkdir($bpath); } if (!is_dir($bpath)) { mkdir($bpath); }
@@ -79,6 +79,7 @@ $bin_qlthumb = __DIR__."/bin/ql-thumbnail";
// Logfile // Logfile
$messages_log_file = $bpath."/".$stamp."_messages.log";
$error_log_file = $bpath."/".$stamp."_error.log"; $error_log_file = $bpath."/".$stamp."_error.log";
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set("display_errors", TRUE); ini_set("display_errors", TRUE);
@@ -89,21 +90,21 @@ ini_set("error_log", $error_log_file);
////////////////////////////////////////// //////////////////////////////////////////
$banner = "Yuba: ".$zpath." -> ".$bpath; $banner = "Yuba: ".$zpath." -> ".$bpath;
echo $banner."\n".str_repeat("-", strlen($banner))."\n"; echo msg($banner."\n".str_repeat("-", strlen($banner)));
// Disk info // Disk info
////////////////////////////////////////// //////////////////////////////////////////
echo "Gathering system info...\n"; echo msg("Gathering system info...");
$host = gethostname(); $host = gethostname();
$disks = shell_exec("diskutil list 2>&1"); $disks = shell_exec("diskutil list -plist 2>&1");
$df = shell_exec("df 2>&1"); $df = shell_exec("df 2>&1");
$df_volume = shell_exec("df ".escapeshellarg($zpath)." | tail -n 1 | rev | cut -d' ' -f1 | rev"); $df_volume = shell_exec("df ".escapeshellarg($zpath)." | tail -n 1 | rev | cut -d' ' -f1 | rev");
$df_device = shell_exec("df ".escapeshellarg($zpath)." | tail -n 1 | cut -d' ' -f1"); $df_device = shell_exec("df ".escapeshellarg($zpath)." | tail -n 1 | cut -d' ' -f1");
$mdutil = shell_exec("mdutil -s ".$df_volume); $mdutil = shell_exec("mdutil -s ".$df_volume);
if (strpos($mdutil,"disabled")) { if (strpos($mdutil,"disabled")) {
echo "Warning: spotlight indexing is disabled\n"; echo msg("Warning: spotlight indexing is disabled");
$p['spotlight'] = false; $p['spotlight'] = false;
} }
@@ -114,6 +115,13 @@ if (substr($zpath, 0, 9) != "/Volumes/") {
$zbase = "/Volumes/".$zparts[2]; $zbase = "/Volumes/".$zparts[2];
} }
$hdiutil = shell_exec("hdiutil info -plist 2>&1");
/////////////////////////////////////////////////////////////////////////////////////////////
// rewrite below to use diskutil info -plist
//
//
//
$diskutil = shell_exec("diskutil info ".$zbase." 2>&1"); $diskutil = shell_exec("diskutil info ".$zbase." 2>&1");
$getdetail = array( "Volume Name", $getdetail = array( "Volume Name",
"Protocol", "Protocol",
@@ -148,6 +156,11 @@ if ($zpath == "/") {
} else { } else {
$type = "Folder"; $type = "Folder";
} }
//
//
//
/////////////////////////////////////////////////////////////////////////////////////////////
if ($wopt_noprofile) { if ($wopt_noprofile) {
$profile = "disabled"; $profile = "disabled";
@@ -160,10 +173,11 @@ $sysvers = shell_exec("sw_vers 2>&1");
// Database // Database
////////////////////////////////////////// //////////////////////////////////////////
echo "Building database...\n"; echo msg("Building database...");
$dbo = new PDO("sqlite:".$bpath."/".$stamp.".sqlite3"); $dbo = new PDO("sqlite:".$bpath."/".$stamp.".sqlite3");
$dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$dbo->query("PRAGMA page_size = 4096"); $dbo->query("PRAGMA page_size = 4096");
$dbo->query("PRAGMA cache_size = 10000"); $dbo->query("PRAGMA cache_size = 10000");
@@ -190,6 +204,7 @@ $dbo->exec("CREATE TABLE _skim (
qlmanage TEXT, qlmanage TEXT,
sysvers TEXT, sysvers TEXT,
diskutil TEXT, diskutil TEXT,
hdiutil TEXT,
disks TEXT, disks TEXT,
df TEXT, df TEXT,
df_device TEXT, df_device TEXT,
@@ -237,7 +252,7 @@ $dbo->exec("CREATE TABLE files (
contents_filename TEXT contents_filename TEXT
)"); )");
$stmt = $dbo->prepare("INSERT INTO _skim VALUES (:version, :opts, :host, :uid, :zpath, :bpath, :type, :passed_file, :passed_dir, :passed_link, :passed_total, :nodescended, :ignored, :dupes, :details, :qlmanage, :sysvers, :diskutil, :disks, :df, :df_device, :df_volume, :mdutil, :profile, :status)"); $stmt = $dbo->prepare("INSERT INTO _skim VALUES (:version, :opts, :host, :uid, :zpath, :bpath, :type, :passed_file, :passed_dir, :passed_link, :passed_total, :nodescended, :ignored, :dupes, :details, :qlmanage, :sysvers, :diskutil, :hdiutil, :disks, :df, :df_device, :df_volume, :mdutil, :profile, :status)");
$stmt->BindValue(":version",$version); $stmt->BindValue(":version",$version);
$stmt->BindValue(":opts",serialize($p)); $stmt->BindValue(":opts",serialize($p));
$stmt->BindValue(":host",$host); $stmt->BindValue(":host",$host);
@@ -249,6 +264,7 @@ $stmt->BindValue(":details",$dstring);
$stmt->BindValue(":qlmanage",$qlmanage); $stmt->BindValue(":qlmanage",$qlmanage);
$stmt->BindValue(":sysvers",$sysvers); $stmt->BindValue(":sysvers",$sysvers);
$stmt->BindValue(":diskutil",$diskutil); $stmt->BindValue(":diskutil",$diskutil);
$stmt->BindValue(":hdiutil",$hdiutil);
$stmt->BindValue(":disks",$disks); $stmt->BindValue(":disks",$disks);
$stmt->BindValue(":df",$df); $stmt->BindValue(":df",$df);
$stmt->BindValue(":df_device",$df_device); $stmt->BindValue(":df_device",$df_device);
@@ -311,17 +327,17 @@ $files = new RecursiveIteratorIterator(
// Tally // Tally
////////////////////////////////////////// //////////////////////////////////////////
echo "Counting files...\n"; echo msg("Counting files...");
foreach ($files as $null) { } foreach ($files as $null) { }
$first_run = 0; $first_run = 0;
if (!$passed_total) { if (!$passed_total) {
echo "Nothing was found, exiting"; echo msg("Nothing was found, exiting");
die; die;
} }
echo "Total files: ".$passed_total."\n"; echo msg("Total files: ".$passed_total."");
// Pool DB // Pool DB
////////////////////////////////////////// //////////////////////////////////////////
@@ -363,7 +379,7 @@ foreach ($files as $splFileInfo) {
$pkey = md5($path); $pkey = md5($path);
if (array_key_exists($key, $family)) { if (array_key_exists($key, $family)) {
echo "Duplicate key on ".$pathname."\n"; die; echo msg("Duplicate key on ".$pathname.""); die;
} }
$family[$key] = array(); $family[$key] = array();
@@ -389,6 +405,7 @@ foreach ($files as $splFileInfo) {
} }
*/ */
//$sty[$i] = "bypass";
$sty[$i] = statToArray(shell_exec("stat -s ".$shellpath." 2>&1")); $sty[$i] = statToArray(shell_exec("stat -s ".$shellpath." 2>&1"));
// Check file can be read // Check file can be read
@@ -412,12 +429,12 @@ echo ProgressBar::finish();
// Thow permissions error // Thow permissions error
if (count($noread)) { if (count($noread)) {
echo "Current user (".posix_getuid().") does not have read access to the following files:\n"; echo msg("Current user (".posix_getuid().") does not have read access to the following files:");
foreach ($noread as $file) { foreach ($noread as $file) {
echo $file."\n"; echo $file."\n";
} }
if ($p['readability']) { if ($p['readability']) {
echo "Exiting..."; echo msg("Exiting...");
die; die;
} }
} }
@@ -574,15 +591,20 @@ if ($p['contents']) {
if (in_array($ext, $c_files)) { if (in_array($ext, $c_files)) {
if (!is_dir($cpath)) { mkdir($cpath); } if (!is_dir($cpath)) { mkdir($cpath); }
if (!file_exists($cfile) && filesize($pathname) < 25000) { if (!file_exists($cfile) && filesize($pathname) < 25000) {
msg("Zipping ".$pathname);
$zip = new ZipArchive();
$zip->open($cfile, ZipArchive::CREATE);
$zip->addfile($pathname,basename($pathname));
$zip->close();
$stmt = $dbp->prepare("INSERT INTO contents VALUES (:fid, :created, :relative_path)"); $stmt = $dbp->prepare("INSERT INTO contents VALUES (:fid, :created, :relative_path)");
$stmt->BindValue(":fid",$fid); $stmt->BindValue(":fid",$fid);
$stmt->BindValue(":created",time()); $stmt->BindValue(":created",time());
$stmt->BindValue(":relative_path",substr($cfile, strlen($bpath))); $stmt->BindValue(":relative_path",substr($cfile, strlen($bpath)));
$stmt->execute(); $stmt->execute();
$zip = new ZipArchive();
$zip->open($cfile, ZipArchive::CREATE);
$zip->addfile($pathname,basename($pathname));
$zip->close();
} }
} }
echo ProgressBar::next(true); echo ProgressBar::next(true);
@@ -689,6 +711,17 @@ if ($p['hash']) {
} }
// Pool Indices
//////////////////////////////////////////
// We are done with the Pool DB, make sure there are indices
$dbp->exec("CREATE INDEX IF NOT EXISTS contents_index ON contents (fid)");
$dbp->exec("CREATE INDEX IF NOT EXISTS exiftool_index ON exiftool (fid)");
$dbp->exec("CREATE INDEX IF NOT EXISTS md5_index ON md5 (fid)");
$dbp->exec("CREATE INDEX IF NOT EXISTS mediainfo_index ON mediainfo (fid)");
$dbp->exec("CREATE INDEX IF NOT EXISTS thumbs_index ON thumbs (fid)");
// Spotlight // Spotlight
////////////////////////////////////////// //////////////////////////////////////////
@@ -741,13 +774,18 @@ if ($p['spotlight']) {
foreach ($files as $splFileInfo) { foreach ($files as $splFileInfo) {
$path = $splFileInfo->getPathname(); $path = $splFileInfo->getPathname();
msg($path);
$pid = md5($path); $pid = md5($path);
$shellpath = escapeshellarg($path); $shellpath = escapeshellarg($path);
$mdls = shell_exec("mdls -plist - ".$shellpath." 2>&1"); $mdls = shell_exec("mdls -plist - ".$shellpath." 2>&1");
if (substr_count(@$mdls,"\n") < 2) { continue; }
if (substr_count(@$mdls,"\n") > 1) {
$parser = new plistParser(); $parser = new plistParser();
$spotlight = $parser->parseString($mdls); $spotlight = $parser->parseString(utf8_for_xml($mdls));
} else {
$spotlight = array();
}
$stmt = $dbo->prepare("INSERT INTO mdls VALUES (".implode(",",$ibuild).")"); $stmt = $dbo->prepare("INSERT INTO mdls VALUES (".implode(",",$ibuild).")");
@@ -868,7 +906,10 @@ foreach ($files as $splFileInfo) {
// Items // Items
if ($type == "dir" || $type == "bundle" ) { if ($type == "dir" || $type == "bundle" ) {
$items = chop(@shell_exec("find ".$shellpath." \( ! -regex '.*/\..*' \) | wc -l 2>&1"))-1; // below commented out because it was causing -1 on dirs beginning with a dot
//$items = chop(@shell_exec("find ".$shellpath." \( ! -regex '.*/\..*' \) | wc -l 2>&1"))-1;
// below should be rewritten to use $wopt_ignore files
$items = chop(@shell_exec("find ".$shellpath." \( ! -regex '.*/\.DS_Store' \) | wc -l 2>&1"))-1;
$stmt->BindValue(":items",@$items); $stmt->BindValue(":items",@$items);
} }
@@ -959,11 +1000,11 @@ foreach ($files as $splFileInfo) {
$message[] = "ctime"; $message[] = "ctime";
} }
if (count($message)) { echo "\nFILE = ".$filename."; CHANGE = ".implode(", ", $message)."\n"; } if (count($message)) { echo msg("FILE = ".$filename."; CHANGE = ".implode(", ", $message).""); }
} }
echo ProgressBar::next($filename); echo ProgressBar::next($pathname);
$j++; $j++;
} }
@@ -973,61 +1014,147 @@ echo ProgressBar::finish();
// Milk // Milk
////////////////////////////////////////// //////////////////////////////////////////
// Aggregate values $milk['t*Title'] = ["e^Title","k^Title","m^Track_name"];
$sb['a'] = array( "t*Title" => array("e_Title","k_Title","m_Title"), $milk['t*Format'] = ["m^Format","e^Compression","e^MIMEType"];
"t*Dimensions" => array("k_PixelWidth.k_PixelHeight","e_PixelWidth.e_PixelHeight","m_PixelWidth.m_PixelHeight"), $milk['t*Dimensions'] = ["k^PixelWidth.k^PixelHeight","e^PixelWidth.e^PixelHeight","m^SkimDims"];
"i*Seconds" => array("k_DurationSeconds","e_Duration","m_Duration"), $milk['s*Seconds'] = ["k^DurationSeconds","e^Duration","m^Duration"];
"d*DateTime" => array("e_DateTimeOriginal","m_EncodedDate","e_CreateDate","e_MediaCreateDate","k_ContentCreationDate"), $milk['d*DateTime'] = ["e^DateTimeOriginal","m^EncodedDate","e^CreateDate","e^MediaCreateDate","k^ContentCreationDate"];
"t*Origin" => array("e_CameraModelName","e_Producer","e_CreatorTool","e_WriterName","e_Software","e_Encoder","m_WritingApplication"), $milk['t*Origin'] = ["e^CameraModelName","e^Producer","e^CreatorTool","e^WriterName","e^Software","e^Encoder","k^Creator"];
"t*GPS" => array("e_GPSPosition","k_Latitude.k_Longitude"), $milk['t*GPS'] = ["k^Latitude.k^Longitude","e^GPSPosition"];
"t*Author" => array("e_Author","e_Artist","e_Creator","e_By-line") $milk['t*Author'] = ["e^Author","e^Artist","e^Creator","e^By-line"];
);
// Exiftool values $milk['i*Tracks'] = ["m^SkimTrackCount"];
$sb['e'] = array( "i*Orientation", $milk['t*Writer'] = ["m^Writing_application.m^Writing_library"];
"t*Compression", $milk['t*Bitrate'] = ["m^Overall_bit_rate"];
"t*ProfileDescription",
"i*BitDepth",
"t*LensType",
"t*FocalLength",
"t*Aperture",
"t*LightSource",
"t*WhiteBalance" );
// Mediainfo values $milk['i*Orientation'] = ["e^Orientation"];
$sb['m'] = array( "t*VideoFormat", $milk['t*Profile'] = ["e^Profile"];
"t*AudioFormat", $milk['i*BitDepth'] = ["e^BitDepth"];
"i*Tracks", $milk['t*LensType'] = ["e^LensType"];
"t*Profile", $milk['t*FocalLength'] = ["e^FocalLength"];
"t*Bitrate" ); $milk['t*Aperture'] = ["e^Aperture"];
$milk['t*LightSource'] = ["e^LightSource"];
$milk['t*WhiteBalance'] = ["e^WhiteBalance"];
$delimiter = ",";
// Build DB // Build DB
unset($cbuild, $ibuild);
foreach (array_merge(array_keys($sb['a']),$sb['e'],$sb['m']) as $name) { $cbuild = $ibuild = array();
$parts = explode("*",$name); foreach (array_keys($milk) as $name) {
$ibuild[] = ":".$parts[1]; list($kind,$item) = explode("*",$name);
if ($parts[0] == "t") { switch ($kind) {
$cbuild[] = $parts[1]." TEXT"; case "t":
} else { case "d":
$cbuild[] = $parts[1]." INTEGER"; case "s":
$cbuild[] = $item." TEXT";
break;
case "i":
$cbuild[] = $item." INTEGER";
break;
} }
$ibuild[] = ":".$item;
} }
$dbo->exec("CREATE TABLE milk (".implode(",",$cbuild).")"); $dbo->exec("CREATE TABLE milk (".implode(",",$cbuild).")");
$stmt = $dbo->prepare("INSERT INTO milk VALUES (".implode(",",$ibuild).")");
$stmt->execute(); $countrows = @reset($dbo->query("SELECT max(rowid) FROM files")->fetch());
echo msg("Milking ".$countrows." rows");
echo ProgressBar::start($countrows, "Milk");
//$q = $dbo->query("SELECT rowid, * FROM files"); $loop = $dbo->query("SELECT rowid, * FROM files");
//while ($row = $q->fetch_assoc()) { while ($row_a = $loop->fetch()) {
// print_r($row);
// } $stmt = $dbo->prepare("INSERT INTO milk VALUES (".implode(",",$ibuild).")");
//$q->free();
$row_b = @$dbo->query("SELECT * FROM mdls WHERE (rowid='".$row_a['rowid']."')")->fetch();
if (count(@$row_b) > 1) {
$m['k'] = $row_b;
} else {
$m['k'] = null;
}
if (isset($row_a['has_exif'])) {
$row_c = $dbp->query("SELECT * FROM exiftool WHERE (rowid='".$row_a['has_exif']."')")->fetch();
$m['e'] = unserialize($row_c['tags']);
} else {
$m['e'] = null;
}
if (isset($row_a['has_mediainfo'])) {
$row_d = $dbp->query("SELECT * FROM mediainfo WHERE (rowid='".$row_a['has_mediainfo']."')")->fetch();
$decoded = @json_decode(json_encode(simplexml_load_string($row_d['info'])),true);
$m['m'] = $decoded['File']['track'][0];
//custom values
$m['m']['SkimTrackCount'] = @count($decoded['File']['track']);
@foreach ($decoded['File']['track'] as $track) {
if (!@$m['m']['SkimDims'] && @$track['Width'] && @$track['Height']) {
$m['m']['SkimDims'] = sanitize($track['Width'],"i").$delimiter.sanitize($track['Height'],"i");
}
}
// do seconds fix here
} else {
$m['m'] = null;
}
// M*I*L*K baby
foreach ($milk as $value => $weighted) {
list($type,$name) = explode("*",$value);
$found = 0;
foreach ($weighted as $dindex) {
// concatenante 2 values
if (!$found && strpos($dindex, ".")) {
$parts = explode(".",$dindex);
$out = array();
foreach ($parts as $part) {
list($kind,$item) = explode("^",$part);
if (@$m[$kind][$item]) {
$out[] = sanitize($m[$kind][$item],$type);
}
}
if (count($out)) {
$stmt->BindValue(":".$name,implode($delimiter,$out));
$found = 1;
}
} elseif (!$found) {
// find a single value
list($kind,$item) = explode("^",$dindex);
if (@$m[$kind][$item]) {
$stmt->BindValue(":".$name,sanitize($m[$kind][$item],$type));
$found = 1;
}
}
}
}
echo ProgressBar::next(true);
$stmt->execute();
}
echo ProgressBar::finish();
// Cleanup // Cleanup
////////////////////////////////////////// //////////////////////////////////////////
echo "\n"; echo msg("");
if (file_exists($error_log_file)) { echo file_get_contents($error_log_file); } if (file_exists($error_log_file)) { echo file_get_contents($error_log_file); }
@@ -1037,7 +1164,7 @@ $dbo->exec("UPDATE _skim SET status='completed_in_".$seconds."'");
// rsync // rsync
if ($p['rsync_dest']) { if ($p['rsync_dest']) {
echo "\nrsync...\n"; echo msg("rsync...");
$command = "rsync -avv -e ssh ".$bpath." ".$p['rsync_dest']; $command = "rsync -avv -e ssh ".$bpath." ".$p['rsync_dest'];
$count = trim(shell_exec("find ".escapeshellarg($bpath)." | wc -l")); $count = trim(shell_exec("find ".escapeshellarg($bpath)." | wc -l"));
echo ProgressBar::start($count,$p['rsync_dest']); echo ProgressBar::start($count,$p['rsync_dest']);
@@ -1047,7 +1174,7 @@ if ($p['rsync_dest']) {
echo ProgressBar::finish(); echo ProgressBar::finish();
} }
echo "Finished in ".$seconds." seconds\n\n"; echo msg("Finished in ".$seconds." seconds");
unset($dbo, $dbp, $files, $family, $fx); unset($dbo, $dbp, $files, $family, $fx);

View File

@@ -45,13 +45,14 @@ class ProgressBar {
self::$total = $total; self::$total = $total;
self::$time_start = time(); self::$time_start = time();
self::$message = $message; self::$message = $message;
return $message."\n".self::display(); return msg($message).self::display();
} }
public static function next($message = null) { public static function next($message = null) {
self::$done++; self::$done++;
if (is_string($message)) { msg($message); }
return self::display($message); return self::display($message);
} }
public static function finish() { public static function finish() {
global $wopt_currstep; global $wopt_currstep;
@@ -76,6 +77,52 @@ function getParents($zpath, $pathname) {
} }
*/ */
function msg($string) {
global $messages_log_file;
$logstring = "[".date('Y-m-d h:i:s')."] ".$string."\n";
file_put_contents($messages_log_file, $logstring, FILE_APPEND);
return $string."\n";
}
function timeToSeconds($val) {
if (!is_numeric($val) && strpos($val,":") === false) {
$val = str_replace(" s","",$val);
$val = str_replace(" h ",":",$val);
$val = str_replace(" min",":00",$val);
}
if (!is_numeric($val)) {
$sec = 0;
foreach (array_reverse(explode(':', $val)) as $k => $v) $sec += pow(60, $k) * $v;
$val = $sec;
}
return number_format($val,2,".","");
}
function sanitize($val,$type) {
switch($type) {
case "t":
return $val;
break;
case "i":
return filter_var($val,FILTER_SANITIZE_NUMBER_FLOAT);
break;
case "s":
return timeToSeconds($val);
break;
case "d":
if ($formatted = @strtotime($val)) {
return $formatted;
} else {
return $val;
}
break;
}
}
function is_serial($string) {
return (@unserialize($string) !== false || $string == 'b:0;');
}
function statToArray($stat) { function statToArray($stat) {
foreach (explode(" ",$stat) as $part) { foreach (explode(" ",$stat) as $part) {
$value = explode("=",$part); $value = explode("=",$part);
@@ -84,7 +131,6 @@ function statToArray($stat) {
return $out; return $out;
} }
function stepString() { function stepString() {
global $wopt_steps; global $wopt_steps;
global $wopt_currstep; global $wopt_currstep;
@@ -109,6 +155,14 @@ function human_filesize($bytes, $decimals = 2) {
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor]; return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor];
} }
function ncenter($string, $title = "DropToPTP") {
exec("osascript -e 'display notification \"".$string."\" with title \"".$title."\"'");
}
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 { class plistParser extends XMLReader {
public function parseString($string) { $this->XML($string); return $this->process(); } public function parseString($string) { $this->XML($string); return $this->process(); }
private function process() { private function process() {

View File

@@ -4,8 +4,10 @@
// Skim RTC Browser // Skim RTC Browser
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
$browser_version = "0.7.9";
require "togggle.php"; require "togggle.php";
require "debug.php"; require "lib/debug.php";
$db_dir = "skim"; $db_dir = "skim";
$icon_size = 64; $icon_size = 64;
@@ -15,6 +17,7 @@ $pad = 28;
<html> <html>
<head> <head>
<meta charset='UTF-8'>
<style> <style>
html { font-family: Helvetica; word-wrap: break-word; } html { font-family: Helvetica; word-wrap: break-word; }
@@ -23,14 +26,48 @@ 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 { width: <?=$icon_size+$pad;?>px; height: <?=$icon_size+$pad;?>px; padding: <?=$pad;?>px; }
div.item { font-size: 11px; } div.item { font-size: 11px; }
div.flexfill { width: <?=$icon_size+($pad*3);?>px; height: 1px; } div.flexfill { width: <?=$icon_size+($pad*3);?>px; height: 1px; }
div.aborted { text-decoration: line-through; }
.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; } div.size { color: grey; margin-top: 3px; }
img.thumb { padding: 6px; border: 1px solid gainsboro; } img#thumb { padding: 6px; border: 1px solid gainsboro; }
img.item { float: left; margin-right: 10px; width: 32px; height: 32px; } img#item { float: left; margin-right: 10px; width: 32px; height: 32px; }
img { margin-bottom: 8px; } img { margin-bottom: 8px; }
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; }
</style> </style>
<script src="lib/lazysizes.min.js"></script>
</head> </head>
<body> <body>
@@ -39,12 +76,58 @@ img { margin-bottom: 8px; }
// Functions // 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) { function human_filesize($bytes, $decimals = 2) {
$size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
$factor = floor((strlen($bytes) - 1) / 3); $factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor]; 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 { class plistParser extends XMLReader {
public function parseString($string) { $this->XML($string); return $this->process(); } public function parseString($string) { $this->XML($string); return $this->process(); }
private function process() { private function process() {
@@ -117,11 +200,7 @@ function shortlabel($filename, $max = 40) {
function findicon($filename) { function findicon($filename) {
$ext = pathinfo($filename)['extension']; $ext = pathinfo($filename)['extension'];
if (!$ext) { $good = "icons/null.png";
$good = "icons/directory.png";
} else {
$good = "icons/null.png";
}
foreach (glob("icons/*.png") as $file) { foreach (glob("icons/*.png") as $file) {
if (pathinfo($file)['filename'] == $ext) { if (pathinfo($file)['filename'] == $ext) {
$good = $file; $good = $file;
@@ -135,6 +214,7 @@ function findicon($filename) {
$db_file = $_GET['db']; $db_file = $_GET['db'];
$pid = $_GET['pid']; $pid = $_GET['pid'];
$search = $_POST['query']; $search = $_POST['query'];
$parser = new plistParser();
if ($db_file) { if ($db_file) {
@@ -156,13 +236,37 @@ if ($db_file) {
if (!$pid) { if (!$pid) {
$pid = $dbo->query("SELECT pid FROM family WHERE (rowid=2)")->fetch()['pid']; $pid = $dbo->query("SELECT pid FROM family WHERE (rowid=2)")->fetch()['pid'];
$view = $dbo->query("SELECT * FROM _skim")->fetchAll()[0]; $view = $dbo->query("SELECT * FROM _skim")->fetch();
// hide long strings // handle special strings
$view['qlmanage'] = "hidden"; $view['opts'] = unserialize($view['opts']);
$view['disks'] = "hidden"; $view['qlmanage'] = "hidden"; //array($view['qlmanage']);
$view['diskutil'] = "hidden"; $view['profile'] = "hidden"; //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']));
$view['disks'] = "hidden";
} else {
$view['disks'] = "hidden";
}
if (substr($view['diskutil'],0,5) == "<?xml") {
$view['diskutil'] = $parser->parseString(utf8_for_xml($view['diskutil']));
} else {
$view['diskutil'] = "hidden";
}
if ($view['vdisks']) {
$view['vdisks'] = $parser->parseString(utf8_for_xml($view['vdisks']));
}
if ($view['hdiutil']) {
$view['hdiutil'] = $parser->parseString(utf8_for_xml($view['hdiutil']));
}
} else { } else {
$view = $dbo->query("SELECT * FROM files WHERE (pid='".$pid."')")->fetchAll()[0]; $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();
} }
// Breadcrumbs // Breadcrumbs
@@ -201,11 +305,15 @@ if ($db_file) {
echo "<table><tr>"; echo "<table><tr>";
echo "<td valign='top'>"; echo "<td valign='top'>";
$row_a = $dbo->query("SELECT rowid, * FROM files WHERE (pid='".$pid."')")->fetchAll()[0]; $row_a = $dbo->query("SELECT rowid, * FROM files WHERE (pid='".$pid."')")->fetch();
if (is_serial($row_a['stat'])) {
$row_a['stat'] = unserialize($row_a['stat']);
}
if (!strpos($spotlight_status,"disabled")) { if (!strpos($spotlight_status,"disabled")) {
$row_b = $dbo->query("SELECT * FROM mdls WHERE (rowid='".$row_a['rowid']."')")->fetchAll()[0]; $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();
} }
@@ -214,18 +322,18 @@ if ($db_file) {
// newer version stores rowid rather than 0 or 1 for has_exif etc // newer version stores rowid rather than 0 or 1 for has_exif etc
if (isset($row_a['has_exif'])) { if (isset($row_a['has_exif'])) {
$row_c = $dbx->query("SELECT * FROM exiftool WHERE (rowid='".$row_a['has_exif']."')")->fetchAll()[0]; $row_c = $dbx->query("SELECT * FROM exiftool WHERE (rowid='".$row_a['has_exif']."')")->fetch();
} }
if (isset($row_a['has_mediainfo'])) { if (isset($row_a['has_mediainfo'])) {
$row_d = $dbx->query("SELECT * FROM mediainfo WHERE (rowid='".$row_a['has_mediainfo']."')")->fetchAll()[0]; $row_d = $dbx->query("SELECT * FROM mediainfo WHERE (rowid='".$row_a['has_mediainfo']."')")->fetch();
} }
} else { } else {
// fetch exif and mediainfo by slower fid // fetch exif and mediainfo by slower fid
$row_c = $dbx->query("SELECT * FROM exiftool WHERE (fid='".$row_a['fid']."')")->fetchAll()[0]; $row_c = $dbx->query("SELECT * FROM exiftool WHERE (fid='".$row_a['fid']."')")->fetch();
$row_d = $dbx->query("SELECT * FROM mediainfo WHERE (fid='".$row_a['fid']."')")->fetchAll()[0]; $row_d = $dbx->query("SELECT * FROM mediainfo WHERE (fid='".$row_a['fid']."')")->fetch();
} }
@@ -233,22 +341,90 @@ if ($db_file) {
$width = $row_a['thumb_width']; $width = $row_a['thumb_width'];
$height = $row_a['thumb_height']; $height = $row_a['thumb_height'];
$realfile = dirname($db_file).$row_a['thumb_filename']; $realfile = dirname($db_file).$row_a['thumb_filename'];
$icon = "<img src='".$realfile."' width='".$width."' height='".$height."'>"; $icon = "<img id='thumb' src='".$realfile."' width='".$width."' height='".$height."' class='lazyload'>";
} elseif ($row_a['Type'] == "dir") {
$icon = "<img src='/icons/directory.png' width='512' height='512'>";
} else { } else {
$icon = "<img src='".findicon($row_a['Filename'])."' width='512' height='512'>"; $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; 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>";
echo "</td>"; echo "</td>";
echo "<td valign='top'>"; echo "<td valign='top'>";
debug(array($row_a),"file"); debug(array($row_a),"file");
if ($row_b) { if ($row_b['spotlight']) {
$parser = new plistParser();
$row_b['spotlight'] = $parser->parseString($row_b['spotlight']);
debug(array($row_b),"mdls"); debug(array($row_b),"mdls");
} }
@@ -280,12 +456,18 @@ if ($db_file) {
///////////////////////// /////////////////////////
$row_a = $dbo->query("SELECT * FROM files WHERE (rowid='".$item."')")->fetchAll()[0]; $row_a = $dbo->query("SELECT rowid, * FROM files WHERE (rowid='".$item."')")->fetch();
$row_b = $dbo->query("SELECT * FROM mdls WHERE (rowid='".$item."')")->fetchAll()[0]; $row_b = $dbo->query("SELECT rowid, * FROM mdls WHERE (rowid='".$item."')")->fetch();
//$row_c = $dbo->query("SELECT * FROM milk WHERE (pid='".$item."')")->fetchAll()[0]; //$row_c = $dbo->query("SELECT * FROM milk WHERE (rowid='".$item."')")->fetch();
///////////////////////// /////////////////////////
if ($row_b['FSInvisible']) {
$visibility = "hidden";
} else {
$visibility = "unhidden";
}
if ($row_a['thumb_filename']) { if ($row_a['thumb_filename']) {
$aspect = $row_a['thumb_width']/$row_a['thumb_height']; $aspect = $row_a['thumb_width']/$row_a['thumb_height'];
if ($aspect > 1) { if ($aspect > 1) {
@@ -296,21 +478,34 @@ if ($db_file) {
$height = $icon_size; $height = $icon_size;
} }
$realfile = dirname($db_file).$row_a['thumb_filename']; $realfile = dirname($db_file).$row_a['thumb_filename'];
$icon = "<img class='thumb' src='".$realfile."' width='".$width."' height='".$height."'>"; $icon = "<img id='thumb' class='lazyload' data-src='".$realfile."' width='".$width."' height='".$height."'>";
} elseif ($row_a['Type'] == "dir") {
$icon = "<img src='/icons/directory.png' width='".$icon_size."' height='".$icon_size."'>";
} else { } else {
$icon = "<img class='icon' src='".findicon($row_a['Filename'])."' width='".$icon_size."' height='".$icon_size."'>"; $icon = "<img 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 "\n<a class='".$visibility."' href='?db=".$db_file."&pid=".$row_a['pid']."'>".$icon."</a>";
echo "<div class='title'>".htmlentities(shortlabel($row_a['Filename']))."</div>"; echo "<div class='title'>";
if ($row_b['UserTags']) {
foreach (unserialize($row_b['UserTags']) as $tag) {
echo "<span class='tag ".$tag."'></span>";
}
echo "&nbsp;";
}
echo htmlentities(shortlabel($row_a['Filename']));
echo "</div>";
if ($row_a['Size']) { if ($row_a['Size']) {
echo "<div class='size'>".human_filesize($row_a['Size'])."</div>"; echo "<div class='size'>".human_filesize($row_a['Size'])."</div>";
} }
if ($row_a['Type'] == "dir" && $row_a['items']) { if ($row_a['Type'] == "dir" && $row_a['items']) {
echo "<div class='size'>".$row_a['items']." items</div>"; echo "<div class='size'>".number_format($row_a['items'])." items</div>";
} }
echo "</div>"; echo "</div>";
@@ -321,7 +516,14 @@ if ($db_file) {
echo str_repeat("<div class='flexfill'></div>", 100); echo str_repeat("<div class='flexfill'></div>", 100);
echo "</div>"; echo "</div>";
echo "</td><td valign='top'>"; echo "</td><td valign='top'>";
debug($view,$view['Pathname']); debug($view,$view['Pathname']);
if ($dirmdls['spotlight']) {
$dirmdls['spotlight'] = $parser->parseString(utf8_for_xml($dirmdls['spotlight']));
debug(array($dirmdls),"mdls");
}
echo "</td></tr></table>"; echo "</td></tr></table>";
} else { } else {
@@ -363,18 +565,25 @@ if ($db_file) {
if ($dbs[0]) { if ($dbs[0]) {
$dbo = new PDO("sqlite:".$dbs[0]); $dbo = new PDO("sqlite:".$dbs[0]);
$type = $dbo->query("SELECT type FROM _skim")->fetch()['type']; $type = $dbo->query("SELECT type FROM _skim")->fetch()['type'];
echo "<img class='item' src='".$icons[$type]."'>"; echo "<img id='item' src='".$icons[$type]."'>";
} }
echo "<h2>".pathinfo($bundle)['filename']."</h2>"; echo "<h2>".pathinfo($bundle)['filename']."</h2>";
foreach ($dbs as $db_file) { foreach ($dbs as $db_file) {
$dbo = new PDO("sqlite:".$db_file); $dbo = new PDO("sqlite:".$db_file);
echo "<div>"; $info = $dbo->query("SELECT * FROM _skim")->fetch();
if (strpos($info['status'],"completed") === 0) {
$seconds = str_replace("completed_in_","",$info['status']);
$status = gmdate("H:i:s",$seconds);
echo "<div>";
} else {
echo "<div class='aborted'>";
}
echo "<a href='?db=".$db_file."'>".pathinfo($db_file)['filename']."</a>&nbsp;"; echo "<a href='?db=".$db_file."'>".pathinfo($db_file)['filename']."</a>&nbsp;";
echo $dbo->query("SELECT version FROM _skim")->fetch()['version'].", "; echo $info['version'].", ";
echo $dbo->query("SELECT passed_total FROM _skim")->fetch()['passed_total']." files, "; echo number_format($info['passed_total'])." files, ";
echo $dbo->query("SELECT status FROM _skim")->fetch()['status']; if ($info['image_file']) { echo $info['image_file'].", "; }
$spotlight_status = $dbo->query("SELECT mdutil FROM _skim")->fetch()['mdutil']; echo $status;
if (strpos($spotlight_status,"disabled")) { echo " (no spotlight)"; } if (strpos($info['spotlight_status'],"disabled")) { echo " (no spotlight)"; }
echo "</div>"; echo "</div>";
} }
echo "</div>"; echo "</div>";