コード例 #1
0
    def get_rows(self):
        try:
            return self._cursor.execute(''.join(self._select_movies))

        except sqlite3.DatabaseError as de:
            LOG.debug(de.message)
            raise PlexCleanerException("Unabled to fetch database rows {0}".format(de.message), severity=logging.ERROR)
コード例 #2
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def backup_database(db):
    backup_time = datetime.now().strftime('.%Y%m%d-%H%M')
    backup = os.path.join(os.path.expanduser('~'), ''.join([os.path.basename(db), backup_time, '.bak']))
    try:
        LOG.info("Creating backup for Plex database at {0}".format(backup))
        shutil.copy(db, backup)
        return True

    except (IOError, OSError) as oe:
        log_error(oe.errno, backup)
        raise PlexCleanerException('Unable to create database backup', severity=logging.ERROR)
コード例 #3
0
ファイル: media.py プロジェクト: aeldaly/plexcleaner
    def __init__(self, db):
        self.library = []
        self.library_paths = []
        self.effective_size = 0
        self.has_missing_file = False

        for row in db.get_rows():
            movie = Movie(*row)
            self._update_library(movie)

        LOG.info("There are {0} different media source".format(len(self.library_paths)))
        LOG.info("Library size is {0:0.3f} gigabyte".format(self.effective_size * self._B_TO_GB))
コード例 #4
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def copy_jacket(src, dst, skip):
    try:
        if os.path.isfile(dst) and skip:
            LOG.debug("Jacket '{0}' already exist, skip.".format(dst))
            return False

        shutil.copy(src, dst)
        return True

    except (IOError, OSError) as oe:
        log_error(oe.errno, dst)
        return False
コード例 #5
0
def copy_jacket(src, dst, skip):
    try:
        if os.path.isfile(dst) and skip:
            LOG.debug("Jacket '{0}' already exist, skip.".format(dst))
            return False

        shutil.copy(src, dst)
        return True

    except (IOError, OSError) as oe:
        log_error(oe.errno, dst)
        return False
コード例 #6
0
def backup_database(db):
    backup_time = datetime.now().strftime('.%Y%m%d-%H%M')
    backup = os.path.join(os.path.expanduser('~'),
                          ''.join([os.path.basename(db), backup_time, '.bak']))
    try:
        LOG.info("Creating backup for Plex database at {0}".format(backup))
        shutil.copy(db, backup)
        return True

    except (IOError, OSError) as oe:
        log_error(oe.errno, backup)
        raise PlexCleanerException('Unable to create database backup',
                                   severity=logging.ERROR)
コード例 #7
0
    def __init__(self, metadata_home='/var/lib/plexmediaserver',
                 database_override=None, database_name='com.plexapp.plugins.library.db'):

        sqlite = sqlite3.sqlite_version_info[:2]
        if sqlite < (3, 7):
            raise PlexCleanerException("SQLite bindings are not up to date "
                                       "(requires 3.7 current is {0}.{1})".format(*sqlite), severity=logging.ERROR)

        db = os.path.join(metadata_home, self._database_path, database_name)
        try:
            if database_override:
                db = database_override
                LOG.debug("User database override {0}".format(db))

            LOG.info("Reading Plex database located at {0}".format(db))
            self.filename = db
            self._connection = sqlite3.connect(db)
            self._cursor = self._connection.cursor()
            self._cursor.execute('ANALYZE')

        except sqlite3.OperationalError as oe:
            LOG.debug(oe)
            raise PlexCleanerException('Could not connect to Plex database', severity=logging.ERROR)

        except sqlite3.DatabaseError as de:
            LOG.debug(de.message)
            raise PlexCleanerException('Could not open Plex database (check permissions)', severity=logging.ERROR)
コード例 #8
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def move_media(src, dst, interrupt=False):
    try:
        LOG.debug(u"Copy file '{0}' to '{1}'".format(src, dst))
        if os.path.isfile(dst):
            LOG.debug(u"File '{0}' already exist, will override if not the same file.".format(src))

        shutil.move(src, dst)
        return True

    except (IOError, OSError) as oe:
        log_error(oe.errno, dst)

        if interrupt:
            raise PlexCleanerException('Media movie move error occurred (file missing)', severity=logging.CRITICAL)
