Merge branch 'devel' of dev.sourcefabric.org:airtime into devel
This commit is contained in:
commit
3b157fd5d9
9 changed files with 107 additions and 43 deletions
|
@ -15,6 +15,7 @@ class ApiController extends Zend_Controller_Action
|
||||||
->addActionContext('media-item-status', 'json')
|
->addActionContext('media-item-status', 'json')
|
||||||
->addActionContext('reload-metadata', 'json')
|
->addActionContext('reload-metadata', 'json')
|
||||||
->addActionContext('list-all-files', 'json')
|
->addActionContext('list-all-files', 'json')
|
||||||
|
->addActionContext('list-all-watched-dirs', 'json')
|
||||||
->initContext();
|
->initContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ class ApiController extends Zend_Controller_Action
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns Airtime version. i.e "1.7.0 alpha"
|
* Returns Airtime version. i.e "1.7.0-beta"
|
||||||
*
|
*
|
||||||
* First checks to ensure the correct API key was
|
* First checks to ensure the correct API key was
|
||||||
* supplied, then returns AIRTIME_VERSION as defined
|
* supplied, then returns AIRTIME_VERSION as defined
|
||||||
|
@ -520,8 +521,35 @@ class ApiController extends Zend_Controller_Action
|
||||||
print 'You are not allowed to access this resource.';
|
print 'You are not allowed to access this resource.';
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
$dir_id = $request->getParam('dir_id');
|
||||||
|
|
||||||
$this->view->files = StoredFile::listAllFiles();
|
$this->view->files = StoredFile::listAllFiles($dir_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listAllWatchedDirsAction() {
|
||||||
|
global $CC_CONFIG;
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$api_key = $request->getParam('api_key');
|
||||||
|
if (!in_array($api_key, $CC_CONFIG["apiKey"]))
|
||||||
|
{
|
||||||
|
header('HTTP/1.0 401 Unauthorized');
|
||||||
|
print 'You are not allowed to access this resource.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$arrWatchedDirs = MusicDir::getWatchedDirs();
|
||||||
|
$storDir = MusicDir::getStorDir();
|
||||||
|
|
||||||
|
$result[$storDir->getId()] = $storDir->getDirectory();
|
||||||
|
|
||||||
|
foreach ($arrWatchedDirs as $watchedDir){
|
||||||
|
$result[$watchedDir->getId()] = $watchedDir->getDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->dirs = $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ class MusicDir {
|
||||||
*/
|
*/
|
||||||
private $_dir;
|
private $_dir;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct($dir)
|
||||||
{
|
{
|
||||||
|
$this->_dir = $dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId()
|
public function getId()
|
||||||
|
@ -50,8 +50,7 @@ class MusicDir {
|
||||||
$dir->setDirectory($p_path);
|
$dir->setDirectory($p_path);
|
||||||
$dir->save();
|
$dir->save();
|
||||||
|
|
||||||
$mus_dir = new MusicDir();
|
$mus_dir = new MusicDir($dir);
|
||||||
$mus_dir->_dir = $dir;
|
|
||||||
|
|
||||||
return $mus_dir;
|
return $mus_dir;
|
||||||
}
|
}
|
||||||
|
@ -65,8 +64,7 @@ class MusicDir {
|
||||||
{
|
{
|
||||||
$dir = CcMusicDirsQuery::create()->findPK($pk);
|
$dir = CcMusicDirsQuery::create()->findPK($pk);
|
||||||
|
|
||||||
$mus_dir = new MusicDir();
|
$mus_dir = new MusicDir($dir);
|
||||||
$mus_dir->_dir = $dir;
|
|
||||||
|
|
||||||
return $mus_dir;
|
return $mus_dir;
|
||||||
}
|
}
|
||||||
|
@ -77,9 +75,7 @@ class MusicDir {
|
||||||
->filterByDirectory($p_path)
|
->filterByDirectory($p_path)
|
||||||
->findOne();
|
->findOne();
|
||||||
|
|
||||||
$mus_dir = new MusicDir();
|
$mus_dir = new MusicDir($dir);
|
||||||
$mus_dir->_dir = $dir;
|
|
||||||
|
|
||||||
return $mus_dir;
|
return $mus_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +88,7 @@ class MusicDir {
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
foreach($dirs as $dir) {
|
foreach($dirs as $dir) {
|
||||||
$tmp = new MusicDir();
|
$tmp = new MusicDir($dir);
|
||||||
$tmp->_dir = $dir;
|
|
||||||
|
|
||||||
$result[] = $tmp;
|
$result[] = $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +101,7 @@ class MusicDir {
|
||||||
->filterByType("stor")
|
->filterByType("stor")
|
||||||
->findOne();
|
->findOne();
|
||||||
|
|
||||||
$mus_dir = new MusicDir();
|
$mus_dir = new MusicDir($dir);
|
||||||
$mus_dir->_dir = $dir;
|
$mus_dir->_dir = $dir;
|
||||||
|
|
||||||
return $mus_dir;
|
return $mus_dir;
|
||||||
|
@ -127,8 +121,7 @@ class MusicDir {
|
||||||
foreach($dirs as $dir) {
|
foreach($dirs as $dir) {
|
||||||
$directory = $dir->getDirectory();
|
$directory = $dir->getDirectory();
|
||||||
if (substr($p_filepath, 0, strlen($directory)) === $directory) {
|
if (substr($p_filepath, 0, strlen($directory)) === $directory) {
|
||||||
$mus_dir = new MusicDir();
|
$mus_dir = new MusicDir($dir);
|
||||||
$mus_dir->_dir = $dir;
|
|
||||||
return $mus_dir;
|
return $mus_dir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -819,14 +819,15 @@ class StoredFile {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function listAllFiles(){
|
public static function listAllFiles($dir_id){
|
||||||
global $CC_CONFIG, $CC_DBC;
|
global $CC_CONFIG, $CC_DBC;
|
||||||
|
|
||||||
$sql = "SELECT m.directory || '/' || f.filepath as fp"
|
$sql = "SELECT m.directory || '/' || f.filepath as fp"
|
||||||
." FROM CC_MUSIC_DIRS m"
|
." FROM CC_MUSIC_DIRS m"
|
||||||
." LEFT JOIN CC_FILES f"
|
." LEFT JOIN CC_FILES f"
|
||||||
." ON m.id = f.directory"
|
." ON m.id = f.directory"
|
||||||
." WHERE m.id = f.directory";
|
." WHERE m.id = f.directory"
|
||||||
|
." AND directory = $dir_id";
|
||||||
$rows = $CC_DBC->getAll($sql);
|
$rows = $CC_DBC->getAll($sql);
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
|
|
|
@ -105,7 +105,10 @@ class ApiClientInterface:
|
||||||
def update_media_metadata(self, md):
|
def update_media_metadata(self, md):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def list_all_db_files(self):
|
def list_all_db_files(self, dir_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def list_all_watched_dirs(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Put here whatever tests you want to run to make sure your API is working
|
# Put here whatever tests you want to run to make sure your API is working
|
||||||
|
@ -406,12 +409,31 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def list_all_db_files(self):
|
def list_all_db_files(self, dir_id):
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
try:
|
try:
|
||||||
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["list_all_db_files"])
|
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["list_all_db_files"])
|
||||||
|
|
||||||
url = url.replace("%%api_key%%", self.config["api_key"])
|
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||||
|
url = url.replace("%%dir_id%%", dir_id)
|
||||||
|
|
||||||
|
req = urllib2.Request(url)
|
||||||
|
response = urllib2.urlopen(req).read()
|
||||||
|
response = json.loads(response)
|
||||||
|
except Exception, e:
|
||||||
|
response = None
|
||||||
|
logger.error("Exception: %s", e)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def list_all_watched_dirs(self):
|
||||||
|
logger = logging.getLogger()
|
||||||
|
try:
|
||||||
|
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["list_all_watched_dirs"])
|
||||||
|
|
||||||
|
|
||||||
|
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||||
|
logger.debug(url)
|
||||||
|
|
||||||
req = urllib2.Request(url)
|
req = urllib2.Request(url)
|
||||||
response = urllib2.urlopen(req).read()
|
response = urllib2.urlopen(req).read()
|
||||||
|
@ -421,7 +443,6 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
logger.error("Exception: %s", e)
|
logger.error("Exception: %s", e)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
|
@ -22,15 +22,21 @@ class AirtimeMediaMonitorBootstrap():
|
||||||
went offline. We can do this by doing a hash of the directory metadata.
|
went offline. We can do this by doing a hash of the directory metadata.
|
||||||
"""
|
"""
|
||||||
def scan(self):
|
def scan(self):
|
||||||
directories = ['/srv/airtime/stor']
|
directories = self.get_list_of_watched_dirs();
|
||||||
|
|
||||||
for dir in directories:
|
self.logger.info("watched directories found: %s", directories)
|
||||||
self.check_for_diff(dir)
|
|
||||||
|
for id, dir in directories:
|
||||||
|
self.check_for_diff(id, dir)
|
||||||
|
|
||||||
def list_db_files(self):
|
def list_db_files(self, dir_id):
|
||||||
return self.api_client.list_all_db_files()
|
return self.api_client.list_all_db_files(dir_id)
|
||||||
|
|
||||||
|
def get_list_of_watched_dirs(self):
|
||||||
|
json = self.api_client.list_all_watched_dirs()
|
||||||
|
return json["dirs"]
|
||||||
|
|
||||||
def check_for_diff(self, dir):
|
def check_for_diff(self, dir_id, dir):
|
||||||
#set to hold new and/or modified files. We use a set to make it ok if files are added
|
#set to hold new and/or modified files. We use a set to make it ok if files are added
|
||||||
#twice. This is become some of the tests for new files return result sets that are not
|
#twice. This is become some of the tests for new files return result sets that are not
|
||||||
#mutually exclusive from each other.
|
#mutually exclusive from each other.
|
||||||
|
@ -39,7 +45,7 @@ class AirtimeMediaMonitorBootstrap():
|
||||||
|
|
||||||
|
|
||||||
db_known_files_set = set()
|
db_known_files_set = set()
|
||||||
files = self.list_db_files()
|
files = self.list_db_files(dir_id)
|
||||||
for file in files['files']:
|
for file in files['files']:
|
||||||
db_known_files_set.add(file)
|
db_known_files_set.add(file)
|
||||||
|
|
||||||
|
@ -53,10 +59,10 @@ class AirtimeMediaMonitorBootstrap():
|
||||||
all_files_set.add(file_path)
|
all_files_set.add(file_path)
|
||||||
|
|
||||||
|
|
||||||
if os.path.exists("/var/tmp/airtime/media_monitor_boot"):
|
if os.path.exists("/var/tmp/airtime/.media_monitor_boot"):
|
||||||
#find files that have been modified since the last time
|
#find files that have been modified since the last time
|
||||||
#media-monitor process started.
|
#media-monitor process started.
|
||||||
time_diff_sec = time.time() - os.path.getmtime("/var/tmp/airtime/media_monitor_boot")
|
time_diff_sec = time.time() - os.path.getmtime("/var/tmp/airtime/.media_monitor_boot")
|
||||||
command = "find %s -type f -iname '*.ogg' -o -iname '*.mp3' -readable -mmin -%d" % (dir, time_diff_sec/60+1)
|
command = "find %s -type f -iname '*.ogg' -o -iname '*.mp3' -readable -mmin -%d" % (dir, time_diff_sec/60+1)
|
||||||
else:
|
else:
|
||||||
command = "find %s -type f -iname '*.ogg' -o -iname '*.mp3' -readable" % dir
|
command = "find %s -type f -iname '*.ogg' -o -iname '*.mp3' -readable" % dir
|
||||||
|
@ -85,9 +91,7 @@ class AirtimeMediaMonitorBootstrap():
|
||||||
self.logger.info("Modified files: \n%s\n\n"%modified_files_set)
|
self.logger.info("Modified files: \n%s\n\n"%modified_files_set)
|
||||||
|
|
||||||
#"touch" file timestamp
|
#"touch" file timestamp
|
||||||
open("/var/tmp/airtime/media_monitor_boot","w")
|
open("/var/tmp/airtime/.media_monitor_boot","w")
|
||||||
#return
|
|
||||||
|
|
||||||
|
|
||||||
for file_path in deleted_files_set:
|
for file_path in deleted_files_set:
|
||||||
self.pe.handle_removed_file(file_path)
|
self.pe.handle_removed_file(file_path)
|
||||||
|
|
|
@ -113,6 +113,7 @@ class AirtimeMetadata:
|
||||||
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.logger.error("failed getting metadata from %s", filepath)
|
self.logger.error("failed getting metadata from %s", filepath)
|
||||||
|
self.logger.error("Exception %s", e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,11 +64,14 @@ class AirtimeNotifier(Notifier):
|
||||||
self.md_manager.save_md_to_file(m)
|
self.md_manager.save_md_to_file(m)
|
||||||
|
|
||||||
elif m['event_type'] == "new_watch":
|
elif m['event_type'] == "new_watch":
|
||||||
self.logger.info("AIRTIME NOTIFIER add watched folder event " + m['directory'])
|
|
||||||
self.walk_newly_watched_directory(m['directory'])
|
|
||||||
|
|
||||||
mm = self.proc_fun()
|
mm = self.proc_fun()
|
||||||
mm.watch_directory(m['directory'])
|
if mm.has_correct_permissions(m['directory']):
|
||||||
|
self.logger.info("AIRTIME NOTIFIER add watched folder event " + m['directory'])
|
||||||
|
self.walk_newly_watched_directory(m['directory'])
|
||||||
|
|
||||||
|
mm.watch_directory(m['directory'])
|
||||||
|
else:
|
||||||
|
self.logger.warn("filepath '%s' has does not have sufficient read permissions. Ignoring.", full_filepath)
|
||||||
|
|
||||||
elif m['event_type'] == "remove_watch":
|
elif m['event_type'] == "remove_watch":
|
||||||
watched_directory = m['directory'].encode('utf-8')
|
watched_directory = m['directory'].encode('utf-8')
|
||||||
|
@ -170,7 +173,10 @@ class AirtimeNotifier(Notifier):
|
||||||
full_filepath = path+"/"+filename
|
full_filepath = path+"/"+filename
|
||||||
|
|
||||||
if mm.is_audio_file(full_filepath):
|
if mm.is_audio_file(full_filepath):
|
||||||
self.logger.info("importing %s", full_filepath)
|
if mm.has_correct_permissions(full_filepath):
|
||||||
event = {'filepath': full_filepath, 'mode': self.config.MODE_CREATE, 'is_recorded_show': False}
|
self.logger.info("importing %s", full_filepath)
|
||||||
mm.multi_queue.put(event)
|
event = {'filepath': full_filepath, 'mode': self.config.MODE_CREATE, 'is_recorded_show': False}
|
||||||
|
mm.multi_queue.put(event)
|
||||||
|
else:
|
||||||
|
self.logger.warn("file '%s' has does not have sufficient read permissions. Ignoring.", full_filepath)
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,13 @@ class AirtimeProcessEvent(ProcessEvent):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
#file needs to be readable by all users, and directories
|
||||||
|
#up to this file needs to be readable AND executable by all
|
||||||
|
#users.
|
||||||
|
def has_correct_permissions(self, filepath):
|
||||||
|
st = os.stat(filepath)
|
||||||
|
return bool(st.st_mode & stat.S_IROTH)
|
||||||
|
|
||||||
def set_needed_file_permissions(self, item, is_dir):
|
def set_needed_file_permissions(self, item, is_dir):
|
||||||
|
|
||||||
|
@ -100,7 +107,7 @@ class AirtimeProcessEvent(ProcessEvent):
|
||||||
omask = os.umask(0)
|
omask = os.umask(0)
|
||||||
os.rename(source, dest)
|
os.rename(source, dest)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.logger.error("failed to move file.")
|
self.logger.error("failed to move file. %s", e)
|
||||||
finally:
|
finally:
|
||||||
os.umask(omask)
|
os.umask(omask)
|
||||||
|
|
||||||
|
@ -289,7 +296,7 @@ class AirtimeProcessEvent(ProcessEvent):
|
||||||
if self.is_parent_directory(event.pathname, storage_directory):
|
if self.is_parent_directory(event.pathname, storage_directory):
|
||||||
file_md = self.md_manager.get_md_from_file(event.pathname)
|
file_md = self.md_manager.get_md_from_file(event.pathname)
|
||||||
if file_md is not None:
|
if file_md is not None:
|
||||||
filepath, is_recorded_show = self.create_file_path(event.pathname)
|
filepath, is_recorded_show = self.create_file_path(event.pathname, file_md)
|
||||||
self.move_file(event.pathname, filepath)
|
self.move_file(event.pathname, filepath)
|
||||||
self.renamed_files[event.pathname] = filepath
|
self.renamed_files[event.pathname] = filepath
|
||||||
self.file_events.append({'mode': self.config.MODE_CREATE, 'filepath': filepath, 'data': file_md, 'is_recorded_show': False})
|
self.file_events.append({'mode': self.config.MODE_CREATE, 'filepath': filepath, 'data': file_md, 'is_recorded_show': False})
|
||||||
|
|
|
@ -31,6 +31,9 @@ update_media_url = 'reload-metadata/format/json/api_key/%%api_key%%/mode/%%mode%
|
||||||
# URL to tell Airtime we want a listing of all files it knows about
|
# URL to tell Airtime we want a listing of all files it knows about
|
||||||
list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%'
|
list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%'
|
||||||
|
|
||||||
|
# URL to tell Airtime we want a listing of all dirs its watching (including the stor dir)
|
||||||
|
list_all_watched_dirs = 'list-all-watched-dirs/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%'
|
||||||
|
|
||||||
############################################
|
############################################
|
||||||
# RabbitMQ settings #
|
# RabbitMQ settings #
|
||||||
############################################
|
############################################
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue