sintonia/python_apps/media-monitor2/media/monitor/bootstrap.py

72 lines
3.4 KiB
Python

import os
from pydispatch import dispatcher
from media.monitor.events import OrganizeFile, NewFile, DeleteFile
from media.monitor.log import Loggable
import media.monitor.pure as mmp
class Bootstrapper(Loggable):
"""
Bootstrapper reads all the info in the filesystem flushes organize
events and watch events
"""
def __init__(self,db,last_run,org_channels,watch_channels):
self.db = db
self.org_channels = org_channels
self.watch_channels = watch_channels
self.last_run = last_run
def flush_organize(self):
"""
walks the organize directories and sends an organize event for every file manually
"""
flushed = 0
for pc in self.org_channels:
for f in mmp.walk_supported(pc.path, clean_empties=True):
self.logger.info("Bootstrapping: File in 'organize' directory: '%s'" % f)
dispatcher.send(signal=pc.signal, sender=self, event=OrganizeFile(f))
flushed += 1
self.logger.info("Flushed organized directory with %d files" % flushed)
def flush_watch(self):
"""
Syncs the file system into the database. Walks over deleted/new/modified files since
the last run in mediamonitor and sends requests to make the database consistent with
file system
"""
# Songs is a dictionary where every key is the watched the directory
# and the value is a set with all the files in that directory.
songs = {}
modded = deleted = 0
signal_by_path = dict( (pc.signal, pc.path) for pc in self.watch_channels )
for pc in self.watch_channels:
songs[ pc.path ] = set()
for f in mmp.walk_supported(pc.path, clean_empties=False):
songs[ pc.path ].add(f)
# We decide whether to update a file's metadata by checking
# its system modification date. If it's above the value
# self.last_run which is passed to us that means media monitor
# wasn't aware when this changes occured in the filesystem
# hence it will send the correct events to sync the database
# with the filesystem
if os.path.getmtime(f) > self.last_run:
modded += 1
dispatcher.send(signal=pc.signal, sender=self, event=DeleteFile(f))
dispatcher.send(signal=pc.signal, sender=self, event=NewFile(f))
# Want all files in the database that are not in the filesystem
for watch_dir in self.db.list_directories():
db_songs = self.db.directory_get_files(watch_dir)
# Get all the files that are in the database but in the file
# system. These are the files marked for deletions
for to_delete in db_songs.difference(songs[watch_dir]):
# need the correct watch channel signal to call delete
if watch_dir in signal_by_path:
dispatcher.send(signal=signal_by_path[watch_dir], sender=self, event=DeleteFile(f))
os.remove(to_delete)
deleted += 1
else:
self.logger.error("Could not find the signal corresponding to path: '%s'" % watch_dir)
self.logger.info( "Flushed watch directories. (modified, deleted) = (%d, %d)"
% (modded, deleted) )