From 52a84629dad633601db4831ef9c207682a446ec1 Mon Sep 17 00:00:00 2001 From: Naomi Date: Mon, 18 Apr 2011 17:50:04 -0400 Subject: [PATCH 01/13] airtime ini files weren't being updated on clean install. --- install/airtime-install.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/airtime-install.php b/install/airtime-install.php index 97a337ca1..5e6923916 100644 --- a/install/airtime-install.php +++ b/install/airtime-install.php @@ -51,10 +51,10 @@ else if (!isset($opts->p) && !isset($opts->o)) { } } else { - echo "* Creating INI files".PHP_EOL; - AirtimeIni::CreateIniFiles(); + $overwrite = true; } } + if ($overwrite) { echo "* Creating INI files".PHP_EOL; AirtimeIni::CreateIniFiles(); From 290d0b1b3fdca27e346fd18d04d80eae9e7641d5 Mon Sep 17 00:00:00 2001 From: Paul Baranowski Date: Tue, 19 Apr 2011 11:12:16 -0400 Subject: [PATCH 02/13] Updated changelog and credits for 1.8 --- CREDITS | 57 +++++++++++++++---------------------------------------- Changelog | 36 ++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/CREDITS b/CREDITS index ecc85298c..f8a2bdd66 100644 --- a/CREDITS +++ b/CREDITS @@ -19,51 +19,24 @@ Daniel James Paul Baranowski (paul.baranowski@sourcefabric.org) Role: Project Manager -Version 1.8.0 -------------- --The calendar is now faster by 5-8X. For example, if the "month" calendar view had shows scheduled for every hour of every day, it used to take 16 seconds to load. Now it takes 2 seconds. --Users can now edit shows. Now it is possible to change a show after it is created - you can change the simple stuff, like "Name", "Description", and "URL", but also change the complex stuff like repeat days and rebroadcast days. --It is possible to have up to ten rebroadcast shows now, previously it was only up to five. Rebroadcast shows are hidden --New improved look & feel of the calendar (thanks to the "FullCalendar" jQuery project). --Installation now puts files in standard locations in the Linux file hierarchy, which prepares the project to be accepted into Ubuntu and Debian. Also because of our wish to be part of those projects, the default output stream type is now OGG instead of MP3 -- due to MP3 licensing issues. This configuration can be changed in "/etc/airtime/liquidsoap.conf". --You now have the ability to start and stop pypo and the show recorder from the command line with the commands "airtime-pypo-start", "airtime-pypo-stop", "airtime-show-recorder-start", and "airtime-show-recorder-stop". --The installation script now has two options: --perserve to keep your existing config files, or --overwrite to replace your existing config files with new ones. --Uninstall will no longer remove your Airtime config files or remove your music storage directory. --Bug fixes: - -CC-2192 Schedule sent to pypo is not sorted by start time. - -CC-2175 Overbooking: Cut off shows when they are done - -CC-2174 Need formatting and a warning icon for the message for overbooking a show - -CC-2039 Upload file: file name cropped - -CC-2177 Schedule editing does not work under Firefox 4 - Version 1.7.0 ------------- --Recording and automatic scheduling/broadcasting of live shows - -Recording/rebroadcast status of a show is shown in "Now Playing" and "Calendar" - -Can rebroadcast a show at multiple times and dates --Automatic upload of recorded shows to Soundcloud --Frontend JQuery widgets for public-facing websites to show your visitors what's playing and the upcoming schedule --Ability to over-book a show and automatically cut and fade out song if it goes beyond the show time --Ability to delete audio files --Ability to cancel the currently playing show --Any changes to the schedule are immediately seen by the playout engine - -In version 1.6, you had to make sure that your show was ready to go 30 seconds before it started. --Upgrade support (should be able to upgrade from any version, unlike 1.6.1 which required an uninstall of 1.6.0 first) --"Now Playing" list view: - -audio items are now grouped by show. - -If a show is not fully scheduled, the user is notified how many seconds of silence are at the end of the show in this View. - -Audio items that play past the show's end time have a visual notification that they will be cut off --Ability to change metadata tag display format for web streams --Config files moved to /etc/airtime. This means all config files are in one convenient location and separated from the code, so you can -upgrade your code independently of your config files. --Redesign of Preferences screen --Bug fixes: - -CC-2082 OGG stream dies after every song when using MPlayer - -CC-1894 Warn users about time zone differences or clock drift problems on the server - -CC-2058 Utilities are not in the system $PATH - -CC-2051 Unable to change user password - -CC-2030 Icon needed for Cue In/Out - -CC-1955 Special character support in the library search +Naomi Aro (naomi.aro@sourcefabric.org) + Role: Software Developer + +Martin Konecny (martin.konecny@sourcefabric.org) + Role: Software Developer + +Ofir Gal (ofir.gal@sourcefabric.org) + Role: QA + +Daniel James + Role: Documentor & QA + +Paul Baranowski (paul.baranowski@sourcefabric.org) + Role: Project Manager + Version 1.6.1 ------------- diff --git a/Changelog b/Changelog index 398838edf..3aba0b7ed 100644 --- a/Changelog +++ b/Changelog @@ -1,10 +1,36 @@ 1.8.0 - April 19, 2011 - * Ability to edit a show - * Speedup of calendar (approx to 5-8x faster now) - * Install process now put files in the right place for linux systems - * Improvements to upgrade framework + * The biggest feature of this release is the ability to edit shows. You can + change everything from ‘Name’, ‘Description’, and ‘URL’, to repeat and + rebroadcast days. Show instances will be dynamically created or removed as + needed. Radio stations will be pleased to know they can now have up to + ten rebroadcast shows too. + * Airtime’s calendar now looks, feels and performs better than ever. Loading + a station schedule is now five to eight times faster. In our tests of 1.7, + if the month calendar had shows scheduled for every hour of every day, it + used to take 16 seconds to load. Now in 1.8 it takes two seconds. + * It is possible to have up to ten rebroadcast shows now, in 1.7 it was only + up to five. + * Airtime’s new installation script has two options for increased install + flexibility: --preserve to keep your existing config files, or --overwrite + to replace your existing config files with new ones. Uninstall no longer + removes Airtime config files or the music storage directory. + * New improved look & feel of the calendar (thanks to the "FullCalendar" + jQuery project). + * Installation now puts files in standard locations in the Linux file + hierarchy, which prepares the project to be accepted into Ubuntu and Debian. + Also because of our wish to be part of those projects, the default output + stream type is now OGG instead of MP3 -- due to MP3 licensing issues. + This configuration can be changed in "/etc/airtime/liquidsoap.conf". + * You now have the ability to start and stop pypo and the show recorder from + the command line with the commands "airtime-pypo-start", + "airtime-pypo-stop", "airtime-show-recorder-start", and + "airtime-show-recorder-stop". * Bug fixes: - o CC-2192 Schedule sent to pypo is not sorted by start time. + * CC-2192 Schedule sent to pypo is not sorted by start time. + * CC-2175 Overbooking: Cut off shows when they are done + * CC-2174 Need formatting and a warning icon for the message for overbooking a show + * CC-2039 Upload file: file name cropped + * CC-2177 Schedule editing does not work under Firefox 4 1.7.0 - April 4, 2011 * Recording and automatic scheduling/broadcasting of live shows From 171828f8ad829bb0bd24e088eb1514fb7ca4184e Mon Sep 17 00:00:00 2001 From: martin Date: Wed, 20 Apr 2011 00:46:03 -0400 Subject: [PATCH 03/13] CC-2186: Integration of a logger tool -initial check-in. Everything appears to be working... --- airtime_mvc/application/Bootstrap.php | 3 ++- airtime_mvc/application/logging/Logging.php | 19 ++++++++++++++++ install/airtime-install.php | 2 ++ install/airtime-uninstall.php | 1 + install/include/AirtimeInstall.php | 25 +++++++++++++++++++++ python_apps/pypo/install/pypo-uninstall.py | 5 +---- 6 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 airtime_mvc/application/logging/Logging.php diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index 40c8e3ec6..f9a62c9f6 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -10,6 +10,7 @@ Propel::init(__DIR__."/configs/airtime-conf.php"); $tz = ini_get('date.timezone') ? ini_get('date.timezone') : 'UTC'; date_default_timezone_set($tz); +require_once __DIR__."/logging/Logging.php"; require_once __DIR__."/configs/constants.php"; require_once __DIR__."/configs/conf.php"; require_once 'DB.php'; @@ -33,8 +34,8 @@ if (PEAR::isError($CC_DBC)) { exit(1); } $CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC); +Logging::setLogPath('/var/log/airtime/zendphp.log'); -//Zend_Session::start(); Zend_Validate::setDefaultNamespaces("Zend"); $front = Zend_Controller_Front::getInstance(); diff --git a/airtime_mvc/application/logging/Logging.php b/airtime_mvc/application/logging/Logging.php new file mode 100644 index 000000000..096dbd717 --- /dev/null +++ b/airtime_mvc/application/logging/Logging.php @@ -0,0 +1,19 @@ + Date: Wed, 20 Apr 2011 12:42:38 -0700 Subject: [PATCH 04/13] CC-2207:Rename 'Schedule Playlist' window to 'Schedule Media' - fixed --- airtime_mvc/public/js/airtime/schedule/schedule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airtime_mvc/public/js/airtime/schedule/schedule.js b/airtime_mvc/public/js/airtime/schedule/schedule.js index 85c7dd34c..d1d513626 100644 --- a/airtime_mvc/public/js/airtime/schedule/schedule.js +++ b/airtime_mvc/public/js/airtime/schedule/schedule.js @@ -228,7 +228,7 @@ function buildScheduleDialog(json){ dialog.dialog({ autoOpen: false, - title: 'Schedule Playlist', + title: 'Schedule Media', width: 1100, height: 550, modal: true, From 96551e0d916e1a001cd35f707c4913a11d01ad4d Mon Sep 17 00:00:00 2001 From: martin Date: Wed, 20 Apr 2011 16:22:06 -0400 Subject: [PATCH 05/13] CC-2186: Integration of a logger tool -added upgrade support --- install/airtime-upgrade.php | 20 ++++++++++++------- .../upgrades/airtime-1.9/airtime-upgrade.php | 14 +++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 install/upgrades/airtime-1.9/airtime-upgrade.php diff --git a/install/airtime-upgrade.php b/install/airtime-upgrade.php index c1c6436fa..4b5a4600b 100644 --- a/install/airtime-upgrade.php +++ b/install/airtime-upgrade.php @@ -14,13 +14,16 @@ require_once(dirname(__FILE__).'/include/AirtimeInstall.php'); AirtimeInstall::ExitIfNotRoot(); AirtimeInstall::DbConnect(true); -if(AirtimeInstall::DbTableExists('cc_show_rebroadcast') === true) { - $version = "1.7.0"; - echo "Airtime Version: ".$version." ".PHP_EOL; -} -else { - $version = "1.6"; - echo "Airtime Version: ".$version." ".PHP_EOL; +$version = AirtimeInstall::GetAirtimeVersion(); +if (!$version){ + if(AirtimeInstall::DbTableExists('cc_show_rebroadcast') === true) { + $version = "1.7.0"; + echo "Airtime Version: ".$version." ".PHP_EOL; + } + else { + $version = "1.6"; + echo "Airtime Version: ".$version." ".PHP_EOL; + } } echo "******************************** Update Begin *********************************".PHP_EOL; @@ -31,6 +34,9 @@ if(strcmp($version, "1.7.0") < 0) { if(strcmp($version, "1.8.0") < 0) { system("php ".__DIR__."/upgrades/airtime-1.8/airtime-upgrade.php"); } +if (strcmp($version, "1.9.0") < 0){ + system("php ".__DIR__."/upgrades/airtime-1.9/airtime-upgrade.php"); +} AirtimeInstall::SetAirtimeVersion(AIRTIME_VERSION); diff --git a/install/upgrades/airtime-1.9/airtime-upgrade.php b/install/upgrades/airtime-1.9/airtime-upgrade.php new file mode 100644 index 000000000..99ff40ee5 --- /dev/null +++ b/install/upgrades/airtime-1.9/airtime-upgrade.php @@ -0,0 +1,14 @@ + Date: Wed, 20 Apr 2011 14:10:58 -0700 Subject: [PATCH 06/13] CC-2155:Can open the rebroadcast options without the 'Record'checkbox being selected - fixed --- .../public/js/airtime/schedule/add-show.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/airtime_mvc/public/js/airtime/schedule/add-show.js b/airtime_mvc/public/js/airtime/schedule/add-show.js index b662ae64c..23e394ef2 100644 --- a/airtime_mvc/public/js/airtime/schedule/add-show.js +++ b/airtime_mvc/public/js/airtime/schedule/add-show.js @@ -104,15 +104,17 @@ function setAddShowEvents() { form.find("#add_show_rebroadcast").click(function(){ $(this).blur(); - if($(this).attr('checked') && !form.find("#add_show_repeats").attr('checked')) { - form.find("#add_show_rebroadcast_absolute").show(); - } - else if($(this).attr('checked') && form.find("#add_show_repeats").attr('checked')) { - form.find("#add_show_rebroadcast_relative").show(); - } - else { - form.find("#schedule-record-rebroadcast > fieldset:not(:first-child)").hide(); - } + if(form.find("#add_show_record").attr('checked')){ + if($(this).attr('checked') && !form.find("#add_show_repeats").attr('checked')) { + form.find("#add_show_rebroadcast_absolute").show(); + } + else if($(this).attr('checked') && form.find("#add_show_repeats").attr('checked')) { + form.find("#add_show_rebroadcast_relative").show(); + } + else { + form.find("#schedule-record-rebroadcast > fieldset:not(:first-child)").hide(); + } + } }); form.find("#add_show_repeat_type").change(function(){ From 4b7ea32c7d2e70c7ede54923c08cb48e105fe97e Mon Sep 17 00:00:00 2001 From: martin Date: Thu, 21 Apr 2011 17:23:59 -0400 Subject: [PATCH 07/13] -syntax errors discovered by eclipse --- .../application/views/scripts/form/preferences_general.phtml | 4 ++-- airtime_mvc/application/views/scripts/user/remove-user.phtml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/airtime_mvc/application/views/scripts/form/preferences_general.phtml b/airtime_mvc/application/views/scripts/form/preferences_general.phtml index 92e7956f4..fa37b59ed 100644 --- a/airtime_mvc/application/views/scripts/form/preferences_general.phtml +++ b/airtime_mvc/application/views/scripts/form/preferences_general.phtml @@ -36,7 +36,7 @@ ?> element->getElement('streamFormat')->getMultiOptions() as $radio) : ?> @@ -59,7 +59,7 @@ ?> element->getElement('thirdPartyApi')->getMultiOptions() as $radio) : ?> diff --git a/airtime_mvc/application/views/scripts/user/remove-user.phtml b/airtime_mvc/application/views/scripts/user/remove-user.phtml index 845092689..c1d521bb3 100644 --- a/airtime_mvc/application/views/scripts/user/remove-user.phtml +++ b/airtime_mvc/application/views/scripts/user/remove-user.phtml @@ -1,3 +1,3 @@ entries; +echo $this->entries; ?> From a9d6bc3db56b649649426638dbad0dd107e9e07a Mon Sep 17 00:00:00 2001 From: Naomi Date: Thu, 21 Apr 2011 17:37:59 -0400 Subject: [PATCH 08/13] CC-1799 : Live Studio Playout from media library (pytagsfs) starting python script using pyinotify --- python_apps/pytag-fs/MediaMonitor.cfg | 29 +++++++++++++++ python_apps/pytag-fs/MediaMonitor.py | 52 +++++++++++++++++++++++++++ python_apps/pytag-fs/logging.cfg | 22 ++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 python_apps/pytag-fs/MediaMonitor.cfg create mode 100644 python_apps/pytag-fs/MediaMonitor.py create mode 100644 python_apps/pytag-fs/logging.cfg diff --git a/python_apps/pytag-fs/MediaMonitor.cfg b/python_apps/pytag-fs/MediaMonitor.cfg new file mode 100644 index 000000000..e4610b720 --- /dev/null +++ b/python_apps/pytag-fs/MediaMonitor.cfg @@ -0,0 +1,29 @@ +api_client = "airtime" + +# Hostname +base_url = 'localhost' +base_port = 80 + +# where the binary files live +bin_dir = '/usr/lib/airtime/media-monitor' + +# base path to store recordered shows at +base_recorded_files = '/var/tmp/airtime/show-recorder/' + +# where the logging files live +log_dir = '/var/log/airtime/show-recorder' + +# Value needed to access the API +api_key = 'AAA' + +# Path to the base of the API +api_base = 'api' + +# URL to get the version number of the server API +version_url = 'version/api_key/%%api_key%%' + +# URL to get the schedule of shows set to record +show_schedule_url = 'recorded-shows/format/json/api_key/%%api_key%%' + +# URL to upload the recorded show's file to Airtime +upload_file_url = 'upload-recorded/format/json/api_key/%%api_key%%' diff --git a/python_apps/pytag-fs/MediaMonitor.py b/python_apps/pytag-fs/MediaMonitor.py new file mode 100644 index 000000000..2bdf148aa --- /dev/null +++ b/python_apps/pytag-fs/MediaMonitor.py @@ -0,0 +1,52 @@ +import os +import pyinotify +from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent + +# configure logging +try: + logging.config.fileConfig("logging.cfg") +except Exception, e: + print 'Error configuring logging: ', e + sys.exit() + +# loading config file +try: + config = ConfigObj('/etc/airtime/recorder.cfg') +except Exception, e: + print 'Error loading config file: ', e + sys.exit() + +# watched events +mask = pyinotify.ALL_EVENTS + +wm = WatchManager() +wdd = wm.add_watch('/srv/airtime/stor', mask, rec=True) + +class PTmp(ProcessEvent): + def process_IN_CREATE(self, event): + if event.dir : + global wm + wdd = wm.add_watch(event.pathname, mask, rec=True) + #print wdd.keys() + + print "%s: %s" % (event.maskname, os.path.join(event.path, event.name)) + + def process_IN_MODIFY(self, event): + if not event.dir : + print event.path + + print "%s: %s" % (event.maskname, os.path.join(event.path, event.name)) + + def process_default(self, event): + print "%s: %s" % (event.maskname, os.path.join(event.path, event.name)) + +if __name__ == '__main__': + + try: + notifier = Notifier(wm, PTmp(), read_freq=2, timeout=1) + notifier.coalesce_events() + notifier.loop() + except KeyboardInterrupt: + notifier.stop() + + diff --git a/python_apps/pytag-fs/logging.cfg b/python_apps/pytag-fs/logging.cfg new file mode 100644 index 000000000..251fce8d7 --- /dev/null +++ b/python_apps/pytag-fs/logging.cfg @@ -0,0 +1,22 @@ +[loggers] +keys=root + +[handlers] +keys=consoleHandler + +[formatters] +keys=simpleFormatter + +[logger_root] +level=DEBUG +handlers=consoleHandler + +[handler_consoleHandler] +class=StreamHandler +level=DEBUG +formatter=simpleFormatter +args=(sys.stdout,) + +[formatter_simpleFormatter] +format=%(asctime)s %(levelname)s - [%(filename)s : %(funcName)s() : line %(lineno)d] - %(message)s +datefmt= From cfcd612d471c96ed6e3b8b9ae63e894d3edb25b7 Mon Sep 17 00:00:00 2001 From: martin Date: Fri, 22 Apr 2011 01:02:35 -0400 Subject: [PATCH 09/13] -updated version string to 1.9.0-beta --- VERSION | 2 +- airtime_mvc/application/configs/conf.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index be6fbdd24..ad191da1e 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ PRODUCT_ID=Airtime -PRODUCT_RELEASE=1.8.0 +PRODUCT_RELEASE=1.9.0-beta diff --git a/airtime_mvc/application/configs/conf.php b/airtime_mvc/application/configs/conf.php index 0c7c39d33..dd20668a6 100644 --- a/airtime_mvc/application/configs/conf.php +++ b/airtime_mvc/application/configs/conf.php @@ -6,7 +6,7 @@ * /etc/airtime/recorder.cfg */ -define('AIRTIME_VERSION', '1.8.0'); +define('AIRTIME_VERSION', '1.9.0-beta'); define('AIRTIME_COPYRIGHT_DATE', '2010-2011'); define('AIRTIME_REST_VERSION', '1.1'); From f1a314aa0af547493e57482f58c79524b4182ac4 Mon Sep 17 00:00:00 2001 From: martin Date: Fri, 22 Apr 2011 01:05:47 -0400 Subject: [PATCH 10/13] -update version string number for pypo --- python_apps/api_clients/api_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 1d252aeb0..8a38e682e 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -180,7 +180,7 @@ class AirTimeApiClient(ApiClientInterface): print 'Unable to get Airtime version number.' print return False - elif (version[0:4] != "1.8."): + elif (version[0:4] != "1.9."): if (verbose): print 'Airtime version: ' + str(version) print 'pypo not compatible with this version of Airtime.' From d46f38fa3f4387c0ae860764f6d1ccddbee14e05 Mon Sep 17 00:00:00 2001 From: martin Date: Mon, 25 Apr 2011 15:11:01 -0400 Subject: [PATCH 11/13] Merge branch 'devel' From 07633ea24900fbabd4a58221a4af9cbd9639be68 Mon Sep 17 00:00:00 2001 From: Paul Baranowski Date: Mon, 25 Apr 2011 16:48:34 -0400 Subject: [PATCH 12/13] CC-2225 airtime-clean-storage doesnt work CC-2224 airtime-import checks if you can write to the stor directory even if you are linking Had to rewrite the airtime-clean-storage script. --- airtime_mvc/application/models/Playlist.php | 6 + airtime_mvc/application/models/Schedule.php | 14 +- airtime_mvc/application/models/StoredFile.php | 48 ++++- utils/airtime-clean-storage | 12 +- utils/airtime-clean-storage.php | 176 ++++++++---------- utils/airtime-import | 2 +- utils/airtime-import.php | 21 ++- 7 files changed, 162 insertions(+), 117 deletions(-) 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) { From 219598ac062a89a6365fc4d8f65d9a945ff10968 Mon Sep 17 00:00:00 2001 From: Paul Baranowski Date: Mon, 25 Apr 2011 18:34:03 -0400 Subject: [PATCH 13/13] CC-2225 airtime-clean-storage doesnt work Forced the user to run the script as superuser. --- airtime_mvc/application/models/StoredFile.php | 10 +++++----- utils/airtime-clean-storage.php | 11 ++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 01e0b8f00..99bccfb5e 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -1174,10 +1174,7 @@ class StoredFile { return TRUE; } else { - return PEAR::raiseError( - "StoredFile::deleteFile: unlink failed ({$this->filepath})", - GBERR_FILEIO - ); + return PEAR::raiseError("StoredFile::deleteFile: unlink failed ({$this->filepath})"); } } else { @@ -1237,7 +1234,10 @@ class StoredFile { $files = StoredFile::getAll(); foreach ($files as $file) { $media = StoredFile::Recall($file["id"]); - $media->delete(); + $result = $media->delete(); + if (PEAR::isError($result)) { + return $result; + } } } diff --git a/utils/airtime-clean-storage.php b/utils/airtime-clean-storage.php index f91d697ef..53aefdc49 100644 --- a/utils/airtime-clean-storage.php +++ b/utils/airtime-clean-storage.php @@ -59,7 +59,10 @@ function airtime_empty_db($db) Playlist::deleteAll(); echo " * Clearing files table...".PHP_EOL; - StoredFile::deleteAll(); + $result = StoredFile::deleteAll(); + if (PEAR::isError($result)) { + echo $result->getMessage().PHP_EOL; + } } @@ -88,6 +91,12 @@ if (isset($opts->h)) { exit; } +// Need to check that we are superuser before running this. +if (exec("whoami") != "root") { + echo PHP_EOL."You must be root to use this script.".PHP_EOL.PHP_EOL; + exit(1); +} + $CC_DBC = DB::connect($CC_CONFIG['dsn'], TRUE); $CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC);