Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

This commit is contained in:
denise 2012-08-17 12:56:52 -04:00
commit 3e879f390a
8 changed files with 102 additions and 26 deletions

View file

@ -484,16 +484,10 @@ 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 $file->setFileExistsFlag(true);
$return_hash['error'] = "File already exists in Airtime."; $file->setMetadata($md);
return $return_hash;
} else {
// file marked as not exists
$file->setFileExistsFlag(true);
$file->setMetadata($md);
}
} }
} }
else if ($mode == "modify") { else if ($mode == "modify") {

View file

@ -138,7 +138,7 @@ var AIRTIME = (function(AIRTIME){
if (aMediaIds.length > 0) { if (aMediaIds.length > 0) {
AIRTIME.playlist.fnAddItems(aMediaIds, undefined, 'after'); AIRTIME.playlist.fnAddItems(aMediaIds, undefined, 'after');
} else { } else {
alert('You cannot add playlists to smart playlists'); alert('You can only add tracks to smart playlists.');
} }
}); });

View file

@ -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()))

View file

@ -10,7 +10,7 @@ from media.monitor.exceptions import BadSongFile
class PathChannel(object): class PathChannel(object):
def __init__(self, signal, path): def __init__(self, signal, path):
self.signal = signal self.signal = signal
self.path = path self.path = path
class EventRegistry(object): class EventRegistry(object):
""" """
@ -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):

View file

@ -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):

View file

@ -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):
""" """

View file

@ -19,9 +19,9 @@ class RequestSync(threading.Thread,Loggable):
""" """
def __init__(self, watcher, requests): def __init__(self, watcher, requests):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.watcher = watcher self.watcher = watcher
self.requests = requests self.requests = requests
self.retries = 1 self.retries = 1
self.request_wait = 0.3 self.request_wait = 0.3
@LazyProperty @LazyProperty
@ -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:

View 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()