From 64c1dd2c1e962be5d800157a036c67236b0d6321 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 27 Feb 2014 17:11:17 -0500 Subject: [PATCH 01/36] CC-5701: Airtime File API Beginnings of fil rest api index, get, post actions working without authentication --- .../application/configs/application.ini | 3 + .../controllers/plugins/Acl_plugin.php | 7 + .../application/modules/rest/Bootstrap.php | 14 ++ .../rest/controllers/MediaController.php | 145 ++++++++++++++++++ .../rest/views/scripts/media/get.phtml | 0 .../rest/views/scripts/media/index.phtml | 0 .../rest/views/scripts/media/post.phtml | 0 7 files changed, 169 insertions(+) create mode 100644 airtime_mvc/application/modules/rest/Bootstrap.php create mode 100644 airtime_mvc/application/modules/rest/controllers/MediaController.php create mode 100644 airtime_mvc/application/modules/rest/views/scripts/media/get.phtml create mode 100644 airtime_mvc/application/modules/rest/views/scripts/media/index.phtml create mode 100644 airtime_mvc/application/modules/rest/views/scripts/media/post.phtml diff --git a/airtime_mvc/application/configs/application.ini b/airtime_mvc/application/configs/application.ini index c342ebda7..706beb249 100644 --- a/airtime_mvc/application/configs/application.ini +++ b/airtime_mvc/application/configs/application.ini @@ -6,6 +6,9 @@ bootstrap.class = "Bootstrap" appnamespace = "Application" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.frontController.params.displayExceptions = 0 +resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" +;load everything in the modules directory including models +resources.modules[] = "" resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/" resources.view[] = resources.db.adapter = "Pdo_Pgsql" diff --git a/airtime_mvc/application/controllers/plugins/Acl_plugin.php b/airtime_mvc/application/controllers/plugins/Acl_plugin.php index 44555e533..4cf9f97b5 100644 --- a/airtime_mvc/application/controllers/plugins/Acl_plugin.php +++ b/airtime_mvc/application/controllers/plugins/Acl_plugin.php @@ -110,6 +110,13 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract { $controller = strtolower($request->getControllerName()); + //Ignore authentication for all access to the rest API. We do auth via API keys for this + //and/or by OAuth. + if (strtolower($request->getModuleName()) == "rest") + { + return; + } + if (in_array($controller, array("api", "auth", "locale"))) { $this->setRoleName("G"); diff --git a/airtime_mvc/application/modules/rest/Bootstrap.php b/airtime_mvc/application/modules/rest/Bootstrap.php new file mode 100644 index 000000000..904d05e4c --- /dev/null +++ b/airtime_mvc/application/modules/rest/Bootstrap.php @@ -0,0 +1,14 @@ +getRouter(); + + $restRoute = new Zend_Rest_Route($front, array(), array( + 'rest'=> array('media'))); + assert($router->addRoute('rest', $restRoute)); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php new file mode 100644 index 000000000..e2759bd2e --- /dev/null +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -0,0 +1,145 @@ +view->layout()->disableLayout(); + } + + public function indexAction() + { + if (!$this->verifyApiKey()) { + return; + } + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody(json_encode(CcFilesQuery::create()->find()->toArray())); + } + public function getAction() + { + if (!$this->verifyApiKey()) { + return; + } + $id = $this->getId(); + if (!$id) { + return; + } + + $file = CcFilesQuery::create()->findPk($id); + if ($file) { + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody(json_encode($file->toArray())); + } else { + $this->fileNotFoundResponse(); + } + } + + public function postAction() + { + if (!$this->verifyApiKey()) { + return; + } + //If we do get an ID on a POST, then that doesn't make any sense + //since POST is only for creating. + if ($id = $this->_getParam('id', false)) { + $resp = $this->getResponse(); + $resp->setHttpResponseCode(400); + $resp->appendBody("ERROR: ID should not be specified when using POST. POST is only used for show creation, and an ID will be chosen by Airtime"); + return; + } + + $file = new CcFiles(); + $file->fromArray($this->getRequest()->getPost()); + $file->save(); + + $resp = $this->getResponse(); + $resp->setHttpResponseCode(201); + $resp->appendBody(json_encode($file->toArray())); + } + + public function putAction() + { + if (!$this->verifyApiKey()) { + return; + } + $id = $this->getId(); + if (!$id) { + return; + } + + $file = CcFilesQuery::create()->findPk($id); + if ($show) + { + $show->importFrom('JSON', $this->getRequest()->getRawBody()); + $show->save(); + $this->getResponse() + ->appendBody("From putAction() updating the requested show"); + } else { + $this->showNotFoundResponse(); + } + } + + public function deleteAction() + { + if (!$this->verifyApiKey()) { + return; + } + $id = $this->getId(); + if (!$id) { + return; + } + $show = CcShowQuery::create()->$query->findPk($id); + if ($show) { + $show->delete(); + } else { + $this->showNotFoundResponse(); + } + } + + private function getId() + { + if (!$id = $this->_getParam('id', false)) { + $resp = $this->getResponse(); + $resp->setHttpResponseCode(400); + $resp->appendBody("ERROR: No show ID specified."); + return false; + } + return $id; + } + + private function verifyAPIKey() + { + //The API key is passed in via HTTP "basic authentication": + // http://en.wikipedia.org/wiki/Basic_access_authentication + + //TODO: Fetch the user's API key from the database to check against + $unencodedStoredApiKey = "foobar"; + $encodedStoredApiKey = base64_encode($unencodedStoredApiKey . ":"); + + //Decode the API key that was passed to us in the HTTP request. + $authHeader = $this->getRequest()->getHeader("Authorization"); + $encodedRequestApiKey = substr($authHeader, strlen("Basic ")); + + //if ($encodedRequestApiKey === $encodedStoredApiKey) + if (true) + { + return true; + } + else + { + $resp = $this->getResponse(); + $resp->setHttpResponseCode(401); + $resp->appendBody("ERROR: Incorrect API key."); + return false; + } + } + + private function fileNotFoundResponse() + { + $resp = $this->getResponse(); + $resp->setHttpResponseCode(404); + $resp->appendBody("ERROR: Show not found."); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/get.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/get.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/index.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/index.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/post.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/post.phtml new file mode 100644 index 000000000..e69de29bb From aba2fb44d14ab0df412093ba4e6c5ff29a370a50 Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 3 Mar 2014 11:21:25 -0500 Subject: [PATCH 02/36] CC-5701: Airtime File API -put and delete actions working --- .../application/configs/application.ini | 1 + .../rest/controllers/MediaController.php | 33 ++++++++++--------- .../rest/views/scripts/media/delete.phtml | 0 .../rest/views/scripts/media/put.phtml | 0 4 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 airtime_mvc/application/modules/rest/views/scripts/media/delete.phtml create mode 100644 airtime_mvc/application/modules/rest/views/scripts/media/put.phtml diff --git a/airtime_mvc/application/configs/application.ini b/airtime_mvc/application/configs/application.ini index 706beb249..71bcd5c46 100644 --- a/airtime_mvc/application/configs/application.ini +++ b/airtime_mvc/application/configs/application.ini @@ -7,6 +7,7 @@ appnamespace = "Application" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.frontController.params.displayExceptions = 0 resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" +resources.frontController.plugins.putHandler = "Zend_Controller_Plugin_PutHandler" ;load everything in the modules directory including models resources.modules[] = "" resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/" diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index e2759bd2e..6c59e1c55 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -54,11 +54,11 @@ class Rest_MediaController extends Zend_Rest_Controller $file->fromArray($this->getRequest()->getPost()); $file->save(); - $resp = $this->getResponse(); - $resp->setHttpResponseCode(201); - $resp->appendBody(json_encode($file->toArray())); + $this->getResponse() + ->setHttpResponseCode(201) + ->appendBody(json_encode($file->toArray())); } - + public function putAction() { if (!$this->verifyApiKey()) { @@ -70,17 +70,18 @@ class Rest_MediaController extends Zend_Rest_Controller } $file = CcFilesQuery::create()->findPk($id); - if ($show) + if ($file) { - $show->importFrom('JSON', $this->getRequest()->getRawBody()); - $show->save(); + $file->fromArray(json_decode($this->getRequest()->getRawBody(), true)); + $file->save(); $this->getResponse() - ->appendBody("From putAction() updating the requested show"); + ->setHttpResponseCode(200) + ->appendBody(json_encode($file->toArray())); } else { - $this->showNotFoundResponse(); + $this->fileNotFoundResponse(); } } - + public function deleteAction() { if (!$this->verifyApiKey()) { @@ -90,11 +91,13 @@ class Rest_MediaController extends Zend_Rest_Controller if (!$id) { return; } - $show = CcShowQuery::create()->$query->findPk($id); - if ($show) { - $show->delete(); + $file = CcFilesQuery::create()->findPk($id); + if ($file) { + $file->delete(); + $this->getResponse() + ->setHttpResponseCode(200); } else { - $this->showNotFoundResponse(); + $this->fileNotFoundResponse(); } } @@ -140,6 +143,6 @@ class Rest_MediaController extends Zend_Rest_Controller { $resp = $this->getResponse(); $resp->setHttpResponseCode(404); - $resp->appendBody("ERROR: Show not found."); + $resp->appendBody("ERROR: Media not found."); } } \ No newline at end of file diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/delete.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/delete.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/put.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/put.phtml new file mode 100644 index 000000000..e69de29bb From f33f49259dc484980afcf6ac8ec291f75438745f Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 3 Mar 2014 11:28:18 -0500 Subject: [PATCH 03/36] CC-5701: Airtime File API Fixed http response code for delete --- .../application/modules/rest/controllers/MediaController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 6c59e1c55..304e11365 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -95,7 +95,7 @@ class Rest_MediaController extends Zend_Rest_Controller if ($file) { $file->delete(); $this->getResponse() - ->setHttpResponseCode(200); + ->setHttpResponseCode(204); } else { $this->fileNotFoundResponse(); } From b6dd2e31527216f7ac382789d245336c1e7c900f Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 3 Mar 2014 16:04:34 -0500 Subject: [PATCH 04/36] CC-5701: Airtime File API --- .../rest/controllers/MediaController.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 304e11365..14eb7c9b4 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -106,7 +106,7 @@ class Rest_MediaController extends Zend_Rest_Controller if (!$id = $this->_getParam('id', false)) { $resp = $this->getResponse(); $resp->setHttpResponseCode(400); - $resp->appendBody("ERROR: No show ID specified."); + $resp->appendBody("ERROR: No file ID specified."); return false; } return $id; @@ -115,23 +115,15 @@ class Rest_MediaController extends Zend_Rest_Controller private function verifyAPIKey() { //The API key is passed in via HTTP "basic authentication": - // http://en.wikipedia.org/wiki/Basic_access_authentication + // http://en.wikipedia.org/wiki/Basic_access_authentication - //TODO: Fetch the user's API key from the database to check against - $unencodedStoredApiKey = "foobar"; - $encodedStoredApiKey = base64_encode($unencodedStoredApiKey . ":"); + $CC_CONFIG = Config::getConfig(); - //Decode the API key that was passed to us in the HTTP request. $authHeader = $this->getRequest()->getHeader("Authorization"); - $encodedRequestApiKey = substr($authHeader, strlen("Basic ")); - //if ($encodedRequestApiKey === $encodedStoredApiKey) - if (true) - { + if (in_array($authHeader, $CC_CONFIG["apiKey"])) { return true; - } - else - { + } else { $resp = $this->getResponse(); $resp->setHttpResponseCode(401); $resp->appendBody("ERROR: Incorrect API key."); From a6a64a2b9e7f91b324221f0ade19b702dd270784 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Wed, 5 Mar 2014 12:15:25 -0500 Subject: [PATCH 05/36] CC-5709 / CC-5705 : Airtime Analyzer * Finished the skeleton of the airtime_analyzer service. * Basic round-robin, reliable AMQP messaging works. * Using multiprocess arch so the daemon survives analyzer crashes and avoids failures propagating to other nodes. * Basic metadata extractor using Mutagen is done. * HTTP requests to the File API to are next to come... --- python_apps/airtime_analyzer/MANIFEST.in | 1 + python_apps/airtime_analyzer/README.rst | 30 ++++++ .../airtime_analyzer/__init__.py | 2 + .../airtime_analyzer/airtime_analyzer.py | 41 +++++++ .../airtime_analyzer/analyzer.py | 10 ++ .../airtime_analyzer/analyzer_pipeline.py | 17 +++ .../airtime_analyzer/message_listener.py | 102 ++++++++++++++++++ .../airtime_analyzer/metadata_analyzer.py | 95 ++++++++++++++++ .../airtime_analyzer/replaygain_analyzer.py | 12 +++ .../airtime_analyzer/bin/airtime_analyzer | 21 ++++ python_apps/airtime_analyzer/setup.py | 20 ++++ .../airtime_analyzer/tests/__init__.py | 0 .../tests/airtime_analyzer_queue_tests.py | 12 +++ .../airtime_analyzer/tools/message_sender.php | 47 ++++++++ .../airtime_analyzer/tools/php-amqplib | 1 + 15 files changed, 411 insertions(+) create mode 100644 python_apps/airtime_analyzer/MANIFEST.in create mode 100644 python_apps/airtime_analyzer/README.rst create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/__init__.py create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/analyzer.py create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/message_listener.py create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/replaygain_analyzer.py create mode 100755 python_apps/airtime_analyzer/bin/airtime_analyzer create mode 100644 python_apps/airtime_analyzer/setup.py create mode 100644 python_apps/airtime_analyzer/tests/__init__.py create mode 100644 python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py create mode 100644 python_apps/airtime_analyzer/tools/message_sender.php create mode 120000 python_apps/airtime_analyzer/tools/php-amqplib diff --git a/python_apps/airtime_analyzer/MANIFEST.in b/python_apps/airtime_analyzer/MANIFEST.in new file mode 100644 index 000000000..9561fb106 --- /dev/null +++ b/python_apps/airtime_analyzer/MANIFEST.in @@ -0,0 +1 @@ +include README.rst diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst new file mode 100644 index 000000000..a7704a2a5 --- /dev/null +++ b/python_apps/airtime_analyzer/README.rst @@ -0,0 +1,30 @@ + +Ghetto temporary installation instructions + +set up a virtualenv +activate it +pip install mutagen python-magic pika + +You will need to allow the "airtime" RabbitMQ user to access the airtime-uploads exchange and queue: + + sudo rabbitmqctl set_permissions -p /airtime airtime airtime-uploads airtime-uploads airtime-uploads + + +Developers +========== + +For development, you want to install AAQ system-wide but with everything symlinked back to the source +directory (for convenience), so run: + + $ sudo python setup.py develop + + + +Unit Tests +========== + +To run the unit tests, execute: + + $ nosetests + + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/__init__.py b/python_apps/airtime_analyzer/airtime_analyzer/__init__.py new file mode 100644 index 000000000..11fe8aa91 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/__init__.py @@ -0,0 +1,2 @@ +from airtime_analyzer import AirtimeAnalyzerServer + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py new file mode 100644 index 000000000..eea4622b7 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py @@ -0,0 +1,41 @@ +import ConfigParser +from metadata_analyzer import MetadataAnalyzer +from replaygain_analyzer import ReplayGainAnalyzer +from message_listener import MessageListener + + +class AirtimeAnalyzerServer: + + _CONFIG_PATH = '/etc/airtime/airtime.conf' + + def __init__(self): + + # Read our config file + rabbitmq_config = self.read_config_file() + + # Start listening for RabbitMQ messages telling us about newly + # uploaded files. + self._msg_listener = MessageListener(rabbitmq_config) + + def read_config_file(self): + config = ConfigParser.SafeConfigParser() + config_path = AirtimeAnalyzerServer._CONFIG_PATH + try: + config.readfp(open(config_path)) + except IOError as e: + print "Failed to open config file at " + config_path + ": " + e.strerror + exit(-1) + except Exception: + print e.strerror + exit(-1) + + return config + + +''' When being run from the command line, analyze a file passed + as an argument. ''' +if __name__ == "__main__": + import sys + analyzers = AnalyzerPipeline() + + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py new file mode 100644 index 000000000..de23a8e68 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py @@ -0,0 +1,10 @@ + +class Analyzer: + + @staticmethod + def analyze(filename): + raise NotImplementedError + +class AnalyzerError(Exception): + def __init__(self): + super.__init__(self) diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py new file mode 100644 index 000000000..da3fbbc71 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -0,0 +1,17 @@ +from metadata_analyzer import MetadataAnalyzer + +class AnalyzerPipeline: + + def __init__(self): + pass + + #TODO: Take a JSON message and perform the necessary analysis. + #TODO: Comment the shit out of this + @staticmethod + def run_analysis(json_msg, queue): + # TODO: Pass the JSON along to each analyzer?? + #print MetadataAnalyzer.analyze("foo.mp3") + #print ReplayGainAnalyzer.analyze("foo.mp3") + #raise Exception("Test Crash") + queue.put(MetadataAnalyzer.analyze("foo.mp3")) + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py new file mode 100644 index 000000000..e256fd7cc --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -0,0 +1,102 @@ +import sys +import pika +import multiprocessing +from analyzer_pipeline import AnalyzerPipeline + +EXCHANGE = "airtime-uploads" +EXCHANGE_TYPE = "topic" +ROUTING_KEY = "" #"airtime.analyzer.tasks" +QUEUE = "airtime-uploads" + + +''' TODO: Document me + - round robin messaging + - acking + - why we use the multiprocess architecture +''' +class MessageListener: + + def __init__(self, config): + + RMQ_CONFIG_SECTION = "rabbitmq" + if not config.has_section(RMQ_CONFIG_SECTION): + print "Error: rabbitmq section not found in config file at " + config_path + exit(-1) + + self._host = config.get(RMQ_CONFIG_SECTION, 'host') + self._port = config.getint(RMQ_CONFIG_SECTION, 'port') + self._username = config.get(RMQ_CONFIG_SECTION, 'user') + self._password = config.get(RMQ_CONFIG_SECTION, 'password') + self._vhost = config.get(RMQ_CONFIG_SECTION, 'vhost') + + self._connection = pika.BlockingConnection(pika.ConnectionParameters(host=self._host, + port=self._port, virtual_host=self._vhost, + credentials=pika.credentials.PlainCredentials(self._username, self._password))) + self._channel = self._connection.channel() + self._channel.exchange_declare(exchange=EXCHANGE, type=EXCHANGE_TYPE) + result = self._channel.queue_declare(queue=QUEUE, durable=True) + + self._channel.queue_bind(exchange=EXCHANGE, queue=QUEUE, routing_key=ROUTING_KEY) + + print " Listening for messages..." + self._channel.basic_consume(MessageListener.msg_received_callback, + queue=QUEUE, no_ack=False) + + try: + self._channel.start_consuming() + except KeyboardInterrupt: + self._channel.stop_consuming() + + self._connection.close() + + # consume callback function + @staticmethod + def msg_received_callback(channel, method_frame, header_frame, body): + print " - Received '%s' on routing_key '%s'" % (body, method_frame.routing_key) + + # Spin up a worker process. We use the multiprocessing module and multiprocessing.Queue + # to pass objects between the processes so that if the analyzer process crashes, it does not + # take down the rest of the daemon and we NACK that message so that it doesn't get + # propagated to other airtime_analyzer daemons (eg. running on other servers). + # We avoid cascading failure this way. + try: + MessageListener.spawn_analyzer_process(body) + except Exception: + #If ANY exception happens while processing a file, we're going to NACK to the + #messaging server and tell it to remove the message from the queue. + #(NACK is a negative acknowledgement. We could use ACK instead, but this might come + # in handy in the future.) + #Exceptions in this context are unexpected, unhandled errors. We try to recover + #from as many errors as possble in AnalyzerPipeline, but we're safeguarding ourselves + #here from any catastrophic or genuinely unexpected errors: + channel.basic_nack(delivery_tag=method_frame.delivery_tag, multiple=False, + requeue=False) #Important that it doesn't requeue the message + + #TODO: Report this as a failed upload to the File Upload REST API. + # + # + + else: + # ACK at the very end, after the message has been successfully processed. + # If we don't ack, then RabbitMQ will redeliver a message in the future. + channel.basic_ack(delivery_tag=method_frame.delivery_tag) + + # Anything else could happen here: + # Send an email alert, send an xmnp message, trigger another process, etc + + @staticmethod + def spawn_analyzer_process(json_msg): + + q = multiprocessing.Queue() + p = multiprocessing.Process(target=AnalyzerPipeline.run_analysis, args=(json_msg, q)) + p.start() + p.join() + if p.exitcode == 0: + results = q.get() + print "Server received results: " + print results + else: + print "Analyzer process terminated unexpectedly." + raise AnalyzerException() + + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py new file mode 100644 index 000000000..af7d81745 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -0,0 +1,95 @@ +import mutagen +import magic # For MIME type detection +from analyzer import Analyzer + +class MetadataAnalyzer(Analyzer): + + def __init__(self): + pass + + @staticmethod + def analyze(filename): + + metadata = dict() + #Extract metadata from an audio file using mutagen + audio_file = mutagen.File(filename, easy=True) + + #Grab other file information that isn't encoded in a tag, but instead usually + #in the file header. Mutagen breaks that out into a separate "info" object: + info = audio_file.info + metadata["sample_rate"] = info.sample_rate + metadata["length_seconds"] = info.length + metadata["bitrate"] = info.bitrate + + #Use the python-magic module to get the MIME type. + mime_magic = magic.Magic(mime=True) + metadata["mime_type"] = mime_magic.from_file(filename) + + #We normalize the mutagen tags slightly here, so in case mutagen changes, + #we find the + mutagen_to_analyzer_mapping = { + 'title': 'title', + 'artist': 'artist', + 'album': 'album', + 'bpm': 'bpm', + 'composer': 'composer', + 'conductor': 'conductor', + 'copyright': 'copyright', + 'encoded_by': 'encoder', + 'genre': 'genre', + 'isrc': 'isrc', + 'label': 'label', + 'language': 'language', + 'last_modified':'last_modified', + 'mood': 'mood', + 'replay_gain': 'replaygain', + 'track_number': 'tracknumber', + 'track_total': 'tracktotal', + 'website': 'website', + 'year': 'year', + } + + for mutagen_tag, analyzer_tag in mutagen_to_analyzer_mapping.iteritems(): + try: + metadata[analyzer_tag] = audio_file[mutagen_tag] + + # Some tags are returned as lists because there could be multiple values. + # This is unusual so we're going to always just take the first item in the list. + if isinstance(metadata[analyzer_tag], list): + metadata[analyzer_tag] = metadata[analyzer_tag][0] + + except KeyError: + pass + + return metadata + + + +''' +For reference, the Airtime metadata fields are: + title + artist ("Creator" in Airtime) + album + bit rate + BPM + composer + conductor + copyright + cue in + cue out + encoded by + genre + ISRC + label + language + last modified + length + mime + mood + owner + replay gain + sample rate + track number + website + year +''' diff --git a/python_apps/airtime_analyzer/airtime_analyzer/replaygain_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/replaygain_analyzer.py new file mode 100644 index 000000000..cf10c0a44 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/replaygain_analyzer.py @@ -0,0 +1,12 @@ +from analyzer import Analyzer + +''' TODO: everything ''' +class ReplayGainAnalyzer(Analyzer): + + def __init__(self): + pass + + @staticmethod + def analyze(filename): + pass + diff --git a/python_apps/airtime_analyzer/bin/airtime_analyzer b/python_apps/airtime_analyzer/bin/airtime_analyzer new file mode 100755 index 000000000..3b163ec49 --- /dev/null +++ b/python_apps/airtime_analyzer/bin/airtime_analyzer @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +import daemon +import argparse +import airtime_analyzer as aa + +VERSION = "1.0" + +print "Airtime Analyzer " + VERSION + +parser = argparse.ArgumentParser() +parser.add_argument("-d", "--daemon", help="run as a daemon", action="store_true") +args = parser.parse_args() + +if args.daemon: + with daemon.DaemonContext(): + analyzer = aa.AirtimeAnalyzerServer() +else: + # Run without daemonizing + analyzer = aa.AirtimeAnalyzerServer() + diff --git a/python_apps/airtime_analyzer/setup.py b/python_apps/airtime_analyzer/setup.py new file mode 100644 index 000000000..259696b8e --- /dev/null +++ b/python_apps/airtime_analyzer/setup.py @@ -0,0 +1,20 @@ +from setuptools import setup + +setup(name='airtime_analyzer', + version='0.1', + description='Airtime Analyzer Worker and File Importer', + url='http://github.com/sourcefabric/Airtime', + author='Albert Santoni', + author_email='albert.santoni@sourcefabric.org', + license='MIT', + packages=['airtime_analyzer'], + scripts=['bin/airtime_analyzer'], + install_requires=[ + 'mutagen', + 'python-magic', + 'pika', + 'nose', + 'python-daemon', + 'requests', + ], + zip_safe=False) diff --git a/python_apps/airtime_analyzer/tests/__init__.py b/python_apps/airtime_analyzer/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py b/python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py new file mode 100644 index 000000000..949033a5c --- /dev/null +++ b/python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py @@ -0,0 +1,12 @@ +from nose.tools import * +import airtime_analyzer_queue + +def setup(): + print "SETUP!" + +def teardown(): + print "TEAR DOWN!" + +def test_basic(): + print "I RAN!" + diff --git a/python_apps/airtime_analyzer/tools/message_sender.php b/python_apps/airtime_analyzer/tools/message_sender.php new file mode 100644 index 000000000..d5c9171c1 --- /dev/null +++ b/python_apps/airtime_analyzer/tools/message_sender.php @@ -0,0 +1,47 @@ +channel(); + +// declare/create the queue +$channel->queue_declare($queue, false, true, false, false); + +// declare/create the exchange as a topic exchange. +$channel->exchange_declare($exchange, $exchangeType, false, false, false); + +$msg = new AMQPMessage($message, array("content_type" => "text/plain")); + +$channel->basic_publish($msg, $exchange, $routingKey); +print "Sent $message ($routingKey)\n"; +$channel->close(); +$connection->close(); + diff --git a/python_apps/airtime_analyzer/tools/php-amqplib b/python_apps/airtime_analyzer/tools/php-amqplib new file mode 120000 index 000000000..68ef0b223 --- /dev/null +++ b/python_apps/airtime_analyzer/tools/php-amqplib @@ -0,0 +1 @@ +../../../airtime_mvc/library/php-amqplib \ No newline at end of file From 59535850e26c7429bf943edeae97874378c6dae2 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Wed, 5 Mar 2014 22:43:47 -0500 Subject: [PATCH 06/36] CC-5709: Airtime Analyzer Queue * Added StatusReporter class to make HTTP requests back to Airtime * Handle even more errors now * Added proper logging and log rotation * Added --debug flag for increased logging. --- python_apps/airtime_analyzer/README.rst | 40 +++++++-- .../airtime_analyzer/airtime_analyzer.py | 37 +++++++- .../airtime_analyzer/analyzer_pipeline.py | 30 +++++-- .../airtime_analyzer/message_listener.py | 88 +++++++++++++------ .../airtime_analyzer/status_reporter.py | 29 ++++++ .../airtime_analyzer/bin/airtime_analyzer | 5 +- ...eue_tests.py => airtime_analyzer_tests.py} | 2 +- 7 files changed, 185 insertions(+), 46 deletions(-) create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py rename python_apps/airtime_analyzer/tests/{airtime_analyzer_queue_tests.py => airtime_analyzer_tests.py} (82%) diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst index a7704a2a5..00067d643 100644 --- a/python_apps/airtime_analyzer/README.rst +++ b/python_apps/airtime_analyzer/README.rst @@ -1,23 +1,49 @@ Ghetto temporary installation instructions +========== -set up a virtualenv -activate it -pip install mutagen python-magic pika + $ sudo python setup.py install -You will need to allow the "airtime" RabbitMQ user to access the airtime-uploads exchange and queue: +You will need to allow the "airtime" RabbitMQ user to access all exchanges and queues within the /airtime vhost: + + sudo rabbitmqctl set_permissions -p /airtime airtime .* .* .* + + +Usage +========== + +To print usage instructions, run: + + $ airtime_analyzer --help + +This application can be run as a daemon by running: + + $ airtime_analyzer -d - sudo rabbitmqctl set_permissions -p /airtime airtime airtime-uploads airtime-uploads airtime-uploads Developers ========== -For development, you want to install AAQ system-wide but with everything symlinked back to the source -directory (for convenience), so run: +For development, you want to install airtime_analyzer system-wide but with everything symlinked back to the source +directory for convenience. This is super easy to do, just run: $ sudo python setup.py develop +To send an test message to airtime_analyzer, you can use the message_sender.php script in the tools directory. +For example, run: + + $ php tools/message_sender.php '{ "tmp_file_path" : "foo.mp3" }' + + +Logging +========= + +By default, logs are saved to: + + /var/log/airtime/airtime_analyzer.log + +This application takes care of rotating logs for you. Unit Tests diff --git a/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py index eea4622b7..1bc2e0534 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py @@ -1,4 +1,7 @@ import ConfigParser +import logging +import logging.handlers +import sys from metadata_analyzer import MetadataAnalyzer from replaygain_analyzer import ReplayGainAnalyzer from message_listener import MessageListener @@ -6,16 +9,46 @@ from message_listener import MessageListener class AirtimeAnalyzerServer: + # Constants _CONFIG_PATH = '/etc/airtime/airtime.conf' + _LOG_PATH = "/var/log/airtime/airtime_analyzer.log" + + # Variables + _log_level = logging.INFO + + def __init__(self, debug=False): + + # Configure logging + self.setup_logging(debug) - def __init__(self): - # Read our config file rabbitmq_config = self.read_config_file() # Start listening for RabbitMQ messages telling us about newly # uploaded files. self._msg_listener = MessageListener(rabbitmq_config) + + + def setup_logging(self, debug): + + if debug: + self._log_level = logging.DEBUG + #self.log = logging.getLogger(__name__) + + # Set up logging + logFormatter = logging.Formatter("%(asctime)s [%(module)s] [%(levelname)-5.5s] %(message)s") + rootLogger = logging.getLogger() + rootLogger.setLevel(self._log_level) + + fileHandler = logging.handlers.RotatingFileHandler(filename=self._LOG_PATH, maxBytes=1024*1024*30, + backupCount=8) + fileHandler.setFormatter(logFormatter) + rootLogger.addHandler(fileHandler) + + consoleHandler = logging.StreamHandler() + consoleHandler.setFormatter(logFormatter) + rootLogger.addHandler(consoleHandler) + def read_config_file(self): config = ConfigParser.SafeConfigParser() diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py index da3fbbc71..94700913b 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -1,17 +1,31 @@ +import logging +import multiprocessing from metadata_analyzer import MetadataAnalyzer class AnalyzerPipeline: + # Constructor def __init__(self): pass - #TODO: Take a JSON message and perform the necessary analysis. - #TODO: Comment the shit out of this + # Take message dictionary and perform the necessary analysis. @staticmethod - def run_analysis(json_msg, queue): - # TODO: Pass the JSON along to each analyzer?? - #print MetadataAnalyzer.analyze("foo.mp3") - #print ReplayGainAnalyzer.analyze("foo.mp3") - #raise Exception("Test Crash") - queue.put(MetadataAnalyzer.analyze("foo.mp3")) + def run_analysis(queue, audio_file_path, final_directory): + + if not isinstance(queue, multiprocessing.queues.Queue): + raise TypeError("queue must be a multiprocessing.Queue()") + if not isinstance(audio_file_path, unicode): + raise TypeError("audio_file_path must be a string. Was of type " + type(audio_file_path).__name__ + " instead.") + if not isinstance(final_directory, unicode): + raise TypeError("final_directory must be a string. Was of type " + type(final_directory).__name__ + " instead.") + + + # Analyze the audio file we were told to analyze: + # First, we extract the ID3 tags and other metadata: + queue.put(MetadataAnalyzer.analyze(audio_file_path)) + + # Note that the queue we're putting the results into is our interprocess communication + # back to the main process. + + #print ReplayGainAnalyzer.analyze("foo.mp3") diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index e256fd7cc..13209dc7d 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -1,7 +1,11 @@ import sys import pika +import json +import time +import logging import multiprocessing from analyzer_pipeline import AnalyzerPipeline +from status_reporter import StatusReporter EXCHANGE = "airtime-uploads" EXCHANGE_TYPE = "topic" @@ -13,22 +17,39 @@ QUEUE = "airtime-uploads" - round robin messaging - acking - why we use the multiprocess architecture + - in general, how it works and why it works this way ''' class MessageListener: def __init__(self, config): + # Read the RabbitMQ connection settings from the config file + # The exceptions throw here by default give good error messages. RMQ_CONFIG_SECTION = "rabbitmq" - if not config.has_section(RMQ_CONFIG_SECTION): - print "Error: rabbitmq section not found in config file at " + config_path - exit(-1) - self._host = config.get(RMQ_CONFIG_SECTION, 'host') self._port = config.getint(RMQ_CONFIG_SECTION, 'port') self._username = config.get(RMQ_CONFIG_SECTION, 'user') self._password = config.get(RMQ_CONFIG_SECTION, 'password') self._vhost = config.get(RMQ_CONFIG_SECTION, 'vhost') + while True: + try: + self.connect_to_messaging_server() + self.wait_for_messages() + except KeyboardInterrupt: + self.disconnect_from_messaging_server() + break + except pika.exceptions.AMQPError as e: + logging.error("Connection to message queue failed. ") + logging.error(e) + logging.info("Retrying in 5 seconds...") + time.sleep(5) + + self._connection.close() + + + def connect_to_messaging_server(self): + self._connection = pika.BlockingConnection(pika.ConnectionParameters(host=self._host, port=self._port, virtual_host=self._vhost, credentials=pika.credentials.PlainCredentials(self._username, self._password))) @@ -38,21 +59,21 @@ class MessageListener: self._channel.queue_bind(exchange=EXCHANGE, queue=QUEUE, routing_key=ROUTING_KEY) - print " Listening for messages..." + logging.info(" Listening for messages...") self._channel.basic_consume(MessageListener.msg_received_callback, queue=QUEUE, no_ack=False) - try: - self._channel.start_consuming() - except KeyboardInterrupt: - self._channel.stop_consuming() + def wait_for_messages(self): + self._channel.start_consuming() + + def disconnect_from_messaging_server(self): + self._channel.stop_consuming() - self._connection.close() # consume callback function @staticmethod def msg_received_callback(channel, method_frame, header_frame, body): - print " - Received '%s' on routing_key '%s'" % (body, method_frame.routing_key) + logging.info(" - Received '%s' on routing_key '%s'" % (body, method_frame.routing_key)) # Spin up a worker process. We use the multiprocessing module and multiprocessing.Queue # to pass objects between the processes so that if the analyzer process crashes, it does not @@ -60,8 +81,22 @@ class MessageListener: # propagated to other airtime_analyzer daemons (eg. running on other servers). # We avoid cascading failure this way. try: - MessageListener.spawn_analyzer_process(body) - except Exception: + msg_dict = json.loads(body) + audio_file_path = msg_dict["tmp_file_path"] + final_directory = msg_dict["final_directory"] + callback_url = msg_dict["callback_url"] + api_key = msg_dict["api_key"] + + audio_metadata = MessageListener.spawn_analyzer_process(audio_file_path, final_directory) + StatusReporter.report_success_to_callback_url(callback_url, api_key, audio_metadata) + + except KeyError as e: + logging.exception("A mandatory airtime_analyzer message field was missing from the message.") + # See the huge comment about NACK below. + channel.basic_nack(delivery_tag=method_frame.delivery_tag, multiple=False, + requeue=False) #Important that it doesn't requeue the message + + except Exception as e: #If ANY exception happens while processing a file, we're going to NACK to the #messaging server and tell it to remove the message from the queue. #(NACK is a negative acknowledgement. We could use ACK instead, but this might come @@ -72,31 +107,32 @@ class MessageListener: channel.basic_nack(delivery_tag=method_frame.delivery_tag, multiple=False, requeue=False) #Important that it doesn't requeue the message - #TODO: Report this as a failed upload to the File Upload REST API. - # + # TODO: Report this as a failed upload to the File Upload REST API. # + # TODO: If the JSON was invalid, then don't report to the REST API + + StatusReporter.report_failure_to_callback_url(callback_url, api_key, error_status=1, + reason=u'An error occurred while importing this file') + + logging.error(e) else: # ACK at the very end, after the message has been successfully processed. - # If we don't ack, then RabbitMQ will redeliver a message in the future. + # If we don't ack, then RabbitMQ will redeliver the message in the future. channel.basic_ack(delivery_tag=method_frame.delivery_tag) - - # Anything else could happen here: - # Send an email alert, send an xmnp message, trigger another process, etc @staticmethod - def spawn_analyzer_process(json_msg): + def spawn_analyzer_process(audio_file_path, final_directory): q = multiprocessing.Queue() - p = multiprocessing.Process(target=AnalyzerPipeline.run_analysis, args=(json_msg, q)) + p = multiprocessing.Process(target=AnalyzerPipeline.run_analysis, + args=(q, audio_file_path, final_directory)) p.start() p.join() if p.exitcode == 0: results = q.get() - print "Server received results: " - print results + logging.info("Main process received results from child: ") + logging.info(results) else: - print "Analyzer process terminated unexpectedly." - raise AnalyzerException() - + raise Exception("Analyzer process terminated unexpectedly.") diff --git a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py new file mode 100644 index 000000000..c8664df08 --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py @@ -0,0 +1,29 @@ +import requests +import json +import logging + +class StatusReporter(): + + _HTTP_REQUEST_TIMEOUT = 30 + + # Report the extracted metadata and status of the successfully imported file + # to the callback URL (which should be the Airtime File Upload API) + @classmethod + def report_success_to_callback_url(self, callback_url, api_key, audio_metadata): + + # Encode the audio metadata as JSON and post it back to the callback_url + post_payload = json.dumps(audio_metadata) + r = requests.put(callback_url, data=post_payload, + auth=requests.auth.HTTPBasicAuth(api_key, ''), + timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) + logging.debug("HTTP request returned status: " + str(r.status_code)) + logging.debug(r.text) # Log the response body + r.raise_for_status() # Raise an exception if there was an HTTP error code returned + + #TODO: Queue up failed requests and try them again later. + + @classmethod + def report_failure_to_callback_url(self, callback_url, api_key, error_status, reason): + # TODO: Make error_status is an int? + pass + diff --git a/python_apps/airtime_analyzer/bin/airtime_analyzer b/python_apps/airtime_analyzer/bin/airtime_analyzer index 3b163ec49..eb1902c2c 100755 --- a/python_apps/airtime_analyzer/bin/airtime_analyzer +++ b/python_apps/airtime_analyzer/bin/airtime_analyzer @@ -10,12 +10,13 @@ print "Airtime Analyzer " + VERSION parser = argparse.ArgumentParser() parser.add_argument("-d", "--daemon", help="run as a daemon", action="store_true") +parser.add_argument("--debug", help="log full debugging output", action="store_true") args = parser.parse_args() if args.daemon: with daemon.DaemonContext(): - analyzer = aa.AirtimeAnalyzerServer() + analyzer = aa.AirtimeAnalyzerServer(debug=args.debug) else: # Run without daemonizing - analyzer = aa.AirtimeAnalyzerServer() + analyzer = aa.AirtimeAnalyzerServer(debug=args.debug) diff --git a/python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py b/python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py similarity index 82% rename from python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py rename to python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py index 949033a5c..f89336589 100644 --- a/python_apps/airtime_analyzer/tests/airtime_analyzer_queue_tests.py +++ b/python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py @@ -1,5 +1,5 @@ from nose.tools import * -import airtime_analyzer_queue +import airtime_analyzer def setup(): print "SETUP!" From 4e39fce7018f42aeb8c4e7caab8ff4176ccc7a4a Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 6 Mar 2014 16:55:20 -0500 Subject: [PATCH 07/36] CC-5709: Airtime Analyzer * Basic HTTP reporting back to the File API works (PUT) * Use the database table names as JSON field names. * Fixed result returning bug in message_listener.py * Fixed API key verification to adhere with the HTTP Basic Auth spec --- .../rest/controllers/MediaController.php | 19 +++++---- .../airtime_analyzer/message_listener.py | 2 + .../airtime_analyzer/metadata_analyzer.py | 39 +++++++++++++------ .../airtime_analyzer/status_reporter.py | 5 ++- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 14eb7c9b4..d9adaa12c 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -14,8 +14,9 @@ class Rest_MediaController extends Zend_Rest_Controller } $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode(CcFilesQuery::create()->find()->toArray())); + ->appendBody(json_encode(CcFilesQuery::create()->find()->toArray(/*BasePeer::TYPE_FIELDNAME*/))); } + public function getAction() { if (!$this->verifyApiKey()) { @@ -30,7 +31,7 @@ class Rest_MediaController extends Zend_Rest_Controller if ($file) { $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($file->toArray())); + ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); } else { $this->fileNotFoundResponse(); } @@ -56,7 +57,7 @@ class Rest_MediaController extends Zend_Rest_Controller $this->getResponse() ->setHttpResponseCode(201) - ->appendBody(json_encode($file->toArray())); + ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); } public function putAction() @@ -72,11 +73,11 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { - $file->fromArray(json_decode($this->getRequest()->getRawBody(), true)); + $file->fromArray(json_decode($this->getRequest()->getRawBody(), true), BasePeer::TYPE_FIELDNAME); $file->save(); $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($file->toArray())); + ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); } else { $this->fileNotFoundResponse(); } @@ -119,9 +120,13 @@ class Rest_MediaController extends Zend_Rest_Controller $CC_CONFIG = Config::getConfig(); + //Decode the API key that was passed to us in the HTTP request. $authHeader = $this->getRequest()->getHeader("Authorization"); - - if (in_array($authHeader, $CC_CONFIG["apiKey"])) { + $encodedRequestApiKey = substr($authHeader, strlen("Basic ")); + $encodedStoredApiKey = base64_encode($CC_CONFIG["apiKey"][0] . ":"); + + if ($encodedRequestApiKey === $encodedStoredApiKey) + { return true; } else { $resp = $this->getResponse(); diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index 13209dc7d..83a53f938 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -136,3 +136,5 @@ class MessageListener: else: raise Exception("Analyzer process terminated unexpectedly.") + return results + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index af7d81745..fd1b8b111 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -19,18 +19,34 @@ class MetadataAnalyzer(Analyzer): info = audio_file.info metadata["sample_rate"] = info.sample_rate metadata["length_seconds"] = info.length - metadata["bitrate"] = info.bitrate + metadata["bit_rate"] = info.bitrate + #metadata["channels"] = info.channels #Use the python-magic module to get the MIME type. mime_magic = magic.Magic(mime=True) metadata["mime_type"] = mime_magic.from_file(filename) + #Try to get the number of channels if mutagen can... + try: + #Special handling for getting the # of channels from MP3s. It's in the "mode" field + #which is 0=Stereo, 1=Joint Stereo, 2=Dual Channel, 3=Mono. Part of the ID3 spec... + if metadata["mime_type"] == "audio/mpeg": + if info.mode == 3: + metadata["channels"] = 1 + else: + metadata["channels"] = 2 + else: + metadata["channels"] = info.channels + except (AttributeError, KeyError): + #If mutagen can't figure out the number of channels, we'll just leave it out... + pass + #We normalize the mutagen tags slightly here, so in case mutagen changes, #we find the - mutagen_to_analyzer_mapping = { - 'title': 'title', - 'artist': 'artist', - 'album': 'album', + mutagen_to_airtime_mapping = { + 'title': 'track_title', + 'artist': 'artist_name', + 'album': 'album_title', 'bpm': 'bpm', 'composer': 'composer', 'conductor': 'conductor', @@ -43,20 +59,21 @@ class MetadataAnalyzer(Analyzer): 'last_modified':'last_modified', 'mood': 'mood', 'replay_gain': 'replaygain', - 'track_number': 'tracknumber', - 'track_total': 'tracktotal', + 'track_number': 'track_number', + 'track_total': 'track_total', 'website': 'website', 'year': 'year', + 'mime_type': 'mime', } - for mutagen_tag, analyzer_tag in mutagen_to_analyzer_mapping.iteritems(): + for mutagen_tag, airtime_tag in mutagen_to_airtime_mapping.iteritems(): try: - metadata[analyzer_tag] = audio_file[mutagen_tag] + metadata[airtime_tag] = audio_file[mutagen_tag] # Some tags are returned as lists because there could be multiple values. # This is unusual so we're going to always just take the first item in the list. - if isinstance(metadata[analyzer_tag], list): - metadata[analyzer_tag] = metadata[analyzer_tag][0] + if isinstance(metadata[airtime_tag], list): + metadata[airtime_tag] = metadata[airtime_tag][0] except KeyError: pass diff --git a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py index c8664df08..acc8ba81a 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py @@ -12,8 +12,9 @@ class StatusReporter(): def report_success_to_callback_url(self, callback_url, api_key, audio_metadata): # Encode the audio metadata as JSON and post it back to the callback_url - post_payload = json.dumps(audio_metadata) - r = requests.put(callback_url, data=post_payload, + put_payload = json.dumps(audio_metadata) + logging.debug("Sending HTTP PUT with payload: " + put_payload) + r = requests.put(callback_url, data=put_payload, auth=requests.auth.HTTPBasicAuth(api_key, ''), timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) logging.debug("HTTP request returned status: " + str(r.status_code)) From c0818682afad0bccb4e80be079e88d2fe2d66a12 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 6 Mar 2014 17:38:57 -0500 Subject: [PATCH 08/36] CC-5709: Airtime Analyzer * Fixed the /rest/media endpoint --- .../modules/rest/controllers/MediaController.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index d9adaa12c..fd626c796 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -12,9 +12,22 @@ class Rest_MediaController extends Zend_Rest_Controller if (!$this->verifyApiKey()) { return; } + + $files_array = []; + foreach (CcFilesQuery::create()->find() as $file) + { + array_push($files_array, $file->toArray(BasePeer::TYPE_FIELDNAME)); + } + + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody(json_encode($files_array)); + + /** TODO: Use this simpler code instead after we upgrade to Propel 1.7 (Airtime 2.6.x branch): $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode(CcFilesQuery::create()->find()->toArray(/*BasePeer::TYPE_FIELDNAME*/))); + ->appendBody(json_encode(CcFilesQuery::create()->find()->toArray(BasePeer::TYPE_FIELDNAME))); + */ } public function getAction() From 6d7117f670a5463b8b865a6d45edd1eb678602a8 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 10 Mar 2014 16:32:23 -0400 Subject: [PATCH 09/36] CC-5709: Airtime Analyzer * Added MetadataAnalyzer unit tests and test data * Improved debug logging and squashed pika logging * Implemented file moving * Extract the track number/total * Fixed mapping of mutagen to Airtime fields in a few spots. The mapping matches the DB column names now. * Fixed the bin/airtime_analyzer binary * Started work on PluploadController to make it work with the new File API --- .../controllers/PluploadController.php | 16 ++- python_apps/airtime_analyzer/README.rst | 5 + .../airtime_analyzer/__init__.py | 1 - .../airtime_analyzer/airtime_analyzer.py | 5 + .../airtime_analyzer/analyzer_pipeline.py | 12 +- .../airtime_analyzer/message_listener.py | 1 + .../airtime_analyzer/metadata_analyzer.py | 21 +++- .../airtime_analyzer/bin/airtime_analyzer | 2 +- .../tests/airtime_analyzer_tests.py | 6 +- .../tests/analyzer_pipeline_tests.py | 24 ++++ .../tests/metadata_analyzer_tests.py | 112 ++++++++++++++++++ .../test_data/44100Hz-16bit-dualmono.mp3 | Bin 0 -> 63436 bytes .../test_data/44100Hz-16bit-jointstereo.mp3 | Bin 0 -> 63436 bytes .../tests/test_data/44100Hz-16bit-mono.mp3 | Bin 0 -> 32298 bytes .../tests/test_data/44100Hz-16bit-mono.ogg | Bin 0 -> 36326 bytes .../test_data/44100Hz-16bit-simplestereo.mp3 | Bin 0 -> 63436 bytes .../test_data/44100Hz-16bit-stereo-utf8.mp3 | Bin 0 -> 63436 bytes .../tests/test_data/44100Hz-16bit-stereo.m4a | Bin 0 -> 51972 bytes .../tests/test_data/44100Hz-16bit-stereo.mp3 | Bin 0 -> 63436 bytes .../tests/test_data/44100Hz-16bit-stereo.ogg | Bin 0 -> 41081 bytes 20 files changed, 194 insertions(+), 11 deletions(-) create mode 100644 python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py create mode 100644 python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-dualmono.mp3 create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-jointstereo.mp3 create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-mono.mp3 create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-mono.ogg create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-simplestereo.mp3 create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo-utf8.mp3 create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.m4a create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.mp3 create mode 100644 python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.ogg diff --git a/airtime_mvc/application/controllers/PluploadController.php b/airtime_mvc/application/controllers/PluploadController.php index 9698b163a..3c4c1048c 100644 --- a/airtime_mvc/application/controllers/PluploadController.php +++ b/airtime_mvc/application/controllers/PluploadController.php @@ -35,6 +35,20 @@ class PluploadController extends Zend_Controller_Action $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "tempfilepath" => $tempFileName)); } + public function uploadFinishedAction() + { + $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; + $filename = $this->_getParam('name'); + $tempname = $this->_getParam('tempname'); + $result = Application_Model_StoredFile::importUploadedFile($upload_dir, $filename, $tempname); + if (!is_null($result)) + $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "error" => $result)); + + $this->_helper->json->sendJson(array("jsonrpc" => "2.0")); + + } + /* FIXME: I renamed this guy to uploadFinishedAction and am just starting to rewrite it to use the new File API. + * -- Albert March 10, 2014 public function copyfileAction() { $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; @@ -46,5 +60,5 @@ class PluploadController extends Zend_Controller_Action $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "error" => $result)); $this->_helper->json->sendJson(array("jsonrpc" => "2.0")); - } + }*/ } diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst index 00067d643..18b6e5aaf 100644 --- a/python_apps/airtime_analyzer/README.rst +++ b/python_apps/airtime_analyzer/README.rst @@ -53,4 +53,9 @@ To run the unit tests, execute: $ nosetests +If you care about seeing console output (stdout), like when you're debugging or developing +a test, run: + + $ nosetests -s + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/__init__.py b/python_apps/airtime_analyzer/airtime_analyzer/__init__.py index 11fe8aa91..8b1378917 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/__init__.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/__init__.py @@ -1,2 +1 @@ -from airtime_analyzer import AirtimeAnalyzerServer diff --git a/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py index 1bc2e0534..9c6f746e1 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/airtime_analyzer.py @@ -33,6 +33,11 @@ class AirtimeAnalyzerServer: if debug: self._log_level = logging.DEBUG + else: + #Disable most pika/rabbitmq logging: + pika_logger = logging.getLogger('pika') + pika_logger.setLevel(logging.CRITICAL) + #self.log = logging.getLogger(__name__) # Set up logging diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py index 94700913b..c4a4d18a3 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -1,5 +1,7 @@ import logging import multiprocessing +import shutil +import os from metadata_analyzer import MetadataAnalyzer class AnalyzerPipeline: @@ -15,9 +17,9 @@ class AnalyzerPipeline: if not isinstance(queue, multiprocessing.queues.Queue): raise TypeError("queue must be a multiprocessing.Queue()") if not isinstance(audio_file_path, unicode): - raise TypeError("audio_file_path must be a string. Was of type " + type(audio_file_path).__name__ + " instead.") + raise TypeError("audio_file_path must be unicode. Was of type " + type(audio_file_path).__name__ + " instead.") if not isinstance(final_directory, unicode): - raise TypeError("final_directory must be a string. Was of type " + type(final_directory).__name__ + " instead.") + raise TypeError("final_directory must be unicode. Was of type " + type(final_directory).__name__ + " instead.") # Analyze the audio file we were told to analyze: @@ -29,3 +31,9 @@ class AnalyzerPipeline: #print ReplayGainAnalyzer.analyze("foo.mp3") + final_audio_file_path = final_directory + os.sep + os.path.basename(audio_file_path) + if os.path.exists(final_audio_file_path) and not os.path.samefile(audio_file_path, final_audio_file_path): + os.remove(final_audio_file_path) + + shutil.move(audio_file_path, final_audio_file_path) + diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index 83a53f938..64b1b8ea9 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -91,6 +91,7 @@ class MessageListener: StatusReporter.report_success_to_callback_url(callback_url, api_key, audio_metadata) except KeyError as e: + # A field in msg_dict that we needed was missing (eg. audio_file_path) logging.exception("A mandatory airtime_analyzer message field was missing from the message.") # See the huge comment about NACK below. channel.basic_nack(delivery_tag=method_frame.delivery_tag, multiple=False, diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index fd1b8b111..266ded2fa 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -40,6 +40,20 @@ class MetadataAnalyzer(Analyzer): except (AttributeError, KeyError): #If mutagen can't figure out the number of channels, we'll just leave it out... pass + + #Try to extract the number of tracks on the album if we can (the "track total") + try: + track_number = audio_file["tracknumber"] + if isinstance(track_number, list): # Sometimes tracknumber is a list, ugh + track_number = track_number[0] + track_number_tokens = track_number.split(u'/') + track_number = track_number_tokens[0] + metadata["track_number"] = track_number + track_total = track_number_tokens[1] + metadata["track_total"] = track_total + except (AttributeError, KeyError, IndexError): + #If we couldn't figure out the track_number or track_total, just ignore it... + pass #We normalize the mutagen tags slightly here, so in case mutagen changes, #we find the @@ -51,6 +65,7 @@ class MetadataAnalyzer(Analyzer): 'composer': 'composer', 'conductor': 'conductor', 'copyright': 'copyright', + 'comment': 'comment', 'encoded_by': 'encoder', 'genre': 'genre', 'isrc': 'isrc', @@ -59,10 +74,10 @@ class MetadataAnalyzer(Analyzer): 'last_modified':'last_modified', 'mood': 'mood', 'replay_gain': 'replaygain', - 'track_number': 'track_number', - 'track_total': 'track_total', + #'tracknumber': 'track_number', + #'track_total': 'track_total', 'website': 'website', - 'year': 'year', + 'date': 'year', 'mime_type': 'mime', } diff --git a/python_apps/airtime_analyzer/bin/airtime_analyzer b/python_apps/airtime_analyzer/bin/airtime_analyzer index eb1902c2c..b90f4c7d9 100755 --- a/python_apps/airtime_analyzer/bin/airtime_analyzer +++ b/python_apps/airtime_analyzer/bin/airtime_analyzer @@ -2,7 +2,7 @@ import daemon import argparse -import airtime_analyzer as aa +import airtime_analyzer.airtime_analyzer as aa VERSION = "1.0" diff --git a/python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py b/python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py index f89336589..928e02b31 100644 --- a/python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py +++ b/python_apps/airtime_analyzer/tests/airtime_analyzer_tests.py @@ -2,11 +2,11 @@ from nose.tools import * import airtime_analyzer def setup(): - print "SETUP!" + pass def teardown(): - print "TEAR DOWN!" + pass def test_basic(): - print "I RAN!" + pass diff --git a/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py b/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py new file mode 100644 index 000000000..4ac1e49ea --- /dev/null +++ b/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py @@ -0,0 +1,24 @@ +from nose.tools import * +import multiprocessing +from airtime_analyzer.analyzer_pipeline import AnalyzerPipeline + +DEFAULT_AUDIO_FILE = u'tests/test_data/44100Hz-16bit-mono.mp3' + +def setup(): + pass + +def teardown(): + pass + +def test_basic(): + q = multiprocessing.Queue() + AnalyzerPipeline.run_analysis(q, DEFAULT_AUDIO_FILE, u'.') + results = q.get() + assert results['track_title'] == u'Test Title' + assert results['artist_name'] == u'Test Artist' + assert results['album_title'] == u'Test Album' + assert results['year'] == u'1999' + assert results['genre'] == u'Test Genre' + assert results['mime_type'] == 'audio/mpeg' # Not unicode because MIMEs aren't. + assert results['length_seconds'] == 3.90925 + diff --git a/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py b/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py new file mode 100644 index 000000000..1107c078a --- /dev/null +++ b/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +from nose.tools import * +from airtime_analyzer.metadata_analyzer import MetadataAnalyzer + +def setup(): + pass + +def teardown(): + pass + +def check_default_metadata(metadata): + assert metadata['track_title'] == u'Test Title' + assert metadata['artist_name'] == u'Test Artist' + assert metadata['album_title'] == u'Test Album' + assert metadata['year'] == u'1999' + assert metadata['genre'] == u'Test Genre' + assert metadata['track_number'] == u'1' + +def test_mp3_mono(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.mp3') + check_default_metadata(metadata) + assert metadata['channels'] == 1 + assert metadata['bit_rate'] == 64000 + assert metadata['length_seconds'] == 3.90925 + assert metadata['mime_type'] == 'audio/mpeg' # Not unicode because MIMEs aren't. + assert metadata['track_total'] == u'10' # MP3s can have a track_total + #Mutagen doesn't extract comments from mp3s it seems + +def test_mp3_jointstereo(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-jointstereo.mp3') + check_default_metadata(metadata) + assert metadata['channels'] == 2 + assert metadata['bit_rate'] == 128000 + assert metadata['length_seconds'] == 3.90075 + assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['track_total'] == u'10' # MP3s can have a track_total + +def test_mp3_simplestereo(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-simplestereo.mp3') + check_default_metadata(metadata) + assert metadata['channels'] == 2 + assert metadata['bit_rate'] == 128000 + assert metadata['length_seconds'] == 3.90075 + assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['track_total'] == u'10' # MP3s can have a track_total + +def test_mp3_dualmono(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-dualmono.mp3') + check_default_metadata(metadata) + assert metadata['channels'] == 2 + assert metadata['bit_rate'] == 128000 + assert metadata['length_seconds'] == 3.90075 + assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['track_total'] == u'10' # MP3s can have a track_total + + +def test_ogg_mono(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.ogg') + check_default_metadata(metadata) + assert metadata['channels'] == 1 + assert metadata['bit_rate'] == 80000 + assert metadata['length_seconds'] == 3.8394104308390022 + assert metadata['mime_type'] == 'application/ogg' + assert metadata['comment'] == u'Test Comment' + +def test_ogg_stereo(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo.ogg') + check_default_metadata(metadata) + assert metadata['channels'] == 2 + assert metadata['bit_rate'] == 112000 + assert metadata['length_seconds'] == 3.8394104308390022 + assert metadata['mime_type'] == 'application/ogg' + assert metadata['comment'] == u'Test Comment' + +''' faac and avconv can't seem to create a proper mono AAC file... ugh +def test_aac_mono(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.m4a') + print "Mono AAC metadata:" + print metadata + check_default_metadata(metadata) + assert metadata['channels'] == 1 + assert metadata['bit_rate'] == 80000 + assert metadata['length_seconds'] == 3.8394104308390022 + assert metadata['mime_type'] == 'video/mp4' + assert metadata['comment'] == u'Test Comment' +''' + +def test_aac_stereo(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo.m4a') + check_default_metadata(metadata) + assert metadata['channels'] == 2 + assert metadata['bit_rate'] == 102619 + assert metadata['length_seconds'] == 3.8626303854875284 + assert metadata['mime_type'] == 'video/mp4' + assert metadata['comment'] == u'Test Comment' + +def test_mp3_utf8(): + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo-utf8.mp3') + # Using a bunch of different UTF-8 codepages here. Test data is from: + # http://winrus.com/utf8-jap.htm + assert metadata['track_title'] == u'アイウエオカキクケコサシスセソタチツテ' + assert metadata['artist_name'] == u'てすと' + assert metadata['album_title'] == u'Ä ä Ü ü ß' + assert metadata['year'] == u'1999' + assert metadata['genre'] == u'Я Б Г Д Ж Й' + assert metadata['track_number'] == u'1' + assert metadata['channels'] == 2 + assert metadata['bit_rate'] == 128000 + assert metadata['length_seconds'] == 3.90075 + assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['track_total'] == u'10' # MP3s can have a track_total + diff --git a/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-dualmono.mp3 b/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-dualmono.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..1e98b616ea4ab4c7f04e8af3f8eadf0b419d7946 GIT binary patch literal 63436 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®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 X2=e|PIssy`va^pIxk^ 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 literal 0 HcmV?d00001 diff --git a/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-mono.mp3 b/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-mono.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..0c12b1b3964caf58d8cff9c75e629d43895a999e GIT binary patch literal 32298 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 z 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 z zkswe?7megnO#)Z;)gdTGkadVJ6wzgkjKmR)zKLu}%0A)03{5GDf95`aS>|zTH>Ry$ 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 literal 0 HcmV?d00001 diff --git a/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.mp3 b/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..649dc371db7aad4f184becdf6bc598ff4b38ab4c GIT binary patch literal 63436 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 literal 0 HcmV?d00001 diff --git a/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.ogg b/python_apps/airtime_analyzer/tests/test_data/44100Hz-16bit-stereo.ogg new file mode 100644 index 0000000000000000000000000000000000000000..83bd04f77196dd97b560d5f857eea6f42bb632bf GIT binary patch literal 41081 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 Qp>}0kOFk-&I0c*fKa})KQUCw| literal 0 HcmV?d00001 From e6cbbdff3388dd368c60ed70f7c689ee99f3cffa Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 13 Mar 2014 11:14:30 -0400 Subject: [PATCH 10/36] CC-5709: Airtime Analyzer * Added session auth to the Media API (if you're logged in) * Started reworking our Plupload interaction with the server to be less awkward. * Basic uploading works with the Add Media page again, but messages aren't dispatched to airtime_analyzer yet (coming next...) --- .../controllers/LoginController.php | 2 +- .../controllers/PluploadController.php | 4 +- airtime_mvc/application/models/RabbitMq.php | 8 ++++ .../rest/controllers/MediaController.php | 45 ++++++++++++++++--- .../public/js/airtime/library/plupload.js | 22 +++++---- 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/airtime_mvc/application/controllers/LoginController.php b/airtime_mvc/application/controllers/LoginController.php index 4c58a6b57..ee4ced5e4 100644 --- a/airtime_mvc/application/controllers/LoginController.php +++ b/airtime_mvc/application/controllers/LoginController.php @@ -65,7 +65,7 @@ class LoginController extends Zend_Controller_Action Application_Model_LoginAttempts::resetAttempts($_SERVER['REMOTE_ADDR']); Application_Model_Subjects::resetLoginAttempts($username); - + $tempSess = new Zend_Session_Namespace("referrer"); $tempSess->referrer = 'login'; diff --git a/airtime_mvc/application/controllers/PluploadController.php b/airtime_mvc/application/controllers/PluploadController.php index 3c4c1048c..c7f4f29d9 100644 --- a/airtime_mvc/application/controllers/PluploadController.php +++ b/airtime_mvc/application/controllers/PluploadController.php @@ -6,8 +6,8 @@ class PluploadController extends Zend_Controller_Action public function init() { $ajaxContext = $this->_helper->getHelper('AjaxContext'); - $ajaxContext->addActionContext('upload', 'json') - ->addActionContext('copyfile', 'json') + $ajaxContext->addActionContext('upload', 'json') + ->addActionContext('uploadFinished', 'json') ->initContext(); } diff --git a/airtime_mvc/application/models/RabbitMq.php b/airtime_mvc/application/models/RabbitMq.php index 371fab0b9..d14d8249f 100644 --- a/airtime_mvc/application/models/RabbitMq.php +++ b/airtime_mvc/application/models/RabbitMq.php @@ -76,4 +76,12 @@ class Application_Model_RabbitMq self::sendMessage($exchange, $data); } + + public static function SendMessageToAnalyzer() + { + $exchange = 'airtime-uploads'; + //$data = json_encode($md); + //TODO: Finish me + //self::sendMessage($exchange, $data); + } } diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index fd626c796..83269de35 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -9,7 +9,7 @@ class Rest_MediaController extends Zend_Rest_Controller public function indexAction() { - if (!$this->verifyApiKey()) { + if (!$this->verifyApiKey() && !$this->verifySession()) { return; } @@ -32,7 +32,7 @@ class Rest_MediaController extends Zend_Rest_Controller public function getAction() { - if (!$this->verifyApiKey()) { + if (!$this->verifyApiKey() && !$this->verifySession()) { return; } $id = $this->getId(); @@ -42,6 +42,8 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { + //TODO: Strip or sanitize the JSON output + $this->getResponse() ->setHttpResponseCode(200) ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); @@ -52,7 +54,7 @@ class Rest_MediaController extends Zend_Rest_Controller public function postAction() { - if (!$this->verifyApiKey()) { + if (!$this->verifyApiKey() && !$this->verifySession()) { return; } //If we do get an ID on a POST, then that doesn't make any sense @@ -60,10 +62,13 @@ class Rest_MediaController extends Zend_Rest_Controller if ($id = $this->_getParam('id', false)) { $resp = $this->getResponse(); $resp->setHttpResponseCode(400); - $resp->appendBody("ERROR: ID should not be specified when using POST. POST is only used for show creation, and an ID will be chosen by Airtime"); + $resp->appendBody("ERROR: ID should not be specified when using POST. POST is only used for file creation, and an ID will be chosen by Airtime"); return; } + $this->processUpload(); + + //TODO: Strip or sanitize the JSON output $file = new CcFiles(); $file->fromArray($this->getRequest()->getPost()); $file->save(); @@ -75,7 +80,7 @@ class Rest_MediaController extends Zend_Rest_Controller public function putAction() { - if (!$this->verifyApiKey()) { + if (!$this->verifyApiKey() && !$this->verifySession()) { return; } $id = $this->getId(); @@ -86,6 +91,8 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { + //TODO: Strip or sanitize the JSON output + $file->fromArray(json_decode($this->getRequest()->getRawBody(), true), BasePeer::TYPE_FIELDNAME); $file->save(); $this->getResponse() @@ -98,7 +105,7 @@ class Rest_MediaController extends Zend_Rest_Controller public function deleteAction() { - if (!$this->verifyApiKey()) { + if (!$this->verifyApiKey() && !$this->verifySession()) { return; } $id = $this->getId(); @@ -107,6 +114,8 @@ class Rest_MediaController extends Zend_Rest_Controller } $file = CcFilesQuery::create()->findPk($id); if ($file) { + $storedFile = Application_Model_StoredFile($file); + $storedFile->delete(); //TODO: This checks your session permissions... Make it work without a session? $file->delete(); $this->getResponse() ->setHttpResponseCode(204); @@ -148,6 +157,20 @@ class Rest_MediaController extends Zend_Rest_Controller return false; } } + + private function verifySession() + { + $auth = Zend_Auth::getInstance(); + if ($auth->hasIdentity()) + { + return true; + } + + //Token checking stub code. We'd need to change LoginController.php to generate a token too, but + //but luckily all the token code already exists and works. + //$auth = new Application_Model_Auth(); + //$auth->checkToken(Application_Model_Preference::getUserId(), $token); + } private function fileNotFoundResponse() { @@ -155,4 +178,14 @@ class Rest_MediaController extends Zend_Rest_Controller $resp->setHttpResponseCode(404); $resp->appendBody("ERROR: Media not found."); } + + private function processUpload() + { + $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; + $tempFilePath = Application_Model_StoredFile::uploadFile($upload_dir); + $tempFileName = basename($tempFilePath); + + //TODO: Dispatch a message to airtime_analyzer through RabbitMQ! + + } } \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index 2d76b3383..2b27166c4 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -5,8 +5,9 @@ $(document).ready(function() { $("#plupload_files").pluploadQueue({ // General settings runtimes : 'gears, html5, html4', - url : baseUrl+'Plupload/upload/format/json', - chunk_size : '5mb', + //url : baseUrl+'Plupload/upload/format/json', + url : baseUrl+'rest/media', + //chunk_size : '5mb', //Disabling chunking since we're using the File Upload REST API now unique_names : 'true', multiple_queues : 'true', filters : [ @@ -17,16 +18,21 @@ $(document).ready(function() { uploader = $("#plupload_files").pluploadQueue(); uploader.bind('FileUploaded', function(up, file, json) { + + /* var j = jQuery.parseJSON(json.response); - - if(j.error !== undefined) { + + console.log(json.response); + if (j.error !== undefined) { var row = $("") .append('' + file.name +'') .append('' + j.error.message + ''); - + $("#plupload_error").find("table").append(row); $("#plupload_error table").css("display", "inline-table"); - }else{ + } else { + //FIXME: This should just update something in the GUI, not communicate with the backend -- Albert + /* var tempFileName = j.tempfilepath; $.get(baseUrl+'Plupload/copyfile/format/json/name/'+ encodeURIComponent(file.name)+'/tempname/' + @@ -35,12 +41,12 @@ $(document).ready(function() { var row = $("") .append('' + file.name +'') .append('' + jr.error.message + ''); - + $("#plupload_error").find("table").append(row); $("#plupload_error table").css("display", "inline-table"); } }); - } + }*/ }); var uploadProgress = false; From f4ea417b83a5463e8136e71b4eae1fb82c9b9514 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 13 Mar 2014 12:12:12 -0400 Subject: [PATCH 11/36] CC-5709: Airtime Analyzer * Renamed a function in MediaController for clarity * Updated airtime_analyzer README --- .../application/modules/rest/controllers/MediaController.php | 4 ++-- python_apps/airtime_analyzer/README.rst | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 83269de35..d7bd9132c 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -66,7 +66,7 @@ class Rest_MediaController extends Zend_Rest_Controller return; } - $this->processUpload(); + $this->processUploadedFile(); //TODO: Strip or sanitize the JSON output $file = new CcFiles(); @@ -179,7 +179,7 @@ class Rest_MediaController extends Zend_Rest_Controller $resp->appendBody("ERROR: Media not found."); } - private function processUpload() + private function processUploadedFile() { $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; $tempFilePath = Application_Model_StoredFile::uploadFile($upload_dir); diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst index 18b6e5aaf..ffd0c8ef8 100644 --- a/python_apps/airtime_analyzer/README.rst +++ b/python_apps/airtime_analyzer/README.rst @@ -33,8 +33,7 @@ directory for convenience. This is super easy to do, just run: To send an test message to airtime_analyzer, you can use the message_sender.php script in the tools directory. For example, run: - $ php tools/message_sender.php '{ "tmp_file_path" : "foo.mp3" }' - + $ php tools/message_sender.php '{ "tmp_file_path" : "foo.mp3", "final_directory" : ".", "callback_url" : "http://airtime.localhost/rest/media/1", "api_key" : "YOUR_API_KEY" }' Logging ========= From 451b19150ba18efe5b5c8d402ffb56b231590161 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 13 Mar 2014 13:35:48 -0400 Subject: [PATCH 12/36] CC-5709: Airtime Analyzer * Notify airtime_analyzer of new uploads with RabbitMQ * Use a durable exchange for airtime-uploads --- airtime_mvc/application/models/RabbitMq.php | 24 ++++++++++++------- .../rest/controllers/MediaController.php | 17 ++++++++++--- .../airtime_analyzer/message_listener.py | 2 +- .../airtime_analyzer/tools/message_sender.php | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/airtime_mvc/application/models/RabbitMq.php b/airtime_mvc/application/models/RabbitMq.php index d14d8249f..a178fb585 100644 --- a/airtime_mvc/application/models/RabbitMq.php +++ b/airtime_mvc/application/models/RabbitMq.php @@ -13,7 +13,7 @@ class Application_Model_RabbitMq self::$doPush = true; } - private static function sendMessage($exchange, $data) + private static function sendMessage($exchange, $exchangeType, $autoDeleteExchange, $data, $queue="") { $CC_CONFIG = Config::getConfig(); @@ -31,7 +31,9 @@ class Application_Model_RabbitMq $channel->access_request($CC_CONFIG["rabbitmq"]["vhost"], false, false, true, true); - $channel->exchange_declare($exchange, 'direct', false, true); + //I'm pretty sure we DON'T want to autodelete ANY exchanges but I'm keeping the code + //the way it is just so I don't accidentally break anything when I add the Analyzer code in. -- Albert, March 13, 2014 + $channel->exchange_declare($exchange, $exchangeType, false, true, $autoDeleteExchange); $msg = new AMQPMessage($data, array('content_type' => 'text/plain')); @@ -46,7 +48,7 @@ class Application_Model_RabbitMq $exchange = 'airtime-pypo'; $data = json_encode($md, JSON_FORCE_OBJECT); - self::sendMessage($exchange, $data); + self::sendMessage($exchange, 'direct', true, $data); } public static function SendMessageToMediaMonitor($event_type, $md) @@ -55,7 +57,7 @@ class Application_Model_RabbitMq $exchange = 'airtime-media-monitor'; $data = json_encode($md); - self::sendMessage($exchange, $data); + self::sendMessage($exchange, 'direct', true, $data); } public static function SendMessageToShowRecorder($event_type) @@ -74,14 +76,18 @@ class Application_Model_RabbitMq } $data = json_encode($temp); - self::sendMessage($exchange, $data); + self::sendMessage($exchange, 'direct', true, $data); } - public static function SendMessageToAnalyzer() + public static function SendMessageToAnalyzer($tmpFilePath, $finalDirectory, $callbackUrl, $apiKey) { $exchange = 'airtime-uploads'; - //$data = json_encode($md); - //TODO: Finish me - //self::sendMessage($exchange, $data); + $data['tmp_file_path'] = $tmpFilePath; + $data['final_directory'] = $finalDirectory; + $data['callback_url'] = $callbackUrl; + $data['api_key'] = $apiKey; + + $jsonData = json_encode($data); + self::sendMessage($exchange, 'topic', false, $jsonData, 'airtime-uploads'); } } diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index d7bd9132c..f0eaf7b53 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -66,7 +66,7 @@ class Rest_MediaController extends Zend_Rest_Controller return; } - $this->processUploadedFile(); + $this->processUploadedFile($this->getRequest()->getRequestUri()); //TODO: Strip or sanitize the JSON output $file = new CcFiles(); @@ -179,13 +179,24 @@ class Rest_MediaController extends Zend_Rest_Controller $resp->appendBody("ERROR: Media not found."); } - private function processUploadedFile() + private function processUploadedFile($callbackUrl) { + $CC_CONFIG = Config::getConfig(); + $apiKey = $CC_CONFIG["apiKey"][0]; + $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; $tempFilePath = Application_Model_StoredFile::uploadFile($upload_dir); $tempFileName = basename($tempFilePath); - //TODO: Dispatch a message to airtime_analyzer through RabbitMQ! + //TODO: Remove copyFileToStor from StoredFile... + + $storDir = Application_Model_MusicDir::getStorDir(); + $finalDestinationDir = $storDir->getDirectory() . "/organize"; + + //Dispatch a message to airtime_analyzer through RabbitMQ, + //notifying it that there's a new upload to process! + Application_Model_RabbitMq::SendMessageToAnalyzer($tempFilePath, + $finalDestinationDir, $callbackUrl, $apiKey); } } \ No newline at end of file diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index 64b1b8ea9..d25219ecd 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -54,7 +54,7 @@ class MessageListener: port=self._port, virtual_host=self._vhost, credentials=pika.credentials.PlainCredentials(self._username, self._password))) self._channel = self._connection.channel() - self._channel.exchange_declare(exchange=EXCHANGE, type=EXCHANGE_TYPE) + self._channel.exchange_declare(exchange=EXCHANGE, type=EXCHANGE_TYPE, durable=True) result = self._channel.queue_declare(queue=QUEUE, durable=True) self._channel.queue_bind(exchange=EXCHANGE, queue=QUEUE, routing_key=ROUTING_KEY) diff --git a/python_apps/airtime_analyzer/tools/message_sender.php b/python_apps/airtime_analyzer/tools/message_sender.php index d5c9171c1..59677673d 100644 --- a/python_apps/airtime_analyzer/tools/message_sender.php +++ b/python_apps/airtime_analyzer/tools/message_sender.php @@ -36,7 +36,7 @@ $channel = $connection->channel(); $channel->queue_declare($queue, false, true, false, false); // declare/create the exchange as a topic exchange. -$channel->exchange_declare($exchange, $exchangeType, false, false, false); +$channel->exchange_declare($exchange, $exchangeType, false, true, false); $msg = new AMQPMessage($message, array("content_type" => "text/plain")); From c0aee37e37f80b6d13f43487e113f968b5b77296 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 13 Mar 2014 14:38:01 -0400 Subject: [PATCH 13/36] CC-5709: Airtime Analyzer * Fixed the RabbitMQ setup instructions in the README --- python_apps/airtime_analyzer/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst index ffd0c8ef8..2f0c9e133 100644 --- a/python_apps/airtime_analyzer/README.rst +++ b/python_apps/airtime_analyzer/README.rst @@ -6,7 +6,7 @@ Ghetto temporary installation instructions You will need to allow the "airtime" RabbitMQ user to access all exchanges and queues within the /airtime vhost: - sudo rabbitmqctl set_permissions -p /airtime airtime .* .* .* + sudo rabbitmqctl set_permissions -p /airtime airtime .\* .\* .\* Usage From 9b390518b75da5dddb2b69f9518f3e60ef44c6b5 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 13 Mar 2014 14:59:48 -0400 Subject: [PATCH 14/36] CC-5709: Airtime Analyzer * Fix the callback URL * Imports files successfully now! --- .../modules/rest/controllers/MediaController.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index f0eaf7b53..dd5f11da1 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -66,13 +66,14 @@ class Rest_MediaController extends Zend_Rest_Controller return; } - $this->processUploadedFile($this->getRequest()->getRequestUri()); - //TODO: Strip or sanitize the JSON output $file = new CcFiles(); $file->fromArray($this->getRequest()->getPost()); $file->save(); + $callbackUrl = $this->getRequest()->getScheme() . '://' . $this->getRequest()->getHttpHost() . $this->getRequest()->getRequestUri() . "/" . $file->getPrimaryKey(); + $this->processUploadedFile($callbackUrl); + $this->getResponse() ->setHttpResponseCode(201) ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); @@ -193,10 +194,11 @@ class Rest_MediaController extends Zend_Rest_Controller $storDir = Application_Model_MusicDir::getStorDir(); $finalDestinationDir = $storDir->getDirectory() . "/organize"; - //Dispatch a message to airtime_analyzer through RabbitMQ, + //Dispatch a message to airtime_analyzer through RabbitMQ, //notifying it that there's a new upload to process! Application_Model_RabbitMq::SendMessageToAnalyzer($tempFilePath, $finalDestinationDir, $callbackUrl, $apiKey); } -} \ No newline at end of file +} + From 259edebadc6eb9e4f64bc3b13f77d0c6c0fe7b87 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Thu, 13 Mar 2014 16:52:11 -0400 Subject: [PATCH 15/36] CC-5709: Airtime Analyzer * Fixed import of length, MIME type, and bitrate into Airtime --- .../airtime_analyzer/metadata_analyzer.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index 266ded2fa..4f262b9d3 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -1,3 +1,5 @@ +import time +import datetime import mutagen import magic # For MIME type detection from analyzer import Analyzer @@ -18,19 +20,21 @@ class MetadataAnalyzer(Analyzer): #in the file header. Mutagen breaks that out into a separate "info" object: info = audio_file.info metadata["sample_rate"] = info.sample_rate - metadata["length_seconds"] = info.length + #Converting the length in seconds (float) to a formatted time string + track_length = datetime.timedelta(seconds=info.length) + metadata["length"] = str(track_length) #time.strftime("%H:%M:%S.%f", track_length) metadata["bit_rate"] = info.bitrate #metadata["channels"] = info.channels #Use the python-magic module to get the MIME type. mime_magic = magic.Magic(mime=True) - metadata["mime_type"] = mime_magic.from_file(filename) + metadata["mime"] = mime_magic.from_file(filename) #Try to get the number of channels if mutagen can... try: #Special handling for getting the # of channels from MP3s. It's in the "mode" field #which is 0=Stereo, 1=Joint Stereo, 2=Dual Channel, 3=Mono. Part of the ID3 spec... - if metadata["mime_type"] == "audio/mpeg": + if metadata["mime"] == "audio/mpeg": if info.mode == 3: metadata["channels"] = 1 else: @@ -70,6 +74,7 @@ class MetadataAnalyzer(Analyzer): 'genre': 'genre', 'isrc': 'isrc', 'label': 'label', + 'length': 'length', 'language': 'language', 'last_modified':'last_modified', 'mood': 'mood', @@ -78,7 +83,7 @@ class MetadataAnalyzer(Analyzer): #'track_total': 'track_total', 'website': 'website', 'date': 'year', - 'mime_type': 'mime', + #'mime_type': 'mime', } for mutagen_tag, airtime_tag in mutagen_to_airtime_mapping.iteritems(): @@ -91,7 +96,11 @@ class MetadataAnalyzer(Analyzer): metadata[airtime_tag] = metadata[airtime_tag][0] except KeyError: - pass + continue + + #Airtime <= 2.5.x nonsense: + metadata["ftype"] = "audioclip" + metadata["cueout"] = metadata["length"] return metadata From 6a68967f81a45dcd564eeaeac589cb4f4a67b70b Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 13 Mar 2014 17:00:15 -0400 Subject: [PATCH 16/36] CC-5734: RESTful API media ownership --- .../rest/controllers/MediaController.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index dd5f11da1..011f2eeff 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -69,6 +69,7 @@ class Rest_MediaController extends Zend_Rest_Controller //TODO: Strip or sanitize the JSON output $file = new CcFiles(); $file->fromArray($this->getRequest()->getPost()); + $file->setDbOwnerId($this->getOwnerId()); $file->save(); $callbackUrl = $this->getRequest()->getScheme() . '://' . $this->getRequest()->getHttpHost() . $this->getRequest()->getRequestUri() . "/" . $file->getPrimaryKey(); @@ -200,5 +201,28 @@ class Rest_MediaController extends Zend_Rest_Controller $finalDestinationDir, $callbackUrl, $apiKey); } + + private function getOwnerId() + { + try { + if ($this->verifySession()) { + $service_user = new Application_Service_UserService(); + return $service_user->getCurrentUser()->getDbId(); + } else { + $defaultOwner = CcSubjsQuery::create() + ->filterByDbType('A') + ->orderByDbId() + ->findOne(); + if (!$defaultOwner) { + // what to do if there is no admin user? + // should we handle this case? + return null; + } + return $defaultOwner->getDbId(); + } + } catch(Exception $e) { + Logging::info($e->getMessage()); + } + } } From 820f7f257a01002a3cfc1f60544a784fa86056a1 Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 14 Mar 2014 17:34:56 -0400 Subject: [PATCH 17/36] CC-5733: RESTful API data sanitization and validation Stripped out fields that are readonly to the RESTful API from the request data for POST and PUT. Stripped out fields that should never be visible outside of Airtime in response data. Set uploaded and modified timestamp on POST request. Set modified timestamp on PUT request. --- .../rest/controllers/MediaController.php | 77 ++++++++++++++++--- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 011f2eeff..6ad5d90cc 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -2,6 +2,26 @@ class Rest_MediaController extends Zend_Rest_Controller { + //fields that are not modifiable via our RESTful API + private $blackList = array( + 'id', + 'file_exists', + 'hidden', + 'silan_check', + 'soundcloud_id', + 'is_scheduled', + 'is_playlist' + ); + + //fields we should never expose through our RESTful API + private $privateFields = array( + 'file_exists', + 'hidden', + 'silan_check', + 'is_scheduled', + 'is_playlist' + ); + public function init() { $this->view->layout()->disableLayout(); @@ -13,10 +33,10 @@ class Rest_MediaController extends Zend_Rest_Controller return; } - $files_array = []; + $files_array = array(); foreach (CcFilesQuery::create()->find() as $file) { - array_push($files_array, $file->toArray(BasePeer::TYPE_FIELDNAME)); + array_push($files_array, $this->sanitize($file)); } $this->getResponse() @@ -42,11 +62,10 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { - //TODO: Strip or sanitize the JSON output $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); + ->appendBody(json_encode($this->sanitize($file))); } else { $this->fileNotFoundResponse(); } @@ -66,18 +85,20 @@ class Rest_MediaController extends Zend_Rest_Controller return; } - //TODO: Strip or sanitize the JSON output $file = new CcFiles(); - $file->fromArray($this->getRequest()->getPost()); + $file->fromArray($this->validateRequestData($this->getRequest()->getPost())); $file->setDbOwnerId($this->getOwnerId()); + $now = new DateTime("now", new DateTimeZone("UTC")); + $file->setDbUtime($now); + $file->setDbMtime($now); $file->save(); - + $callbackUrl = $this->getRequest()->getScheme() . '://' . $this->getRequest()->getHttpHost() . $this->getRequest()->getRequestUri() . "/" . $file->getPrimaryKey(); $this->processUploadedFile($callbackUrl); - + $this->getResponse() ->setHttpResponseCode(201) - ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); + ->appendBody(json_encode($this->sanitize($file))); } public function putAction() @@ -94,12 +115,13 @@ class Rest_MediaController extends Zend_Rest_Controller if ($file) { //TODO: Strip or sanitize the JSON output - - $file->fromArray(json_decode($this->getRequest()->getRawBody(), true), BasePeer::TYPE_FIELDNAME); + $file->fromArray($this->validateRequestData(json_decode($this->getRequest()->getRawBody(), true)), BasePeer::TYPE_FIELDNAME); + $now = new DateTime("now", new DateTimeZone("UTC")); + $file->setDbMtime($now); $file->save(); $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($file->toArray(BasePeer::TYPE_FIELDNAME))); + ->appendBody(json_encode($this->sanitize($file))); } else { $this->fileNotFoundResponse(); } @@ -224,5 +246,36 @@ class Rest_MediaController extends Zend_Rest_Controller Logging::info($e->getMessage()); } } + + /** + * + * Strips out fields from incoming request data that should never be modified + * from outside of Airtime + * @param array $data + */ + private function validateRequestData($data) + { + foreach ($this->blackList as $key) { + unset($data[$key]); + } + + return $data; + } + + /** + * + * Strips out the private fields we do not want to send back in API responses + */ + //TODO: rename this function? + public function sanitize($file) + { + $response = $file->toArray(BasePeer::TYPE_FIELDNAME); + + foreach ($this->privateFields as $key) { + unset($response[$key]); + } + + return $response; + } } From 65ab49baee6657a86377c3571e4260c81bb5e31c Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 14 Mar 2014 17:53:03 -0400 Subject: [PATCH 18/36] CC-5733: RESTful API data sanitization and validation Renamed sanitize function to sanitizeResponse --- .../modules/rest/controllers/MediaController.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 6ad5d90cc..80d3b1656 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -36,7 +36,7 @@ class Rest_MediaController extends Zend_Rest_Controller $files_array = array(); foreach (CcFilesQuery::create()->find() as $file) { - array_push($files_array, $this->sanitize($file)); + array_push($files_array, $this->sanitizeResponse($file)); } $this->getResponse() @@ -65,7 +65,7 @@ class Rest_MediaController extends Zend_Rest_Controller $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($this->sanitize($file))); + ->appendBody(json_encode($this->sanitizeResponse($file))); } else { $this->fileNotFoundResponse(); } @@ -98,7 +98,7 @@ class Rest_MediaController extends Zend_Rest_Controller $this->getResponse() ->setHttpResponseCode(201) - ->appendBody(json_encode($this->sanitize($file))); + ->appendBody(json_encode($this->sanitizeResponse($file))); } public function putAction() @@ -114,14 +114,13 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { - //TODO: Strip or sanitize the JSON output $file->fromArray($this->validateRequestData(json_decode($this->getRequest()->getRawBody(), true)), BasePeer::TYPE_FIELDNAME); $now = new DateTime("now", new DateTimeZone("UTC")); $file->setDbMtime($now); $file->save(); $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($this->sanitize($file))); + ->appendBody(json_encode($this->sanitizeResponse($file))); } else { $this->fileNotFoundResponse(); } @@ -267,7 +266,7 @@ class Rest_MediaController extends Zend_Rest_Controller * Strips out the private fields we do not want to send back in API responses */ //TODO: rename this function? - public function sanitize($file) + public function sanitizeResponse($file) { $response = $file->toArray(BasePeer::TYPE_FIELDNAME); From 50a42f12bb44d9f885ea562f42a93a02f8f08d91 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 17 Mar 2014 10:19:39 -0400 Subject: [PATCH 19/36] CC-5709: Airtime Analyzer * File import via the Add Media page now works! * Reworked StoredFile::copyFileToStor() because it's still needed. * Reworked the way file paths are reported in airtime_analyzer and in the RESTful media API --- airtime_mvc/application/models/RabbitMq.php | 8 +- airtime_mvc/application/models/StoredFile.php | 75 ++++++++++++------- .../rest/controllers/MediaController.php | 54 +++++++++++-- .../airtime_analyzer/analyzer_pipeline.py | 51 ++++++++++--- .../airtime_analyzer/message_listener.py | 10 ++- 5 files changed, 144 insertions(+), 54 deletions(-) diff --git a/airtime_mvc/application/models/RabbitMq.php b/airtime_mvc/application/models/RabbitMq.php index a178fb585..7af846127 100644 --- a/airtime_mvc/application/models/RabbitMq.php +++ b/airtime_mvc/application/models/RabbitMq.php @@ -78,12 +78,14 @@ class Application_Model_RabbitMq self::sendMessage($exchange, 'direct', true, $data); } - - public static function SendMessageToAnalyzer($tmpFilePath, $finalDirectory, $callbackUrl, $apiKey) + + public static function SendMessageToAnalyzer($tmpFilePath, $importedStorageDirectory, $originalFilename, + $callbackUrl, $apiKey) { $exchange = 'airtime-uploads'; $data['tmp_file_path'] = $tmpFilePath; - $data['final_directory'] = $finalDirectory; + $data['import_directory'] = $importedStorageDirectory; + $data['original_filename'] = $originalFilename; $data['callback_url'] = $callbackUrl; $data['api_key'] = $apiKey; diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 009572647..7f1aa7d69 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -988,48 +988,69 @@ SQL; return $freeSpace >= $fileSize; } - public static function copyFileToStor($p_targetDir, $fileName, $tempname) + /** + * Copy a newly uploaded audio file from its temporary upload directory + * on the local disk (like /tmp) over to Airtime's "stor" directory, + * which is where all ingested music/media live. + * + * This is done in PHP here on the web server rather than in airtime_analyzer because + * the airtime_analyzer might be running on a different physical computer than the web server, + * and it probably won't have access to the web server's /tmp folder. The stor/organize directory + * is, however, both accessible to the machines running airtime_analyzer and the web server + * on Airtime Pro. + * + * The file is actually copied to "stor/organize", which is a staging directory where files go + * before they're processed by airtime_analyzer, which then moves them to "stor/imported" in the final + * step. + * + * TODO: Implement better error handling here... + * + * @param string $tempFilePath + * @param string $originalFilename + * @throws Exception + * @return Ambigous + */ + public static function copyFileToStor($tempFilePath, $originalFilename) { - $audio_file = $p_targetDir . DIRECTORY_SEPARATOR . $tempname; + $audio_file = $tempFilePath; Logging::info('copyFileToStor: moving file '.$audio_file); - + $storDir = Application_Model_MusicDir::getStorDir(); $stor = $storDir->getDirectory(); // check if "organize" dir exists and if not create one if (!file_exists($stor."/organize")) { if (!mkdir($stor."/organize", 0777)) { - return array( - "code" => 109, - "message" => _("Failed to create 'organize' directory.")); + throw new Exception("Failed to create organize directory."); } } - + if (chmod($audio_file, 0644) === false) { Logging::info("Warning: couldn't change permissions of $audio_file to 0644"); } - + // Check if we have enough space before copying if (!self::isEnoughDiskSpaceToCopy($stor, $audio_file)) { $freeSpace = disk_free_space($stor); $fileSize = filesize($audio_file); - - return array("code" => 107, - "message" => sprintf(_("The file was not uploaded, there is " - ."%s MB of disk space left and the file you are " - ."uploading has a size of %s MB."), $freeSpace, $fileSize)); + + throw new Exception(sprintf(_("The file was not uploaded, there is " + ."%s MB of disk space left and the file you are " + ."uploading has a size of %s MB."), $freeSpace, $fileSize)); } - + // Check if liquidsoap can play this file + // TODO: Move this to airtime_analyzer if (!self::liquidsoapFilePlayabilityTest($audio_file)) { return array( - "code" => 110, - "message" => _("This file appears to be corrupted and will not " - ."be added to media library.")); + "code" => 110, + "message" => _("This file appears to be corrupted and will not " + ."be added to media library.")); } + // Did all the checks for real, now trying to copy $audio_stor = Application_Common_OsPath::join($stor, "organize", - $fileName); + $originalFilename); $user = Application_Model_User::getCurrentUser(); if (is_null($user)) { $uid = Application_Model_User::getFirstAdminId(); @@ -1044,7 +1065,7 @@ SQL; written)"); } else { Logging::info("Successfully written identification file for - uploaded '$audio_stor'"); + uploaded '$audio_stor'"); } //if the uploaded file is not UTF-8 encoded, let's encode it. Assuming source //encoding is ISO-8859-1 @@ -1059,18 +1080,14 @@ SQL; //is enough disk space . unlink($audio_file); //remove the file after failed rename unlink($id_file); // Also remove the identifier file - - return array( - "code" => 108, - "message" => _("The file was not uploaded, this error can occur if the computer " - ."hard drive does not have enough disk space or the stor " - ."directory does not have correct write permissions.")); + + throw new Exception("The file was not uploaded, this error can occur if the computer " + ."hard drive does not have enough disk space or the stor " + ."directory does not have correct write permissions."); } - // Now that we successfully added this file, we will add another tag - // file that will identify the user that owns it - return null; + return $audio_stor; } - + /* * Pass the file through Liquidsoap and test if it is readable. Return True if readable, and False otherwise. */ diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 011f2eeff..e0f893930 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -73,7 +73,7 @@ class Rest_MediaController extends Zend_Rest_Controller $file->save(); $callbackUrl = $this->getRequest()->getScheme() . '://' . $this->getRequest()->getHttpHost() . $this->getRequest()->getRequestUri() . "/" . $file->getPrimaryKey(); - $this->processUploadedFile($callbackUrl); + $this->processUploadedFile($callbackUrl, $_FILES["file"]["name"], $this->getOwnerId()); $this->getResponse() ->setHttpResponseCode(201) @@ -95,7 +95,27 @@ class Rest_MediaController extends Zend_Rest_Controller { //TODO: Strip or sanitize the JSON output - $file->fromArray(json_decode($this->getRequest()->getRawBody(), true), BasePeer::TYPE_FIELDNAME); + $fileFromJson = json_decode($this->getRequest()->getRawBody(), true); + + //Our RESTful API takes "full_path" as a field, which we then split and translate to match + //our internal schema. Internally, file path is stored relative to a directory, with the directory + //as a foreign key to cc_music_dirs. + if ($fileFromJson["full_path"]) { + + $fullPath = $fileFromJson["full_path"]; + $storDir = Application_Model_MusicDir::getStorDir()->getDirectory(); + $pos = strpos($fullPath, $storDir); + + if ($pos !== FALSE) + { + assert($pos == 0); //Path must start with the stor directory path + + $filePathRelativeToStor = substr($fullPath, strlen($storDir)); + $fileFromJson["filepath"] = $filePathRelativeToStor; + $fileFromJson["directory"] = 1; //1 corresponds to the default stor/imported directory. + } + } + $file->fromArray($fileFromJson, BasePeer::TYPE_FIELDNAME); $file->save(); $this->getResponse() ->setHttpResponseCode(200) @@ -181,7 +201,7 @@ class Rest_MediaController extends Zend_Rest_Controller $resp->appendBody("ERROR: Media not found."); } - private function processUploadedFile($callbackUrl) + private function processUploadedFile($callbackUrl, $originalFilename, $ownerId) { $CC_CONFIG = Config::getConfig(); $apiKey = $CC_CONFIG["apiKey"][0]; @@ -192,14 +212,32 @@ class Rest_MediaController extends Zend_Rest_Controller //TODO: Remove copyFileToStor from StoredFile... - $storDir = Application_Model_MusicDir::getStorDir(); - $finalDestinationDir = $storDir->getDirectory() . "/organize"; + //TODO: Remove uploadFileAction from ApiController.php **IMPORTANT** - It's used by the recorder daemon? + $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; + $tempFilePath = $upload_dir . "/" . $tempFileName; + + $storDir = Application_Model_MusicDir::getStorDir(); + //$finalFullFilePath = $storDir->getDirectory() . "/imported/" . $ownerId . "/" . $originalFilename; + $importedStorageDirectory = $storDir->getDirectory() . "/imported/" . $ownerId; + + + try { + //Copy the temporary file over to the "organize" folder so that it's off our webserver + //and accessible by airtime_analyzer which could be running on a different machine. + $newTempFilePath = Application_Model_StoredFile::copyFileToStor($tempFilePath, $originalFilename); + } catch (Exception $e) { + Logging::error($e->getMessage()); + } + + //Logging::info("New temporary file path: " . $newTempFilePath); + //Logging::info("Final file path: " . $finalFullFilePath); + //Dispatch a message to airtime_analyzer through RabbitMQ, //notifying it that there's a new upload to process! - Application_Model_RabbitMq::SendMessageToAnalyzer($tempFilePath, - $finalDestinationDir, $callbackUrl, $apiKey); - + Application_Model_RabbitMq::SendMessageToAnalyzer($newTempFilePath, + $importedStorageDirectory, $originalFilename, + $callbackUrl, $apiKey); } private function getOwnerId() diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py index c4a4d18a3..af880a735 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -1,7 +1,7 @@ import logging import multiprocessing import shutil -import os +import os, errno from metadata_analyzer import MetadataAnalyzer class AnalyzerPipeline: @@ -12,28 +12,59 @@ class AnalyzerPipeline: # Take message dictionary and perform the necessary analysis. @staticmethod - def run_analysis(queue, audio_file_path, final_directory): + def run_analysis(queue, audio_file_path, import_directory, original_filename): if not isinstance(queue, multiprocessing.queues.Queue): raise TypeError("queue must be a multiprocessing.Queue()") if not isinstance(audio_file_path, unicode): raise TypeError("audio_file_path must be unicode. Was of type " + type(audio_file_path).__name__ + " instead.") - if not isinstance(final_directory, unicode): - raise TypeError("final_directory must be unicode. Was of type " + type(final_directory).__name__ + " instead.") + if not isinstance(import_directory, unicode): + raise TypeError("import_directory must be unicode. Was of type " + type(import_directory).__name__ + " instead.") + if not isinstance(original_filename, unicode): + raise TypeError("original_filename must be unicode. Was of type " + type(original_filename).__name__ + " instead.") + #print ReplayGainAnalyzer.analyze("foo.mp3") # Analyze the audio file we were told to analyze: # First, we extract the ID3 tags and other metadata: - queue.put(MetadataAnalyzer.analyze(audio_file_path)) + results = MetadataAnalyzer.analyze(audio_file_path) # Note that the queue we're putting the results into is our interprocess communication # back to the main process. - #print ReplayGainAnalyzer.analyze("foo.mp3") + #Import the file over to it's final location. + + final_file_path = import_directory + if results.has_key("artist_name"): + final_file_path += "/" + results["artist_name"] + if results.has_key("album"): + final_file_path += "/" + results["album"] + final_file_path += "/" + original_filename - final_audio_file_path = final_directory + os.sep + os.path.basename(audio_file_path) - if os.path.exists(final_audio_file_path) and not os.path.samefile(audio_file_path, final_audio_file_path): - os.remove(final_audio_file_path) + #Ensure any redundant slashes are stripped + final_file_path = os.path.normpath(final_file_path) - shutil.move(audio_file_path, final_audio_file_path) + #final_audio_file_path = final_directory + os.sep + os.path.basename(audio_file_path) + if os.path.exists(final_file_path) and not os.path.samefile(audio_file_path, final_file_path): + raise Exception("File exists and will not be overwritten.") # by design + #Overwriting a file would mean Airtime's database has the wrong information... + + #Ensure the full path to the file exists + mkdir_p(os.path.dirname(final_file_path)) + + #Move the file into its final destination directory + shutil.move(audio_file_path, final_file_path) + + #Pass the full path back to Airtime + results["full_path"] = final_file_path + queue.put(results) + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index d25219ecd..d1311a468 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -83,11 +83,13 @@ class MessageListener: try: msg_dict = json.loads(body) audio_file_path = msg_dict["tmp_file_path"] - final_directory = msg_dict["final_directory"] + #final_file_path = msg_dict["final_file_path"] + import_directory = msg_dict["import_directory"] + original_filename = msg_dict["original_filename"] callback_url = msg_dict["callback_url"] api_key = msg_dict["api_key"] - audio_metadata = MessageListener.spawn_analyzer_process(audio_file_path, final_directory) + audio_metadata = MessageListener.spawn_analyzer_process(audio_file_path, import_directory, original_filename) StatusReporter.report_success_to_callback_url(callback_url, api_key, audio_metadata) except KeyError as e: @@ -123,11 +125,11 @@ class MessageListener: channel.basic_ack(delivery_tag=method_frame.delivery_tag) @staticmethod - def spawn_analyzer_process(audio_file_path, final_directory): + def spawn_analyzer_process(audio_file_path, import_directory, original_filename): q = multiprocessing.Queue() p = multiprocessing.Process(target=AnalyzerPipeline.run_analysis, - args=(q, audio_file_path, final_directory)) + args=(q, audio_file_path, import_directory, original_filename)) p.start() p.join() if p.exitcode == 0: From f7cb923cebe65f1ef43d2d287c15e8cd9e6c362f Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 17 Mar 2014 10:25:26 -0400 Subject: [PATCH 20/36] CC-5709: Airtime Analyzer * Fixed breakage --- .../application/modules/rest/controllers/MediaController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 8a40b912f..05f4af259 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -115,7 +115,8 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { - $fileFromJson = json_decode($this->getRequest()->getRawBody(), true); + $fileFromJson = $file->fromArray($this->validateRequestData(json_decode($this->getRequest()->getRawBody(), true)), + BasePeer::TYPE_FIELDNAME); //Our RESTful API takes "full_path" as a field, which we then split and translate to match //our internal schema. Internally, file path is stored relative to a directory, with the directory @@ -136,7 +137,6 @@ class Rest_MediaController extends Zend_Rest_Controller } } - $file->fromArray($this->validateRequestData(json_decode($fileFromJson, true)), BasePeer::TYPE_FIELDNAME); $now = new DateTime("now", new DateTimeZone("UTC")); $file->setDbMtime($now); $file->save(); From 86a34635bbd025509cac9e7f0c5dd976ccbc0b90 Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 17 Mar 2014 10:56:49 -0400 Subject: [PATCH 21/36] CC-5701: Airtime File API Fixed saving filepath and directory --- .../modules/rest/controllers/MediaController.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 05f4af259..9bf4866a8 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -114,16 +114,16 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) - { - $fileFromJson = $file->fromArray($this->validateRequestData(json_decode($this->getRequest()->getRawBody(), true)), - BasePeer::TYPE_FIELDNAME); - + { + $requestData = json_decode($this->getRequest()->getRawBody(), true); + $file->fromArray($this->validateRequestData($requestData), BasePeer::TYPE_FIELDNAME); + //Our RESTful API takes "full_path" as a field, which we then split and translate to match //our internal schema. Internally, file path is stored relative to a directory, with the directory //as a foreign key to cc_music_dirs. - if ($fileFromJson["full_path"]) { + if ($requestData["full_path"]) { - $fullPath = $fileFromJson["full_path"]; + $fullPath = $requestData["full_path"]; $storDir = Application_Model_MusicDir::getStorDir()->getDirectory(); $pos = strpos($fullPath, $storDir); @@ -132,8 +132,8 @@ class Rest_MediaController extends Zend_Rest_Controller assert($pos == 0); //Path must start with the stor directory path $filePathRelativeToStor = substr($fullPath, strlen($storDir)); - $fileFromJson["filepath"] = $filePathRelativeToStor; - $fileFromJson["directory"] = 1; //1 corresponds to the default stor/imported directory. + $file->setDbFilepath($filePathRelativeToStor); + $file->setDbDirectory(1); //1 corresponds to the default stor/imported directory. } } From 13a664207fc1cbeacd7182668a5de00415f212bb Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 17 Mar 2014 11:19:06 -0400 Subject: [PATCH 22/36] CC-5742: Airtime isn't handling caught exceptions properly --- airtime_mvc/public/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/airtime_mvc/public/index.php b/airtime_mvc/public/index.php index 7c6d5cfb4..5c4dcdae8 100644 --- a/airtime_mvc/public/index.php +++ b/airtime_mvc/public/index.php @@ -74,5 +74,6 @@ try { } else { Logging::info($e->getTrace()); } + throw $e; } From 16c56e6aff39211eb9c57f98447d89babbea6f87 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 17 Mar 2014 14:43:50 -0400 Subject: [PATCH 23/36] CC-5709: Airtime Analyzer * Fixed error in media API authentication * Improved documentation --- .../rest/controllers/MediaController.php | 49 +++++++++++++++---- python_apps/airtime_analyzer/README.rst | 11 +++++ .../airtime_analyzer/message_listener.py | 5 +- .../airtime_analyzer/status_reporter.py | 2 +- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 9bf4866a8..ae10c6792 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -1,5 +1,6 @@ view->layout()->disableLayout(); } - + public function indexAction() { - if (!$this->verifyApiKey() && !$this->verifySession()) { + if (!$this->verifyAuth(true, true)) + { return; } @@ -52,9 +54,11 @@ class Rest_MediaController extends Zend_Rest_Controller public function getAction() { - if (!$this->verifyApiKey() && !$this->verifySession()) { + if (!$this->verifyAuth(true, true)) + { return; } + $id = $this->getId(); if (!$id) { return; @@ -73,9 +77,11 @@ class Rest_MediaController extends Zend_Rest_Controller public function postAction() { - if (!$this->verifyApiKey() && !$this->verifySession()) { + if (!$this->verifyAuth(true, true)) + { return; } + //If we do get an ID on a POST, then that doesn't make any sense //since POST is only for creating. if ($id = $this->_getParam('id', false)) { @@ -104,9 +110,11 @@ class Rest_MediaController extends Zend_Rest_Controller public function putAction() { - if (!$this->verifyApiKey() && !$this->verifySession()) { + if (!$this->verifyAuth(true, true)) + { return; } + $id = $this->getId(); if (!$id) { return; @@ -150,9 +158,11 @@ class Rest_MediaController extends Zend_Rest_Controller public function deleteAction() { - if (!$this->verifyApiKey() && !$this->verifySession()) { + if (!$this->verifyAuth(true, true)) + { return; } + $id = $this->getId(); if (!$id) { return; @@ -179,6 +189,27 @@ class Rest_MediaController extends Zend_Rest_Controller } return $id; } + + private function verifyAuth($checkApiKey, $checkSession) + { + //Session takes precedence over API key for now: + if ($checkSession && $this->verifySession()) + { + return true; + } + + if ($checkApiKey && $this->verifyAPIKey()) + { + return true; + } + + $resp = $this->getResponse(); + $resp->setHttpResponseCode(401); + $resp->appendBody("ERROR: Incorrect API key."); + + return false; + } + private function verifyAPIKey() { @@ -196,11 +227,10 @@ class Rest_MediaController extends Zend_Rest_Controller { return true; } else { - $resp = $this->getResponse(); - $resp->setHttpResponseCode(401); - $resp->appendBody("ERROR: Incorrect API key."); return false; } + + return false; } private function verifySession() @@ -210,6 +240,7 @@ class Rest_MediaController extends Zend_Rest_Controller { return true; } + return false; //Token checking stub code. We'd need to change LoginController.php to generate a token too, but //but luckily all the token code already exists and works. diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst index 2f0c9e133..7b2ba335d 100644 --- a/python_apps/airtime_analyzer/README.rst +++ b/python_apps/airtime_analyzer/README.rst @@ -12,6 +12,15 @@ You will need to allow the "airtime" RabbitMQ user to access all exchanges and q Usage ========== +This program must run as a user with permissions to write to your Airtime music library +directory. For standard Airtime installations, run it as the www-data user: + + $ sudo -u www-data airtime_analyzer --debug + +Or during development, add the --debug flag for more verbose output: + + $ sudo -u www-data airtime_analyzer --debug + To print usage instructions, run: $ airtime_analyzer --help @@ -35,6 +44,8 @@ For example, run: $ php tools/message_sender.php '{ "tmp_file_path" : "foo.mp3", "final_directory" : ".", "callback_url" : "http://airtime.localhost/rest/media/1", "api_key" : "YOUR_API_KEY" }' + $ php tools/message_sender.php '{"tmp_file_path":"foo.mp3", "import_directory":"/srv/airtime/stor/imported/1","original_filename":"foo.mp3","callback_url": "http://airtime.localhost/rest/media/1", "api_key":"YOUR_API_KEY"}' + Logging ========= diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index d1311a468..edde9c083 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -112,12 +112,13 @@ class MessageListener: # TODO: Report this as a failed upload to the File Upload REST API. # - # TODO: If the JSON was invalid, then don't report to the REST API + # TODO: If the JSON was invalid or the web server is down, + # then don't report that failure to the REST API StatusReporter.report_failure_to_callback_url(callback_url, api_key, error_status=1, reason=u'An error occurred while importing this file') - logging.error(e) + logging.exception(e) else: # ACK at the very end, after the message has been successfully processed. diff --git a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py index acc8ba81a..e91b246a8 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py @@ -19,9 +19,9 @@ class StatusReporter(): timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) logging.debug("HTTP request returned status: " + str(r.status_code)) logging.debug(r.text) # Log the response body - r.raise_for_status() # Raise an exception if there was an HTTP error code returned #TODO: Queue up failed requests and try them again later. + r.raise_for_status() # Raise an exception if there was an HTTP error code returned @classmethod def report_failure_to_callback_url(self, callback_url, api_key, error_status, reason): From 2b696dbee5e59c1f0d2f980722493f86a8f05d67 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 18 Mar 2014 13:04:06 -0400 Subject: [PATCH 24/36] CC-5741: Create a download action for the File API --- .../application/modules/rest/Bootstrap.php | 13 ++++++++++ .../rest/controllers/MediaController.php | 26 +++++++++++++++++++ .../rest/views/scripts/media/download.phtml | 0 3 files changed, 39 insertions(+) create mode 100644 airtime_mvc/application/modules/rest/views/scripts/media/download.phtml diff --git a/airtime_mvc/application/modules/rest/Bootstrap.php b/airtime_mvc/application/modules/rest/Bootstrap.php index 904d05e4c..e7017ba16 100644 --- a/airtime_mvc/application/modules/rest/Bootstrap.php +++ b/airtime_mvc/application/modules/rest/Bootstrap.php @@ -10,5 +10,18 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap $restRoute = new Zend_Rest_Route($front, array(), array( 'rest'=> array('media'))); assert($router->addRoute('rest', $restRoute)); + + $downloadRoute = new Zend_Controller_Router_Route( + 'rest/media/:id/download', + array( + 'controller' => 'media', + 'action' => 'download', + 'module' => 'rest' + ), + array( + 'id' => '\d+' + ) + ); + $router->addRoute('download', $downloadRoute); } } \ No newline at end of file diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index ae10c6792..7cd269c28 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -51,6 +51,32 @@ class Rest_MediaController extends Zend_Rest_Controller ->appendBody(json_encode(CcFilesQuery::create()->find()->toArray(BasePeer::TYPE_FIELDNAME))); */ } + + public function downloadAction() + { + if (!$this->verifyAuth(true, true)) + { + return; + } + + $id = $this->getId(); + if (!$id) { + return; + } + + $file = CcFilesQuery::create()->findPk($id); + if ($file) { + $con = Propel::getConnection(); + $storedFile = new Application_Model_StoredFile($file, $con); + $baseUrl = Application_Common_OsPath::getBaseDir(); + + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody($this->_redirect($storedFile->getRelativeFileUrl($baseUrl).'/download/true')); + } else { + $this->fileNotFoundResponse(); + } + } public function getAction() { diff --git a/airtime_mvc/application/modules/rest/views/scripts/media/download.phtml b/airtime_mvc/application/modules/rest/views/scripts/media/download.phtml new file mode 100644 index 000000000..e69de29bb From 7800cb1e15a869231827046ea47834bf5e3187cb Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 21 Mar 2014 09:50:03 -0400 Subject: [PATCH 25/36] SAAS-382: Reimplement Storage Quota Storing disk usage in cc_pref Add/subtract filesize to/from disk usage total when a file is uploaded or deleted TODO: Hook this into the ftp server --- .../controllers/LibraryController.php | 1 + airtime_mvc/application/models/Preference.php | 20 +++++++++++++++++++ .../rest/controllers/MediaController.php | 5 ++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index 2102a662e..c241599d7 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -356,6 +356,7 @@ class LibraryController extends Zend_Controller_Action if (isset($file)) { try { + Application_Model_Preference::updateDiskUsage(-1 * abs(filesize($file->getFilePath()))); $res = $file->delete(); } catch (FileNoPermissionException $e) { $message = $noPermissionMsg; diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index 0bc4fc7ac..749aa8e06 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -1415,4 +1415,24 @@ class Application_Model_Preference public static function GetHistoryFileTemplate() { return self::getValue("history_file_template"); } + + public static function getDiskUsage() + { + return self::getValue("disk_usage"); + } + + public static function setDiskUsage($value) + { + self::setValue("disk_usage", $value); + } + + public static function updateDiskUsage($filesize) + { + $currentDiskUsage = self::getDiskUsage(); + if (empty($currentDiskUsage)) { + $currentDiskUsage = 0; + } + + self::setDiskUsage($currentDiskUsage + $filesize); + } } diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 7cd269c28..041178736 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -156,7 +156,8 @@ class Rest_MediaController extends Zend_Rest_Controller //our internal schema. Internally, file path is stored relative to a directory, with the directory //as a foreign key to cc_music_dirs. if ($requestData["full_path"]) { - + Application_Model_Preference::updateDiskUsage(filesize($requestData["full_path"])); + $fullPath = $requestData["full_path"]; $storDir = Application_Model_MusicDir::getStorDir()->getDirectory(); $pos = strpos($fullPath, $storDir); @@ -196,6 +197,7 @@ class Rest_MediaController extends Zend_Rest_Controller $file = CcFilesQuery::create()->findPk($id); if ($file) { $storedFile = Application_Model_StoredFile($file); + Application_Model_Preference::updateDiskUsage(-1 * abs(filesize($storedFile->getFilePath()))); $storedFile->delete(); //TODO: This checks your session permissions... Make it work without a session? $file->delete(); $this->getResponse() @@ -373,5 +375,6 @@ class Rest_MediaController extends Zend_Rest_Controller return $response; } + } From 878dd11ccc44f36496be936e215b1498b4518d9f Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Fri, 21 Mar 2014 13:22:00 -0400 Subject: [PATCH 26/36] CC-5709: Airtime Analyzer * Overhauled Add Media screen, now shows state of recent uploads * Dropped old unused "state" column, added new file_import column to cc_files * New PluploadController methods * Save the filename as the track title for unprocessed uploads * Hide pending files from the library until they've been processed. * Don't overwrite files with duplicate names, we rename them instead. --- .../controllers/PluploadController.php | 63 +++++++++++-------- .../rest/controllers/MediaController.php | 6 +- .../views/scripts/plupload/index.phtml | 16 +++++ airtime_mvc/build/schema.xml | 2 +- .../public/js/airtime/library/plupload.js | 37 ++++++++++- .../airtime_analyzer/analyzer_pipeline.py | 33 +++++++--- .../airtime_analyzer/metadata_analyzer.py | 2 + 7 files changed, 122 insertions(+), 37 deletions(-) diff --git a/airtime_mvc/application/controllers/PluploadController.php b/airtime_mvc/application/controllers/PluploadController.php index c7f4f29d9..daeacd758 100644 --- a/airtime_mvc/application/controllers/PluploadController.php +++ b/airtime_mvc/application/controllers/PluploadController.php @@ -2,12 +2,11 @@ class PluploadController extends Zend_Controller_Action { - public function init() { $ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext->addActionContext('upload', 'json') - ->addActionContext('uploadFinished', 'json') + ->addActionContext('recent-uploads', 'json') ->initContext(); } @@ -18,12 +17,14 @@ class PluploadController extends Zend_Controller_Action $baseUrl = Application_Common_OsPath::getBaseDir(); $locale = Application_Model_Preference::GetLocale(); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/plupload/plupload.full.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/plupload/jquery.plupload.queue.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/plupload.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/plupload/i18n/'.$locale.'.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headLink()->appendStylesheet($baseUrl.'css/plupload.queue.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/addmedia.css?'.$CC_CONFIG['airtime_version']); } public function uploadAction() @@ -34,31 +35,43 @@ class PluploadController extends Zend_Controller_Action $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "tempfilepath" => $tempFileName)); } - - public function uploadFinishedAction() + + public function recentUploadsAction() { - $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; - $filename = $this->_getParam('name'); - $tempname = $this->_getParam('tempname'); - $result = Application_Model_StoredFile::importUploadedFile($upload_dir, $filename, $tempname); - if (!is_null($result)) - $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "error" => $result)); + //$this->dis + //( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' ) + $limit = isset($_GET['iDisplayLength']) ? $_GET['iDisplayLength'] : 10; + $rowStart = isset($_GET['iDisplayStart']) ? $_GET['iDisplayStart'] : 0; - $this->_helper->json->sendJson(array("jsonrpc" => "2.0")); + $recentUploads = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) + ->orderByDbUtime(Criteria::DESC) + ->offset($rowStart) + ->limit($limit) + ->find(); + $numRecentUploads = $limit; + + $numTotalRecentUploads = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) + ->count(); + + //$this->_helper->json->sendJson(array("jsonrpc" => "2.0", "tempfilepath" => $tempFileName)); + + $uploadsArray = array(); + + foreach ($recentUploads as $upload) + { + $upload->toArray(BasePeer::TYPE_FIELDNAME); + //array_push($uploadsArray, $upload); //TODO: $this->sanitizeResponse($upload)); + + //$this->_helper->json->sendJson($upload->asJson()); + array_push($uploadsArray, $upload->toArray(BasePeer::TYPE_FIELDNAME)); + } + + + $this->view->sEcho = intval($this->getRequest()->getParam('sEcho')); + $this->view->iTotalDisplayRecords = $numTotalRecentUploads; + //$this->view->iTotalDisplayRecords = $numRecentUploads; //$r["iTotalDisplayRecords"]; + $this->view->iTotalRecords = $numTotalRecentUploads; //$r["iTotalRecords"]; + $this->view->files = $uploadsArray; //$r["aaData"]; } - /* FIXME: I renamed this guy to uploadFinishedAction and am just starting to rewrite it to use the new File API. - * -- Albert March 10, 2014 - public function copyfileAction() - { - $upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload"; - $filename = $this->_getParam('name'); - $tempname = $this->_getParam('tempname'); - $result = Application_Model_StoredFile::copyFileToStor($upload_dir, - $filename, $tempname); - if (!is_null($result)) - $this->_helper->json->sendJson(array("jsonrpc" => "2.0", "error" => $result)); - - $this->_helper->json->sendJson(array("jsonrpc" => "2.0")); - }*/ } diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 7cd269c28..b850254da 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -43,7 +43,7 @@ class Rest_MediaController extends Zend_Rest_Controller $this->getResponse() ->setHttpResponseCode(200) - ->appendBody(json_encode($files_array)); + ->appendBody(json_encode($files_array)); /** TODO: Use this simpler code instead after we upgrade to Propel 1.7 (Airtime 2.6.x branch): $this->getResponse() @@ -121,8 +121,10 @@ class Rest_MediaController extends Zend_Rest_Controller $file->fromArray($this->validateRequestData($this->getRequest()->getPost())); $file->setDbOwnerId($this->getOwnerId()); $now = new DateTime("now", new DateTimeZone("UTC")); + $file->setDbTrackTitle($_FILES["file"]["name"]); $file->setDbUtime($now); $file->setDbMtime($now); + $file->setDbHidden(true); $file->save(); $callbackUrl = $this->getRequest()->getScheme() . '://' . $this->getRequest()->getHttpHost() . $this->getRequest()->getRequestUri() . "/" . $file->getPrimaryKey(); @@ -170,7 +172,7 @@ class Rest_MediaController extends Zend_Rest_Controller $file->setDbDirectory(1); //1 corresponds to the default stor/imported directory. } } - + $now = new DateTime("now", new DateTimeZone("UTC")); $file->setDbMtime($now); $file->save(); diff --git a/airtime_mvc/application/views/scripts/plupload/index.phtml b/airtime_mvc/application/views/scripts/plupload/index.phtml index cf236b8d6..1c3f42e55 100644 --- a/airtime_mvc/application/views/scripts/plupload/index.phtml +++ b/airtime_mvc/application/views/scripts/plupload/index.phtml @@ -9,3 +9,19 @@

+ +
+
+ +
+
+ + + +
+
+

Recent Uploads

+
+
+
+
diff --git a/airtime_mvc/build/schema.xml b/airtime_mvc/build/schema.xml index d5ba76516..e614748bf 100644 --- a/airtime_mvc/build/schema.xml +++ b/airtime_mvc/build/schema.xml @@ -18,7 +18,7 @@ - + diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index 2b27166c4..d1ac34ff7 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -1,6 +1,7 @@ $(document).ready(function() { var uploader; + var self = this; $("#plupload_files").pluploadQueue({ // General settings @@ -19,6 +20,13 @@ $(document).ready(function() { uploader.bind('FileUploaded', function(up, file, json) { + var j = jQuery.parseJSON(json.response); + console.log(j); + console.log(file.name); + + self.recentUploadsTable.fnDraw(); //Only works because we're using bServerSide + //In DataTables 1.10 and greater, we can use .fnAjaxReload() + /* var j = jQuery.parseJSON(json.response); @@ -52,7 +60,7 @@ $(document).ready(function() { var uploadProgress = false; uploader.bind('QueueChanged', function(){ - uploadProgress = (uploader.files.length > 0) + uploadProgress = (uploader.files.length > 0); }); uploader.bind('UploadComplete', function(){ @@ -65,5 +73,32 @@ $(document).ready(function() { "\n", "\n"); } }); + + self.setupRecentUploadsTable = function() { + return recentUploadsTable = $("#recent_uploads_table").dataTable({ + "bJQueryUI": true, + "bProcessing": false, + "bServerSide": true, + "sAjaxSource": '/Plupload/recent-uploads/format/json', + "sAjaxDataProp": 'files', + "bSearchable": false, + "bInfo": true, + "sScrollY": "200px", + "bFilter": false, + "bSort": false, + "sDom": '<"H"l>frtip', + "bPaginate" : true, + "sPaginationType": "full_numbers", + "aoColumns": [ + { "mData" : "artist_name", "sTitle" : $.i18n._("Creator") }, + { "mData" : "track_title", "sTitle" : $.i18n._("Title") }, + { "mData" : "state", "sTitle" : $.i18n._("Import Status")}, + { "mData" : "utime", "sTitle" : $.i18n._("Uploaded") } + ] + }); + }; + self.recentUploadsTable = self.setupRecentUploadsTable(); + + $("#recent_uploads_table.div.fg-toolbar").prepend('Custom tool bar! Text/images etc.'); }); diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py index af880a735..cdda6bd65 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -2,6 +2,8 @@ import logging import multiprocessing import shutil import os, errno +import time +import uuid from metadata_analyzer import MetadataAnalyzer class AnalyzerPipeline: @@ -33,6 +35,9 @@ class AnalyzerPipeline: # back to the main process. #Import the file over to it's final location. + #TODO: Move all this file moving stuff to its own Analyzer class. + # Also, handle the case where the move fails and write some code + # to possibly move the file to problem_files. final_file_path = import_directory if results.has_key("artist_name"): @@ -44,16 +49,28 @@ class AnalyzerPipeline: #Ensure any redundant slashes are stripped final_file_path = os.path.normpath(final_file_path) - #final_audio_file_path = final_directory + os.sep + os.path.basename(audio_file_path) + #If a file with the same name already exists in the "import" directory, then + #we add a unique string to the end of this one. We never overwrite a file on import + #because if we did that, it would mean Airtime's database would have + #the wrong information for the file we just overwrote (eg. the song length would be wrong!) if os.path.exists(final_file_path) and not os.path.samefile(audio_file_path, final_file_path): - raise Exception("File exists and will not be overwritten.") # by design - #Overwriting a file would mean Airtime's database has the wrong information... + #If the final file path is the same as the file we've been told to import (which + #you often do when you're debugging), then don't move the file at all. + + base_file_path, file_extension = os.path.splitext(final_file_path) + final_file_path = "%s_%s%s" % (base_file_path, time.strftime("%m-%d-%Y-%H-%M-%S", time.localtime()), file_extension) + + #If THAT path exists, append a UUID instead: + while os.path.exists(final_file_path): + base_file_path, file_extension = os.path.splitext(final_file_path) + final_file_path = "%s_%s%s" % (base_file_path, str(uuid.uuid4()), file_extension) + + #Ensure the full path to the file exists + mkdir_p(os.path.dirname(final_file_path)) + + #Move the file into its final destination directory + shutil.move(audio_file_path, final_file_path) - #Ensure the full path to the file exists - mkdir_p(os.path.dirname(final_file_path)) - - #Move the file into its final destination directory - shutil.move(audio_file_path, final_file_path) #Pass the full path back to Airtime results["full_path"] = final_file_path diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index 4f262b9d3..b2876119d 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -100,7 +100,9 @@ class MetadataAnalyzer(Analyzer): #Airtime <= 2.5.x nonsense: metadata["ftype"] = "audioclip" + #Other fields we'll want to set for Airtime: metadata["cueout"] = metadata["length"] + metadata["hidden"] = False return metadata From 8f7ecafcf639e0c40d66bdce1f06dad67dc51c6d Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Fri, 21 Mar 2014 14:03:17 -0400 Subject: [PATCH 27/36] CC-5709: Airtime Analyzer * A bunch of changes that somehow didn't make it into my last commit... * confused --- .../application/configs/airtime-conf.php | 10 +- .../controllers/PluploadController.php | 22 +++- .../models/airtime/map/CcFilesTableMap.php | 2 +- .../models/airtime/om/BaseCcFiles.php | 52 ++++---- .../models/airtime/om/BaseCcFilesPeer.php | 28 ++-- .../models/airtime/om/BaseCcFilesQuery.php | 37 ++++-- .../rest/controllers/MediaController.php | 3 +- airtime_mvc/build/build.properties | 2 +- airtime_mvc/build/sql/schema.sql | 2 +- .../public/js/airtime/library/plupload.js | 123 ++++++++++++------ .../upgrades/airtime-2.5.3/DbUpgrade.php | 24 ++++ .../airtime-2.5.3/airtime-upgrade.php | 8 ++ .../upgrades/airtime-2.5.3/data/upgrade.sql | 6 + python_apps/airtime_analyzer/README.rst | 2 +- 14 files changed, 212 insertions(+), 109 deletions(-) create mode 100644 install_minimal/upgrades/airtime-2.5.3/DbUpgrade.php create mode 100644 install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php create mode 100644 install_minimal/upgrades/airtime-2.5.3/data/upgrade.sql diff --git a/airtime_mvc/application/configs/airtime-conf.php b/airtime_mvc/application/configs/airtime-conf.php index aa69b6156..e767e18b8 100644 --- a/airtime_mvc/application/configs/airtime-conf.php +++ b/airtime_mvc/application/configs/airtime-conf.php @@ -1,6 +1,6 @@ array ( @@ -12,6 +12,14 @@ $conf = array ( 'dsn' => 'pgsql:host=localhost;port=5432;dbname=airtime;user=airtime;password=airtime', ), ), + 'airtime_test' => + array ( + 'adapter' => 'pgsql', + 'connection' => + array ( + 'dsn' => 'pgsql:host=localhost;port=5432;dbname=airtime_test;user=airtime;password=airtime', + ), + ), 'default' => 'airtime', ), 'generator_version' => '1.5.2', diff --git a/airtime_mvc/application/controllers/PluploadController.php b/airtime_mvc/application/controllers/PluploadController.php index daeacd758..37f856b8a 100644 --- a/airtime_mvc/application/controllers/PluploadController.php +++ b/airtime_mvc/application/controllers/PluploadController.php @@ -38,19 +38,28 @@ class PluploadController extends Zend_Controller_Action public function recentUploadsAction() { - //$this->dis - //( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' ) + if (isset($_GET['uploadFilter'])) { + $filter = $_GET['uploadFilter']; + } else { + $filter = "all"; + } + $limit = isset($_GET['iDisplayLength']) ? $_GET['iDisplayLength'] : 10; $rowStart = isset($_GET['iDisplayStart']) ? $_GET['iDisplayStart'] : 0; - $recentUploads = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) + $recentUploadsQuery = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) ->orderByDbUtime(Criteria::DESC) ->offset($rowStart) - ->limit($limit) - ->find(); + ->limit($limit); + + if ($filter == "pending") { + $recentUploadsQuery->filterByDbImportStatus("1"); + } else if ($filter == "failed") { + $recentUploadsQuery->filterByDbImportStatus(array('min' => 100)); + } + $recentUploads = $recentUploadsQuery->find(); $numRecentUploads = $limit; - $numTotalRecentUploads = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) ->count(); @@ -64,6 +73,7 @@ class PluploadController extends Zend_Controller_Action //array_push($uploadsArray, $upload); //TODO: $this->sanitizeResponse($upload)); //$this->_helper->json->sendJson($upload->asJson()); + //TODO: Invoke sanitization here array_push($uploadsArray, $upload->toArray(BasePeer::TYPE_FIELDNAME)); } diff --git a/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php b/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php index 6f9f414dd..348d2482e 100644 --- a/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php +++ b/airtime_mvc/application/models/airtime/map/CcFilesTableMap.php @@ -44,7 +44,7 @@ class CcFilesTableMap extends TableMap { $this->addColumn('FTYPE', 'DbFtype', 'VARCHAR', true, 128, ''); $this->addForeignKey('DIRECTORY', 'DbDirectory', 'INTEGER', 'cc_music_dirs', 'ID', false, null, null); $this->addColumn('FILEPATH', 'DbFilepath', 'LONGVARCHAR', false, null, ''); - $this->addColumn('STATE', 'DbState', 'VARCHAR', true, 128, 'empty'); + $this->addColumn('IMPORT_STATUS', 'DbImportStatus', 'INTEGER', true, null, 0); $this->addColumn('CURRENTLYACCESSING', 'DbCurrentlyaccessing', 'INTEGER', true, null, 0); $this->addForeignKey('EDITEDBY', 'DbEditedby', 'INTEGER', 'cc_subjs', 'ID', false, null, null); $this->addColumn('MTIME', 'DbMtime', 'TIMESTAMP', false, 6, null); diff --git a/airtime_mvc/application/models/airtime/om/BaseCcFiles.php b/airtime_mvc/application/models/airtime/om/BaseCcFiles.php index 38d147c07..59ea2b6c8 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcFiles.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcFiles.php @@ -65,11 +65,11 @@ abstract class BaseCcFiles extends BaseObject implements Persistent protected $filepath; /** - * The value for the state field. - * Note: this column has a database default value of: 'empty' - * @var string + * The value for the import_status field. + * Note: this column has a database default value of: 0 + * @var int */ - protected $state; + protected $import_status; /** * The value for the currentlyaccessing field. @@ -524,7 +524,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent $this->mime = ''; $this->ftype = ''; $this->filepath = ''; - $this->state = 'empty'; + $this->import_status = 0; $this->currentlyaccessing = 0; $this->length = '00:00:00'; $this->file_exists = true; @@ -607,13 +607,13 @@ abstract class BaseCcFiles extends BaseObject implements Persistent } /** - * Get the [state] column value. + * Get the [import_status] column value. * - * @return string + * @return int */ - public function getDbState() + public function getDbImportStatus() { - return $this->state; + return $this->import_status; } /** @@ -1463,24 +1463,24 @@ abstract class BaseCcFiles extends BaseObject implements Persistent } // setDbFilepath() /** - * Set the value of [state] column. + * Set the value of [import_status] column. * - * @param string $v new value + * @param int $v new value * @return CcFiles The current object (for fluent API support) */ - public function setDbState($v) + public function setDbImportStatus($v) { if ($v !== null) { - $v = (string) $v; + $v = (int) $v; } - if ($this->state !== $v || $this->isNew()) { - $this->state = $v; - $this->modifiedColumns[] = CcFilesPeer::STATE; + if ($this->import_status !== $v || $this->isNew()) { + $this->import_status = $v; + $this->modifiedColumns[] = CcFilesPeer::IMPORT_STATUS; } return $this; - } // setDbState() + } // setDbImportStatus() /** * Set the value of [currentlyaccessing] column. @@ -2892,7 +2892,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent return false; } - if ($this->state !== 'empty') { + if ($this->import_status !== 0) { return false; } @@ -2960,7 +2960,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent $this->ftype = ($row[$startcol + 3] !== null) ? (string) $row[$startcol + 3] : null; $this->directory = ($row[$startcol + 4] !== null) ? (int) $row[$startcol + 4] : null; $this->filepath = ($row[$startcol + 5] !== null) ? (string) $row[$startcol + 5] : null; - $this->state = ($row[$startcol + 6] !== null) ? (string) $row[$startcol + 6] : null; + $this->import_status = ($row[$startcol + 6] !== null) ? (int) $row[$startcol + 6] : null; $this->currentlyaccessing = ($row[$startcol + 7] !== null) ? (int) $row[$startcol + 7] : null; $this->editedby = ($row[$startcol + 8] !== null) ? (int) $row[$startcol + 8] : null; $this->mtime = ($row[$startcol + 9] !== null) ? (string) $row[$startcol + 9] : null; @@ -3502,7 +3502,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent return $this->getDbFilepath(); break; case 6: - return $this->getDbState(); + return $this->getDbImportStatus(); break; case 7: return $this->getDbCurrentlyaccessing(); @@ -3723,7 +3723,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent $keys[3] => $this->getDbFtype(), $keys[4] => $this->getDbDirectory(), $keys[5] => $this->getDbFilepath(), - $keys[6] => $this->getDbState(), + $keys[6] => $this->getDbImportStatus(), $keys[7] => $this->getDbCurrentlyaccessing(), $keys[8] => $this->getDbEditedby(), $keys[9] => $this->getDbMtime(), @@ -3848,7 +3848,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent $this->setDbFilepath($value); break; case 6: - $this->setDbState($value); + $this->setDbImportStatus($value); break; case 7: $this->setDbCurrentlyaccessing($value); @@ -4069,7 +4069,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent if (array_key_exists($keys[3], $arr)) $this->setDbFtype($arr[$keys[3]]); if (array_key_exists($keys[4], $arr)) $this->setDbDirectory($arr[$keys[4]]); if (array_key_exists($keys[5], $arr)) $this->setDbFilepath($arr[$keys[5]]); - if (array_key_exists($keys[6], $arr)) $this->setDbState($arr[$keys[6]]); + if (array_key_exists($keys[6], $arr)) $this->setDbImportStatus($arr[$keys[6]]); if (array_key_exists($keys[7], $arr)) $this->setDbCurrentlyaccessing($arr[$keys[7]]); if (array_key_exists($keys[8], $arr)) $this->setDbEditedby($arr[$keys[8]]); if (array_key_exists($keys[9], $arr)) $this->setDbMtime($arr[$keys[9]]); @@ -4150,7 +4150,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent if ($this->isColumnModified(CcFilesPeer::FTYPE)) $criteria->add(CcFilesPeer::FTYPE, $this->ftype); if ($this->isColumnModified(CcFilesPeer::DIRECTORY)) $criteria->add(CcFilesPeer::DIRECTORY, $this->directory); if ($this->isColumnModified(CcFilesPeer::FILEPATH)) $criteria->add(CcFilesPeer::FILEPATH, $this->filepath); - if ($this->isColumnModified(CcFilesPeer::STATE)) $criteria->add(CcFilesPeer::STATE, $this->state); + if ($this->isColumnModified(CcFilesPeer::IMPORT_STATUS)) $criteria->add(CcFilesPeer::IMPORT_STATUS, $this->import_status); if ($this->isColumnModified(CcFilesPeer::CURRENTLYACCESSING)) $criteria->add(CcFilesPeer::CURRENTLYACCESSING, $this->currentlyaccessing); if ($this->isColumnModified(CcFilesPeer::EDITEDBY)) $criteria->add(CcFilesPeer::EDITEDBY, $this->editedby); if ($this->isColumnModified(CcFilesPeer::MTIME)) $criteria->add(CcFilesPeer::MTIME, $this->mtime); @@ -4280,7 +4280,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent $copyObj->setDbFtype($this->ftype); $copyObj->setDbDirectory($this->directory); $copyObj->setDbFilepath($this->filepath); - $copyObj->setDbState($this->state); + $copyObj->setDbImportStatus($this->import_status); $copyObj->setDbCurrentlyaccessing($this->currentlyaccessing); $copyObj->setDbEditedby($this->editedby); $copyObj->setDbMtime($this->mtime); @@ -5328,7 +5328,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent $this->ftype = null; $this->directory = null; $this->filepath = null; - $this->state = null; + $this->import_status = null; $this->currentlyaccessing = null; $this->editedby = null; $this->mtime = null; diff --git a/airtime_mvc/application/models/airtime/om/BaseCcFilesPeer.php b/airtime_mvc/application/models/airtime/om/BaseCcFilesPeer.php index dbfbeaf06..dd2e9bec5 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcFilesPeer.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcFilesPeer.php @@ -49,8 +49,8 @@ abstract class BaseCcFilesPeer { /** the column name for the FILEPATH field */ const FILEPATH = 'cc_files.FILEPATH'; - /** the column name for the STATE field */ - const STATE = 'cc_files.STATE'; + /** the column name for the IMPORT_STATUS field */ + const IMPORT_STATUS = 'cc_files.IMPORT_STATUS'; /** the column name for the CURRENTLYACCESSING field */ const CURRENTLYACCESSING = 'cc_files.CURRENTLYACCESSING'; @@ -257,11 +257,11 @@ abstract class BaseCcFilesPeer { * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ private static $fieldNames = array ( - BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbMime', 'DbFtype', 'DbDirectory', 'DbFilepath', 'DbState', 'DbCurrentlyaccessing', 'DbEditedby', 'DbMtime', 'DbUtime', 'DbLPtime', 'DbMd5', 'DbTrackTitle', 'DbArtistName', 'DbBitRate', 'DbSampleRate', 'DbFormat', 'DbLength', 'DbAlbumTitle', 'DbGenre', 'DbComments', 'DbYear', 'DbTrackNumber', 'DbChannels', 'DbUrl', 'DbBpm', 'DbRating', 'DbEncodedBy', 'DbDiscNumber', 'DbMood', 'DbLabel', 'DbComposer', 'DbEncoder', 'DbChecksum', 'DbLyrics', 'DbOrchestra', 'DbConductor', 'DbLyricist', 'DbOriginalLyricist', 'DbRadioStationName', 'DbInfoUrl', 'DbArtistUrl', 'DbAudioSourceUrl', 'DbRadioStationUrl', 'DbBuyThisUrl', 'DbIsrcNumber', 'DbCatalogNumber', 'DbOriginalArtist', 'DbCopyright', 'DbReportDatetime', 'DbReportLocation', 'DbReportOrganization', 'DbSubject', 'DbContributor', 'DbLanguage', 'DbFileExists', 'DbSoundcloudId', 'DbSoundcloudErrorCode', 'DbSoundcloudErrorMsg', 'DbSoundcloudLinkToFile', 'DbSoundCloundUploadTime', 'DbReplayGain', 'DbOwnerId', 'DbCuein', 'DbCueout', 'DbSilanCheck', 'DbHidden', 'DbIsScheduled', 'DbIsPlaylist', ), - BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbMime', 'dbFtype', 'dbDirectory', 'dbFilepath', 'dbState', 'dbCurrentlyaccessing', 'dbEditedby', 'dbMtime', 'dbUtime', 'dbLPtime', 'dbMd5', 'dbTrackTitle', 'dbArtistName', 'dbBitRate', 'dbSampleRate', 'dbFormat', 'dbLength', 'dbAlbumTitle', 'dbGenre', 'dbComments', 'dbYear', 'dbTrackNumber', 'dbChannels', 'dbUrl', 'dbBpm', 'dbRating', 'dbEncodedBy', 'dbDiscNumber', 'dbMood', 'dbLabel', 'dbComposer', 'dbEncoder', 'dbChecksum', 'dbLyrics', 'dbOrchestra', 'dbConductor', 'dbLyricist', 'dbOriginalLyricist', 'dbRadioStationName', 'dbInfoUrl', 'dbArtistUrl', 'dbAudioSourceUrl', 'dbRadioStationUrl', 'dbBuyThisUrl', 'dbIsrcNumber', 'dbCatalogNumber', 'dbOriginalArtist', 'dbCopyright', 'dbReportDatetime', 'dbReportLocation', 'dbReportOrganization', 'dbSubject', 'dbContributor', 'dbLanguage', 'dbFileExists', 'dbSoundcloudId', 'dbSoundcloudErrorCode', 'dbSoundcloudErrorMsg', 'dbSoundcloudLinkToFile', 'dbSoundCloundUploadTime', 'dbReplayGain', 'dbOwnerId', 'dbCuein', 'dbCueout', 'dbSilanCheck', 'dbHidden', 'dbIsScheduled', 'dbIsPlaylist', ), - BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::MIME, self::FTYPE, self::DIRECTORY, self::FILEPATH, self::STATE, self::CURRENTLYACCESSING, self::EDITEDBY, self::MTIME, self::UTIME, self::LPTIME, self::MD5, self::TRACK_TITLE, self::ARTIST_NAME, self::BIT_RATE, self::SAMPLE_RATE, self::FORMAT, self::LENGTH, self::ALBUM_TITLE, self::GENRE, self::COMMENTS, self::YEAR, self::TRACK_NUMBER, self::CHANNELS, self::URL, self::BPM, self::RATING, self::ENCODED_BY, self::DISC_NUMBER, self::MOOD, self::LABEL, self::COMPOSER, self::ENCODER, self::CHECKSUM, self::LYRICS, self::ORCHESTRA, self::CONDUCTOR, self::LYRICIST, self::ORIGINAL_LYRICIST, self::RADIO_STATION_NAME, self::INFO_URL, self::ARTIST_URL, self::AUDIO_SOURCE_URL, self::RADIO_STATION_URL, self::BUY_THIS_URL, self::ISRC_NUMBER, self::CATALOG_NUMBER, self::ORIGINAL_ARTIST, self::COPYRIGHT, self::REPORT_DATETIME, self::REPORT_LOCATION, self::REPORT_ORGANIZATION, self::SUBJECT, self::CONTRIBUTOR, self::LANGUAGE, self::FILE_EXISTS, self::SOUNDCLOUD_ID, self::SOUNDCLOUD_ERROR_CODE, self::SOUNDCLOUD_ERROR_MSG, self::SOUNDCLOUD_LINK_TO_FILE, self::SOUNDCLOUD_UPLOAD_TIME, self::REPLAY_GAIN, self::OWNER_ID, self::CUEIN, self::CUEOUT, self::SILAN_CHECK, self::HIDDEN, self::IS_SCHEDULED, self::IS_PLAYLIST, ), - BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'MIME', 'FTYPE', 'DIRECTORY', 'FILEPATH', 'STATE', 'CURRENTLYACCESSING', 'EDITEDBY', 'MTIME', 'UTIME', 'LPTIME', 'MD5', 'TRACK_TITLE', 'ARTIST_NAME', 'BIT_RATE', 'SAMPLE_RATE', 'FORMAT', 'LENGTH', 'ALBUM_TITLE', 'GENRE', 'COMMENTS', 'YEAR', 'TRACK_NUMBER', 'CHANNELS', 'URL', 'BPM', 'RATING', 'ENCODED_BY', 'DISC_NUMBER', 'MOOD', 'LABEL', 'COMPOSER', 'ENCODER', 'CHECKSUM', 'LYRICS', 'ORCHESTRA', 'CONDUCTOR', 'LYRICIST', 'ORIGINAL_LYRICIST', 'RADIO_STATION_NAME', 'INFO_URL', 'ARTIST_URL', 'AUDIO_SOURCE_URL', 'RADIO_STATION_URL', 'BUY_THIS_URL', 'ISRC_NUMBER', 'CATALOG_NUMBER', 'ORIGINAL_ARTIST', 'COPYRIGHT', 'REPORT_DATETIME', 'REPORT_LOCATION', 'REPORT_ORGANIZATION', 'SUBJECT', 'CONTRIBUTOR', 'LANGUAGE', 'FILE_EXISTS', 'SOUNDCLOUD_ID', 'SOUNDCLOUD_ERROR_CODE', 'SOUNDCLOUD_ERROR_MSG', 'SOUNDCLOUD_LINK_TO_FILE', 'SOUNDCLOUD_UPLOAD_TIME', 'REPLAY_GAIN', 'OWNER_ID', 'CUEIN', 'CUEOUT', 'SILAN_CHECK', 'HIDDEN', 'IS_SCHEDULED', 'IS_PLAYLIST', ), - BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'mime', 'ftype', 'directory', 'filepath', 'state', 'currentlyaccessing', 'editedby', 'mtime', 'utime', 'lptime', 'md5', 'track_title', 'artist_name', 'bit_rate', 'sample_rate', 'format', 'length', 'album_title', 'genre', 'comments', 'year', 'track_number', 'channels', 'url', 'bpm', 'rating', 'encoded_by', 'disc_number', 'mood', 'label', 'composer', 'encoder', 'checksum', 'lyrics', 'orchestra', 'conductor', 'lyricist', 'original_lyricist', 'radio_station_name', 'info_url', 'artist_url', 'audio_source_url', 'radio_station_url', 'buy_this_url', 'isrc_number', 'catalog_number', 'original_artist', 'copyright', 'report_datetime', 'report_location', 'report_organization', 'subject', 'contributor', 'language', 'file_exists', 'soundcloud_id', 'soundcloud_error_code', 'soundcloud_error_msg', 'soundcloud_link_to_file', 'soundcloud_upload_time', 'replay_gain', 'owner_id', 'cuein', 'cueout', 'silan_check', 'hidden', 'is_scheduled', 'is_playlist', ), + BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbMime', 'DbFtype', 'DbDirectory', 'DbFilepath', 'DbImportStatus', 'DbCurrentlyaccessing', 'DbEditedby', 'DbMtime', 'DbUtime', 'DbLPtime', 'DbMd5', 'DbTrackTitle', 'DbArtistName', 'DbBitRate', 'DbSampleRate', 'DbFormat', 'DbLength', 'DbAlbumTitle', 'DbGenre', 'DbComments', 'DbYear', 'DbTrackNumber', 'DbChannels', 'DbUrl', 'DbBpm', 'DbRating', 'DbEncodedBy', 'DbDiscNumber', 'DbMood', 'DbLabel', 'DbComposer', 'DbEncoder', 'DbChecksum', 'DbLyrics', 'DbOrchestra', 'DbConductor', 'DbLyricist', 'DbOriginalLyricist', 'DbRadioStationName', 'DbInfoUrl', 'DbArtistUrl', 'DbAudioSourceUrl', 'DbRadioStationUrl', 'DbBuyThisUrl', 'DbIsrcNumber', 'DbCatalogNumber', 'DbOriginalArtist', 'DbCopyright', 'DbReportDatetime', 'DbReportLocation', 'DbReportOrganization', 'DbSubject', 'DbContributor', 'DbLanguage', 'DbFileExists', 'DbSoundcloudId', 'DbSoundcloudErrorCode', 'DbSoundcloudErrorMsg', 'DbSoundcloudLinkToFile', 'DbSoundCloundUploadTime', 'DbReplayGain', 'DbOwnerId', 'DbCuein', 'DbCueout', 'DbSilanCheck', 'DbHidden', 'DbIsScheduled', 'DbIsPlaylist', ), + BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbMime', 'dbFtype', 'dbDirectory', 'dbFilepath', 'dbImportStatus', 'dbCurrentlyaccessing', 'dbEditedby', 'dbMtime', 'dbUtime', 'dbLPtime', 'dbMd5', 'dbTrackTitle', 'dbArtistName', 'dbBitRate', 'dbSampleRate', 'dbFormat', 'dbLength', 'dbAlbumTitle', 'dbGenre', 'dbComments', 'dbYear', 'dbTrackNumber', 'dbChannels', 'dbUrl', 'dbBpm', 'dbRating', 'dbEncodedBy', 'dbDiscNumber', 'dbMood', 'dbLabel', 'dbComposer', 'dbEncoder', 'dbChecksum', 'dbLyrics', 'dbOrchestra', 'dbConductor', 'dbLyricist', 'dbOriginalLyricist', 'dbRadioStationName', 'dbInfoUrl', 'dbArtistUrl', 'dbAudioSourceUrl', 'dbRadioStationUrl', 'dbBuyThisUrl', 'dbIsrcNumber', 'dbCatalogNumber', 'dbOriginalArtist', 'dbCopyright', 'dbReportDatetime', 'dbReportLocation', 'dbReportOrganization', 'dbSubject', 'dbContributor', 'dbLanguage', 'dbFileExists', 'dbSoundcloudId', 'dbSoundcloudErrorCode', 'dbSoundcloudErrorMsg', 'dbSoundcloudLinkToFile', 'dbSoundCloundUploadTime', 'dbReplayGain', 'dbOwnerId', 'dbCuein', 'dbCueout', 'dbSilanCheck', 'dbHidden', 'dbIsScheduled', 'dbIsPlaylist', ), + BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::MIME, self::FTYPE, self::DIRECTORY, self::FILEPATH, self::IMPORT_STATUS, self::CURRENTLYACCESSING, self::EDITEDBY, self::MTIME, self::UTIME, self::LPTIME, self::MD5, self::TRACK_TITLE, self::ARTIST_NAME, self::BIT_RATE, self::SAMPLE_RATE, self::FORMAT, self::LENGTH, self::ALBUM_TITLE, self::GENRE, self::COMMENTS, self::YEAR, self::TRACK_NUMBER, self::CHANNELS, self::URL, self::BPM, self::RATING, self::ENCODED_BY, self::DISC_NUMBER, self::MOOD, self::LABEL, self::COMPOSER, self::ENCODER, self::CHECKSUM, self::LYRICS, self::ORCHESTRA, self::CONDUCTOR, self::LYRICIST, self::ORIGINAL_LYRICIST, self::RADIO_STATION_NAME, self::INFO_URL, self::ARTIST_URL, self::AUDIO_SOURCE_URL, self::RADIO_STATION_URL, self::BUY_THIS_URL, self::ISRC_NUMBER, self::CATALOG_NUMBER, self::ORIGINAL_ARTIST, self::COPYRIGHT, self::REPORT_DATETIME, self::REPORT_LOCATION, self::REPORT_ORGANIZATION, self::SUBJECT, self::CONTRIBUTOR, self::LANGUAGE, self::FILE_EXISTS, self::SOUNDCLOUD_ID, self::SOUNDCLOUD_ERROR_CODE, self::SOUNDCLOUD_ERROR_MSG, self::SOUNDCLOUD_LINK_TO_FILE, self::SOUNDCLOUD_UPLOAD_TIME, self::REPLAY_GAIN, self::OWNER_ID, self::CUEIN, self::CUEOUT, self::SILAN_CHECK, self::HIDDEN, self::IS_SCHEDULED, self::IS_PLAYLIST, ), + BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'MIME', 'FTYPE', 'DIRECTORY', 'FILEPATH', 'IMPORT_STATUS', 'CURRENTLYACCESSING', 'EDITEDBY', 'MTIME', 'UTIME', 'LPTIME', 'MD5', 'TRACK_TITLE', 'ARTIST_NAME', 'BIT_RATE', 'SAMPLE_RATE', 'FORMAT', 'LENGTH', 'ALBUM_TITLE', 'GENRE', 'COMMENTS', 'YEAR', 'TRACK_NUMBER', 'CHANNELS', 'URL', 'BPM', 'RATING', 'ENCODED_BY', 'DISC_NUMBER', 'MOOD', 'LABEL', 'COMPOSER', 'ENCODER', 'CHECKSUM', 'LYRICS', 'ORCHESTRA', 'CONDUCTOR', 'LYRICIST', 'ORIGINAL_LYRICIST', 'RADIO_STATION_NAME', 'INFO_URL', 'ARTIST_URL', 'AUDIO_SOURCE_URL', 'RADIO_STATION_URL', 'BUY_THIS_URL', 'ISRC_NUMBER', 'CATALOG_NUMBER', 'ORIGINAL_ARTIST', 'COPYRIGHT', 'REPORT_DATETIME', 'REPORT_LOCATION', 'REPORT_ORGANIZATION', 'SUBJECT', 'CONTRIBUTOR', 'LANGUAGE', 'FILE_EXISTS', 'SOUNDCLOUD_ID', 'SOUNDCLOUD_ERROR_CODE', 'SOUNDCLOUD_ERROR_MSG', 'SOUNDCLOUD_LINK_TO_FILE', 'SOUNDCLOUD_UPLOAD_TIME', 'REPLAY_GAIN', 'OWNER_ID', 'CUEIN', 'CUEOUT', 'SILAN_CHECK', 'HIDDEN', 'IS_SCHEDULED', 'IS_PLAYLIST', ), + BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'mime', 'ftype', 'directory', 'filepath', 'import_status', 'currentlyaccessing', 'editedby', 'mtime', 'utime', 'lptime', 'md5', 'track_title', 'artist_name', 'bit_rate', 'sample_rate', 'format', 'length', 'album_title', 'genre', 'comments', 'year', 'track_number', 'channels', 'url', 'bpm', 'rating', 'encoded_by', 'disc_number', 'mood', 'label', 'composer', 'encoder', 'checksum', 'lyrics', 'orchestra', 'conductor', 'lyricist', 'original_lyricist', 'radio_station_name', 'info_url', 'artist_url', 'audio_source_url', 'radio_station_url', 'buy_this_url', 'isrc_number', 'catalog_number', 'original_artist', 'copyright', 'report_datetime', 'report_location', 'report_organization', 'subject', 'contributor', 'language', 'file_exists', 'soundcloud_id', 'soundcloud_error_code', 'soundcloud_error_msg', 'soundcloud_link_to_file', 'soundcloud_upload_time', 'replay_gain', 'owner_id', 'cuein', 'cueout', 'silan_check', 'hidden', 'is_scheduled', 'is_playlist', ), BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, ) ); @@ -272,11 +272,11 @@ abstract class BaseCcFilesPeer { * e.g. self::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0 */ private static $fieldKeys = array ( - BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbMime' => 2, 'DbFtype' => 3, 'DbDirectory' => 4, 'DbFilepath' => 5, 'DbState' => 6, 'DbCurrentlyaccessing' => 7, 'DbEditedby' => 8, 'DbMtime' => 9, 'DbUtime' => 10, 'DbLPtime' => 11, 'DbMd5' => 12, 'DbTrackTitle' => 13, 'DbArtistName' => 14, 'DbBitRate' => 15, 'DbSampleRate' => 16, 'DbFormat' => 17, 'DbLength' => 18, 'DbAlbumTitle' => 19, 'DbGenre' => 20, 'DbComments' => 21, 'DbYear' => 22, 'DbTrackNumber' => 23, 'DbChannels' => 24, 'DbUrl' => 25, 'DbBpm' => 26, 'DbRating' => 27, 'DbEncodedBy' => 28, 'DbDiscNumber' => 29, 'DbMood' => 30, 'DbLabel' => 31, 'DbComposer' => 32, 'DbEncoder' => 33, 'DbChecksum' => 34, 'DbLyrics' => 35, 'DbOrchestra' => 36, 'DbConductor' => 37, 'DbLyricist' => 38, 'DbOriginalLyricist' => 39, 'DbRadioStationName' => 40, 'DbInfoUrl' => 41, 'DbArtistUrl' => 42, 'DbAudioSourceUrl' => 43, 'DbRadioStationUrl' => 44, 'DbBuyThisUrl' => 45, 'DbIsrcNumber' => 46, 'DbCatalogNumber' => 47, 'DbOriginalArtist' => 48, 'DbCopyright' => 49, 'DbReportDatetime' => 50, 'DbReportLocation' => 51, 'DbReportOrganization' => 52, 'DbSubject' => 53, 'DbContributor' => 54, 'DbLanguage' => 55, 'DbFileExists' => 56, 'DbSoundcloudId' => 57, 'DbSoundcloudErrorCode' => 58, 'DbSoundcloudErrorMsg' => 59, 'DbSoundcloudLinkToFile' => 60, 'DbSoundCloundUploadTime' => 61, 'DbReplayGain' => 62, 'DbOwnerId' => 63, 'DbCuein' => 64, 'DbCueout' => 65, 'DbSilanCheck' => 66, 'DbHidden' => 67, 'DbIsScheduled' => 68, 'DbIsPlaylist' => 69, ), - BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbMime' => 2, 'dbFtype' => 3, 'dbDirectory' => 4, 'dbFilepath' => 5, 'dbState' => 6, 'dbCurrentlyaccessing' => 7, 'dbEditedby' => 8, 'dbMtime' => 9, 'dbUtime' => 10, 'dbLPtime' => 11, 'dbMd5' => 12, 'dbTrackTitle' => 13, 'dbArtistName' => 14, 'dbBitRate' => 15, 'dbSampleRate' => 16, 'dbFormat' => 17, 'dbLength' => 18, 'dbAlbumTitle' => 19, 'dbGenre' => 20, 'dbComments' => 21, 'dbYear' => 22, 'dbTrackNumber' => 23, 'dbChannels' => 24, 'dbUrl' => 25, 'dbBpm' => 26, 'dbRating' => 27, 'dbEncodedBy' => 28, 'dbDiscNumber' => 29, 'dbMood' => 30, 'dbLabel' => 31, 'dbComposer' => 32, 'dbEncoder' => 33, 'dbChecksum' => 34, 'dbLyrics' => 35, 'dbOrchestra' => 36, 'dbConductor' => 37, 'dbLyricist' => 38, 'dbOriginalLyricist' => 39, 'dbRadioStationName' => 40, 'dbInfoUrl' => 41, 'dbArtistUrl' => 42, 'dbAudioSourceUrl' => 43, 'dbRadioStationUrl' => 44, 'dbBuyThisUrl' => 45, 'dbIsrcNumber' => 46, 'dbCatalogNumber' => 47, 'dbOriginalArtist' => 48, 'dbCopyright' => 49, 'dbReportDatetime' => 50, 'dbReportLocation' => 51, 'dbReportOrganization' => 52, 'dbSubject' => 53, 'dbContributor' => 54, 'dbLanguage' => 55, 'dbFileExists' => 56, 'dbSoundcloudId' => 57, 'dbSoundcloudErrorCode' => 58, 'dbSoundcloudErrorMsg' => 59, 'dbSoundcloudLinkToFile' => 60, 'dbSoundCloundUploadTime' => 61, 'dbReplayGain' => 62, 'dbOwnerId' => 63, 'dbCuein' => 64, 'dbCueout' => 65, 'dbSilanCheck' => 66, 'dbHidden' => 67, 'dbIsScheduled' => 68, 'dbIsPlaylist' => 69, ), - BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::MIME => 2, self::FTYPE => 3, self::DIRECTORY => 4, self::FILEPATH => 5, self::STATE => 6, self::CURRENTLYACCESSING => 7, self::EDITEDBY => 8, self::MTIME => 9, self::UTIME => 10, self::LPTIME => 11, self::MD5 => 12, self::TRACK_TITLE => 13, self::ARTIST_NAME => 14, self::BIT_RATE => 15, self::SAMPLE_RATE => 16, self::FORMAT => 17, self::LENGTH => 18, self::ALBUM_TITLE => 19, self::GENRE => 20, self::COMMENTS => 21, self::YEAR => 22, self::TRACK_NUMBER => 23, self::CHANNELS => 24, self::URL => 25, self::BPM => 26, self::RATING => 27, self::ENCODED_BY => 28, self::DISC_NUMBER => 29, self::MOOD => 30, self::LABEL => 31, self::COMPOSER => 32, self::ENCODER => 33, self::CHECKSUM => 34, self::LYRICS => 35, self::ORCHESTRA => 36, self::CONDUCTOR => 37, self::LYRICIST => 38, self::ORIGINAL_LYRICIST => 39, self::RADIO_STATION_NAME => 40, self::INFO_URL => 41, self::ARTIST_URL => 42, self::AUDIO_SOURCE_URL => 43, self::RADIO_STATION_URL => 44, self::BUY_THIS_URL => 45, self::ISRC_NUMBER => 46, self::CATALOG_NUMBER => 47, self::ORIGINAL_ARTIST => 48, self::COPYRIGHT => 49, self::REPORT_DATETIME => 50, self::REPORT_LOCATION => 51, self::REPORT_ORGANIZATION => 52, self::SUBJECT => 53, self::CONTRIBUTOR => 54, self::LANGUAGE => 55, self::FILE_EXISTS => 56, self::SOUNDCLOUD_ID => 57, self::SOUNDCLOUD_ERROR_CODE => 58, self::SOUNDCLOUD_ERROR_MSG => 59, self::SOUNDCLOUD_LINK_TO_FILE => 60, self::SOUNDCLOUD_UPLOAD_TIME => 61, self::REPLAY_GAIN => 62, self::OWNER_ID => 63, self::CUEIN => 64, self::CUEOUT => 65, self::SILAN_CHECK => 66, self::HIDDEN => 67, self::IS_SCHEDULED => 68, self::IS_PLAYLIST => 69, ), - BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'MIME' => 2, 'FTYPE' => 3, 'DIRECTORY' => 4, 'FILEPATH' => 5, 'STATE' => 6, 'CURRENTLYACCESSING' => 7, 'EDITEDBY' => 8, 'MTIME' => 9, 'UTIME' => 10, 'LPTIME' => 11, 'MD5' => 12, 'TRACK_TITLE' => 13, 'ARTIST_NAME' => 14, 'BIT_RATE' => 15, 'SAMPLE_RATE' => 16, 'FORMAT' => 17, 'LENGTH' => 18, 'ALBUM_TITLE' => 19, 'GENRE' => 20, 'COMMENTS' => 21, 'YEAR' => 22, 'TRACK_NUMBER' => 23, 'CHANNELS' => 24, 'URL' => 25, 'BPM' => 26, 'RATING' => 27, 'ENCODED_BY' => 28, 'DISC_NUMBER' => 29, 'MOOD' => 30, 'LABEL' => 31, 'COMPOSER' => 32, 'ENCODER' => 33, 'CHECKSUM' => 34, 'LYRICS' => 35, 'ORCHESTRA' => 36, 'CONDUCTOR' => 37, 'LYRICIST' => 38, 'ORIGINAL_LYRICIST' => 39, 'RADIO_STATION_NAME' => 40, 'INFO_URL' => 41, 'ARTIST_URL' => 42, 'AUDIO_SOURCE_URL' => 43, 'RADIO_STATION_URL' => 44, 'BUY_THIS_URL' => 45, 'ISRC_NUMBER' => 46, 'CATALOG_NUMBER' => 47, 'ORIGINAL_ARTIST' => 48, 'COPYRIGHT' => 49, 'REPORT_DATETIME' => 50, 'REPORT_LOCATION' => 51, 'REPORT_ORGANIZATION' => 52, 'SUBJECT' => 53, 'CONTRIBUTOR' => 54, 'LANGUAGE' => 55, 'FILE_EXISTS' => 56, 'SOUNDCLOUD_ID' => 57, 'SOUNDCLOUD_ERROR_CODE' => 58, 'SOUNDCLOUD_ERROR_MSG' => 59, 'SOUNDCLOUD_LINK_TO_FILE' => 60, 'SOUNDCLOUD_UPLOAD_TIME' => 61, 'REPLAY_GAIN' => 62, 'OWNER_ID' => 63, 'CUEIN' => 64, 'CUEOUT' => 65, 'SILAN_CHECK' => 66, 'HIDDEN' => 67, 'IS_SCHEDULED' => 68, 'IS_PLAYLIST' => 69, ), - BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'mime' => 2, 'ftype' => 3, 'directory' => 4, 'filepath' => 5, 'state' => 6, 'currentlyaccessing' => 7, 'editedby' => 8, 'mtime' => 9, 'utime' => 10, 'lptime' => 11, 'md5' => 12, 'track_title' => 13, 'artist_name' => 14, 'bit_rate' => 15, 'sample_rate' => 16, 'format' => 17, 'length' => 18, 'album_title' => 19, 'genre' => 20, 'comments' => 21, 'year' => 22, 'track_number' => 23, 'channels' => 24, 'url' => 25, 'bpm' => 26, 'rating' => 27, 'encoded_by' => 28, 'disc_number' => 29, 'mood' => 30, 'label' => 31, 'composer' => 32, 'encoder' => 33, 'checksum' => 34, 'lyrics' => 35, 'orchestra' => 36, 'conductor' => 37, 'lyricist' => 38, 'original_lyricist' => 39, 'radio_station_name' => 40, 'info_url' => 41, 'artist_url' => 42, 'audio_source_url' => 43, 'radio_station_url' => 44, 'buy_this_url' => 45, 'isrc_number' => 46, 'catalog_number' => 47, 'original_artist' => 48, 'copyright' => 49, 'report_datetime' => 50, 'report_location' => 51, 'report_organization' => 52, 'subject' => 53, 'contributor' => 54, 'language' => 55, 'file_exists' => 56, 'soundcloud_id' => 57, 'soundcloud_error_code' => 58, 'soundcloud_error_msg' => 59, 'soundcloud_link_to_file' => 60, 'soundcloud_upload_time' => 61, 'replay_gain' => 62, 'owner_id' => 63, 'cuein' => 64, 'cueout' => 65, 'silan_check' => 66, 'hidden' => 67, 'is_scheduled' => 68, 'is_playlist' => 69, ), + BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbMime' => 2, 'DbFtype' => 3, 'DbDirectory' => 4, 'DbFilepath' => 5, 'DbImportStatus' => 6, 'DbCurrentlyaccessing' => 7, 'DbEditedby' => 8, 'DbMtime' => 9, 'DbUtime' => 10, 'DbLPtime' => 11, 'DbMd5' => 12, 'DbTrackTitle' => 13, 'DbArtistName' => 14, 'DbBitRate' => 15, 'DbSampleRate' => 16, 'DbFormat' => 17, 'DbLength' => 18, 'DbAlbumTitle' => 19, 'DbGenre' => 20, 'DbComments' => 21, 'DbYear' => 22, 'DbTrackNumber' => 23, 'DbChannels' => 24, 'DbUrl' => 25, 'DbBpm' => 26, 'DbRating' => 27, 'DbEncodedBy' => 28, 'DbDiscNumber' => 29, 'DbMood' => 30, 'DbLabel' => 31, 'DbComposer' => 32, 'DbEncoder' => 33, 'DbChecksum' => 34, 'DbLyrics' => 35, 'DbOrchestra' => 36, 'DbConductor' => 37, 'DbLyricist' => 38, 'DbOriginalLyricist' => 39, 'DbRadioStationName' => 40, 'DbInfoUrl' => 41, 'DbArtistUrl' => 42, 'DbAudioSourceUrl' => 43, 'DbRadioStationUrl' => 44, 'DbBuyThisUrl' => 45, 'DbIsrcNumber' => 46, 'DbCatalogNumber' => 47, 'DbOriginalArtist' => 48, 'DbCopyright' => 49, 'DbReportDatetime' => 50, 'DbReportLocation' => 51, 'DbReportOrganization' => 52, 'DbSubject' => 53, 'DbContributor' => 54, 'DbLanguage' => 55, 'DbFileExists' => 56, 'DbSoundcloudId' => 57, 'DbSoundcloudErrorCode' => 58, 'DbSoundcloudErrorMsg' => 59, 'DbSoundcloudLinkToFile' => 60, 'DbSoundCloundUploadTime' => 61, 'DbReplayGain' => 62, 'DbOwnerId' => 63, 'DbCuein' => 64, 'DbCueout' => 65, 'DbSilanCheck' => 66, 'DbHidden' => 67, 'DbIsScheduled' => 68, 'DbIsPlaylist' => 69, ), + BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbMime' => 2, 'dbFtype' => 3, 'dbDirectory' => 4, 'dbFilepath' => 5, 'dbImportStatus' => 6, 'dbCurrentlyaccessing' => 7, 'dbEditedby' => 8, 'dbMtime' => 9, 'dbUtime' => 10, 'dbLPtime' => 11, 'dbMd5' => 12, 'dbTrackTitle' => 13, 'dbArtistName' => 14, 'dbBitRate' => 15, 'dbSampleRate' => 16, 'dbFormat' => 17, 'dbLength' => 18, 'dbAlbumTitle' => 19, 'dbGenre' => 20, 'dbComments' => 21, 'dbYear' => 22, 'dbTrackNumber' => 23, 'dbChannels' => 24, 'dbUrl' => 25, 'dbBpm' => 26, 'dbRating' => 27, 'dbEncodedBy' => 28, 'dbDiscNumber' => 29, 'dbMood' => 30, 'dbLabel' => 31, 'dbComposer' => 32, 'dbEncoder' => 33, 'dbChecksum' => 34, 'dbLyrics' => 35, 'dbOrchestra' => 36, 'dbConductor' => 37, 'dbLyricist' => 38, 'dbOriginalLyricist' => 39, 'dbRadioStationName' => 40, 'dbInfoUrl' => 41, 'dbArtistUrl' => 42, 'dbAudioSourceUrl' => 43, 'dbRadioStationUrl' => 44, 'dbBuyThisUrl' => 45, 'dbIsrcNumber' => 46, 'dbCatalogNumber' => 47, 'dbOriginalArtist' => 48, 'dbCopyright' => 49, 'dbReportDatetime' => 50, 'dbReportLocation' => 51, 'dbReportOrganization' => 52, 'dbSubject' => 53, 'dbContributor' => 54, 'dbLanguage' => 55, 'dbFileExists' => 56, 'dbSoundcloudId' => 57, 'dbSoundcloudErrorCode' => 58, 'dbSoundcloudErrorMsg' => 59, 'dbSoundcloudLinkToFile' => 60, 'dbSoundCloundUploadTime' => 61, 'dbReplayGain' => 62, 'dbOwnerId' => 63, 'dbCuein' => 64, 'dbCueout' => 65, 'dbSilanCheck' => 66, 'dbHidden' => 67, 'dbIsScheduled' => 68, 'dbIsPlaylist' => 69, ), + BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::MIME => 2, self::FTYPE => 3, self::DIRECTORY => 4, self::FILEPATH => 5, self::IMPORT_STATUS => 6, self::CURRENTLYACCESSING => 7, self::EDITEDBY => 8, self::MTIME => 9, self::UTIME => 10, self::LPTIME => 11, self::MD5 => 12, self::TRACK_TITLE => 13, self::ARTIST_NAME => 14, self::BIT_RATE => 15, self::SAMPLE_RATE => 16, self::FORMAT => 17, self::LENGTH => 18, self::ALBUM_TITLE => 19, self::GENRE => 20, self::COMMENTS => 21, self::YEAR => 22, self::TRACK_NUMBER => 23, self::CHANNELS => 24, self::URL => 25, self::BPM => 26, self::RATING => 27, self::ENCODED_BY => 28, self::DISC_NUMBER => 29, self::MOOD => 30, self::LABEL => 31, self::COMPOSER => 32, self::ENCODER => 33, self::CHECKSUM => 34, self::LYRICS => 35, self::ORCHESTRA => 36, self::CONDUCTOR => 37, self::LYRICIST => 38, self::ORIGINAL_LYRICIST => 39, self::RADIO_STATION_NAME => 40, self::INFO_URL => 41, self::ARTIST_URL => 42, self::AUDIO_SOURCE_URL => 43, self::RADIO_STATION_URL => 44, self::BUY_THIS_URL => 45, self::ISRC_NUMBER => 46, self::CATALOG_NUMBER => 47, self::ORIGINAL_ARTIST => 48, self::COPYRIGHT => 49, self::REPORT_DATETIME => 50, self::REPORT_LOCATION => 51, self::REPORT_ORGANIZATION => 52, self::SUBJECT => 53, self::CONTRIBUTOR => 54, self::LANGUAGE => 55, self::FILE_EXISTS => 56, self::SOUNDCLOUD_ID => 57, self::SOUNDCLOUD_ERROR_CODE => 58, self::SOUNDCLOUD_ERROR_MSG => 59, self::SOUNDCLOUD_LINK_TO_FILE => 60, self::SOUNDCLOUD_UPLOAD_TIME => 61, self::REPLAY_GAIN => 62, self::OWNER_ID => 63, self::CUEIN => 64, self::CUEOUT => 65, self::SILAN_CHECK => 66, self::HIDDEN => 67, self::IS_SCHEDULED => 68, self::IS_PLAYLIST => 69, ), + BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'MIME' => 2, 'FTYPE' => 3, 'DIRECTORY' => 4, 'FILEPATH' => 5, 'IMPORT_STATUS' => 6, 'CURRENTLYACCESSING' => 7, 'EDITEDBY' => 8, 'MTIME' => 9, 'UTIME' => 10, 'LPTIME' => 11, 'MD5' => 12, 'TRACK_TITLE' => 13, 'ARTIST_NAME' => 14, 'BIT_RATE' => 15, 'SAMPLE_RATE' => 16, 'FORMAT' => 17, 'LENGTH' => 18, 'ALBUM_TITLE' => 19, 'GENRE' => 20, 'COMMENTS' => 21, 'YEAR' => 22, 'TRACK_NUMBER' => 23, 'CHANNELS' => 24, 'URL' => 25, 'BPM' => 26, 'RATING' => 27, 'ENCODED_BY' => 28, 'DISC_NUMBER' => 29, 'MOOD' => 30, 'LABEL' => 31, 'COMPOSER' => 32, 'ENCODER' => 33, 'CHECKSUM' => 34, 'LYRICS' => 35, 'ORCHESTRA' => 36, 'CONDUCTOR' => 37, 'LYRICIST' => 38, 'ORIGINAL_LYRICIST' => 39, 'RADIO_STATION_NAME' => 40, 'INFO_URL' => 41, 'ARTIST_URL' => 42, 'AUDIO_SOURCE_URL' => 43, 'RADIO_STATION_URL' => 44, 'BUY_THIS_URL' => 45, 'ISRC_NUMBER' => 46, 'CATALOG_NUMBER' => 47, 'ORIGINAL_ARTIST' => 48, 'COPYRIGHT' => 49, 'REPORT_DATETIME' => 50, 'REPORT_LOCATION' => 51, 'REPORT_ORGANIZATION' => 52, 'SUBJECT' => 53, 'CONTRIBUTOR' => 54, 'LANGUAGE' => 55, 'FILE_EXISTS' => 56, 'SOUNDCLOUD_ID' => 57, 'SOUNDCLOUD_ERROR_CODE' => 58, 'SOUNDCLOUD_ERROR_MSG' => 59, 'SOUNDCLOUD_LINK_TO_FILE' => 60, 'SOUNDCLOUD_UPLOAD_TIME' => 61, 'REPLAY_GAIN' => 62, 'OWNER_ID' => 63, 'CUEIN' => 64, 'CUEOUT' => 65, 'SILAN_CHECK' => 66, 'HIDDEN' => 67, 'IS_SCHEDULED' => 68, 'IS_PLAYLIST' => 69, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'mime' => 2, 'ftype' => 3, 'directory' => 4, 'filepath' => 5, 'import_status' => 6, 'currentlyaccessing' => 7, 'editedby' => 8, 'mtime' => 9, 'utime' => 10, 'lptime' => 11, 'md5' => 12, 'track_title' => 13, 'artist_name' => 14, 'bit_rate' => 15, 'sample_rate' => 16, 'format' => 17, 'length' => 18, 'album_title' => 19, 'genre' => 20, 'comments' => 21, 'year' => 22, 'track_number' => 23, 'channels' => 24, 'url' => 25, 'bpm' => 26, 'rating' => 27, 'encoded_by' => 28, 'disc_number' => 29, 'mood' => 30, 'label' => 31, 'composer' => 32, 'encoder' => 33, 'checksum' => 34, 'lyrics' => 35, 'orchestra' => 36, 'conductor' => 37, 'lyricist' => 38, 'original_lyricist' => 39, 'radio_station_name' => 40, 'info_url' => 41, 'artist_url' => 42, 'audio_source_url' => 43, 'radio_station_url' => 44, 'buy_this_url' => 45, 'isrc_number' => 46, 'catalog_number' => 47, 'original_artist' => 48, 'copyright' => 49, 'report_datetime' => 50, 'report_location' => 51, 'report_organization' => 52, 'subject' => 53, 'contributor' => 54, 'language' => 55, 'file_exists' => 56, 'soundcloud_id' => 57, 'soundcloud_error_code' => 58, 'soundcloud_error_msg' => 59, 'soundcloud_link_to_file' => 60, 'soundcloud_upload_time' => 61, 'replay_gain' => 62, 'owner_id' => 63, 'cuein' => 64, 'cueout' => 65, 'silan_check' => 66, 'hidden' => 67, 'is_scheduled' => 68, 'is_playlist' => 69, ), BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, ) ); @@ -355,7 +355,7 @@ abstract class BaseCcFilesPeer { $criteria->addSelectColumn(CcFilesPeer::FTYPE); $criteria->addSelectColumn(CcFilesPeer::DIRECTORY); $criteria->addSelectColumn(CcFilesPeer::FILEPATH); - $criteria->addSelectColumn(CcFilesPeer::STATE); + $criteria->addSelectColumn(CcFilesPeer::IMPORT_STATUS); $criteria->addSelectColumn(CcFilesPeer::CURRENTLYACCESSING); $criteria->addSelectColumn(CcFilesPeer::EDITEDBY); $criteria->addSelectColumn(CcFilesPeer::MTIME); @@ -426,7 +426,7 @@ abstract class BaseCcFilesPeer { $criteria->addSelectColumn($alias . '.FTYPE'); $criteria->addSelectColumn($alias . '.DIRECTORY'); $criteria->addSelectColumn($alias . '.FILEPATH'); - $criteria->addSelectColumn($alias . '.STATE'); + $criteria->addSelectColumn($alias . '.IMPORT_STATUS'); $criteria->addSelectColumn($alias . '.CURRENTLYACCESSING'); $criteria->addSelectColumn($alias . '.EDITEDBY'); $criteria->addSelectColumn($alias . '.MTIME'); diff --git a/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php b/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php index 50a21a332..e93985922 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcFilesQuery.php @@ -12,7 +12,7 @@ * @method CcFilesQuery orderByDbFtype($order = Criteria::ASC) Order by the ftype column * @method CcFilesQuery orderByDbDirectory($order = Criteria::ASC) Order by the directory column * @method CcFilesQuery orderByDbFilepath($order = Criteria::ASC) Order by the filepath column - * @method CcFilesQuery orderByDbState($order = Criteria::ASC) Order by the state column + * @method CcFilesQuery orderByDbImportStatus($order = Criteria::ASC) Order by the import_status column * @method CcFilesQuery orderByDbCurrentlyaccessing($order = Criteria::ASC) Order by the currentlyaccessing column * @method CcFilesQuery orderByDbEditedby($order = Criteria::ASC) Order by the editedby column * @method CcFilesQuery orderByDbMtime($order = Criteria::ASC) Order by the mtime column @@ -83,7 +83,7 @@ * @method CcFilesQuery groupByDbFtype() Group by the ftype column * @method CcFilesQuery groupByDbDirectory() Group by the directory column * @method CcFilesQuery groupByDbFilepath() Group by the filepath column - * @method CcFilesQuery groupByDbState() Group by the state column + * @method CcFilesQuery groupByDbImportStatus() Group by the import_status column * @method CcFilesQuery groupByDbCurrentlyaccessing() Group by the currentlyaccessing column * @method CcFilesQuery groupByDbEditedby() Group by the editedby column * @method CcFilesQuery groupByDbMtime() Group by the mtime column @@ -193,7 +193,7 @@ * @method CcFiles findOneByDbFtype(string $ftype) Return the first CcFiles filtered by the ftype column * @method CcFiles findOneByDbDirectory(int $directory) Return the first CcFiles filtered by the directory column * @method CcFiles findOneByDbFilepath(string $filepath) Return the first CcFiles filtered by the filepath column - * @method CcFiles findOneByDbState(string $state) Return the first CcFiles filtered by the state column + * @method CcFiles findOneByDbImportStatus(int $import_status) Return the first CcFiles filtered by the import_status column * @method CcFiles findOneByDbCurrentlyaccessing(int $currentlyaccessing) Return the first CcFiles filtered by the currentlyaccessing column * @method CcFiles findOneByDbEditedby(int $editedby) Return the first CcFiles filtered by the editedby column * @method CcFiles findOneByDbMtime(string $mtime) Return the first CcFiles filtered by the mtime column @@ -264,7 +264,7 @@ * @method array findByDbFtype(string $ftype) Return CcFiles objects filtered by the ftype column * @method array findByDbDirectory(int $directory) Return CcFiles objects filtered by the directory column * @method array findByDbFilepath(string $filepath) Return CcFiles objects filtered by the filepath column - * @method array findByDbState(string $state) Return CcFiles objects filtered by the state column + * @method array findByDbImportStatus(int $import_status) Return CcFiles objects filtered by the import_status column * @method array findByDbCurrentlyaccessing(int $currentlyaccessing) Return CcFiles objects filtered by the currentlyaccessing column * @method array findByDbEditedby(int $editedby) Return CcFiles objects filtered by the editedby column * @method array findByDbMtime(string $mtime) Return CcFiles objects filtered by the mtime column @@ -574,25 +574,34 @@ abstract class BaseCcFilesQuery extends ModelCriteria } /** - * Filter the query on the state column + * Filter the query on the import_status column * - * @param string $dbState The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) + * @param int|array $dbImportStatus The value to use as filter. + * Accepts an associative array('min' => $minValue, 'max' => $maxValue) * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * * @return CcFilesQuery The current query, for fluid interface */ - public function filterByDbState($dbState = null, $comparison = null) + public function filterByDbImportStatus($dbImportStatus = null, $comparison = null) { - if (null === $comparison) { - if (is_array($dbState)) { + if (is_array($dbImportStatus)) { + $useMinMax = false; + if (isset($dbImportStatus['min'])) { + $this->addUsingAlias(CcFilesPeer::IMPORT_STATUS, $dbImportStatus['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($dbImportStatus['max'])) { + $this->addUsingAlias(CcFilesPeer::IMPORT_STATUS, $dbImportStatus['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $dbState)) { - $dbState = str_replace('*', '%', $dbState); - $comparison = Criteria::LIKE; } } - return $this->addUsingAlias(CcFilesPeer::STATE, $dbState, $comparison); + return $this->addUsingAlias(CcFilesPeer::IMPORT_STATUS, $dbImportStatus, $comparison); } /** diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index d96be3260..7d17b63a0 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -198,7 +198,8 @@ class Rest_MediaController extends Zend_Rest_Controller } $file = CcFilesQuery::create()->findPk($id); if ($file) { - $storedFile = Application_Model_StoredFile($file); + $con = Propel::getConnection(); + $storedFile = new Application_Model_StoredFile($file, $con); Application_Model_Preference::updateDiskUsage(-1 * abs(filesize($storedFile->getFilePath()))); $storedFile->delete(); //TODO: This checks your session permissions... Make it work without a session? $file->delete(); diff --git a/airtime_mvc/build/build.properties b/airtime_mvc/build/build.properties index de8c64cb5..da4a76877 100644 --- a/airtime_mvc/build/build.properties +++ b/airtime_mvc/build/build.properties @@ -1,6 +1,6 @@ #Note: project.home is automatically generated by the propel-install script. #Any manual changes to this value will be overwritten. -project.home = /home/asantoni/airtime/airtime_mvc +project.home = /home/ubuntu/airtime/airtime_mvc project.build = ${project.home}/build #Database driver diff --git a/airtime_mvc/build/sql/schema.sql b/airtime_mvc/build/sql/schema.sql index 13d1654a5..8eb638878 100644 --- a/airtime_mvc/build/sql/schema.sql +++ b/airtime_mvc/build/sql/schema.sql @@ -36,7 +36,7 @@ CREATE TABLE "cc_files" "ftype" VARCHAR(128) default '' NOT NULL, "directory" INTEGER, "filepath" TEXT default '', - "state" VARCHAR(128) default 'empty' NOT NULL, + "import_status" INTEGER default 0 NOT NULL, "currentlyaccessing" INTEGER default 0 NOT NULL, "editedby" INTEGER, "mtime" TIMESTAMP(6), diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index d1ac34ff7..e98e7f165 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -2,11 +2,11 @@ $(document).ready(function() { var uploader; var self = this; + self.uploadFilter = "all"; $("#plupload_files").pluploadQueue({ // General settings runtimes : 'gears, html5, html4', - //url : baseUrl+'Plupload/upload/format/json', url : baseUrl+'rest/media', //chunk_size : '5mb', //Disabling chunking since we're using the File Upload REST API now unique_names : 'true', @@ -18,43 +18,11 @@ $(document).ready(function() { uploader = $("#plupload_files").pluploadQueue(); - uploader.bind('FileUploaded', function(up, file, json) { - - var j = jQuery.parseJSON(json.response); - console.log(j); - console.log(file.name); - + uploader.bind('FileUploaded', function(up, file, json) + { + //Refresh the upload table: self.recentUploadsTable.fnDraw(); //Only works because we're using bServerSide //In DataTables 1.10 and greater, we can use .fnAjaxReload() - - /* - var j = jQuery.parseJSON(json.response); - - console.log(json.response); - if (j.error !== undefined) { - var row = $("") - .append('' + file.name +'') - .append('' + j.error.message + ''); - - $("#plupload_error").find("table").append(row); - $("#plupload_error table").css("display", "inline-table"); - } else { - //FIXME: This should just update something in the GUI, not communicate with the backend -- Albert - /* - var tempFileName = j.tempfilepath; - $.get(baseUrl+'Plupload/copyfile/format/json/name/'+ - encodeURIComponent(file.name)+'/tempname/' + - encodeURIComponent(tempFileName), function(jr){ - if(jr.error !== undefined) { - var row = $("") - .append('' + file.name +'') - .append('' + jr.error.message + ''); - - $("#plupload_error").find("table").append(row); - $("#plupload_error table").css("display", "inline-table"); - } - }); - }*/ }); var uploadProgress = false; @@ -74,8 +42,49 @@ $(document).ready(function() { } }); + self.renderImportStatus = function ( data, type, full ) { + if (typeof data !== "number") { + console.log("Invalid data type for the import_status."); + return; + } + var statusStr = $.i18n._("Unknown"); + if (data == 0) + { + statusStr = $.i18n._("Successfully imported"); + } + else if (data == 1) + { + statusStr = $.i18n._("Pending import"); + } + + return statusStr; + }; + + self.renderFileActions = function ( data, type, full ) { + return '
Delete'; + }; + + $("#recent_uploads_table").on("click", "a.deleteFileAction", function () { + //Grab the file object for the row that was clicked. + // Some tips from the DataTables forums: + // fnGetData is used to get the object behind the row - you can also use + // fnGetPosition if you need to get the index instead + file = $("#recent_uploads_table").dataTable().fnGetData($(this).closest("tr")[0]); + + $.ajax({ + type: 'DELETE', + url: '/rest/media/' + file.id, + success: function(resp) { + self.recentUploadsTable.fnDraw(); + }, + error: function() { + alert($.i18n._("Error: The file could not be deleted. Please try again later.")); + } + }); + }); + self.setupRecentUploadsTable = function() { - return recentUploadsTable = $("#recent_uploads_table").dataTable({ + recentUploadsTable = $("#recent_uploads_table").dataTable({ "bJQueryUI": true, "bProcessing": false, "bServerSide": true, @@ -83,7 +92,7 @@ $(document).ready(function() { "sAjaxDataProp": 'files', "bSearchable": false, "bInfo": true, - "sScrollY": "200px", + //"sScrollY": "200px", "bFilter": false, "bSort": false, "sDom": '<"H"l>frtip', @@ -92,13 +101,41 @@ $(document).ready(function() { "aoColumns": [ { "mData" : "artist_name", "sTitle" : $.i18n._("Creator") }, { "mData" : "track_title", "sTitle" : $.i18n._("Title") }, - { "mData" : "state", "sTitle" : $.i18n._("Import Status")}, - { "mData" : "utime", "sTitle" : $.i18n._("Uploaded") } - ] + { "mData" : "import_status", "sTitle" : $.i18n._("Import Status"), + "mRender": self.renderImportStatus + }, + { "mData" : "utime", "sTitle" : $.i18n._("Uploaded") }, + { "mData" : "id", "sTitle" : $.i18n._("Actions"), + "mRender": self.renderFileActions + } + ], + "fnServerData": function ( sSource, aoData, fnCallback ) { + /* Add some extra data to the sender */ + aoData.push( { "name": "uploadFilter", "value": self.uploadFilter } ); + $.getJSON( sSource, aoData, function (json) { + fnCallback(json); + } ); + } }); + + return recentUploadsTable; }; + + $("#upload_status_all").click(function() { + self.uploadFilter = "all"; + self.recentUploadsTable.fnDraw(); + }); + $("#upload_status_pending").click(function() { + self.uploadFilter = "pending"; + self.recentUploadsTable.fnDraw(); + }); + $("#upload_status_failed").click(function() { + self.uploadFilter = "failed"; + self.recentUploadsTable.fnDraw(); + }); + + //Create the recent uploads table. self.recentUploadsTable = self.setupRecentUploadsTable(); - $("#recent_uploads_table.div.fg-toolbar").prepend('Custom tool bar! Text/images etc.'); - + //$("#recent_uploads_table.div.fg-toolbar").prepend('Custom tool bar! Text/images etc.'); }); diff --git a/install_minimal/upgrades/airtime-2.5.3/DbUpgrade.php b/install_minimal/upgrades/airtime-2.5.3/DbUpgrade.php new file mode 100644 index 000000000..dbfef98c5 --- /dev/null +++ b/install_minimal/upgrades/airtime-2.5.3/DbUpgrade.php @@ -0,0 +1,24 @@ +&1 | grep -v \"will create implicit index\""); + } +} diff --git a/install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php b/install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php new file mode 100644 index 000000000..042b92d05 --- /dev/null +++ b/install_minimal/upgrades/airtime-2.5.3/airtime-upgrade.php @@ -0,0 +1,8 @@ + Date: Sat, 22 Mar 2014 02:12:03 -0400 Subject: [PATCH 28/36] CC-5709: Airtime Analyzer * Remove the "hidden" field from the REST blacklist, the analyzer needs to set it. * Added import_status column messages in the recent uploads table * Auto-refresh the recent uploads table while imports are pending * Moved the file moving stuff to its own analyzer in airtime_analyzer * Basic error reporting to the REST API in airtime_analyzer, needs hardeneing though * Fixed a bug with the number of recent uploads * Prevent airtime_analyzer from running if media_monitor is running --- .../controllers/PluploadController.php | 12 ++-- .../rest/controllers/MediaController.php | 2 - .../public/js/airtime/library/plupload.js | 62 ++++++++++++++++--- .../airtime_analyzer/analyzer.py | 2 +- .../airtime_analyzer/analyzer_pipeline.py | 62 +++---------------- .../airtime_analyzer/message_listener.py | 4 +- .../airtime_analyzer/metadata_analyzer.py | 7 ++- .../airtime_analyzer/status_reporter.py | 35 +++++++---- .../airtime_analyzer/bin/airtime_analyzer | 20 ++++++ 9 files changed, 118 insertions(+), 88 deletions(-) diff --git a/airtime_mvc/application/controllers/PluploadController.php b/airtime_mvc/application/controllers/PluploadController.php index 37f856b8a..c919207b4 100644 --- a/airtime_mvc/application/controllers/PluploadController.php +++ b/airtime_mvc/application/controllers/PluploadController.php @@ -48,20 +48,20 @@ class PluploadController extends Zend_Controller_Action $rowStart = isset($_GET['iDisplayStart']) ? $_GET['iDisplayStart'] : 0; $recentUploadsQuery = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) - ->orderByDbUtime(Criteria::DESC) - ->offset($rowStart) - ->limit($limit); + ->orderByDbUtime(Criteria::DESC); + + $numTotalRecentUploads = $recentUploadsQuery->find()->count(); if ($filter == "pending") { $recentUploadsQuery->filterByDbImportStatus("1"); } else if ($filter == "failed") { $recentUploadsQuery->filterByDbImportStatus(array('min' => 100)); } - $recentUploads = $recentUploadsQuery->find(); + + $recentUploads = $recentUploadsQuery->offset($rowStart)->limit($limit)->find(); $numRecentUploads = $limit; - $numTotalRecentUploads = CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) - ->count(); + //CcFilesQuery::create()->filterByDbUtime(array('min' => time() - 30 * 24 * 60 * 60)) //$this->_helper->json->sendJson(array("jsonrpc" => "2.0", "tempfilepath" => $tempFileName)); diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 7d17b63a0..245da3b0b 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -7,7 +7,6 @@ class Rest_MediaController extends Zend_Rest_Controller private $blackList = array( 'id', 'file_exists', - 'hidden', 'silan_check', 'soundcloud_id', 'is_scheduled', @@ -17,7 +16,6 @@ class Rest_MediaController extends Zend_Rest_Controller //fields we should never expose through our RESTful API private $privateFields = array( 'file_exists', - 'hidden', 'silan_check', 'is_scheduled', 'is_playlist' diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index e98e7f165..6d50a2598 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -3,6 +3,16 @@ $(document).ready(function() { var uploader; var self = this; self.uploadFilter = "all"; + + self.IMPORT_STATUS_CODES = { + 0 : { message: $.i18n._("Successfully imported")}, + 1 : { message: $.i18n._("Pending import")}, + 2 : { message: $.i18n._("Import failed.")}, + UNKNOWN : { message: $.i18n._("Unknown")} + }; + if (Object.freeze) { + Object.freeze(self.IMPORT_STATUS_CODES); + } $("#plupload_files").pluploadQueue({ // General settings @@ -47,17 +57,13 @@ $(document).ready(function() { console.log("Invalid data type for the import_status."); return; } - var statusStr = $.i18n._("Unknown"); - if (data == 0) - { - statusStr = $.i18n._("Successfully imported"); - } - else if (data == 1) - { - statusStr = $.i18n._("Pending import"); - } + var statusStr = self.IMPORT_STATUS_CODES.UNKNOWN.message; + var importStatusCode = data; + if (self.IMPORT_STATUS_CODES[importStatusCode]) { + statusStr = self.IMPORT_STATUS_CODES[importStatusCode].message; + }; - return statusStr; + return statusStr; }; self.renderFileActions = function ( data, type, full ) { @@ -114,6 +120,23 @@ $(document).ready(function() { aoData.push( { "name": "uploadFilter", "value": self.uploadFilter } ); $.getJSON( sSource, aoData, function (json) { fnCallback(json); + if (json.files) { + var areAnyFileImportsPending = false; + for (var i = 0; i < json.files.length; i++) { + //console.log(file); + var file = json.files[i]; + if (file.import_status == 1) + { + areAnyFileImportsPending = true; + } + } + if (areAnyFileImportsPending) { + //alert("pending uploads, starting refresh on timer"); + self.startRefreshingRecentUploads(); + } else { + self.stopRefreshingRecentUploads(); + } + } } ); } }); @@ -121,6 +144,25 @@ $(document).ready(function() { return recentUploadsTable; }; + self.startRefreshingRecentUploads = function() + { + if (self.isRecentUploadsRefreshTimerActive()) { //Prevent multiple timers from running + return; + } + self.recentUploadsRefreshTimer = setTimeout("self.recentUploadsTable.fnDraw()", 3000); + }; + + self.isRecentUploadsRefreshTimerActive = function() + { + return (self.recentUploadsRefreshTimer != null); + }; + + self.stopRefreshingRecentUploads = function() + { + clearTimeout(self.recentUploadsRefreshTimer); + self.recentUploadsRefreshTimer = null; + }; + $("#upload_status_all").click(function() { self.uploadFilter = "all"; self.recentUploadsTable.fnDraw(); diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py index de23a8e68..d897b479b 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py @@ -2,7 +2,7 @@ class Analyzer: @staticmethod - def analyze(filename): + def analyze(filename, results): raise NotImplementedError class AnalyzerError(Exception): diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py index cdda6bd65..3a267280f 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -1,10 +1,7 @@ import logging import multiprocessing -import shutil -import os, errno -import time -import uuid from metadata_analyzer import MetadataAnalyzer +from filemover_analyzer import FileMoverAnalyzer class AnalyzerPipeline: @@ -29,59 +26,16 @@ class AnalyzerPipeline: # Analyze the audio file we were told to analyze: # First, we extract the ID3 tags and other metadata: - results = MetadataAnalyzer.analyze(audio_file_path) + metadata = dict() + metadata = MetadataAnalyzer.analyze(audio_file_path, metadata) + metadata = FileMoverAnalyzer.move(audio_file_path, import_directory, original_filename, metadata) + metadata["import_status"] = 0 # imported # Note that the queue we're putting the results into is our interprocess communication # back to the main process. - #Import the file over to it's final location. - #TODO: Move all this file moving stuff to its own Analyzer class. - # Also, handle the case where the move fails and write some code - # to possibly move the file to problem_files. - - final_file_path = import_directory - if results.has_key("artist_name"): - final_file_path += "/" + results["artist_name"] - if results.has_key("album"): - final_file_path += "/" + results["album"] - final_file_path += "/" + original_filename - - #Ensure any redundant slashes are stripped - final_file_path = os.path.normpath(final_file_path) - - #If a file with the same name already exists in the "import" directory, then - #we add a unique string to the end of this one. We never overwrite a file on import - #because if we did that, it would mean Airtime's database would have - #the wrong information for the file we just overwrote (eg. the song length would be wrong!) - if os.path.exists(final_file_path) and not os.path.samefile(audio_file_path, final_file_path): - #If the final file path is the same as the file we've been told to import (which - #you often do when you're debugging), then don't move the file at all. - - base_file_path, file_extension = os.path.splitext(final_file_path) - final_file_path = "%s_%s%s" % (base_file_path, time.strftime("%m-%d-%Y-%H-%M-%S", time.localtime()), file_extension) - - #If THAT path exists, append a UUID instead: - while os.path.exists(final_file_path): - base_file_path, file_extension = os.path.splitext(final_file_path) - final_file_path = "%s_%s%s" % (base_file_path, str(uuid.uuid4()), file_extension) - - #Ensure the full path to the file exists - mkdir_p(os.path.dirname(final_file_path)) - - #Move the file into its final destination directory - shutil.move(audio_file_path, final_file_path) + #Pass all the file metadata back to the main analyzer process, which then passes + #it back to the Airtime web application. + queue.put(metadata) - #Pass the full path back to Airtime - results["full_path"] = final_file_path - queue.put(results) - - -def mkdir_p(path): - try: - os.makedirs(path) - except OSError as exc: # Python >2.5 - if exc.errno == errno.EEXIST and os.path.isdir(path): - pass - else: raise - diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index edde9c083..5fc04058e 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -114,8 +114,8 @@ class MessageListener: # # TODO: If the JSON was invalid or the web server is down, # then don't report that failure to the REST API - - StatusReporter.report_failure_to_callback_url(callback_url, api_key, error_status=1, + #TODO: Catch exceptions from this HTTP request too: + StatusReporter.report_failure_to_callback_url(callback_url, api_key, import_status=2, reason=u'An error occurred while importing this file') logging.exception(e) diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index b2876119d..a75c4815d 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -10,9 +10,12 @@ class MetadataAnalyzer(Analyzer): pass @staticmethod - def analyze(filename): + def analyze(filename, metadata): + if not isinstance(filename, unicode): + raise TypeError("filename must be unicode. Was of type " + type(filename).__name__) + if not isinstance(metadata, dict): + raise TypeError("metadata must be a dict. Was of type " + type(metadata).__name__) - metadata = dict() #Extract metadata from an audio file using mutagen audio_file = mutagen.File(filename, easy=True) diff --git a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py index e91b246a8..75769a692 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py @@ -11,20 +11,33 @@ class StatusReporter(): @classmethod def report_success_to_callback_url(self, callback_url, api_key, audio_metadata): - # Encode the audio metadata as JSON and post it back to the callback_url + # encode the audio metadata as json and post it back to the callback_url put_payload = json.dumps(audio_metadata) - logging.debug("Sending HTTP PUT with payload: " + put_payload) + logging.debug("sending http put with payload: " + put_payload) r = requests.put(callback_url, data=put_payload, - auth=requests.auth.HTTPBasicAuth(api_key, ''), - timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) - logging.debug("HTTP request returned status: " + str(r.status_code)) - logging.debug(r.text) # Log the response body + auth=requests.auth.httpbasicauth(api_key, ''), + timeout=statusreporter._http_request_timeout) + logging.debug("http request returned status: " + str(r.status_code)) + logging.debug(r.text) # log the response body - #TODO: Queue up failed requests and try them again later. - r.raise_for_status() # Raise an exception if there was an HTTP error code returned + #todo: queue up failed requests and try them again later. + r.raise_for_status() # raise an exception if there was an http error code returned @classmethod - def report_failure_to_callback_url(self, callback_url, api_key, error_status, reason): - # TODO: Make error_status is an int? - pass + def report_failure_to_callback_url(self, callback_url, api_key, import_status, reason): + # TODO: Make import_status is an int? + + logging.debug("Reporting import failure to Airtime REST API...") + audio_metadata["import_status"] = import_status + audio_metadata["comment"] = reason # hack attack + put_payload = json.dumps(audio_metadata) + logging.debug("sending http put with payload: " + put_payload) + r = requests.put(callback_url, data=put_payload, + auth=requests.auth.httpbasicauth(api_key, ''), + timeout=statusreporter._http_request_timeout) + logging.debug("http request returned status: " + str(r.status_code)) + logging.debug(r.text) # log the response body + + #todo: queue up failed requests and try them again later. + r.raise_for_status() # raise an exception if there was an http error code returned diff --git a/python_apps/airtime_analyzer/bin/airtime_analyzer b/python_apps/airtime_analyzer/bin/airtime_analyzer index b90f4c7d9..23865fdc6 100755 --- a/python_apps/airtime_analyzer/bin/airtime_analyzer +++ b/python_apps/airtime_analyzer/bin/airtime_analyzer @@ -2,6 +2,7 @@ import daemon import argparse +import os import airtime_analyzer.airtime_analyzer as aa VERSION = "1.0" @@ -13,6 +14,25 @@ parser.add_argument("-d", "--daemon", help="run as a daemon", action="store_true parser.add_argument("--debug", help="log full debugging output", action="store_true") args = parser.parse_args() +'''Ensure media_monitor isn't running before we start, because it'll move newly uploaded + files into the library on us and screw up the operation of airtime_analyzer. + media_monitor is deprecated. +''' +def check_if_media_monitor_is_running(): + pids = [pid for pid in os.listdir('/proc') if pid.isdigit()] + + for pid in pids: + try: + process_name = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read() + if 'media_monitor.py' in process_name: + print "Error: This process conflicts with media_monitor, and media_monitor is running." + print " Please terminate the running media_monitor.py process and try again." + exit(1) + except IOError: # proc has already terminated + continue + +check_if_media_monitor_is_running() + if args.daemon: with daemon.DaemonContext(): analyzer = aa.AirtimeAnalyzerServer(debug=args.debug) From eb37b39406a0bf206f2b4c8dea0e30ec00093bc2 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 24 Mar 2014 13:03:20 -0400 Subject: [PATCH 29/36] CC-5709: Airtime Analyzer * Added missing FileMoverAnalyzer file that I forgot to commit --- .../airtime_analyzer/filemover_analyzer.py | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py diff --git a/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py new file mode 100644 index 000000000..0920bb8ec --- /dev/null +++ b/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py @@ -0,0 +1,80 @@ +import logging +import os +import time +import shutil +import os, errno +import time +import uuid + +from analyzer import Analyzer + +class FileMoverAnalyzer(Analyzer): + + def __init__(self): + pass + + @staticmethod + def analyze(audio_file_path, metadata): + raise Exception("Use FileMoverAnalyzer.move() instead.") + + @staticmethod + def move(audio_file_path, import_directory, original_filename, metadata): + if not isinstance(audio_file_path, unicode): + raise TypeError("audio_file_path must be unicode. Was of type " + type(audio_file_path).__name__) + if not isinstance(import_directory, unicode): + raise TypeError("import_directory must be unicode. Was of type " + type(import_directory).__name__) + if not isinstance(original_filename, unicode): + raise TypeError("original_filename must be unicode. Was of type " + type(original_filename).__name__) + if not isinstance(metadata, dict): + raise TypeError("metadata must be a dict. Was of type " + type(metadata).__name__) + + #Import the file over to it's final location. + # TODO: Also, handle the case where the move fails and write some code + # to possibly move the file to problem_files. + + final_file_path = import_directory + if metadata.has_key("artist_name"): + final_file_path += "/" + metadata["artist_name"] + if metadata.has_key("album"): + final_file_path += "/" + metadata["album"] + final_file_path += "/" + original_filename + + #Ensure any redundant slashes are stripped + final_file_path = os.path.normpath(final_file_path) + + #If a file with the same name already exists in the "import" directory, then + #we add a unique string to the end of this one. We never overwrite a file on import + #because if we did that, it would mean Airtime's database would have + #the wrong information for the file we just overwrote (eg. the song length would be wrong!) + #If the final file path is the same as the file we've been told to import (which + #you often do when you're debugging), then don't move the file at all. + if os.path.exists(final_file_path): + if os.path.samefile(audio_file_path, final_file_path): + metadata["full_path"] = final_file_path + return metadata + base_file_path, file_extension = os.path.splitext(final_file_path) + final_file_path = "%s_%s%s" % (base_file_path, time.strftime("%m-%d-%Y-%H-%M-%S", time.localtime()), file_extension) + + #If THAT path exists, append a UUID instead: + while os.path.exists(final_file_path): + base_file_path, file_extension = os.path.splitext(final_file_path) + final_file_path = "%s_%s%s" % (base_file_path, str(uuid.uuid4()), file_extension) + + #Ensure the full path to the file exists + mkdir_p(os.path.dirname(final_file_path)) + + #Move the file into its final destination directory + logging.debug("Moving %s to %s" % (audio_file_path, final_file_path)) + shutil.move(audio_file_path, final_file_path) + + metadata["full_path"] = final_file_path + return metadata + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + From 6952902b22404a23182459fc17c7998d7ca61db0 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 24 Mar 2014 16:05:53 -0400 Subject: [PATCH 30/36] CC-5709: Airtime Analyzer * Unbreak stuff --- .../modules/rest/controllers/MediaController.php | 2 +- .../airtime_analyzer/message_listener.py | 2 +- .../airtime_analyzer/status_reporter.py | 15 ++++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 245da3b0b..63d60d4b1 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -155,7 +155,7 @@ class Rest_MediaController extends Zend_Rest_Controller //Our RESTful API takes "full_path" as a field, which we then split and translate to match //our internal schema. Internally, file path is stored relative to a directory, with the directory //as a foreign key to cc_music_dirs. - if ($requestData["full_path"]) { + if (isset($requestData["full_path"])) { Application_Model_Preference::updateDiskUsage(filesize($requestData["full_path"])); $fullPath = $requestData["full_path"]; diff --git a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py index 5fc04058e..c5e4da373 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/message_listener.py @@ -100,6 +100,7 @@ class MessageListener: requeue=False) #Important that it doesn't requeue the message except Exception as e: + logging.exception(e) #If ANY exception happens while processing a file, we're going to NACK to the #messaging server and tell it to remove the message from the queue. #(NACK is a negative acknowledgement. We could use ACK instead, but this might come @@ -118,7 +119,6 @@ class MessageListener: StatusReporter.report_failure_to_callback_url(callback_url, api_key, import_status=2, reason=u'An error occurred while importing this file') - logging.exception(e) else: # ACK at the very end, after the message has been successfully processed. diff --git a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py index 75769a692..2a0963dd9 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/status_reporter.py @@ -15,9 +15,9 @@ class StatusReporter(): put_payload = json.dumps(audio_metadata) logging.debug("sending http put with payload: " + put_payload) r = requests.put(callback_url, data=put_payload, - auth=requests.auth.httpbasicauth(api_key, ''), - timeout=statusreporter._http_request_timeout) - logging.debug("http request returned status: " + str(r.status_code)) + auth=requests.auth.HTTPBasicAuth(api_key, ''), + timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) + logging.debug("HTTP request returned status: " + str(r.status_code)) logging.debug(r.text) # log the response body #todo: queue up failed requests and try them again later. @@ -28,16 +28,17 @@ class StatusReporter(): # TODO: Make import_status is an int? logging.debug("Reporting import failure to Airtime REST API...") + audio_metadata = dict() audio_metadata["import_status"] = import_status audio_metadata["comment"] = reason # hack attack put_payload = json.dumps(audio_metadata) logging.debug("sending http put with payload: " + put_payload) r = requests.put(callback_url, data=put_payload, - auth=requests.auth.httpbasicauth(api_key, ''), - timeout=statusreporter._http_request_timeout) - logging.debug("http request returned status: " + str(r.status_code)) + auth=requests.auth.HTTPBasicAuth(api_key, ''), + timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) + logging.debug("HTTP request returned status: " + str(r.status_code)) logging.debug(r.text) # log the response body - #todo: queue up failed requests and try them again later. + #TODO: queue up failed requests and try them again later. r.raise_for_status() # raise an exception if there was an http error code returned From db2b52a1bfc4b1cf52df3d1ffd0c5939d5d37b8e Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Mon, 24 Mar 2014 17:14:04 -0400 Subject: [PATCH 31/36] CC-5709: Airtime Analyzer * Some cleanup and refactoring for file deletion in the Media REST API * Fix the refresh timer on the Add Media page when there's pending imports. --- .../controllers/LibraryController.php | 1 - airtime_mvc/application/models/MusicDir.php | 4 ++- airtime_mvc/application/models/StoredFile.php | 29 +++++++++++++++++-- .../rest/controllers/MediaController.php | 5 ++-- .../public/js/airtime/library/plupload.js | 4 +-- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index c241599d7..2102a662e 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -356,7 +356,6 @@ class LibraryController extends Zend_Controller_Action if (isset($file)) { try { - Application_Model_Preference::updateDiskUsage(-1 * abs(filesize($file->getFilePath()))); $res = $file->delete(); } catch (FileNoPermissionException $e) { $message = $noPermissionMsg; diff --git a/airtime_mvc/application/models/MusicDir.php b/airtime_mvc/application/models/MusicDir.php index 08b2b2649..80f6cbe25 100644 --- a/airtime_mvc/application/models/MusicDir.php +++ b/airtime_mvc/application/models/MusicDir.php @@ -301,7 +301,9 @@ SQL; public static function getDirByPK($pk) { $dir = CcMusicDirsQuery::create()->findPK($pk); - + if (!$dir) { + return null; + } $mus_dir = new Application_Model_MusicDir($dir); return $mus_dir; diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 7f1aa7d69..23247522c 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -346,6 +346,21 @@ SQL; return array(); } } + + /** + * Check if the file (on disk) corresponding to this class exists or not. + * @return boolean true if the file exists, false otherwise. + */ + public function existsOnDisk() + { + $exists = false; + try { + $exists = file_exists($this->getFilePath()); + } catch (Exception $e) { + return false; + } + return $exists; + } /** * Delete stored virtual file @@ -355,8 +370,11 @@ SQL; */ public function delete() { - $filepath = $this->getFilePath(); + + //Update the user's disk usage + Application_Model_Preference::updateDiskUsage(-1 * abs(filesize($filepath))); + // Check if the file is scheduled to be played in the future if (Application_Model_Schedule::IsFileScheduledInTheFuture($this->getId())) { throw new DeleteScheduledFileException(); @@ -370,8 +388,10 @@ SQL; } $music_dir = Application_Model_MusicDir::getDirByPK($this->_file->getDbDirectory()); + assert($music_dir); $type = $music_dir->getType(); - + + if (file_exists($filepath) && $type == "stor") { $data = array("filepath" => $filepath, "delete" => 1); try { @@ -473,8 +493,13 @@ SQL; */ public function getFilePath() { + assert($this->_file); + $music_dir = Application_Model_MusicDir::getDirByPK($this-> _file->getDbDirectory()); + if (!$music_dir) { + throw new Exception("Invalid music_dir for file in database."); + } $directory = $music_dir->getDirectory(); $filepath = $this->_file->getDbFilepath(); diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index 63d60d4b1..f092574b3 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -198,8 +198,9 @@ class Rest_MediaController extends Zend_Rest_Controller if ($file) { $con = Propel::getConnection(); $storedFile = new Application_Model_StoredFile($file, $con); - Application_Model_Preference::updateDiskUsage(-1 * abs(filesize($storedFile->getFilePath()))); - $storedFile->delete(); //TODO: This checks your session permissions... Make it work without a session? + if ($storedFile->existsOnDisk()) { + $storedFile->delete(); //TODO: This checks your session permissions... Make it work without a session? + } $file->delete(); $this->getResponse() ->setHttpResponseCode(204); diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index 6d50a2598..9e67f7ad2 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -149,7 +149,7 @@ $(document).ready(function() { if (self.isRecentUploadsRefreshTimerActive()) { //Prevent multiple timers from running return; } - self.recentUploadsRefreshTimer = setTimeout("self.recentUploadsTable.fnDraw()", 3000); + self.recentUploadsRefreshTimer = setInterval("self.recentUploadsTable.fnDraw()", 3000); }; self.isRecentUploadsRefreshTimerActive = function() @@ -159,7 +159,7 @@ $(document).ready(function() { self.stopRefreshingRecentUploads = function() { - clearTimeout(self.recentUploadsRefreshTimer); + clearInterval(self.recentUploadsRefreshTimer); self.recentUploadsRefreshTimer = null; }; From 3bffb02bc058d0946185f1ae8eb469d7decb1995 Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 24 Mar 2014 18:22:34 -0400 Subject: [PATCH 32/36] CC-5708: proftpd hook for new File API --- python_apps/airtime_analyzer/tools/ftp-upload-hook.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 python_apps/airtime_analyzer/tools/ftp-upload-hook.sh diff --git a/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh b/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh new file mode 100755 index 000000000..b753b917d --- /dev/null +++ b/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +php /home/denise/airtime/python_apps/airtime_analyzer/tools/message_sender.php '{"tmp_file_path":"/home/denise/uploads/01 - Larger Than Life.ogg", "import_directory":"/srv/airtime/stor/imported/1","original_filename":"01 - Larger Than Life.ogg","callback_url": "http://localhost/rest/media/1", "api_key":"3TQY7JASUNVZ8IGOZQXJ"}' From f8c221a61037afbd36d0297a129a72b70c72b7a1 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 25 Mar 2014 14:34:50 -0400 Subject: [PATCH 33/36] CC-5709: Airtime Analyzer * Fixed and updated the unit tests --- .../airtime_analyzer/analyzer.py | 2 +- .../airtime_analyzer/metadata_analyzer.py | 1 + .../tests/analyzer_pipeline_tests.py | 18 +++++++--- .../tests/metadata_analyzer_tests.py | 36 ++++++++++--------- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py index d897b479b..7fb00d8db 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py @@ -2,7 +2,7 @@ class Analyzer: @staticmethod - def analyze(filename, results): + def analyze(filename, metadata): raise NotImplementedError class AnalyzerError(Exception): diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index a75c4815d..12a792a31 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -23,6 +23,7 @@ class MetadataAnalyzer(Analyzer): #in the file header. Mutagen breaks that out into a separate "info" object: info = audio_file.info metadata["sample_rate"] = info.sample_rate + metadata["length_seconds"] = info.length #Converting the length in seconds (float) to a formatted time string track_length = datetime.timedelta(seconds=info.length) metadata["length"] = str(track_length) #time.strftime("%H:%M:%S.%f", track_length) diff --git a/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py b/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py index 4ac1e49ea..cc5dc96b5 100644 --- a/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py +++ b/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py @@ -1,24 +1,34 @@ from nose.tools import * +import os +import shutil import multiprocessing +import datetime from airtime_analyzer.analyzer_pipeline import AnalyzerPipeline DEFAULT_AUDIO_FILE = u'tests/test_data/44100Hz-16bit-mono.mp3' +DEFAULT_IMPORT_DEST = u'Test Artist/44100Hz-16bit-mono.mp3' def setup(): pass def teardown(): - pass + #Move the file back + shutil.move(DEFAULT_IMPORT_DEST, DEFAULT_AUDIO_FILE) + assert os.path.exists(DEFAULT_AUDIO_FILE) def test_basic(): + filename = os.path.basename(DEFAULT_AUDIO_FILE) q = multiprocessing.Queue() - AnalyzerPipeline.run_analysis(q, DEFAULT_AUDIO_FILE, u'.') + #This actually imports the file into the "./Test Artist" directory. + AnalyzerPipeline.run_analysis(q, DEFAULT_AUDIO_FILE, u'.', filename) results = q.get() assert results['track_title'] == u'Test Title' assert results['artist_name'] == u'Test Artist' assert results['album_title'] == u'Test Album' assert results['year'] == u'1999' assert results['genre'] == u'Test Genre' - assert results['mime_type'] == 'audio/mpeg' # Not unicode because MIMEs aren't. - assert results['length_seconds'] == 3.90925 + assert results['mime'] == 'audio/mpeg' # Not unicode because MIMEs aren't. + assert results['length_seconds'] == 3.90925 + assert results["length"] == str(datetime.timedelta(seconds=results["length_seconds"])) + assert os.path.exists(DEFAULT_IMPORT_DEST) diff --git a/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py b/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py index 1107c078a..01a2c3d77 100644 --- a/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py +++ b/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import datetime from nose.tools import * from airtime_analyzer.metadata_analyzer import MetadataAnalyzer @@ -15,61 +16,62 @@ def check_default_metadata(metadata): assert metadata['year'] == u'1999' assert metadata['genre'] == u'Test Genre' assert metadata['track_number'] == u'1' + assert metadata["length"] == str(datetime.timedelta(seconds=metadata["length_seconds"])) def test_mp3_mono(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.mp3') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.mp3', dict()) check_default_metadata(metadata) assert metadata['channels'] == 1 assert metadata['bit_rate'] == 64000 assert metadata['length_seconds'] == 3.90925 - assert metadata['mime_type'] == 'audio/mpeg' # Not unicode because MIMEs aren't. + assert metadata['mime'] == 'audio/mpeg' # Not unicode because MIMEs aren't. assert metadata['track_total'] == u'10' # MP3s can have a track_total #Mutagen doesn't extract comments from mp3s it seems def test_mp3_jointstereo(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-jointstereo.mp3') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-jointstereo.mp3', dict()) check_default_metadata(metadata) assert metadata['channels'] == 2 assert metadata['bit_rate'] == 128000 assert metadata['length_seconds'] == 3.90075 - assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['mime'] == 'audio/mpeg' assert metadata['track_total'] == u'10' # MP3s can have a track_total def test_mp3_simplestereo(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-simplestereo.mp3') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-simplestereo.mp3', dict()) check_default_metadata(metadata) assert metadata['channels'] == 2 assert metadata['bit_rate'] == 128000 assert metadata['length_seconds'] == 3.90075 - assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['mime'] == 'audio/mpeg' assert metadata['track_total'] == u'10' # MP3s can have a track_total def test_mp3_dualmono(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-dualmono.mp3') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-dualmono.mp3', dict()) check_default_metadata(metadata) assert metadata['channels'] == 2 assert metadata['bit_rate'] == 128000 assert metadata['length_seconds'] == 3.90075 - assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['mime'] == 'audio/mpeg' assert metadata['track_total'] == u'10' # MP3s can have a track_total def test_ogg_mono(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.ogg') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-mono.ogg', dict()) check_default_metadata(metadata) assert metadata['channels'] == 1 assert metadata['bit_rate'] == 80000 assert metadata['length_seconds'] == 3.8394104308390022 - assert metadata['mime_type'] == 'application/ogg' + assert metadata['mime'] == 'application/ogg' assert metadata['comment'] == u'Test Comment' def test_ogg_stereo(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo.ogg') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo.ogg', dict()) check_default_metadata(metadata) assert metadata['channels'] == 2 assert metadata['bit_rate'] == 112000 assert metadata['length_seconds'] == 3.8394104308390022 - assert metadata['mime_type'] == 'application/ogg' + assert metadata['mime'] == 'application/ogg' assert metadata['comment'] == u'Test Comment' ''' faac and avconv can't seem to create a proper mono AAC file... ugh @@ -81,21 +83,21 @@ def test_aac_mono(): assert metadata['channels'] == 1 assert metadata['bit_rate'] == 80000 assert metadata['length_seconds'] == 3.8394104308390022 - assert metadata['mime_type'] == 'video/mp4' + assert metadata['mime'] == 'video/mp4' assert metadata['comment'] == u'Test Comment' ''' def test_aac_stereo(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo.m4a') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo.m4a', dict()) check_default_metadata(metadata) assert metadata['channels'] == 2 assert metadata['bit_rate'] == 102619 assert metadata['length_seconds'] == 3.8626303854875284 - assert metadata['mime_type'] == 'video/mp4' + assert metadata['mime'] == 'video/mp4' assert metadata['comment'] == u'Test Comment' def test_mp3_utf8(): - metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo-utf8.mp3') + metadata = MetadataAnalyzer.analyze(u'tests/test_data/44100Hz-16bit-stereo-utf8.mp3', dict()) # Using a bunch of different UTF-8 codepages here. Test data is from: # http://winrus.com/utf8-jap.htm assert metadata['track_title'] == u'アイウエオカキクケコサシスセソタチツテ' @@ -107,6 +109,6 @@ def test_mp3_utf8(): assert metadata['channels'] == 2 assert metadata['bit_rate'] == 128000 assert metadata['length_seconds'] == 3.90075 - assert metadata['mime_type'] == 'audio/mpeg' + assert metadata['mime'] == 'audio/mpeg' assert metadata['track_total'] == u'10' # MP3s can have a track_total From 9e9e676b5432186b9b05031cccf00e924189243f Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 25 Mar 2014 15:35:50 -0400 Subject: [PATCH 34/36] CC-5709: Airtime Analyzer * Make the Recent Uplods file actions a bit clearer --- airtime_mvc/public/js/airtime/library/plupload.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index 9e67f7ad2..71aff7336 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -67,8 +67,15 @@ $(document).ready(function() { }; self.renderFileActions = function ( data, type, full ) { - return 'Delete'; - }; + if (full.import_status == 0) { + return '' + $.i18n._('Delete from Library') + ''; + } else if (full.import_status == 1) { + //No actions for pending files + return $.i18n._('N/A'); + } else { //Failed downloads + return '' + $.i18n._('Clear') + ''; + } + }; $("#recent_uploads_table").on("click", "a.deleteFileAction", function () { //Grab the file object for the row that was clicked. From 681fe4630b82eff8af3353ebac59ad7b66e83387 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 25 Mar 2014 18:09:47 -0400 Subject: [PATCH 35/36] CC-5708: proftpd hook for new File API url and API key are hard coded right now. Next task is to somehow decipher these with whatever ftp parameters we can pass in to the scipt. --- python_apps/airtime_analyzer/tools/ftp-upload-hook.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh b/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh index b753b917d..4d8dc789a 100755 --- a/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh +++ b/python_apps/airtime_analyzer/tools/ftp-upload-hook.sh @@ -1,3 +1,5 @@ #! /bin/bash -php /home/denise/airtime/python_apps/airtime_analyzer/tools/message_sender.php '{"tmp_file_path":"/home/denise/uploads/01 - Larger Than Life.ogg", "import_directory":"/srv/airtime/stor/imported/1","original_filename":"01 - Larger Than Life.ogg","callback_url": "http://localhost/rest/media/1", "api_key":"3TQY7JASUNVZ8IGOZQXJ"}' +path=$1 +filename="${path##*/}" +curl http://localhost/rest/media -u 3188BDIMPJROQP89Z0OX: -X POST -F "file=@$path" -F "name=$filename" From 58a38ffd3a52a972a744af67c097f55c92408dde Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Wed, 26 Mar 2014 15:06:48 -0400 Subject: [PATCH 36/36] CC-5709: Airtime Analyzer * Added unit test coverage report stuff * Added more unit tests * 98% test coverage :-) * Fixed a few bugs and removed some dead code --- python_apps/airtime_analyzer/README.rst | 2 ++ .../airtime_analyzer/analyzer.py | 2 ++ .../airtime_analyzer/analyzer_pipeline.py | 4 --- .../airtime_analyzer/filemover_analyzer.py | 9 +++-- .../airtime_analyzer/metadata_analyzer.py | 6 ++-- python_apps/airtime_analyzer/setup.py | 2 ++ .../tests/analyzer_pipeline_tests.py | 19 +++++++++- .../tests/metadata_analyzer_tests.py | 35 +++++++++++++++++++ 8 files changed, 66 insertions(+), 13 deletions(-) diff --git a/python_apps/airtime_analyzer/README.rst b/python_apps/airtime_analyzer/README.rst index 0f6a12205..e6a5a08b9 100644 --- a/python_apps/airtime_analyzer/README.rst +++ b/python_apps/airtime_analyzer/README.rst @@ -68,4 +68,6 @@ a test, run: $ nosetests -s +To run the unit tests and generate a code coverage report, run: + $ nosetests --with-coverage --cover-package=airtime_analyzer diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py index 7fb00d8db..b47ebe0ab 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer.py @@ -5,6 +5,8 @@ class Analyzer: def analyze(filename, metadata): raise NotImplementedError +''' class AnalyzerError(Exception): def __init__(self): super.__init__(self) +''' diff --git a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py index 3a267280f..2266fb9a2 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/analyzer_pipeline.py @@ -5,10 +5,6 @@ from filemover_analyzer import FileMoverAnalyzer class AnalyzerPipeline: - # Constructor - def __init__(self): - pass - # Take message dictionary and perform the necessary analysis. @staticmethod def run_analysis(queue, audio_file_path, import_directory, original_filename): diff --git a/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py index 0920bb8ec..ab12aad79 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/filemover_analyzer.py @@ -10,9 +10,6 @@ from analyzer import Analyzer class FileMoverAnalyzer(Analyzer): - def __init__(self): - pass - @staticmethod def analyze(audio_file_path, metadata): raise Exception("Use FileMoverAnalyzer.move() instead.") @@ -35,8 +32,8 @@ class FileMoverAnalyzer(Analyzer): final_file_path = import_directory if metadata.has_key("artist_name"): final_file_path += "/" + metadata["artist_name"] - if metadata.has_key("album"): - final_file_path += "/" + metadata["album"] + if metadata.has_key("album_title"): + final_file_path += "/" + metadata["album_title"] final_file_path += "/" + original_filename #Ensure any redundant slashes are stripped @@ -71,6 +68,8 @@ class FileMoverAnalyzer(Analyzer): return metadata def mkdir_p(path): + if path == "": + return try: os.makedirs(path) except OSError as exc: # Python >2.5 diff --git a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py index 12a792a31..fa0a88807 100644 --- a/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py +++ b/python_apps/airtime_analyzer/airtime_analyzer/metadata_analyzer.py @@ -6,9 +6,6 @@ from analyzer import Analyzer class MetadataAnalyzer(Analyzer): - def __init__(self): - pass - @staticmethod def analyze(filename, metadata): if not isinstance(filename, unicode): @@ -33,6 +30,9 @@ class MetadataAnalyzer(Analyzer): #Use the python-magic module to get the MIME type. mime_magic = magic.Magic(mime=True) metadata["mime"] = mime_magic.from_file(filename) + + if isinstance(info, mutagen.mp3.MPEGInfo): + print "mode is: " + str(info.mode) #Try to get the number of channels if mutagen can... try: diff --git a/python_apps/airtime_analyzer/setup.py b/python_apps/airtime_analyzer/setup.py index 259696b8e..5691676f3 100644 --- a/python_apps/airtime_analyzer/setup.py +++ b/python_apps/airtime_analyzer/setup.py @@ -14,6 +14,8 @@ setup(name='airtime_analyzer', 'python-magic', 'pika', 'nose', + 'coverage', + 'mock', 'python-daemon', 'requests', ], diff --git a/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py b/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py index cc5dc96b5..ba7b6f202 100644 --- a/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py +++ b/python_apps/airtime_analyzer/tests/analyzer_pipeline_tests.py @@ -2,11 +2,12 @@ from nose.tools import * import os import shutil import multiprocessing +import Queue import datetime from airtime_analyzer.analyzer_pipeline import AnalyzerPipeline DEFAULT_AUDIO_FILE = u'tests/test_data/44100Hz-16bit-mono.mp3' -DEFAULT_IMPORT_DEST = u'Test Artist/44100Hz-16bit-mono.mp3' +DEFAULT_IMPORT_DEST = u'Test Artist/Test Album/44100Hz-16bit-mono.mp3' def setup(): pass @@ -32,3 +33,19 @@ def test_basic(): assert results["length"] == str(datetime.timedelta(seconds=results["length_seconds"])) assert os.path.exists(DEFAULT_IMPORT_DEST) +@raises(TypeError) +def test_wrong_type_queue_param(): + AnalyzerPipeline.run_analysis(Queue.Queue(), u'', u'', u'') + +@raises(TypeError) +def test_wrong_type_string_param2(): + AnalyzerPipeline.run_analysis(multiprocessing.queues.Queue(), '', u'', u'') + +@raises(TypeError) +def test_wrong_type_string_param3(): + AnalyzerPipeline.run_analysis(multiprocessing.queues.Queue(), u'', '', u'') + +@raises(TypeError) +def test_wrong_type_string_param4(): + AnalyzerPipeline.run_analysis(multiprocessing.queues.Queue(), u'', u'', '') + diff --git a/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py b/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py index 01a2c3d77..8baad0c54 100644 --- a/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py +++ b/python_apps/airtime_analyzer/tests/metadata_analyzer_tests.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- import datetime +import mutagen +import mock from nose.tools import * from airtime_analyzer.metadata_analyzer import MetadataAnalyzer @@ -112,3 +114,36 @@ def test_mp3_utf8(): assert metadata['mime'] == 'audio/mpeg' assert metadata['track_total'] == u'10' # MP3s can have a track_total +# Make sure the parameter checking works +@raises(TypeError) +def test_move_wrong_string_param1(): + not_unicode = 'asdfasdf' + MetadataAnalyzer.analyze(not_unicode, dict()) + +@raises(TypeError) +def test_move_wrong_metadata_dict(): + not_a_dict = list() + MetadataAnalyzer.analyze(u'asdfasdf', not_a_dict) + +# Test an mp3 file where the number of channels is invalid or missing: +def test_mp3_bad_channels(): + filename = u'tests/test_data/44100Hz-16bit-mono.mp3' + ''' + It'd be a pain in the ass to construct a real MP3 with an invalid number + of channels by hand because that value is stored in every MP3 frame in the file + ''' + print "testing bad channels..." + audio_file = mutagen.File(filename, easy=True) + audio_file.info.mode = 1777 + with mock.patch('airtime_analyzer.metadata_analyzer.mutagen') as mock_mutagen: + mock_mutagen.File.return_value = audio_file + #mock_mutagen.side_effect = lambda *args, **kw: audio_file #File(*args, **kw) + + metadata = MetadataAnalyzer.analyze(filename, dict()) + check_default_metadata(metadata) + assert metadata['channels'] == 1 + assert metadata['bit_rate'] == 64000 + assert metadata['length_seconds'] == 3.90925 + assert metadata['mime'] == 'audio/mpeg' # Not unicode because MIMEs aren't. + assert metadata['track_total'] == u'10' # MP3s can have a track_total + #Mutagen doesn't extract comments from mp3s it seems