Merge branch 'devel' of dev.sourcefabric.org:airtime into devel
This commit is contained in:
commit
99437147dc
11 changed files with 133 additions and 38 deletions
|
@ -484,18 +484,12 @@ class ApiController extends Zend_Controller_Action
|
||||||
if (is_null($file)) {
|
if (is_null($file)) {
|
||||||
$file = Application_Model_StoredFile::Insert($md);
|
$file = Application_Model_StoredFile::Insert($md);
|
||||||
} else {
|
} else {
|
||||||
// path already exist
|
// If the file already exists we will update and make sure that
|
||||||
if ($file->getFileExistsFlag()) {
|
// it's marked as 'exists'.
|
||||||
// file marked as exists
|
|
||||||
$return_hash['error'] = "File already exists in Airtime.";
|
|
||||||
return $return_hash;
|
|
||||||
} else {
|
|
||||||
// file marked as not exists
|
|
||||||
$file->setFileExistsFlag(true);
|
$file->setFileExistsFlag(true);
|
||||||
$file->setMetadata($md);
|
$file->setMetadata($md);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ($mode == "modify") {
|
else if ($mode == "modify") {
|
||||||
$filepath = $md['MDATA_KEY_FILEPATH'];
|
$filepath = $md['MDATA_KEY_FILEPATH'];
|
||||||
$file = Application_Model_StoredFile::RecallByFilepath($filepath);
|
$file = Application_Model_StoredFile::RecallByFilepath($filepath);
|
||||||
|
|
|
@ -311,13 +311,27 @@ var AIRTIME = (function(AIRTIME){
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFadeIcon(){
|
function setFadeIcon(){
|
||||||
|
var contents = $("#spl_sortable");
|
||||||
|
var show = contents.is(":visible");
|
||||||
var empty = $(".spl_empty");
|
var empty = $(".spl_empty");
|
||||||
if (empty.length > 0) {
|
|
||||||
|
if (!show || empty.length > 0) {
|
||||||
|
$("#spl_crossfade").hide();
|
||||||
|
} else {
|
||||||
|
//get list of playlist contents
|
||||||
|
var list = contents.children();
|
||||||
|
|
||||||
|
//if first and last items are blocks, hide the fade icon
|
||||||
|
var first = list.first();
|
||||||
|
var last = list.last();
|
||||||
|
if (first.find(':first-child').children().attr('blockid') !== undefined &&
|
||||||
|
last.find(':first-child').children().attr('blockid') !== undefined) {
|
||||||
$("#spl_crossfade").hide();
|
$("#spl_crossfade").hide();
|
||||||
} else {
|
} else {
|
||||||
$("#spl_crossfade").show();
|
$("#spl_crossfade").show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getId() {
|
function getId() {
|
||||||
return parseInt($("#obj_id").val(), 10);
|
return parseInt($("#obj_id").val(), 10);
|
||||||
|
@ -468,8 +482,10 @@ var AIRTIME = (function(AIRTIME){
|
||||||
fadeOut.show();
|
fadeOut.show();
|
||||||
fadeOut.empty().append(json.fadeOut);
|
fadeOut.empty().append(json.fadeOut);
|
||||||
}
|
}
|
||||||
|
if (json.fadeIn != null || json.fadeOut != null) {
|
||||||
$pl.find("#crossfade_main").show();
|
$pl.find("#crossfade_main").show();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -889,6 +905,7 @@ var AIRTIME = (function(AIRTIME){
|
||||||
setPlaylistEntryEvents();
|
setPlaylistEntryEvents();
|
||||||
setCueEvents();
|
setCueEvents();
|
||||||
setFadeEvents();
|
setFadeEvents();
|
||||||
|
setFadeIcon();
|
||||||
|
|
||||||
initialEvents();
|
initialEvents();
|
||||||
setUpPlaylist();
|
setUpPlaylist();
|
||||||
|
|
|
@ -239,16 +239,6 @@ function getRowIndex(ele) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFadeIcon(){
|
|
||||||
var contents = $("#spl_sortable");
|
|
||||||
var show = contents.is(":visible");
|
|
||||||
if (show) {
|
|
||||||
$("#spl_crossfade").show();
|
|
||||||
} else {
|
|
||||||
$("#spl_crossfade").hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function appends a '+' button for the last
|
/* This function appends a '+' button for the last
|
||||||
* modifier row of each criteria.
|
* modifier row of each criteria.
|
||||||
* If there are no modifier rows, the '+' button
|
* If there are no modifier rows, the '+' button
|
||||||
|
|
|
@ -29,6 +29,7 @@ class EventContractor(Loggable):
|
||||||
some other event in the storage was morphed into this newer one.
|
some other event in the storage was morphed into this newer one.
|
||||||
Which should mean that the old event should be discarded.
|
Which should mean that the old event should be discarded.
|
||||||
"""
|
"""
|
||||||
|
self.logger.info("Attempting to register: '%s'" % str(evt))
|
||||||
if self.event_registered(evt):
|
if self.event_registered(evt):
|
||||||
old_e = self.get_old_event(evt)
|
old_e = self.get_old_event(evt)
|
||||||
# TODO : Perhaps there are other events that we can "contract"
|
# TODO : Perhaps there are other events that we can "contract"
|
||||||
|
@ -42,11 +43,20 @@ class EventContractor(Loggable):
|
||||||
elif isinstance(evt, DeleteFile):
|
elif isinstance(evt, DeleteFile):
|
||||||
old_e.morph_into(evt)
|
old_e.morph_into(evt)
|
||||||
return False
|
return False
|
||||||
|
# Unregister the old event anyway, because we only want to keep
|
||||||
|
# track of the old one. This means that the old event cannot be
|
||||||
|
# morphed again and new events with the same path will only be
|
||||||
|
# checked against the newest event 'evt' in this case
|
||||||
|
self.unregister( old_e )
|
||||||
evt.add_safe_pack_hook( lambda : self.__unregister(evt) )
|
evt.add_safe_pack_hook( lambda : self.__unregister(evt) )
|
||||||
self.store[ evt.path ] = evt
|
self.store[ evt.path ] = evt
|
||||||
return True # We actually added something, hence we return true.
|
return True # We actually added something, hence we return true.
|
||||||
|
|
||||||
|
def unregister(self, evt):
|
||||||
|
evt.reset_hook()
|
||||||
|
|
||||||
def __unregister(self, evt):
|
def __unregister(self, evt):
|
||||||
self.logger.info("Unregistering. Left: '%d'" % len(self.store.keys()))
|
|
||||||
try: del self.store[evt.path]
|
try: del self.store[evt.path]
|
||||||
except Exception as e: self.unexpected_exception(e)
|
except Exception as e:
|
||||||
|
self.unexpected_exception(e)
|
||||||
|
self.logger.info("Unregistering. Left: '%d'" % len(self.store.keys()))
|
||||||
|
|
|
@ -59,6 +59,10 @@ class BaseEvent(Loggable):
|
||||||
self._pack_hook = lambda: None # no op
|
self._pack_hook = lambda: None # no op
|
||||||
# into another event
|
# into another event
|
||||||
|
|
||||||
|
def reset_hook(self):
|
||||||
|
self._pack_hook()
|
||||||
|
self._pack_hook = lambda: None
|
||||||
|
|
||||||
def exists(self): return os.path.exists(self.path)
|
def exists(self): return os.path.exists(self.path)
|
||||||
|
|
||||||
@LazyProperty
|
@LazyProperty
|
||||||
|
@ -84,8 +88,8 @@ class BaseEvent(Loggable):
|
||||||
# pack will only throw an exception if it processes one file but this
|
# pack will only throw an exception if it processes one file but this
|
||||||
# is a little bit hacky
|
# is a little bit hacky
|
||||||
try:
|
try:
|
||||||
ret = self.pack()
|
|
||||||
self._pack_hook()
|
self._pack_hook()
|
||||||
|
ret = self.pack()
|
||||||
return ret
|
return ret
|
||||||
except BadSongFile as e: return [e]
|
except BadSongFile as e: return [e]
|
||||||
|
|
||||||
|
@ -95,7 +99,7 @@ class BaseEvent(Loggable):
|
||||||
self._raw_event = evt
|
self._raw_event = evt
|
||||||
self.path = evt.path
|
self.path = evt.path
|
||||||
self.__class__ = evt.__class__
|
self.__class__ = evt.__class__
|
||||||
self.add_safe_pack_hook(evt._pack_hook)
|
# We don't transfer the _pack_hook over to the new event
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class FakePyinotify(object):
|
class FakePyinotify(object):
|
||||||
|
@ -104,8 +108,7 @@ class FakePyinotify(object):
|
||||||
instantiate objects from the classes below whenever we want to turn
|
instantiate objects from the classes below whenever we want to turn
|
||||||
a single event into multiple events
|
a single event into multiple events
|
||||||
"""
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path): self.pathname = path
|
||||||
self.pathname = path
|
|
||||||
|
|
||||||
class OrganizeFile(BaseEvent, HasMetaData):
|
class OrganizeFile(BaseEvent, HasMetaData):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -88,7 +88,7 @@ class OrganizeListener(BaseListener, pyinotify.ProcessEvent, Loggable):
|
||||||
dispatcher.send(signal=self.signal, sender=self,
|
dispatcher.send(signal=self.signal, sender=self,
|
||||||
event=OrganizeFile(f))
|
event=OrganizeFile(f))
|
||||||
flushed += 1
|
flushed += 1
|
||||||
self.logger.info("Flushed organized directory with %d files" % flushed)
|
#self.logger.info("Flushed organized directory with %d files" % flushed)
|
||||||
|
|
||||||
@IncludeOnly(mmp.supported_extensions)
|
@IncludeOnly(mmp.supported_extensions)
|
||||||
def process_to_organize(self, event):
|
def process_to_organize(self, event):
|
||||||
|
|
|
@ -20,7 +20,7 @@ class ManagerTimeout(threading.Thread,Loggable):
|
||||||
while True:
|
while True:
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
self.manager.flush_organize()
|
self.manager.flush_organize()
|
||||||
self.logger.info("Force flushed organize...")
|
#self.logger.info("Force flushed organize...")
|
||||||
|
|
||||||
class Manager(Loggable):
|
class Manager(Loggable):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -124,9 +124,8 @@ class WatchSyncer(ReportHandler,Loggable):
|
||||||
try:
|
try:
|
||||||
# If there is a strange bug anywhere in the code the next line
|
# If there is a strange bug anywhere in the code the next line
|
||||||
# should be a suspect
|
# should be a suspect
|
||||||
#if self.contractor.register( event ):
|
if self.contractor.register(event): self.push_queue( event )
|
||||||
#self.push_queue( event )
|
#self.push_queue( event )
|
||||||
self.push_queue( event )
|
|
||||||
except BadSongFile as e:
|
except BadSongFile as e:
|
||||||
self.fatal_exception("Received bas song file '%s'" % e.path, e)
|
self.fatal_exception("Received bas song file '%s'" % e.path, e)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
70
python_apps/media-monitor2/tests/test_eventcontractor.py
Normal file
70
python_apps/media-monitor2/tests/test_eventcontractor.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import unittest
|
||||||
|
from media.monitor.eventcontractor import EventContractor
|
||||||
|
#from media.monitor.exceptions import BadSongFile
|
||||||
|
from media.monitor.events import FakePyinotify, NewFile, MoveFile, \
|
||||||
|
DeleteFile
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
class TestMMP(unittest.TestCase):
|
||||||
|
def test_event_registered(self):
|
||||||
|
ev = EventContractor()
|
||||||
|
e1 = NewFile( FakePyinotify('bullshit.mp3') )
|
||||||
|
e2 = MoveFile( FakePyinotify('bullshit.mp3') )
|
||||||
|
ev.register(e1)
|
||||||
|
self.assertTrue( ev.event_registered(e2) )
|
||||||
|
|
||||||
|
def test_get_old_event(self):
|
||||||
|
ev = EventContractor()
|
||||||
|
e1 = NewFile( FakePyinotify('bullshit.mp3') )
|
||||||
|
e2 = MoveFile( FakePyinotify('bullshit.mp3') )
|
||||||
|
ev.register(e1)
|
||||||
|
self.assertEqual( ev.get_old_event(e2), e1 )
|
||||||
|
|
||||||
|
def test_register(self):
|
||||||
|
ev = EventContractor()
|
||||||
|
e1 = NewFile( FakePyinotify('bullshit.mp3') )
|
||||||
|
e2 = DeleteFile( FakePyinotify('bullshit.mp3') )
|
||||||
|
self.assertTrue( ev.register(e1) )
|
||||||
|
|
||||||
|
# Check that morph_into is called when it should be
|
||||||
|
with patch.object(NewFile, 'morph_into', return_value='kimchi') \
|
||||||
|
as mock_method:
|
||||||
|
ret = ev.register(e2)
|
||||||
|
self.assertFalse(ret)
|
||||||
|
mock_method.assert_called_once_with(e2)
|
||||||
|
|
||||||
|
# This time we are not patching morph
|
||||||
|
self.assertFalse( ev.register(e2) )
|
||||||
|
# We did not an element
|
||||||
|
self.assertTrue( len(ev.store.keys()) == 1 )
|
||||||
|
morphed = ev.get_old_event(e2)
|
||||||
|
self.assertTrue( isinstance(morphed, DeleteFile) )
|
||||||
|
|
||||||
|
delete_ev = e1.safe_pack()[0]
|
||||||
|
print( ev.store )
|
||||||
|
self.assertEqual( delete_ev['mode'], u'delete')
|
||||||
|
self.assertTrue( len(ev.store.keys()) == 0 )
|
||||||
|
|
||||||
|
e3 = DeleteFile( FakePyinotify('horseshit.mp3') )
|
||||||
|
self.assertTrue( ev.register(e3) )
|
||||||
|
self.assertTrue( ev.register(e2) )
|
||||||
|
|
||||||
|
|
||||||
|
def test_register2(self):
|
||||||
|
ev = EventContractor()
|
||||||
|
p = 'bullshit.mp3'
|
||||||
|
events = [
|
||||||
|
NewFile( FakePyinotify(p) ),
|
||||||
|
NewFile( FakePyinotify(p) ),
|
||||||
|
DeleteFile( FakePyinotify(p) ),
|
||||||
|
NewFile( FakePyinotify(p) ),
|
||||||
|
NewFile( FakePyinotify(p) ), ]
|
||||||
|
actual_events = []
|
||||||
|
for e in events:
|
||||||
|
if ev.register(e):
|
||||||
|
actual_events.append(e)
|
||||||
|
self.assertEqual( len(ev.store.keys()), 1 )
|
||||||
|
packed = [ x.safe_pack() for x in actual_events ]
|
||||||
|
print(packed)
|
||||||
|
|
||||||
|
if __name__ == '__main__': unittest.main()
|
Binary file not shown.
12
python_apps/python-virtualenv/requirements
Normal file
12
python_apps/python-virtualenv/requirements
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
argparse==1.2.1
|
||||||
|
amqplib==1.0.2
|
||||||
|
PyDispatcher==2.0.3
|
||||||
|
anyjson==0.3.3
|
||||||
|
kombu==2.2.6
|
||||||
|
pyinotify==0.9.3
|
||||||
|
poster==0.8.1
|
||||||
|
pytz==2011k
|
||||||
|
wsgiref==0.1.2
|
||||||
|
configobj==4.7.2
|
||||||
|
mutagen==1.20
|
||||||
|
docopt==0.4.2
|
Loading…
Add table
Add a link
Reference in a new issue