Mercurial > hg > fapweb
view faptool.php @ 968:c71afc1a3a85
Moar work.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 29 Nov 2014 08:38:34 +0200 |
parents | 62c90ec5edce |
children | 26ae3f21a3bb |
line wrap: on
line source
#!/usr/bin/php <? // // FAPWeb - Simple Web-based Demoparty Management System // Special entry/preview/etc backend management commandline utility // (C) Copyright 2012-2014 Tecnic Software productions (TNSP) // require_once "mconfig.inc.php"; require_once "msite.inc.php"; function wtConvertImage($inFilename, $inFileType, $outFilename, $setDim, $setFormat, $setQuality, $thumb) { global $setPreviewPath; $isTemp = FALSE; if ($inFileType == "gfx") { // Oh great .. we need gfxconv here because Imagick handles ILBM like shit $tmpFilename = tempnam($setPreviewPath, "tmp"); $isTemp = TRUE; if (wtExec( "/usr/local/bin/gfxconv", escapeshellarg($inFilename)." -f png -o ".escapeshellarg($tmpFilename)) === false) return FALSE; if (!file_exists($tmpFilename)) { echo "ERROR: gfxconv did not output a temporary conversion inbetween.\n"; return FALSE; } } else $tmpFilename = $inFilename; // convert -resize 640x480 -background black -gravity center -extent 640x480 // -unsharp "0x0.75+0.75+0.008" lol.lbm -quality 95 test.jpg // Create conversion entity $img = new Imagick($tmpFilename); if ($img === false) { echo "ERROR: Oh noes! ImageMagick could not digest the file '".$tmpFilename."' (".$inFilename.")\n"; return FALSE; } if ($setDim !== FALSE) { if (($outDim = stGetSetting($setDim)) === FALSE || ($outFormat = stGetSetting($setFormat)) === FALSE || ($outQuality = stGetSetting($setQuality)) === FALSE) { die("Missing one of res/format/quality settings for '".$outFilename."'\n"); } // Get dimensions, setup background $dim = $img->getImageGeometry(); $img->setBackgroundColor(imagick::COLOR_BLACK); $img->setGravity(imagick::GRAVITY_CENTER); // Act based on image size vs. desired size and $thumb mode if ($thumb || $dim["width"] > $outDim[0] || $dim["height"] > $outDim[1]) { // Image is larger $img->resizeImage($outDim[0], $outDim[1], Imagick::FILTER_QUADRATIC, 1); $img->setExtent($outDim[0], $outDim[1]); $img->normalizeImage(); $img->unsharpMaskImage(0, 0.5, 1, 0.05); } else if ($dim["width"] < $outDim[0] || $dim["height"] < $outDim[1]) { // Image is smaller than requested dimension(s)? $img->resizeImage($outDim[0], $outDim[1], Imagick::FILTER_POINT, 1); $img->setExtent($outDim[0], $outDim[1]); } } $img->setFormat($outFormat); $img->setCompressionQuality($outQuality); $img->stripImage(); $img->writeImage($outFilename); $img->removeImage(); } function wtRenderSample($inFilename, $outFilename) { $sfreq = intval(stGetSetting("sampleFreq")); $sduration = intval(stGetSetting("sampleDuration")); $schannels = intval(stGetSetting("sampleChannels")); return wtExec( "/usr/local/bin/openmpt123" , "--force --quiet ". "--samplerate ".$sfreq." ". "--channels ".$schannels." ". "--playtime ".$sduration." ". escapeshellarg($inFilename)." -o ".escapeshellarg($outFilename), 0); } function wtConvertSample($inFilename, $outFilename, $outOpts) { $sfreq = intval(stGetSetting("sampleFreq")); $sduration = intval(stGetSetting("sampleDuration")); $schannels = intval(stGetSetting("sampleChannels")); foreach ($outOpts as $okey => $oval) $optStr .= $okey." ".$oval." "; return wtExec( "/usr/local/bin/avconv", "-y -t ".intval($sduration)." ". "-i ".escapeshellarg($inFilename). " ".$optStr." -ac ".$schannels. " -map_metadata -1 ". escapeshellarg($outFilename)); } function wtRenderConvertEntryToSource($inFilename, $edata, $entryFilename, &$outData, &$outFilename) { // Does compo preview type match this file class? if ($edata["class"] != $compo["preview_type"]) return FALSE; $outFilename = stReplaceFileExt($entryFilename, "_preview.".$edata["fext"]); if (file_exists($outFilename) && filemtime($outFilename) >= filemtime($entryFilename)) return FALSE; echo "CHECKING: ".$inFilename." / ".$edata["id"]."\n"; switch ($edata["class"]) { case EFILE_AUDIO: if ($edata["mime"] == "audio/x-mod") $res = wtRenderSample($inFilename, $outFilename); else $res = wtConvertSample($inFilename, $outFilename, array()); break; case EFILE_IMAGE: $res = wtConvertImage( $inFilename, $edata["mime"], $outFilename, FALSE, "PNG", 9, FALSE); break; default: return FALSE; } return $res; } function wtUnpackArchiveTo($atype, $filename, $path) { // Check file type before doing anything echo "INFO: Preparing to unpack archive file '".$filename."' ...\n"; switch ($atype) { case "LHA": $exe = "/usr/bin/lha"; $args = "x ".escapeshellarg($filename); break; case "ZIP": $exe = "/usr/bin/unzip"; $args = "-d ".escapeshellarg($path)." ".escapeshellarg($filename); break; case "RAR": $exe = "/usr/bin/rar"; $args = "x -w".escapeshellarg($path)." ".escapeshellarg($filename); break; case "7ZIP": $exe = "/usr/bin/7z"; $args = "x -o".escapeshellarg($path)." ".escapeshellarg($filename); break; default: echo "Unsupported archive file type: ".$atype."\n"; return FALSE; } // Create temporary directory wtPurgeDir($path); wtMakeDir($path, 0700); if (!is_dir($path) || chdir($path) === false) { echo "ERROR: Failed to chdir to '".$path."', can't unpack archive.\n"; return FALSE; } // Unpack archive return wtExec($exe, $args); } function wtNiceName($compo, $entry, $efile = FALSE) { return sprintf( "%d: %s by %s%s", $entry["id"], $entry["name"], $entry["author"], ($efile !== false) ? " [".$efile["filename"]." / TYPE: '".$efile["filetype"]."']" : ""); } function wtHandleEntryPreview($compo, $entry, $mode) { global $fileTypeData, $setEntryPath; // Get current preview file(s) data if (!stGetPreviewFileData($compo, $entry, $pdata)) return FALSE; // Get entry file data $efile = stFetchSQL("SELECT * FROM files WHERE deleted=0 AND id=".$entry["file_id"]); // Check preview file(s) status if ($mode == "sta" || $mode == "lis") { printf(" %03d | %s%s%s | %-40s | %-5s | %s\n", $entry["id"], ($efile !== false) ? "E" : ".", isset($pdata["file"]) ? "P" : ".", $pdata["valid"] ? "V" : ".", substr($entry["name"]." by ".$entry["author"], 0, 40), isset($pdata["file"]) ? $pdata["file"]["filetype"] : "", isset($pdata["file"]) ? $pdata["file"]["filename"] : "" ); return TRUE; } else if ($mode != "upd") die("ERROR: Unsupported previews mode ".$mode."\n"); // Check validity of previews if ($pdata["valid"]) return TRUE; // Okay, no valid previews .. lets see what we can do .. // First, check if we have a source preview file if (!isset($pdata["file"])) { // No source preview, check if we have entry file either? if ($efile === false) { echo "INFO: No entry file for ".wtNiceName($compo, $entry, $efile). ", can't attempt to generate preview.\n"; return FALSE; } // Actual entry filename + path $filename = stMakePath(FALSE, TRUE, array($setEntryPath, $compo["cpath"], $efile["filename"])); if (!file_exists($filename)) { echo "ERROR: Entry file '".$filename."' for ".wtNiceName($compo, $entry, FALSE)." does not exist!\n"; return FALSE; } // Preview source file does not exist, let's see .. $edata = stProbeFileInfo($filename, TRUE); if ($edata === false) { echo "ERROR: Invalid/unsupported file type for entry ".wtNiceName($compo, $entry, $efile)."\n"; return FALSE; } $found = FALSE; if ($edata["class"] == EFILE_ARCHIVE) { // Entry is an archive file .. $path = stMakePath(FALSE, FALSE, array($setEntryPath, "UNPACKS", $efile["filename"])); echo "INFO: Entry file is an ".$efile["filetype"]." archive, scanning '".$filename."' ...\n"; if (wtUnpackArchiveTo($efile["filetype"], $filename, $path) === false) return FALSE; // Scan through files ... $dir = opendir($path); while (($dentry = readdir($dir)) !== false) { $fname = $path."/".$dentry; // check file type against entry's preview_type // if match, render / convert / cp to as source and exit loop. if (is_file($fname) && ($mdata = stProbeFileInfo($fname, TRUE)) !== false && ($found = wtRenderConvertEntryToSource($fname, $mdata, $filename, $pdata, $outFilename)) === true) break; } // Cleanup closedir($dir); wtPurgeDir($path); } else if ($edata["class"] == $compo["preview_type"]) { // Single file $found = wtRenderConvertEntryToSource($filename, $edata, $filename, $pdata, $outFilename); } if (!$found) { echo "WARNING: Could not generate preview from entry ".wtNiceName($compo, $entry, $efile)."\n"; return FALSE; } } // Either we now have a sourcefile or generated file switch ($outData["class"]) { case EFILE_AUDIO: foreach (stGetSetting("sampleTypes") as $stype => $sopts) { if (!isset($fileTypeData[$stype])) die("Internal error: Sample type ".$stype." in sampleTypes in mconfig.inc.php, but not defined in file type data.\n"); $filename = $pdata["files"][$sdata]["file"]; wtConvertSample( $inFilename, stMakePath(FALSE, TRUE, array($setPreviewPath, $compo["cpath"], $filename)), $sopts ); } break; case EFILE_IMAGE: wtConvertImage($inFilename, stMakePath(FALSE, TRUE, array($setPreviewPath, $compo["cpath"], $filename)), "previewImageSize", "previewImageType", "previewImageQuality", FALSE); wtConvertImage($inFilename, stMakePath(FALSE, TRUE, array($setPreviewPath, $compo["cpath"], $setThumbPath, $filename)), "previewThumbSize", "previewThumbType", "previewThumbQuality", TRUE); break; } return TRUE; } function wtHandleEntry($compo, $entry, $mode) { } function wtUnpackEntry($compo, $entry, $pathPrefix, $useOrig = TRUE) { global $setEntryPath; if (($efile = stFetchSQL("SELECT * FROM files WHERE deleted=0 AND id=".$entry["file_id"])) === false) { echo "INFO: No entry file for ".wtNiceName($compo, $entry, $efile)."\n"; return FALSE; } $filename = stMakePath(FALSE, TRUE, array($setEntryPath, $compo["cpath"], $efile["filename"])); if (!file_exists($filename)) { echo "ERROR: Entry file '".$filename."' for ".wtNiceName($compo, $entry, FALSE)." does not exist!\n"; return FALSE; } $edata = stProbeFileInfo($filename, TRUE); if ($edata === false) { echo "ERROR: Invalid/unsupported file type for entry ".wtNiceName($compo, $entry, $efile)."\n"; return FALSE; } if (wtMakeDir(stMakePath(FALSE, FALSE, array($pathPrefix, $compo["cpath"])), 0755) === false) return FALSE; $dstFileBase = $entry["show_id"]."--".($useOrig ? $efile["origname"] : $efile["filename"]); if ($edata["class"] == EFILE_ARCHIVE) { // Entry is an archive file .. $dstPath = stMakePath(FALSE, FALSE, array($pathPrefix, $compo["cpath"], stReplaceFileExt($dstFileBase, ""))); if (wtUnpackArchiveTo($edata["id"], $filename, $dstPath) === false) return FALSE; } else { $dstFilename = stMakePath(FALSE, FALSE, array($pathPrefix, $compo["cpath"], $dstFileBase)); if (copy($filename, $dstFilename) === false) { echo "Failed to copy '".$filename."' to '".$dstFilename."'\n"; return FALSE; } } return TRUE; } // // Misc helper functions // function wtExec($exe, $args, $expect = 0) { echo "EXEC: ".$exe." ".$args."\n"; exec(escapeshellcmd($exe)." ".$args, $output, $code); if ($code !== $expect) { echo "ERROR: Executing ".$exe.": ".$code."\n".$args."\n". "------------------------------------------------\n". implode("\n", $output). "------------------------------------------------\n"; return FALSE; } return TRUE; } function wtExecOrDie($exe, $args) { if (wtExec($exe, $args) === false) die(); } function wtPurgeDir($path) { if ($path != "" && $path !== false && file_exists($path) && is_dir($path)) { echo "PURGING: ".$path."\n"; foreach (scandir($path) as $file) if ($file !== "." && $file !== "..") { $sub = $path."/".$file; if (is_dir($sub)) wtPurgeDir($sub); else { echo " - ".$sub."\n"; unlink($sub); } } rmdir($path); } } function wtMakeDir($path, $perm) { if (!file_exists($path)) { echo "INFO: Creating ".$path."\n"; if (mkdir($path, $perm, TRUE) === false) die("Could not create directory '".$path."'\n"); } } function wtInitializeDirs() { global $setEntryPath, $setPreviewPath, $setThumbDir, $setEntryPathPerms, $setPrevPathPerms; echo "Checking for missing directories ...\n"; wtMakeDir($setEntryPath, $setEntryPathPerms); wtMakeDir($setPreviewPath, $setPrevPathPerms); foreach (stExecSQL("SELECT * FROM compos WHERE cpath <> '' AND cpath IS NOT NULL") as $compo) { wtMakeDir(stMakePath(FALSE, FALSE, array($setEntryPath, $compo["cpath"])), $setEntryPathPerms); wtMakeDir(stMakePath(FALSE, FALSE, array($setPreviewPath, $compo["cpath"])), $setPrevPathPerms); wtMakeDir(stMakePath(FALSE, FALSE, array($setPreviewPath, $compo["cpath"], $setThumbDir)), $setPrevPathPerms); } } function wtPrintCompoHeader($compo) { global $setTermWidth; printf("==%'=-".($setTermWidth-2)."s\n", sprintf("[ #%03d - %s ]", $compo["id"], substr($compo["name"], 0, 40)) ); } function wtPrintDivider($chr = "-") { global $setTermWidth; echo str_repeat($chr, $setTermWidth)."\n"; } function wtShowHelp() { global $argv; echo "faptool - Do stuff with FAPWeb database\n". "(C) Copyright 2014 ccr/TNSP\n". "\n". "Usage: ".$argv[0]." <command> [args]\n". "Where command is one of following:\n". "\n". " init\n". " Create directories for entries and previews, if needed.\n". "\n". /* " clean [delete|crap]\n". " Clean files marked to be deleted and 'stale' files. This includes\n". " any old or stale preview files and entry files.\n". " Without 'delete' parameter just checks and shows what would deleted.\n". " 'crap' parameter will purge EVERYTHING that is NOT in the database,\n". " e.g. any other files, like temp files, etc. DANGEROUS IF YOU DO NOT\n". " KNOW WHAT YOU ARE DOING!!!!!\n". "\n". */ " probe <filename> [filename2 ..]\n". " Probe specified file for file information.\n". "\n". " previews <cmd> [args]\n". " Where <cmd> is one of:\n". " status [cid] - List files and show what is missing, etc. (All or <cid>)\n". " update - Generate preview files that are missing OR out of date.\n". " (older then preview source file OR entry file where appropriate)\n". // " add <entry_id> <filename> - Add file as preview for entry_id.\n". "\n". " entry <cmd> [args]\n". " status [cid] - List entries for all compos or <cid>.\n". " unpack <path> - Create subdirs and copy all entries UNPACKED there.\n". /* " add <filename> '<name>' '<author>' - Add file as entry file\n". " (works same as uploading from admin interface)\n". " package <lha|zip|rar|7z>\n". " Repackages/packages entries (unpacks first if archive),\n". " and adds generated infofile.txt to packages.\n". */ "\n"; } // // Main program starts // stCheckCLIExec(); if ($argc < 2) { wtShowHelp(); exit; } // Try to connect to database $spec = stGetSetting("sqlDB"); if (($db = stConnectSQLDBSpec($spec)) === false) die("Could not connect to SQL database '".$spec."'.\n"); echo "Using database spec '".$spec."'.\n"; // Fetch non-"hardcoded" settings from SQL database stReloadSettings(); // Set some globals for our benefit $setTermWidth = 75; $setEntryPath = stGetSetting("entryPath"); $setPreviewPath = stGetSetting("previewPath"); $setPreviewURL = stGetSetting("previewURL"); $setThumbDir = stGetSetting("thumbnailSubDir"); $setEntryPathPerms = stGetSetting("entryPathPerms"); $setPrevPathPerms = stGetSetting("previewPathPerms"); if ($setEntryPath === FALSE || $setPreviewPath === FALSE || $setPreviewURL === FALSE || $setThumbDir === FALSE || $setEntryPathPerms === FALSE || $setPrevPathPerms === FALSE) { die("Some required settings are not defined in mconfig.inc.php!\n"); } // Act according to specified command switch (substr(stCArgLC(1), 0, 3)) { case "-?": case "--h": wtShowHelp(); exit; break; case "ini": // // Initialize the data directories etc // echo "INFO: Checking for missing directories ...\n"; wtInitializeDirs(); break; case "pro": // // Probe specified files // if ($argc < 2) die("No filename specified.\n"); if (($finfo = finfo_open()) === false) die("Internal error. Failed to initialize finfo()."); for ($i = 2; $i < $argc; $i++) { // Probe one file $filename = $argv[$i]; $sdata = @finfo_file($finfo, $filename, FILEINFO_NONE); $smime = @finfo_file($finfo, $filename, FILEINFO_MIME_TYPE); echo "\n". "File : ".$filename."\n". "Probed : ".$sdata."\n". "Mime : ".$smime."\n"; if (($info = stProbeFileInfo($filename, TRUE)) !== false) { $tmp = array(); foreach ($info as $ikey => $ival) $tmp[] = $ikey."='".$ival."'"; echo "Data : ".implode(", ", $tmp)."\n"; } } finfo_close($finfo); break; case "cle": // // File cleanup / deletion // $doDelete = (stCArgLC(2) == "delete"); foreach (stExecSQL("SELECT * FROM compos WHERE cpath <> '' AND cpath IS NOT NULL") as $compo) if (stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo["id"]) > 0) { wtPrintCompoHeader($compo); wtPrintDivider(); foreach (stExecSQL("SELECT * FROM entries WHERE compo_id=".$compo["id"]) as $entry) { foreach (stExecSQL("SELECT * FROM files WHERE entry_id=".$entry["id"]) as $efile) { if ($efile["deleted"] != 0) { echo "X"; } } } echo "\n"; wtPrintDivider(); } break; case "ent": // // Entry files handling // $mode = substr(stCArgLC(2), 0, 3); switch ($mode) { case "sta": case "lis": $sql = (stCArg(3) != "") ? " AND id=".intval(stCArg(3)) : ""; foreach (stExecSQL("SELECT * FROM compos WHERE cpath <> '' AND cpath IS NOT NULL".$sql) as $compo) if (stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo["id"]) > 0) { wtPrintCompoHeader($compo); wtPrintDivider(); foreach (stExecSQL("SELECT * FROM entries WHERE compo_id=".$compo["id"]) as $entry) wtHandleEntry($compo, $entry, $mode); wtPrintDivider(); } break; case "unp": if (($setPrefix = stCArg(3)) == "") die("Unpack needs a destination path.\n"); foreach (stExecSQL("SELECT * FROM compos WHERE cpath <> '' AND cpath IS NOT NULL") as $compo) foreach (stExecSQL("SELECT * FROM entries WHERE compo_id=".$compo["id"]) as $entry) { wtUnpackEntry($compo, $entry, $setPrefix); } break; case "pac": echo "Not implemented. :D\n"; break; case "add": echo "Not implemented. :D\n"; break; default: if ($mode == "") die("ERROR! Entry command requires a sub-command argument.\n"); else die("ERROR! Invalid entry sub-command '".stCArg(2)."'.\n"); break; } break; case "pre": // // Preview files handling // $mode = substr(stCArgLC(2), 0, 3); switch ($mode) { case "upd": case "sta": case "lis": $sql = (stCArg(3) != "") ? " AND id=".intval(stCArg(3)) : ""; foreach (stExecSQL("SELECT * FROM compos WHERE cpath <> '' AND cpath IS NOT NULL".$sql) as $compo) if (stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo["id"]) > 0) { wtPrintCompoHeader($compo); printf( "PrevType : %s\n", $previewTypeList[$compo["preview_type"]][0]); if ($mode == "sta" || $mode == "lis") { printf(" %-3s | %-3s | %-40s |\n", "#ID", "EPV", "Entry name/author"); } wtPrintDivider("-"); foreach (stExecSQL("SELECT * FROM entries WHERE compo_id=".$compo["id"]) as $entry) wtHandleEntryPreview($compo, $entry, $mode); wtPrintDivider("="); } if ($mode == "sta" || $mode == "lis") { echo "Flags: E = Entry has file, P = Has preview file, V = Generated previews are up to date.\n"; } break; case "add": echo "Not implemented. :D\n"; break; default: if ($mode == "") die("ERROR! Previews command requires a sub-command argument.\n"); else die("ERROR! Invalid previews sub-command '".stCArg(2)."'.\n"); break; } break; default: echo "ERROR! Invalid operation mode '".stCArg(1)."'.\n"; break; } /* Dummy { } */ ?>