From 1eea96eefc0e5e9416ef8e60108aecd53b230f0c Mon Sep 17 00:00:00 2001 From: Naomi Date: Fri, 13 May 2011 13:27:25 -0400 Subject: [PATCH 1/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention naming convention in fallback order stor/artist/album/track - title.ext stor/artist/album/title.ext stor/artist/album/originalfilename.ext stor/artist/track - title.ext stor/artist/title.ext stor/artist/originalfilename.ext stor/originalfilename.ext --- airtime_mvc/application/models/StoredFile.php | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index d5d4faf80..32ced891d 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -773,6 +773,31 @@ class StoredFile { return $rows; } + private function ensureDir($dir) + { + if (!is_dir($dir)) { + mkdir($dir, 02775); + chmod($dir, 02775); + } + } + + private function createUniqueFilename($base, $ext) + { + if(file_exists("$base.$ext")) { + $i = 1; + while(true) { + if(file_exists("$base($i).$ext")) { + $i = $i+1; + } + else { + return "$base($i).$ext"; + } + } + } + + return "$base.$ext"; + } + /** * Generate the location to store the file. * It creates the subdirectory if needed. @@ -780,14 +805,48 @@ class StoredFile { private function generateFilePath() { global $CC_CONFIG, $CC_DBC; - $resDir = $CC_CONFIG['storageDir']."/".substr($this->gunid, 0, 3); - if (!is_dir($resDir)) { - mkdir($resDir, 02775); - chmod($resDir, 02775); - } + + $storageDir = $CC_CONFIG['storageDir']; $info = pathinfo($this->name); + $origName = $info['filename']; $fileExt = strtolower($info["extension"]); - return "{$resDir}/{$this->gunid}.{$fileExt}"; + + $this->loadMetadata(); + + $artist = $this->md["dc:creator"]; + $album = $this->md["dc:source"]; + $title = $this->md["dc:title"]; + $track_num = $this->md["ls:track_num"]; + + if(isset($artist) && $artist != "") { + $base = "$storageDir/$artist"; + $this->ensureDir($base); + + if(isset($album) && $album != "") { + $base = "$base/$album"; + $this->ensureDir($base); + } + + if(isset($title) && $title != "") { + if(isset($track_num) && $track_num != "") { + if($track_num < 10 && strlen($track_num) == 1) { + $track_num = "0$track_num"; + } + $base = "$base/$track_num - $title"; + } + else { + $base = "$base/$title"; + } + } + else { + $base = "$base/$origName"; + } + } + else { + $base = "$storageDir/$origName"; + } + + return $this->createUniqueFilename($base, $fileExt); } /** From ea1b254ebd4db8743c6feff49298124a461858d3 Mon Sep 17 00:00:00 2001 From: Naomi Date: Fri, 13 May 2011 18:03:34 -0400 Subject: [PATCH 2/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention searching database by filename to retrieve file. Checking if is supported audio file/temp audio file. --- .../application/controllers/ApiController.php | 7 +-- airtime_mvc/application/models/StoredFile.php | 4 +- python_apps/pytag-fs/MediaMonitor.py | 45 +++++++++++-------- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index a6f0825b7..23073c351 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -64,7 +64,7 @@ class ApiController extends Zend_Controller_Action $api_key = $this->_getParam('api_key'); $downlaod = $this->_getParam('download'); - + if(!in_array($api_key, $CC_CONFIG["apiKey"])) { header('HTTP/1.0 401 Unauthorized'); @@ -331,8 +331,9 @@ class ApiController extends Zend_Controller_Action } $md = $this->_getParam('md'); - - $file = StoredFile::Recall(null, $md['gunid']); + $filepath = $md['filepath']; + $filepath = str_replace("\\", "", $filepath); + $file = StoredFile::Recall(null, null, null, $filepath); if (PEAR::isError($file) || is_null($file)) { $this->view->response = "File not in Airtime's Database"; return; diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 32ced891d..1657f2318 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -701,7 +701,7 @@ class StoredFile { * @return StoredFile|Playlist|NULL * Return NULL if the object doesnt exist in the DB. */ - public static function Recall($p_id=null, $p_gunid=null, $p_md5sum=null) + public static function Recall($p_id=null, $p_gunid=null, $p_md5sum=null, $p_filepath=null) { global $CC_DBC; global $CC_CONFIG; @@ -711,6 +711,8 @@ class StoredFile { $cond = "gunid='$p_gunid'"; } elseif (!is_null($p_md5sum)) { $cond = "md5='$p_md5sum'"; + } elseif (!is_null($p_filepath)) { + $cond = "filepath='$p_filepath'"; } else { return null; } diff --git a/python_apps/pytag-fs/MediaMonitor.py b/python_apps/pytag-fs/MediaMonitor.py index 38423fcc9..d63e7c3b5 100644 --- a/python_apps/pytag-fs/MediaMonitor.py +++ b/python_apps/pytag-fs/MediaMonitor.py @@ -70,7 +70,7 @@ class AirtimeNotifier(Notifier): "isrc_number": "isrc",\ "copyright": "copyright",\ } - + schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True) schedule_queue = Queue("media-monitor", exchange=schedule_exchange, key="filesystem") self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], "/") @@ -86,7 +86,7 @@ class AirtimeNotifier(Notifier): logger = logging.getLogger('root') logger.info("Received md from RabbitMQ: " + body) - m = json.loads(message.body) + m = json.loads(message.body) airtime_file = mutagen.File(m['filepath'], easy=True) del m['filepath'] for key in m.keys() : @@ -123,21 +123,19 @@ class MediaMonitor(ProcessEvent): "copyright": "copyright",\ } + self.supported_file_formats = ['mp3', 'ogg'] self.logger = logging.getLogger('root') - self.temp_files = {} def update_airtime(self, event): self.logger.info("Updating Change to Airtime") - try: + try: f = open(event.pathname, 'rb') m = hashlib.md5() m.update(f.read()) - md5 = m.hexdigest() - gunid = event.name.split('.')[0] - md = {'gunid':gunid, 'md5':md5} + md = {'filepath':event.pathname, 'md5':md5} file_info = mutagen.File(event.pathname, easy=True) attrs = self.mutagen2airtime @@ -152,12 +150,28 @@ class MediaMonitor(ProcessEvent): except Exception, e: self.logger.info("%s", e) + def is_temp_file(self, filename): + info = filename.split(".") + + if(info[-2] in self.supported_file_formats): + return True + else : + return False + + def is_audio_file(self, filename): + info = filename.split(".") + + if(info[-1] in self.supported_file_formats): + return True + else : + return False + + def process_IN_CREATE(self, event): if not event.dir : - filename_info = event.name.split(".") #file created is a tmp file which will be modified and then moved back to the original filename. - if len(filename_info) > 2 : + if self.is_temp_file(event.name) : self.temp_files[event.pathname] = None #This is a newly imported file. else : @@ -165,18 +179,13 @@ class MediaMonitor(ProcessEvent): self.logger.info("%s: %s", event.maskname, event.pathname) - #event.path : /srv/airtime/stor/bd2 - #event.name : bd2aa73b58d9c8abcced989621846e99.mp3 - #event.pathname : /srv/airtime/stor/bd2/bd2aa73b58d9c8abcced989621846e99.mp3 def process_IN_MODIFY(self, event): if not event.dir : - filename_info = event.name.split(".") - #file modified is not a tmp file. - if len(filename_info) == 2 : - self.update_airtime(event) + if self.is_audio_file(event.name) : + self.update_airtime(event) - self.logger.info("%s: path: %s name: %s", event.maskname, event.path, event.name) + self.logger.info("%s: %s", event.maskname, event.pathname) def process_IN_MOVED_FROM(self, event): if event.pathname in self.temp_files : @@ -189,7 +198,7 @@ class MediaMonitor(ProcessEvent): if event.cookie in self.temp_files : del self.temp_files[event.cookie] self.update_airtime(event) - + self.logger.info("%s: %s", event.maskname, event.pathname) def process_default(self, event): From efc8d0664cea0f85b8902a1b4cd61218cdc61387 Mon Sep 17 00:00:00 2001 From: Naomi Date: Fri, 13 May 2011 13:27:25 -0400 Subject: [PATCH 3/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention naming convention in fallback order stor/artist/album/track - title.ext stor/artist/album/title.ext stor/artist/album/originalfilename.ext stor/artist/track - title.ext stor/artist/title.ext stor/artist/originalfilename.ext stor/originalfilename.ext --- airtime_mvc/application/models/StoredFile.php | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 370b27cdb..ba152f49e 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -782,6 +782,31 @@ class StoredFile { return $rows; } + private function ensureDir($dir) + { + if (!is_dir($dir)) { + mkdir($dir, 02775); + chmod($dir, 02775); + } + } + + private function createUniqueFilename($base, $ext) + { + if(file_exists("$base.$ext")) { + $i = 1; + while(true) { + if(file_exists("$base($i).$ext")) { + $i = $i+1; + } + else { + return "$base($i).$ext"; + } + } + } + + return "$base.$ext"; + } + /** * Generate the location to store the file. * It creates the subdirectory if needed. @@ -789,14 +814,48 @@ class StoredFile { private function generateFilePath() { global $CC_CONFIG, $CC_DBC; - $resDir = $CC_CONFIG['storageDir']."/".substr($this->gunid, 0, 3); - if (!is_dir($resDir)) { - mkdir($resDir, 02775); - chmod($resDir, 02775); - } + + $storageDir = $CC_CONFIG['storageDir']; $info = pathinfo($this->name); + $origName = $info['filename']; $fileExt = strtolower($info["extension"]); - return "{$resDir}/{$this->gunid}.{$fileExt}"; + + $this->loadMetadata(); + + $artist = $this->md["dc:creator"]; + $album = $this->md["dc:source"]; + $title = $this->md["dc:title"]; + $track_num = $this->md["ls:track_num"]; + + if(isset($artist) && $artist != "") { + $base = "$storageDir/$artist"; + $this->ensureDir($base); + + if(isset($album) && $album != "") { + $base = "$base/$album"; + $this->ensureDir($base); + } + + if(isset($title) && $title != "") { + if(isset($track_num) && $track_num != "") { + if($track_num < 10 && strlen($track_num) == 1) { + $track_num = "0$track_num"; + } + $base = "$base/$track_num - $title"; + } + else { + $base = "$base/$title"; + } + } + else { + $base = "$base/$origName"; + } + } + else { + $base = "$storageDir/$origName"; + } + + return $this->createUniqueFilename($base, $fileExt); } /** From 6dfad55b89489dfaeab178e45818c93b5cc36a14 Mon Sep 17 00:00:00 2001 From: Naomi Date: Fri, 13 May 2011 18:03:34 -0400 Subject: [PATCH 4/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention searching database by filename to retrieve file. Checking if is supported audio file/temp audio file. --- .../application/controllers/ApiController.php | 13 +++--- airtime_mvc/application/models/StoredFile.php | 4 +- python_apps/media-monitor/MediaMonitor.py | 45 +++++++++++-------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index dce293b0d..3441668da 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -63,7 +63,7 @@ class ApiController extends Zend_Controller_Action $this->_helper->viewRenderer->setNoRender(true); $api_key = $this->_getParam('api_key'); - $download = $this->_getParam('download'); + $downlaod = $this->_getParam('download'); if(!in_array($api_key, $CC_CONFIG["apiKey"])) { @@ -100,15 +100,15 @@ class ApiController extends Zend_Controller_Action // !! binary mode !! $fp = fopen($filepath, 'rb'); - + //We can have multiple levels of output buffering. Need to //keep looping until all have been disabled!!! //http://www.php.net/manual/en/function.ob-end-flush.php while (@ob_end_flush()); - + fpassthru($fp); fclose($fp); - + return; } } @@ -357,8 +357,9 @@ class ApiController extends Zend_Controller_Action } $md = $this->_getParam('md'); - - $file = StoredFile::Recall(null, $md['gunid']); + $filepath = $md['filepath']; + $filepath = str_replace("\\", "", $filepath); + $file = StoredFile::Recall(null, null, null, $filepath); if (PEAR::isError($file) || is_null($file)) { $this->view->response = "File not in Airtime's Database"; return; diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index ba152f49e..cdc17423e 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -703,7 +703,7 @@ class StoredFile { * @return StoredFile|Playlist|NULL * Return NULL if the object doesnt exist in the DB. */ - public static function Recall($p_id=null, $p_gunid=null, $p_md5sum=null) + public static function Recall($p_id=null, $p_gunid=null, $p_md5sum=null, $p_filepath=null) { global $CC_DBC; global $CC_CONFIG; @@ -713,6 +713,8 @@ class StoredFile { $cond = "gunid='$p_gunid'"; } elseif (!is_null($p_md5sum)) { $cond = "md5='$p_md5sum'"; + } elseif (!is_null($p_filepath)) { + $cond = "filepath='$p_filepath'"; } else { return null; } diff --git a/python_apps/media-monitor/MediaMonitor.py b/python_apps/media-monitor/MediaMonitor.py index afb249f73..5b34455e7 100644 --- a/python_apps/media-monitor/MediaMonitor.py +++ b/python_apps/media-monitor/MediaMonitor.py @@ -71,7 +71,7 @@ class AirtimeNotifier(Notifier): "isrc_number": "isrc",\ "copyright": "copyright",\ } - + schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True) schedule_queue = Queue("media-monitor", exchange=schedule_exchange, key="filesystem") self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], "/") @@ -87,7 +87,7 @@ class AirtimeNotifier(Notifier): logger = logging.getLogger('root') logger.info("Received md from RabbitMQ: " + body) - m = json.loads(message.body) + m = json.loads(message.body) airtime_file = mutagen.File(m['filepath'], easy=True) del m['filepath'] for key in m.keys() : @@ -124,21 +124,19 @@ class MediaMonitor(ProcessEvent): "copyright": "copyright",\ } + self.supported_file_formats = ['mp3', 'ogg'] self.logger = logging.getLogger('root') - self.temp_files = {} def update_airtime(self, event): self.logger.info("Updating Change to Airtime") - try: + try: f = open(event.pathname, 'rb') m = hashlib.md5() m.update(f.read()) - md5 = m.hexdigest() - gunid = event.name.split('.')[0] - md = {'gunid':gunid, 'md5':md5} + md = {'filepath':event.pathname, 'md5':md5} file_info = mutagen.File(event.pathname, easy=True) attrs = self.mutagen2airtime @@ -153,12 +151,28 @@ class MediaMonitor(ProcessEvent): except Exception, e: self.logger.info("%s", e) + def is_temp_file(self, filename): + info = filename.split(".") + + if(info[-2] in self.supported_file_formats): + return True + else : + return False + + def is_audio_file(self, filename): + info = filename.split(".") + + if(info[-1] in self.supported_file_formats): + return True + else : + return False + + def process_IN_CREATE(self, event): if not event.dir : - filename_info = event.name.split(".") #file created is a tmp file which will be modified and then moved back to the original filename. - if len(filename_info) > 2 : + if self.is_temp_file(event.name) : self.temp_files[event.pathname] = None #This is a newly imported file. else : @@ -166,18 +180,13 @@ class MediaMonitor(ProcessEvent): self.logger.info("%s: %s", event.maskname, event.pathname) - #event.path : /srv/airtime/stor/bd2 - #event.name : bd2aa73b58d9c8abcced989621846e99.mp3 - #event.pathname : /srv/airtime/stor/bd2/bd2aa73b58d9c8abcced989621846e99.mp3 def process_IN_MODIFY(self, event): if not event.dir : - filename_info = event.name.split(".") - #file modified is not a tmp file. - if len(filename_info) == 2 : - self.update_airtime(event) + if self.is_audio_file(event.name) : + self.update_airtime(event) - self.logger.info("%s: path: %s name: %s", event.maskname, event.path, event.name) + self.logger.info("%s: %s", event.maskname, event.pathname) def process_IN_MOVED_FROM(self, event): if event.pathname in self.temp_files : @@ -190,7 +199,7 @@ class MediaMonitor(ProcessEvent): if event.cookie in self.temp_files : del self.temp_files[event.cookie] self.update_airtime(event) - + self.logger.info("%s: %s", event.maskname, event.pathname) def process_default(self, event): From f271f31ad88157a5efce0415b8e445fc20598828 Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Fri, 3 Jun 2011 14:26:11 -0400 Subject: [PATCH 5/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention adding ability to drag music into stor folder. --- python_apps/media-monitor/MediaMonitor.py | 76 ++++++++++++++++++++- python_apps/media-monitor/media-monitor.cfg | 2 +- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/python_apps/media-monitor/MediaMonitor.py b/python_apps/media-monitor/MediaMonitor.py index 5b34455e7..92e5e8dfe 100644 --- a/python_apps/media-monitor/MediaMonitor.py +++ b/python_apps/media-monitor/MediaMonitor.py @@ -8,6 +8,7 @@ import os import sys import hashlib import json +import shutil from subprocess import Popen, PIPE, STDOUT @@ -22,6 +23,9 @@ from kombu.connection import BrokerConnection from kombu.messaging import Exchange, Queue, Consumer, Producer from api_clients import api_client +global storage_directory +storage_directory = "/srv/airtime/stor" + # configure logging try: logging.config.fileConfig("logging.cfg") @@ -42,6 +46,7 @@ list of supported easy tags in mutagen version 1.20 ['albumartistsort', 'musicbrainz_albumstatus', 'lyricist', 'releasecountry', 'date', 'performer', 'musicbrainz_albumartistid', 'composer', 'encodedby', 'tracknumber', 'musicbrainz_albumid', 'album', 'asin', 'musicbrainz_artistid', 'mood', 'copyright', 'author', 'media', 'length', 'version', 'artistsort', 'titlesort', 'discsubtitle', 'website', 'musicip_fingerprint', 'conductor', 'compilation', 'barcode', 'performer:*', 'composersort', 'musicbrainz_discid', 'musicbrainz_albumtype', 'genre', 'isrc', 'discnumber', 'musicbrainz_trmid', 'replaygain_*_gain', 'musicip_puid', 'artist', 'title', 'bpm', 'musicbrainz_trackid', 'arranger', 'albumsort', 'replaygain_*_peak', 'organization'] """ + def checkRabbitMQ(notifier): try: notifier.connection.drain_events(timeout=int(config["check_airtime_events"])) @@ -128,6 +133,72 @@ class MediaMonitor(ProcessEvent): self.logger = logging.getLogger('root') self.temp_files = {} + def ensure_dir(self, filepath): + + directory = os.path.dirname(filepath) + + if ((not os.path.exists(directory)) or ((os.path.exists(directory) and not os.path.isdir(directory)))): + os.makedirs(directory, 02775) + + def create_unique_filename(self, filepath): + + file_dir = os.path.dirname(filepath) + print file_dir + filename = os.path.basename(filepath).split(".")[0] + print filename + file_ext = os.path.splitext(filepath)[1] + print file_ext + + if(os.path.exists(filepath)): + i = 1; + while(True): + new_filepath = "%s/%s(%s).%s" % (file_dir, filename, i, file_ext) + + if(os.path.exists(new_filepath)): + i = i+1; + else: + return new_filepath + + return filepath + + def create_file_path(self, imported_filepath): + + global storage_directory + + original_name = os.path.basename(imported_filepath) + file_ext = os.path.splitext(imported_filepath)[1] + file_info = mutagen.File(imported_filepath, easy=True) + + metadata = {'artist':None, + 'album':None, + 'title':None, + 'tracknumber':None} + + for key in metadata.keys(): + if key in file_info: + metadata[key] = file_info[key][0] + + if metadata['artist'] is not None: + base = "%s/%s" % (storage_directory, metadata['artist']) + if metadata['album'] is not None: + base = "%s/%s" % (base, metadata['album']) + if metadata['title'] is not None: + if metadata['tracknumber'] is not None: + metadata['tracknumber'] = "%02d" % (int(metadata['tracknumber'])) + base = "%s/%s - %s" % (base, metadata['tracknumber'], metadata['title']) + else: + base = "%s/%s" % (base, metadata['title']) + else: + base = "%s/%s" % (base, original_name) + else: + base = "%s/%s" % (storage_directory, original_name) + + base = "%s%s" % (base, file_ext) + + filepath = self.create_unique_filename(base) + self.ensure_dir(filepath) + shutil.move(imported_filepath, filepath) + def update_airtime(self, event): self.logger.info("Updating Change to Airtime") try: @@ -145,7 +216,6 @@ class MediaMonitor(ProcessEvent): md[attrs[key]] = file_info[key][0] data = {'md': md} - response = self.api_client.update_media_metadata(data) except Exception, e: @@ -176,7 +246,7 @@ class MediaMonitor(ProcessEvent): self.temp_files[event.pathname] = None #This is a newly imported file. else : - pass + self.create_file_path(event.pathname) self.logger.info("%s: %s", event.maskname, event.pathname) @@ -213,7 +283,7 @@ if __name__ == '__main__': #mask = pyinotify.ALL_EVENTS wm = WatchManager() - wdd = wm.add_watch('/srv/airtime/stor', mask, rec=True, auto_add=True) + wdd = wm.add_watch(storage_directory, mask, rec=True, auto_add=True) notifier = AirtimeNotifier(wm, MediaMonitor(), read_freq=int(config["check_filesystem_events"]), timeout=1) notifier.coalesce_events() diff --git a/python_apps/media-monitor/media-monitor.cfg b/python_apps/media-monitor/media-monitor.cfg index 5f2a79a83..38b44cea7 100644 --- a/python_apps/media-monitor/media-monitor.cfg +++ b/python_apps/media-monitor/media-monitor.cfg @@ -32,5 +32,5 @@ rabbitmq_password = 'guest' ############################################ # Media-Monitor preferences # ############################################ -check_filesystem_events = 30 #how long to queue up events performed on the files themselves. +check_filesystem_events = 5 #how long to queue up events performed on the files themselves. check_airtime_events = 30 #how long to queue metadata input from airtime. From f7e86100af1535b8a7b35d3bf7156ba6300c03b5 Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Mon, 6 Jun 2011 10:53:08 +0200 Subject: [PATCH 6/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention enabling media monitor changes. --- install/include/AirtimeIni.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/install/include/AirtimeIni.php b/install/include/AirtimeIni.php index 7f2ff24e8..a5adf6faf 100644 --- a/install/include/AirtimeIni.php +++ b/install/include/AirtimeIni.php @@ -33,7 +33,8 @@ class AirtimeIni $configFiles = array(AirtimeIni::CONF_FILE_AIRTIME, AirtimeIni::CONF_FILE_PYPO, AirtimeIni::CONF_FILE_RECORDER, - AirtimeIni::CONF_FILE_LIQUIDSOAP); + AirtimeIni::CONF_FILE_LIQUIDSOAP, + AirtimeIni::CONF_FILE_MEDIAMONITOR); $exist = false; foreach ($configFiles as $conf) { if (file_exists($conf)) { @@ -102,9 +103,9 @@ class AirtimeIni } //wait until Airtime 1.9.0 - //if (file_exists(AirtimeIni::CONF_FILE_MEDIAMONITOR)){ - // unlink(AirtimeIni::CONF_FILE_MEDIAMONITOR); - //} + if (file_exists(AirtimeIni::CONF_FILE_MEDIAMONITOR)){ + unlink(AirtimeIni::CONF_FILE_MEDIAMONITOR); + } if (file_exists("etc/airtime")){ rmdir("/etc/airtime/"); @@ -157,8 +158,8 @@ class AirtimeIni foreach ($lines as &$line) { if ($line[0] != "#"){ $key_value = split("=", $line); - $key = trim($key_value[0]); - + $key = trim($key_value[0]); + if ($key == $p_property){ $line = "$p_property = $p_value".PHP_EOL; } @@ -185,7 +186,7 @@ class AirtimeIni AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_AIRTIME, 'airtime_dir', AirtimeInstall::CONF_DIR_WWW); AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_PYPO, 'api_key', "'$api_key'"); AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_RECORDER, 'api_key', "'$api_key'"); - //AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_MEDIAMONITOR, 'api_key', "'$api_key'"); + AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_MEDIAMONITOR, 'api_key', "'$api_key'"); AirtimeIni::UpdateIniValue(AirtimeInstall::CONF_DIR_WWW.'/build/build.properties', 'project.home', AirtimeInstall::CONF_DIR_WWW); } From b1d4b3442b7ecf186e7613a2b01b87b5251421d6 Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Mon, 6 Jun 2011 10:56:50 +0200 Subject: [PATCH 7/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention enabling uninstall of media monitor. --- install/airtime-uninstall | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/airtime-uninstall b/install/airtime-uninstall index 4168eb8e7..b65700d00 100755 --- a/install/airtime-uninstall +++ b/install/airtime-uninstall @@ -12,12 +12,12 @@ php ${SCRIPTPATH}/airtime-uninstall.php echo -e "\n*** Uninstalling Pypo ***" python ${SCRIPTPATH}/../python_apps/pypo/install/pypo-uninstall.py -#echo -e "\n*** Uninstalling Media Monitor ***" -#python ${SCRIPTPATH}/../python_apps/pytag-fs/install/media-monitor-uninstall.py - echo -e "\n*** Uninstalling Show Recorder ***" python ${SCRIPTPATH}/../python_apps/show-recorder/install/recorder-uninstall.py +echo -e "\n*** Uninstalling Media Monitor ***" +python ${SCRIPTPATH}/../python_apps/media-monitor/install/media-monitor-uninstall.py + echo -e "\n*** Removing Pypo User ***" python ${SCRIPTPATH}/../python_apps/remove-pypo-user.py From 7c65623477f3cc8a509e301a3b856f55f11dab14 Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Mon, 6 Jun 2011 11:06:34 +0200 Subject: [PATCH 8/8] CC-1799 Put Airtime Storage into a Human Readable File Naming Convention --- python_apps/media-monitor/MediaMonitor.py | 39 +++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/python_apps/media-monitor/MediaMonitor.py b/python_apps/media-monitor/MediaMonitor.py index 92e5e8dfe..dce10f579 100644 --- a/python_apps/media-monitor/MediaMonitor.py +++ b/python_apps/media-monitor/MediaMonitor.py @@ -132,6 +132,15 @@ class MediaMonitor(ProcessEvent): self.supported_file_formats = ['mp3', 'ogg'] self.logger = logging.getLogger('root') self.temp_files = {} + self.imported_renamed_files = {} + + def get_md5(self, filepath): + f = open(filepath, 'rb') + m = hashlib.md5() + m.update(f.read()) + md5 = m.hexdigest() + + return md5 def ensure_dir(self, filepath): @@ -143,11 +152,8 @@ class MediaMonitor(ProcessEvent): def create_unique_filename(self, filepath): file_dir = os.path.dirname(filepath) - print file_dir filename = os.path.basename(filepath).split(".")[0] - print filename file_ext = os.path.splitext(filepath)[1] - print file_ext if(os.path.exists(filepath)): i = 1; @@ -157,7 +163,9 @@ class MediaMonitor(ProcessEvent): if(os.path.exists(new_filepath)): i = i+1; else: - return new_filepath + filepath = new_filepath + + self.imported_renamed_files[filepath] = 0 return filepath @@ -202,11 +210,7 @@ class MediaMonitor(ProcessEvent): def update_airtime(self, event): self.logger.info("Updating Change to Airtime") try: - f = open(event.pathname, 'rb') - m = hashlib.md5() - m.update(f.read()) - md5 = m.hexdigest() - + md5 = self.get_md5(event.pathname) md = {'filepath':event.pathname, 'md5':md5} file_info = mutagen.File(event.pathname, easy=True) @@ -221,6 +225,13 @@ class MediaMonitor(ProcessEvent): except Exception, e: self.logger.info("%s", e) + def is_renamed_file(self, filename): + if filename in self.imported_renamed_files: + del self.imported_renamed_files[filename] + return True + + return False + def is_temp_file(self, filename): info = filename.split(".") @@ -239,16 +250,17 @@ class MediaMonitor(ProcessEvent): def process_IN_CREATE(self, event): - if not event.dir : + if not event.dir: #file created is a tmp file which will be modified and then moved back to the original filename. if self.is_temp_file(event.name) : self.temp_files[event.pathname] = None #This is a newly imported file. else : + #if not is_renamed_file(event.pathname): self.create_file_path(event.pathname) - self.logger.info("%s: %s", event.maskname, event.pathname) + self.logger.info("%s: %s", event.maskname, event.pathname) def process_IN_MODIFY(self, event): if not event.dir : @@ -285,10 +297,11 @@ if __name__ == '__main__': wm = WatchManager() wdd = wm.add_watch(storage_directory, mask, rec=True, auto_add=True) + logger = logging.getLogger('root') + logger.info("Added watch to %s", storage_directory) + notifier = AirtimeNotifier(wm, MediaMonitor(), read_freq=int(config["check_filesystem_events"]), timeout=1) notifier.coalesce_events() notifier.loop(callback=checkRabbitMQ) except KeyboardInterrupt: notifier.stop() - -