From 3b94a602ede324965dcc0fcc8bddab01644c3261 Mon Sep 17 00:00:00 2001 From: artus Date: Sun, 18 Nov 2018 21:47:04 +0100 Subject: [PATCH] major refactoring --- photograb/__main__.py | 24 +---------- photograb/backup.py | 30 -------------- photograb/config.py | 17 ++------ photograb/grab.py | 21 ---------- photograb/main.py | 39 ++++++++++++++++++ photograb/store.py | 92 +++++++++++++++++++++++++++++++++++++++++++ photograb/sync.py | 37 ----------------- photograb/trash.py | 29 -------------- photograb/utils.py | 50 ----------------------- 9 files changed, 137 insertions(+), 202 deletions(-) delete mode 100644 photograb/backup.py delete mode 100644 photograb/grab.py create mode 100644 photograb/main.py create mode 100644 photograb/store.py delete mode 100644 photograb/sync.py delete mode 100644 photograb/trash.py delete mode 100644 photograb/utils.py diff --git a/photograb/__main__.py b/photograb/__main__.py index 46ad379..857d3e1 100644 --- a/photograb/__main__.py +++ b/photograb/__main__.py @@ -26,9 +26,7 @@ __version__ = "0.1" import argparse -from .grab import grab -from .sync import sync -from .trash import manage_trash +from .main import main parser = argparse.ArgumentParser() parser.add_argument('-a', '--all', action="store_true") @@ -38,31 +36,13 @@ parser.add_argument('-t', '--clean-trash', action="store_true") parser.add_argument('-u', '--update-card', action="store_true") parser.add_argument('--wipe-card', action="store_true") opts = parser.parse_args() - - # --all, -a : Perform all actions (except --wipe-card !) if opts.all: opts.grab = True opts.sync = True opts.clean_trash = True - # Do not update card if we are going to wipe it anyway. if opts.wipe_card: opts.update_card = False - print(opts) - -# --grab, -g : Grab the files -if opts.grab: - grab() -# --sync, -c : Synchronize deleted files -# --update-card, -u : Update the card too. -if opts.sync: - sync(update_card=opts.update_card) -# --wipe : Completely wipe the card. -if opts.wipe_card: - # TODO - pass -# --clean-trash, -t : Clean the trash. -if opts.clean_trash: - manage_trash() +main(opts) diff --git a/photograb/backup.py b/photograb/backup.py deleted file mode 100644 index a1fd6d9..0000000 --- a/photograb/backup.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding:utf-8 -*- - -from .config import BACKUP_PATH, TRASH_NAME -from .utils import copy_files, get_content - - -class Backup: - - def __init__(self): - from .config import BACKUP_CONF - self.stores = BACKUP_CONF - - def add(self, files): - """ Add a set of files to backup folder """ - - def sort_by_ext(content): - # Returns separate sets of files with valid extensions - return {} - - for ext, files in sort_by_ext(files): - backup_path = self.stores[ext] - copy_files(files, backup_path) - - - def list(self, exclude_trash=True): - """ List files in backup folders """ - return get_content( - BACKUP_PATH, - exclude=TRASH_NAME if exclude_trash else None, - ) diff --git a/photograb/config.py b/photograb/config.py index d3395df..3bf6c0d 100644 --- a/photograb/config.py +++ b/photograb/config.py @@ -3,17 +3,8 @@ import configparser from pathlib import Path -config = configparser.ConfigParser() -config.read("config.ini") +CONFIG = configparser.ConfigParser() +CONFIG.read("config.ini") -IMPORT_PATH = Path(config["GLOBAL"]["Import"]) -CAMERA_PATH = Path(config["GLOBAL"]["Camera"]) -BACKUP_CONF = dict() -for ext in config.sections(): - if ext == "GLOBAL": - continue - path = config[ext].get("Backup", None) - if path: - BACKUP_CONF[ext] = Path(path) - -TRASH_NAME = ".trash" +IMPORT_PATH = Path(CONFIG["GLOBAL"]["Import"]) +CAMERA_PATH = Path(CONFIG["GLOBAL"]["Camera"]) diff --git a/photograb/grab.py b/photograb/grab.py deleted file mode 100644 index d67710c..0000000 --- a/photograb/grab.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding:utf-8 -*- - -""" - Grab photos from camera and store them. -""" -from .utils import copy_files, get_content -from .config import CAMERA_PATH, IMPORT_PATH -from . import backup - - -def prepare_import(content): - copy_files(content, IMPORT_PATH) - - -def grab(): - # Get new files from camera - camera_files = get_content(CAMERA_PATH) - backup_files = backup.list(exclude_trash=False) - new_files = camera_files.difference(backup_files) - backup.add(new_files) - prepare_import(new_files) diff --git a/photograb/main.py b/photograb/main.py new file mode 100644 index 0000000..b02d78b --- /dev/null +++ b/photograb/main.py @@ -0,0 +1,39 @@ +# -*- coding:utf-8 -*- + +from .store import Content, Store, Backup +from .config import CONFIG, CAMERA_PATH + + +def find_deleted(): + return Content() + + +def main(opts): + camera = Store(CAMERA_PATH) + backups = { + ext: Backup(CONFIG[ext]['Backup']) + for ext in CONFIG.sections() + } + + if opts.grab: # Grab new files from camera + camera_files = camera.read_content() + for ext, backup in backups.items(): + bkp_files = backup.read_content(exclude_trash=False) + with_ext = camera_files.filter_by_ext(ext) + new_files = with_ext.difference(bkp_files) + backup.copy_files(new_files) + # prepare_import(new_files) + + if opts.sync: # Synchronize deleted files + deleted = find_deleted() + for ext, backup in backups.items(): + backup.trash_content(deleted.filter_by_ext(ext)) + if opts.update_card: + camera.remove_content(deleted) + + if opts.wipe_card: # Wipe the camera memory + pass + + if opts.clean_trash: # Clean the bins + for _, backup in backups.items(): + backup.clean_trash() diff --git a/photograb/store.py b/photograb/store.py new file mode 100644 index 0000000..a8db6af --- /dev/null +++ b/photograb/store.py @@ -0,0 +1,92 @@ +# -*- coding:utf-8 -*- +from pathlib import Path +import shutil +import os +import time + + +class Content(dict): + + def difference(self, other): + """ + Returns a new view containing only items from + this instance that are not present in the other + """ + my_keys = set(self.keys()) + your_keys = set(other.keys()) + new_keys = my_keys.difference(your_keys) + + def in_new_keys(item): + return item[0] in new_keys + + return Content(filter(in_new_keys, self.items())) + + def filter_by_ext(self, ext): + """ Returns a new view containing only items with file extension """ + ext = ext.lower() + + def has_extension(item): + return item[1].suffix[1:].lower() == ext + + return Content(filter(has_extension, self.items())) + + +class Store: + def __init__(self, path): + if not isinstance(path, Path): + path = Path(path) + if not path.exists(): + path.mkdir() + elif not path.is_dir(): + raise ValueError(f"{path} is not a folder !") + self.path = path + + def read_content(self, exclude=None): + content = Content() + for path, _, filenames in os.walk(self.path): + # Ignore excluded folders + if exclude and Path(path).absolute().name == exclude: + continue + for name in filenames: + content[name] = path + "/" + name + return content + + def copy_content(self, content): + print(f"Copy files to {self.path} : ", end="") + count = len(content) + start_time = time.process_time() + for name, path in content.items(): + shutil.copy2(str(path), self.path) + elapsed = time.process_time() - start_time + print(f"{count} in {elapsed:.2f}s.") + + def move_content(self, content): + print(f"Move files to {self.path} : ", end="") + count = len(content) + start_time = time.process_time() + for name, path in content.items(): + shutil.move(str(path), self.path) + elapsed = time.process_time() - start_time + print(f"{count} in {elapsed:.2f}s.") + + def remove_content(self, content): + print("Removing files from {self.path} : ", end="") + count = len(content) + start_time = time.process_time() + for name, path in content.items(): + shutil.rm(path) + elapsed = time.process_time() - start_time + print(f"{count} in {elapsed:.2f}s.") + + +class Backup(Store): + + def __init__(self, path): + super().__init__(path) + self.trash = Store(self.path / self.TRASH_NAME) + + def trash_content(self, content): + self.trash.move_content(content) + + def clean_trash(self): + raise NotImplementedError diff --git a/photograb/sync.py b/photograb/sync.py deleted file mode 100644 index 8289ca2..0000000 --- a/photograb/sync.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding:utf-8 -*- - -""" - Synchronize files from gallery. - - Mark deleted files from gallery, to be deleted at later time. -""" -import shutil -import time -from . import trash -from .utils import get_content, Content -from .config import CAMERA_PATH - - -def find_deleted(): - return Content() - - -def remove_trashed_from_card(): - print("Removing trashed files from camera : ", end="") - trashed = trash.list() - on_card = get_content(CAMERA_PATH) - del_count = 0 - start_time = time.process_time() - for name, path in on_card.items(): - if name in trashed: - shutil.rm(path) - del_count += 1 - elapsed = time.process_time() - start_time - print(f"{del_count} in {elapsed:.2f}s.") - - -def sync(update_card=False): - deleted = find_deleted() - trash.add(deleted) - if update_card: - remove_trashed_from_card() diff --git a/photograb/trash.py b/photograb/trash.py deleted file mode 100644 index c897a2f..0000000 --- a/photograb/trash.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding:utf-8 -*- - -""" - Trash container -""" -import os -from .utils import move_files, get_content -from .config import BACKUP_PATH, TRASH_NAME - -TRASH_PATH = BACKUP_PATH + TRASH_NAME - - -def add(files): - # Ensure trash folder exists - if not os.exists(TRASH_PATH): - os.mkdir(TRASH_PATH) - move_files(files, TRASH_PATH) - - -def list(): - return get_content(TRASH_PATH) - - -def manage_trash(): - """ Remove files that have been sitting there for too long """ - pass - - - diff --git a/photograb/utils.py b/photograb/utils.py deleted file mode 100644 index 9c0dca3..0000000 --- a/photograb/utils.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding:utf-8 -*- -import itertools -import os -import time -from pathlib import Path -import shutil - - -def copy_files(content, target_dir): - print(f"Copy files to {target_dir} : ", end="") - count = len(content) - start_time = time.process_time() - for name, path in content.items(): - shutil.copy2(str(path), target_dir) - elapsed = time.process_time() - start_time - print(f"{count} in {elapsed:.2f}s.") - - -def move_files(content, target_dir): - print(f"Move files to {target_dir} : ", end="") - count = len(content) - start_time = time.process_time() - for name, path in content.items(): - shutil.move(str(path), target_dir) - elapsed = time.process_time() - start_time - print(f"{count} in {elapsed:.2f}s.") - - -class Content(dict): - - def difference(self, other): - """ Returns a new dict that only contains items from - this instance that are not present in the other - """ - my_keys = set(self.keys()) - your_keys = set(other.keys()) - new_keys = my_keys.difference(your_keys) - return dict(filter(lambda i: i[0] in new_keys, self.items())) - - -def get_content(folder, exclude=None): - result = Content() - for path, _, filenames in os.walk(folder): - # Ignore excluded folders - if exclude and Path(path).absolute().name == exclude: - continue - - for name in filenames: - result[name] = path + "/" + name - return result