diff --git a/larigira/mpc.py b/larigira/mpc.py index 9925b8b..c291d02 100644 --- a/larigira/mpc.py +++ b/larigira/mpc.py @@ -9,6 +9,7 @@ from mpd import MPDClient, ConnectionError, CommandError from .event import Monitor from .eventutils import ParentedLet, Timer from .audiogen import audiogenerate +from .unused import UnusedCleaner def get_mpd_client(conf): @@ -99,6 +100,7 @@ class Controller(gevent.Greenlet): self.conf = conf self.q = Queue() self.player = Player(self.conf) + self.tmpcleaner = UnusedCleaner(conf) if 'DB_URI' in self.conf: self.monitor = Monitor(self.q, self.conf) self.monitor.parent_greenlet = self @@ -125,6 +127,7 @@ class Controller(gevent.Greenlet): if kind == 'timer' or (kind == 'mpc' and args[0] in ('player', 'playlist')): gevent.Greenlet.spawn(self.player.check_playlist) + self.tmpcleaner.check_playlist() elif kind == 'mpc': pass elif kind == 'uris_enqueue': @@ -135,6 +138,9 @@ class Controller(gevent.Greenlet): except Exception: self.log.exception("Error while adding to queue; " "bad audiogen output?") + else: + for fname in args[0]['uris']: + self.tmpcleaner.watch(fname) elif (kind == 'signal' and args[0] == signal.SIGALRM) or \ kind == 'refresh': # it's a tick! diff --git a/larigira/unused.py b/larigira/unused.py new file mode 100644 index 0000000..ccc75ab --- /dev/null +++ b/larigira/unused.py @@ -0,0 +1,46 @@ +''' +This component will look for files to be removed. There are some assumptions: + * Only files in $TMPDIR are removed. Please remember that larigira has its + own specific TMPDIR + * MPD URIs are parsed, and only file:/// is supported +''' +import os +import logging +import mpd + + +class UnusedCleaner: + def __init__(self, conf): + self.conf = conf + self.waiting_removal_files = set() + self.log = logging.getLogger(self.__class__.__name__) + + def _get_mpd(self): + mpd_client = mpd.MPDClient(use_unicode=True) + mpd_client.connect(self.conf['MPD_HOST'], self.conf['MPD_PORT']) + return mpd_client + + def watch(self, uri): + ''' + adds fpath to the list of "watched" file + + as soon as it leaves the mpc playlist, it is removed + ''' + if not uri.startswith('file:///'): + raise ValueError('not a file URI') + fpath = uri[len('file://'):] + if not os.path.exists(fpath): + self.log.warning('a path that does not exist is being monitored') + self.waiting_removal_files.add(fpath) + + def check_playlist(self): + '''check playlist + internal watchlist to see what can be removed''' + mpd = self._get_mpd() + files_in_playlist = {song['file'] for song in mpd.playlistid() + if song['file'].startswith('/')} + for fpath in self.waiting_removal_files - files_in_playlist: + # we can remove it! + self.log.debug('removing unused: {}'.format(fpath)) + self.waiting_removal_files.remove(fpath) + if os.path.exists(fpath): + os.unlink(fpath)