major refactoring

This commit is contained in:
artus
2018-11-18 21:47:04 +01:00
parent 77fd72cb22
commit 3b94a602ed
9 changed files with 137 additions and 202 deletions

View File

@@ -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)

View File

@@ -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,
)

View File

@@ -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"])

View File

@@ -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)

39
photograb/main.py Normal file
View File

@@ -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()

92
photograb/store.py Normal file
View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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