From 878dd11ccc44f36496be936e215b1498b4518d9f Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Fri, 21 Mar 2014 13:22:00 -0400 Subject: [PATCH] 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