diff --git a/airtime_mvc/application/models/Playlist.php b/airtime_mvc/application/models/Playlist.php index 826977be6..07f9ef848 100644 --- a/airtime_mvc/application/models/Playlist.php +++ b/airtime_mvc/application/models/Playlist.php @@ -113,6 +113,12 @@ class Playlist { return TRUE; } + public static function deleteAll() + { + global $CC_CONFIG, $CC_DBC; + $sql = 'DELETE FROM '.$CC_CONFIG["playListTable"]; + $CC_DBC->query($sql); + } /** * Delete the file from all playlists. diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index 4d68df7b3..7b9183d8f 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -60,10 +60,10 @@ class ScheduleGroup { if (empty($length)) { return new PEAR_Error("Length is empty."); } - + // Insert into the table $this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')"); - + $sql = "INSERT INTO ".$CC_CONFIG["scheduleTable"] ." (instance_id, starts, ends, clip_length, group_id, file_id, cue_out)" ." VALUES ($p_showInstance, TIMESTAMP '$p_datetime', " @@ -76,7 +76,7 @@ class ScheduleGroup { return $result; } - } + } elseif (!is_null($p_playlistId)){ // Schedule a whole playlist @@ -606,7 +606,7 @@ class Schedule { } else { $range_end = Schedule::PypoTimeToAirtimeTime($p_toDateTime); } - + // Scheduler wants everything in a playlist $data = Schedule::GetItems($range_start, $range_end, true); $playlists = array(); @@ -681,5 +681,11 @@ class Schedule { return $result; } + + public static function deleteAll() + { + global $CC_CONFIG, $CC_DBC; + $CC_DBC->query("TRUNCATE TABLE ".$CC_CONFIG["scheduleTable"]); + } } diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 06a69ce08..01e0b8f00 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -1,6 +1,6 @@ gunid = $p_gunid; if (empty($this->gunid)) { $this->gunid = StoredFile::generateGunid(); } else { - $this->loadMetadata(); - $this->exists = is_file($this->filepath) && is_readable($this->filepath); + if ($p_autoload) { + $this->loadMetadata(); + $this->exists = is_file($this->filepath) && is_readable($this->filepath); + } } } @@ -730,7 +734,6 @@ class StoredFile { return $storedFile; } - /** * Create instance of StoreFile object and recall existing file * by gunid. @@ -757,6 +760,14 @@ class StoredFile { } + public static function GetAll() + { + global $CC_CONFIG, $CC_DBC; + $sql = "SELECT * FROM ".$CC_CONFIG["filesTable"]; + $rows = $CC_DBC->GetAll($sql); + return $rows; + } + /** * Generate the location to store the file. * It creates the subdirectory if needed. @@ -1205,6 +1216,31 @@ class StoredFile { } + public static function deleteById($p_id) + { + global $CC_CONFIG, $CC_DBC; + if (!is_numeric($p_id)) { + return FALSE; + } + $sql = "DELETE FROM ".$CC_CONFIG["filesTable"]." WHERE id=$p_id"; + + $res = $CC_DBC->query($sql); + if (PEAR::isError($res)) { + return $res; + } + return TRUE; + } + + public static function deleteAll() + { + global $CC_CONFIG, $CC_DBC; + $files = StoredFile::getAll(); + foreach ($files as $file) { + $media = StoredFile::Recall($file["id"]); + $media->delete(); + } + } + /** * Returns an array of playlist objects that this file is a part of. * @return array @@ -1555,7 +1591,7 @@ class StoredFile { } - public static function searchPlaylistsForSchedule($datatables) + public static function searchPlaylistsForSchedule($datatables) { $fromTable = "cc_playlist AS pl LEFT JOIN cc_playlisttimes AS plt USING(id) LEFT JOIN cc_subjs AS sub ON pl.editedby = sub.id"; //$datatables["optWhere"][] = "INTERVAL '{$time_remaining}' > INTERVAL '00:00:00'"; diff --git a/utils/airtime-clean-storage b/utils/airtime-clean-storage index b96bb7d21..9f100b0ef 100755 --- a/utils/airtime-clean-storage +++ b/utils/airtime-clean-storage @@ -21,6 +21,14 @@ # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- -# This script cleans audio files in the Airtime storageServer. +# This script cleans audio files in Airtime. +# +# Absolute path to this script +SCRIPT=`readlink -f $0` +# Absolute path this script is in +SCRIPTPATH=`dirname $SCRIPT` -php -q airtime-clean-storage.php "$@" || exit 1 +invokePwd=$PWD +cd $SCRIPTPATH + +php -q airtime-clean-storage.php "$@" || exit 1 diff --git a/utils/airtime-clean-storage.php b/utils/airtime-clean-storage.php index ba962e29f..f91d697ef 100644 --- a/utils/airtime-clean-storage.php +++ b/utils/airtime-clean-storage.php @@ -8,118 +8,102 @@ if (isset($arr["DOCUMENT_ROOT"]) && ($arr["DOCUMENT_ROOT"] != "") ) { echo "400 Not executable\r\n"; exit(1); } - +set_include_path('/var/www/airtime/library' . PATH_SEPARATOR . get_include_path()); +set_include_path('/var/www/airtime/application/models' . PATH_SEPARATOR . get_include_path()); require_once('/var/www/airtime/application/configs/conf.php'); -//require_once('/var/www/airtime/install/installInit.php'); require_once('/var/www/airtime/application/models/StoredFile.php'); require_once('DB.php'); +require_once 'propel/runtime/lib/Propel.php'; +Propel::init('/var/www/airtime/application/configs/airtime-conf.php'); -function printUsage() { - global $CC_CONFIG; - - echo "Usage:\n"; - echo " ./airtime-clean-storage [OPTION] \n"; - echo "\n"; - echo "Options:\n"; - echo " -c, --clean Removes all broken links from the storage server\n"; - echo " and empties all missing file information from the database.\n"; - echo "\n"; - echo " -e, --empty Removes all files from the storage server \n"; - echo " and empties all relevant information from the database.\n\n"; - echo "Storage server: ". realpath($CC_CONFIG["storageDir"]) ."\n\n\n"; -} - -function airtime_clean_files($p_path) { - if (!empty($p_path) && (strlen($p_path) > 4)) { - list($dirList,$fileList) = File_Find::maptree($p_path); - - $array_mus; - foreach ($fileList as $filepath) { - - if (@substr($filepath, strlen($filepath) - 3) != "xml") { - $array_mus[] = $filepath; - } - } - - foreach ($array_mus as $audio_file) { - - if (@is_link($audio_file) && !@stat($audio_file)) { - - //filesystem clean up. - @unlink($audio_file); - echo "unlinked $audio_file\n"; - @unlink($audio_file . ".xml"); - echo "unlinked " . $audio_file . ".xml\n"; - @rmdir(@dirname($audio_file)); - echo "removed dir " . @dirname($audio_file) . "\n"; - - //database clean up. - $stored_audio_file = StoredFile::RecallByGunid(@basename($audio_file)); - $stored_audio_file->delete(); - } - } - - } -} - -function airtime_remove_files($p_path) { - - if (!empty($p_path) && (strlen($p_path) > 4)) { - list($dirList,$fileList) = File_Find::maptree($p_path); - - foreach ($fileList as $filepath) { - echo " * Removing $filepath\n"; - @unlink($filepath); - echo "done.\n"; - } - foreach ($dirList as $dirpath) { - echo " * Removing $dirpath\n"; - @rmdir($dirpath); - echo "done.\n"; +/** + * + * Look through all the files in the database and remove the rows + * that have no associated file. + * + * @return int + * The total number of files that were missing. + */ +function airtime_clean_files() { + $count = 0; + $files = StoredFile::GetAll(); + foreach ($files as $file) { + if (($file["ftype"] == "audioclip") && !@file_exists($file["filepath"])) { + echo " * Removing metadata for id ".$file["id"].":".PHP_EOL; + echo " * File path: ".$file["filepath"].PHP_EOL; + echo " * Track title: ".$file["track_title"].PHP_EOL; + echo " * Artist: ".$file["artist_name"].PHP_EOL; + echo " * Album: ".$file["album_title"].PHP_EOL; + StoredFile::deleteById($file["id"]); + $count++; } } + return $count; } -function airtime_empty_db($db) { - global $CC_CONFIG; +function airtime_empty_db($db) +{ + global $CC_CONFIG, $CC_DBC; - if (!PEAR::isError($db)) { - if (AirtimeInstall::DbTableExists($CC_CONFIG['filesTable'])) { - echo " * Deleting from database table ".$CC_CONFIG['filesTable']."\n"; - $sql = "DELETE FROM ".$CC_CONFIG['filesTable']; - AirtimeInstall::InstallQuery($sql, false); - } - else { - echo " * Skipping: database table ".$CC_CONFIG['filesTable']."\n"; - } - } + // NOTE: order matter here. + echo " * Clearing schedule table...".PHP_EOL; + Schedule::deleteAll(); + + // Ugly hack + echo " * Resetting show instance times to zero...".PHP_EOL; + $sql = "UPDATE cc_show_instances SET time_filled='00:00:00'"; + $CC_DBC->query($sql); + + echo " * Clearing playlist table...".PHP_EOL; + Playlist::deleteAll(); + + echo " * Clearing files table...".PHP_EOL; + StoredFile::deleteAll(); } global $CC_CONFIG; +require_once('Zend/Loader/Autoloader.php'); +$autoloader = Zend_Loader_Autoloader::getInstance(); + +try { + $opts = new Zend_Console_Getopt( + array( + 'help|h' => 'Displays usage information.', + 'clean|c' => 'Removes all audio file metadata from the database that does not have a matching file in the filesystem.', + 'empty|e' => 'Removes all files and playlists from Airtime.' + ) + ); + $opts->parse(); +} catch (Zend_Console_Getopt_Exception $e) { + exit($e->getMessage() .PHP_EOL. $e->getUsageMessage()); +} + +if (isset($opts->h)) { + echo PHP_EOL; + echo $opts->getUsageMessage(); + echo "Storage directory: ". realpath($CC_CONFIG["storageDir"]).PHP_EOL.PHP_EOL; + exit; +} + $CC_DBC = DB::connect($CC_CONFIG['dsn'], TRUE); $CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC); -if ($argc != 2){ - printUsage(); - exit(1); +if (isset($opts->e)) { + echo PHP_EOL; + airtime_empty_db($CC_DBC); + echo "Done.".PHP_EOL.PHP_EOL; +} elseif (isset($opts->c)) { + $count = airtime_clean_files($CC_CONFIG['storageDir']); + if ($count == 0) { + echo PHP_EOL."All file metadata in the database is linked to a real file. Nothing to be done.".PHP_EOL.PHP_EOL; + } else { + echo PHP_EOL."Total rows removed: $count".PHP_EOL; + } +} else { + echo PHP_EOL; + echo $opts->getUsageMessage(); + echo "Storage directory: ". realpath($CC_CONFIG["storageDir"]).PHP_EOL.PHP_EOL; } - -switch($argv[1]){ - - case '-e': - case '--empty': - airtime_empty_db($CC_DBC); - airtime_remove_files($CC_CONFIG['storageDir']); - break; - case '-c': - case '--clean': - airtime_clean_files($CC_CONFIG['storageDir']); - break; - default: - printUsage(); - -} - diff --git a/utils/airtime-import b/utils/airtime-import index 4c8d8fdc1..d2c67c12f 100755 --- a/utils/airtime-import +++ b/utils/airtime-import @@ -21,7 +21,7 @@ # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- -# This script imports audio files to the Airtime storageServer. +# This script imports audio files into Airtime. # # To get usage help, try the -h option #------------------------------------------------------------------------------- diff --git a/utils/airtime-import.php b/utils/airtime-import.php index 3e497e7f9..5c11165c3 100644 --- a/utils/airtime-import.php +++ b/utils/airtime-import.php @@ -10,14 +10,16 @@ ini_set('memory_limit', '128M'); set_time_limit(0); error_reporting(E_ALL); -set_error_handler("camp_import_error_handler", E_ALL & !E_NOTICE); +set_error_handler("import_error_handler", E_ALL & !E_NOTICE); + +set_include_path('/var/www/airtime/library' . PATH_SEPARATOR . get_include_path()); require_once("/var/www/airtime/application/configs/conf.php"); require_once("/var/www/airtime/application/models/StoredFile.php"); require_once('DB.php'); require_once('Console/Getopt.php'); -function camp_import_error_handler() +function import_error_handler() { echo var_dump(debug_backtrace()); exit(); @@ -92,7 +94,7 @@ function import_err($p_pearErrorObj, $txt='') * * @return int */ -function camp_import_audio_file($p_filepath, $p_importMode = null, $p_testOnly = false) +function import_audio_file($p_filepath, $p_importMode = null, $p_testOnly = false) { global $STORAGE_SERVER_PATH; global $g_fileCount; @@ -126,7 +128,7 @@ function camp_import_audio_file($p_filepath, $p_importMode = null, $p_testOnly = while (false !== ($file = readdir($d))) { if ($file != "." && $file != "..") { $path = "$p_filepath/$file"; - camp_import_audio_file($path, $p_importMode, $p_testOnly); + import_audio_file($path, $p_importMode, $p_testOnly); } } closedir($d); @@ -241,7 +243,7 @@ if ($DEBUG_IMPORT) { $dsn = $CC_CONFIG['dsn']; } //PEAR::setErrorHandling(PEAR_ERROR_RETURN); -PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, "camp_import_error_handler"); +PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, "import_error_handler"); $CC_DBC = DB::connect($dsn, TRUE); if (PEAR::isError($CC_DBC)) { echo "ERROR: ".$CC_DBC->getMessage()." ".$CC_DBC->getUserInfo()."\n"; @@ -301,13 +303,14 @@ if (is_null($importMode)) { global $CC_CONFIG; -if (!is_writable($CC_CONFIG["storageDir"])) { +if ( ($importMode == "copy") && !is_writable($CC_CONFIG["storageDir"])) { echo "ERROR: You do not have write permissions to the directory you are trying to import to:\n " . $CC_CONFIG["storageDir"] . "\n\n"; exit; } global $g_fileCount; global $g_duplicates; +$g_fileCount = 0; if (is_array($files)) { foreach ($files as $filepath) { // absolute path @@ -323,7 +326,7 @@ if (is_array($files)) { echo "ERROR: I cant find the given file: $filepath\n\n"; exit; } - camp_import_audio_file($fullPath, $importMode, $testonly); + import_audio_file($fullPath, $importMode, $testonly); } } $end = intval(date('U')); @@ -336,7 +339,9 @@ if ($time > 0) { echo "==========================================================================\n"; echo " *** Import mode: $importMode\n"; -echo " *** Destination folder: ".$CC_CONFIG['storageDir']."\n"; +if ($importMode == "copy") { + echo " *** Destination folder: ".$CC_CONFIG['storageDir']."\n"; +} echo " *** Files imported: $g_fileCount\n"; echo " *** Duplicate files (not imported): $g_duplicates\n"; if ($g_errors > 0) {