コード例 #9
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def create_dir(dst):
    try:
        LOG.debug("Creating directory '{0}'.".format(dst))
        os.mkdir(dst)

        return True

    except OSError as e:
        if e.errno == errno.EEXIST:
            LOG.debug("Directory '{0}' already exist.".format(dst))
            return False

        raise PlexCleanerException("Unable to create directory '{0}' check permissions".format(dst),
                                   severity=logging.ERROR)
コード例 #10
0
def create_dir(dst):
    try:
        LOG.debug("Creating directory '{0}'.".format(dst))
        os.mkdir(dst)

        return True

    except OSError as e:
        if e.errno == errno.EEXIST:
            LOG.debug("Directory '{0}' already exist.".format(dst))
            return False

        raise PlexCleanerException(
            "Unable to create directory '{0}' check permissions".format(dst),
            severity=logging.ERROR)
コード例 #11
0
ファイル: media.py プロジェクト: aeldaly/plexcleaner
    def _update_library(self, movie):
        if int(movie.count) > 1:
            LOG.warning("Movie {0} has duplicate file. Will not process.".format(movie.original_file))
            return False

        self.library.append(movie)

        if movie.library_path not in self.library_paths:
            self.library_paths.append(movie.library_path)

        if movie.exist and movie.matched:  # Movie might be in the database but it might be absent in the filesystem
            self.effective_size += movie.size

        if not movie.exist:
            self.has_missing_file = True
            LOG.warning("The file {0} is missing from the library".format(movie.original_file))
コード例 #12
0
def move_media(src, dst, interrupt=False):
    try:
        LOG.debug(u"Copy file '{0}' to '{1}'".format(src, dst))
        if os.path.isfile(dst):
            LOG.debug(
                u"File '{0}' already exist, will override if not the same file."
                .format(src))

        shutil.move(src, dst)
        return True

    except (IOError, OSError) as oe:
        log_error(oe.errno, dst)

        if interrupt:
            raise PlexCleanerException(
                'Media movie move error occurred (file missing)',
                severity=logging.CRITICAL)
コード例 #13
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def log_error(err, dst):
    if err == errno.EACCES:
        LOG.error(u"Not enough permission on: {0}".format(dst))

    elif err == errno.ENOSPC:
        LOG.error(u"Not enough space on destination: {0}".format(os.path.dirname(dst)))

    elif err == errno.ENOENT:
        LOG.error(u"Unable to locate source file to copy to {0}".format(dst))

    else:
        LOG.error(u"Unknown error occurred while executing operation to destination: {0}".format(os.path.dirname(dst)))
コード例 #14
0
def log_error(err, dst):
    if err == errno.EACCES:
        LOG.error(u"Not enough permission on: {0}".format(dst))

    elif err == errno.ENOSPC:
        LOG.error(u"Not enough space on destination: {0}".format(
            os.path.dirname(dst)))

    elif err == errno.ENOENT:
        LOG.error(u"Unable to locate source file to copy to {0}".format(dst))

    else:
        LOG.error(
            u"Unknown error occurred while executing operation to destination: {0}"
            .format(os.path.dirname(dst)))
コード例 #15
0
 def update_row(self, mid, value):
     LOG.debug("Updating movie '{0}' with '{1}'".format(mid, value))
     self._cursor.execute(self._update_movie, (value, mid))
     self._uncommited = True
コード例 #16
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def clean(config):
    LOG.setLevel(logging.getLevelName(config.log_level))
    try:
        if config.update and is_plex_running():
            raise PlexCleanerException('Should not update database if Plex is running', severity=logging.ERROR)

        with database.Database(metadata_home=config.plex_home, database_override=config.database_override) as db:
            if config.database_backup:
                backup_database(db.filename)

            library = Library(db)

            if not len(library):
                raise PlexCleanerException('Library is empty', severity=logging.WARNING)

            if library.has_missing_file and config.interrupt:
                raise PlexCleanerException('Missing media file on the filesystem', severity=logging.WARNING)

            if config.export:
                LOG.info("Will consolidate library in: '{0}'".format(config.export))
                has_permission([config.export])
                space = get_free_fs_space(config.export)
                if library.effective_size > space:
                    raise PlexCleanerException('Remaining space on the target filesystem is not enough to export the '
                                               "library {0} Bytes > {1} Bytes".format(library.effective_size, space),
                                               severity=logging.CRITICAL)

            else:
                has_permission(library.library_paths)

            for movie in library:
                LOG.info(u"Processing: '{0}'".format(movie.basename))

                if movie.matched:
                    new_path = movie.get_correct_absolute_path(override=config.export)
                    create_dir(new_path)

                    jacket = os.path.join(new_path, config.jacket)
                    copy_jacket(movie.get_metadata_jacket(metadata_home=config.plex_home), jacket, config.skip_jacket)
                    # TODO: Copy SRT to library

                    moved = move_media(movie.original_file,
                                       movie.get_correct_absolute_file(override=config.export),
                                       config.interrupt)
                    if not moved:
                        LOG.info("{0} was not moved to {1}".format(movie.correct_title, new_path))

                    elif config.update and movie.need_update(override=config.export):
                        update_database(db, movie)

                else:
                    LOG.info(u"Movie '{0}' was not matched in Plex".format(movie.basename))

    except PlexCleanerException:
        LOG.warning('PlexCleaner did not process media library.')
        sys.exit(1)

    except KeyboardInterrupt:
        LOG.info('bye')
        sys.exit(0)
