#!/usr/bin/python # coding: utf-8 # This file is part of Supysonic. # # Supysonic is a Python implementation of the Subsonic server API. # Copyright (C) 2014 Alban 'spl0k' FĂ©ron # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import time, sys import logging from logging.handlers import TimedRotatingFileHandler from watchdog.observers import Observer from watchdog.events import PatternMatchingEventHandler from supysonic import config from supysonic.scanner import Scanner class SupysonicWatcherEventHandler(PatternMatchingEventHandler): def __init__(self, logger): extensions = config.get('base', 'scanner_extensions') patterns = map(lambda e: "*." + e.lower(), extensions.split()) if extensions else None super(SupysonicWatcherEventHandler, self).__init__(patterns = patterns, ignore_directories = True) self.__logger = logger def on_created(self, event): self.__logger.debug("Scanning created file %s", event.src_path) Scanner(db.session).scan_file(event.src_path) db.session.commit() def on_deleted(self, event): self.__logger.debug("File %s deleted", event.src_path) track = db.Track.query.filter(db.Track.path == event.src_path).first() if track: folder = track.root_folder Scanner(db.session).prune(folder) db.session.commit() else: self.__logger.debug("Deleted file %s not in the database", event.src_path) def on_modified(self, event): self.__logger.debug("Scanning modified file %s", event.src_path) Scanner(db.session).scan_file(event.src_path) db.session.commit() def on_moved(self, event): pass if __name__ == "__main__": if not config.check(): sys.exit(1) logger = logging.getLogger(__name__) if config.get('daemon', 'log_file'): log_handler = TimedRotatingFileHandler(config.get('daemon', 'log_file'), when = 'midnight') else: log_handler = logging.NullHandler() log_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")) logger.addHandler(log_handler) if config.get('daemon', 'log_level'): mapping = { 'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARNING': logging.WARNING, 'ERROR': logging.ERROR, 'CRTICAL': logging.CRITICAL } logger.setLevel(mapping.get(config.get('daemon', 'log_level').upper(), logging.NOTSET)) from supysonic import db db.init_db() if not db.Folder.query.filter(db.Folder.root == True).count(): logger.info("No folder set. Exiting.") sys.exit(0) handler = SupysonicWatcherEventHandler(logger) observer = Observer() for folder in db.Folder.query.filter(db.Folder.root == True): logger.info("Starting watcher for %s", folder.path) observer.schedule(handler, folder.path, recursive = True) observer.start() try: while True: time.sleep(1) except KeyboardInterrupt: logger.info("Stopping watcher") observer.stop() observer.join()