unused.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. '''
  2. This component will look for files to be removed. There are some assumptions:
  3. * Only files in $TMPDIR are removed. Please remember that larigira has its
  4. own specific TMPDIR
  5. * MPD URIs are parsed, and only file:/// is supported
  6. '''
  7. import os
  8. from os.path import normpath
  9. import logging
  10. import mpd
  11. def old_commonpath(directories):
  12. if any(p for p in directories if p.startswith('/')) and \
  13. any(p for p in directories if not p.startswith('/')):
  14. raise ValueError("Can't mix absolute and relative paths")
  15. norm_paths = [normpath(p) + os.path.sep for p in directories]
  16. ret = os.path.dirname(os.path.commonprefix(norm_paths))
  17. if len(ret) > 0 and ret == '/' * len(ret):
  18. return '/'
  19. return ret
  20. try:
  21. from os.path import commonpath
  22. except ImportError:
  23. commonpath = old_commonpath
  24. class UnusedCleaner:
  25. def __init__(self, conf):
  26. self.conf = conf
  27. self.waiting_removal_files = set()
  28. self.log = logging.getLogger(self.__class__.__name__)
  29. def _get_mpd(self):
  30. mpd_client = mpd.MPDClient(use_unicode=True)
  31. mpd_client.connect(self.conf['MPD_HOST'], self.conf['MPD_PORT'])
  32. return mpd_client
  33. def watch(self, uri):
  34. '''
  35. adds fpath to the list of "watched" file
  36. as soon as it leaves the mpc playlist, it is removed
  37. '''
  38. if not uri.startswith('file:///'):
  39. return # not a file URI
  40. fpath = uri[len('file://'):]
  41. if 'TMPDIR' in self.conf and self.conf['TMPDIR'] \
  42. and commonpath([self.conf['TMPDIR'], fpath]) != \
  43. normpath(self.conf['TMPDIR']):
  44. self.log.info('Not watching file %s: not in TMPDIR', fpath)
  45. return
  46. if not os.path.exists(fpath):
  47. self.log.warning('a path that does not exist is being monitored')
  48. self.waiting_removal_files.add(fpath)
  49. def check_playlist(self):
  50. '''check playlist + internal watchlist to see what can be removed'''
  51. mpdc = self._get_mpd()
  52. files_in_playlist = {song['file'] for song in mpdc.playlistid()
  53. if song['file'].startswith('/')}
  54. for fpath in self.waiting_removal_files - files_in_playlist:
  55. # we can remove it!
  56. self.log.debug('removing unused: %s', fpath)
  57. self.waiting_removal_files.remove(fpath)
  58. if os.path.exists(fpath):
  59. os.unlink(fpath)