コード例 #17
0
ファイル: cleaner.py プロジェクト: nap/plexcleaner
def update_database(db, m):
    filename = m.get_correct_absolute_file()
    db.update_row(m.mid, filename)
    LOG.debug("Updating movie '{0}' with path '{1}'".format(m.correct_title, filename))
    return True
コード例 #18
0
 def update_many_row(self, values):
     LOG.debug("Updating {0} movies".format(len(values)))
     self._cursor.executemany(self._update_movie, values)
     self._uncommited = True
コード例 #19
0
 def commit(self):
     LOG.debug('Commiting last changes to database.')
     self._connection.commit()
     self._uncommited = False
コード例 #20
0
 def rollback(self):
     LOG.debug('Rollback last changes to database.')
     self._connection.rollback()
     self._uncommited = False
コード例 #21
0
def clean(config):
    LOG.setLevel(logging.getLevelName(config.log_level))
    try:
        if config.update and is_plex_running():
            raise PlexCleanerException(
                'Should not update database if Plex is running',
                severity=logging.ERROR)

        with database.Database(
                metadata_home=config.plex_home,
                database_override=config.database_override) as db:
            if config.database_backup:
                backup_database(db.filename)

            library = Library(db)

            if not len(library):
                raise PlexCleanerException('Library is empty',
                                           severity=logging.WARNING)

            if library.has_missing_file and config.interrupt:
                raise PlexCleanerException(
                    'Missing media file on the filesystem',
                    severity=logging.WARNING)

            if config.export:
                LOG.info("Will consolidate library in: '{0}'".format(
                    config.export))
                has_permission([config.export])
                space = get_free_fs_space(config.export)
                if library.effective_size > space:
                    raise PlexCleanerException(
                        'Remaining space on the target filesystem is not enough to export the '
                        "library {0} Bytes > {1} Bytes".format(
                            library.effective_size, space),
                        severity=logging.CRITICAL)

            else:
                has_permission(library.library_paths)

            for movie in library:
                LOG.info(u"Processing: '{0}'".format(movie.basename))

                if movie.matched:
                    new_path = movie.get_correct_absolute_path(
                        override=config.export)
                    create_dir(new_path)

                    jacket = os.path.join(new_path, config.jacket)
                    copy_jacket(
                        movie.get_metadata_jacket(
                            metadata_home=config.plex_home), jacket,
                        config.skip_jacket)
                    # TODO: Copy SRT to library

                    moved = move_media(
                        movie.original_file,
                        movie.get_correct_absolute_file(
                            override=config.export), config.interrupt)
                    if not moved:
                        LOG.info("{0} was not moved to {1}".format(
                            movie.correct_title, new_path))

                    elif config.update and movie.need_update(
                            override=config.export):
                        update_database(db, movie)

                else:
                    LOG.info(u"Movie '{0}' was not matched in Plex".format(
                        movie.basename))

    except PlexCleanerException:
        LOG.warning('PlexCleaner did not process media library.')
        sys.exit(1)

    except KeyboardInterrupt:
        LOG.info('bye')
        sys.exit(0)
コード例 #22
0
def update_database(db, m):
    filename = m.get_correct_absolute_file()
    db.update_row(m.mid, filename)
    LOG.debug("Updating movie '{0}' with path '{1}'".format(
        m.correct_title, filename))
    return True