Code improvements
This commit is contained in:
parent
7688d0e7c4
commit
da4a388697
109
ordigi/cli.py
109
ordigi/cli.py
|
@ -1,8 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
@ -94,7 +92,7 @@ _sort_options = [
|
||||||
help="Use filename date for media original date.",
|
help="Use filename date for media original date.",
|
||||||
),
|
),
|
||||||
click.option(
|
click.option(
|
||||||
'--use-file-dates',
|
'--use-file-dates',
|
||||||
'-F',
|
'-F',
|
||||||
default=False,
|
default=False,
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
|
@ -102,6 +100,7 @@ _sort_options = [
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def print_help(command):
|
def print_help(command):
|
||||||
click.echo(command.get_help(click.Context(command)))
|
click.echo(command.get_help(click.Context(command)))
|
||||||
|
|
||||||
|
@ -127,7 +126,33 @@ def _get_paths(paths, root):
|
||||||
return paths, root
|
return paths, root
|
||||||
|
|
||||||
|
|
||||||
@click.command('check')
|
def _cli_get_location(collection):
|
||||||
|
gopt = collection.opt['Geolocation']
|
||||||
|
return GeoLocation(
|
||||||
|
{
|
||||||
|
'geocoder': gopt['geocoder'],
|
||||||
|
'prefer_english_names': gopt['prefer_english_names'],
|
||||||
|
'timeout': gopt['timeout'],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _cli_sort(collection, src_paths, import_mode, remove_duplicates):
|
||||||
|
loc = _cli_get_location(collection)
|
||||||
|
|
||||||
|
path_format = collection.opt['Path']['path_format']
|
||||||
|
|
||||||
|
return collection.sort_files(
|
||||||
|
src_paths, path_format, loc, import_mode, remove_duplicates
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def cli(**kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command('check')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@click.argument('path', required=True, nargs=1, type=click.Path())
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
||||||
def _check(**kwargs):
|
def _check(**kwargs):
|
||||||
|
@ -152,7 +177,7 @@ def _check(**kwargs):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@click.command('clean')
|
@cli.command('clean')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@add_options(_dry_run_options)
|
@add_options(_dry_run_options)
|
||||||
@add_options(_filter_options)
|
@add_options(_filter_options)
|
||||||
|
@ -202,9 +227,11 @@ def _clean(**kwargs):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO
|
# os.path.join(
|
||||||
|
# TODO make function to remove duplicates
|
||||||
|
# path_format = collection.opt['Path']['path_format']
|
||||||
# summary = collection.sort_files(
|
# summary = collection.sort_files(
|
||||||
# paths, remove_duplicates=kwargs['remove_duplicates']
|
# paths, path_format, None, remove_duplicates=kwargs['remove_duplicates']
|
||||||
# )
|
# )
|
||||||
|
|
||||||
if kwargs['path_string']:
|
if kwargs['path_string']:
|
||||||
|
@ -229,7 +256,7 @@ def _clean(**kwargs):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@click.command('compare')
|
@cli.command('compare')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@add_options(_dry_run_options)
|
@add_options(_dry_run_options)
|
||||||
@add_options(_filter_options)
|
@add_options(_filter_options)
|
||||||
|
@ -283,7 +310,7 @@ def _compare(**kwargs):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@click.command('init')
|
@cli.command('init')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@click.argument('path', required=True, nargs=1, type=click.Path())
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
||||||
def _init(**kwargs):
|
def _init(**kwargs):
|
||||||
|
@ -296,11 +323,7 @@ def _init(**kwargs):
|
||||||
|
|
||||||
collection = Collection(root)
|
collection = Collection(root)
|
||||||
|
|
||||||
# TODO retrieve collection.opt
|
loc = _cli_get_location(collection)
|
||||||
geocoder='Nominatim'
|
|
||||||
prefer_english_names=False
|
|
||||||
timeout=1
|
|
||||||
loc = GeoLocation(geocoder, prefer_english_names, timeout)
|
|
||||||
|
|
||||||
summary = collection.init(loc)
|
summary = collection.init(loc)
|
||||||
|
|
||||||
|
@ -308,7 +331,7 @@ def _init(**kwargs):
|
||||||
summary.print()
|
summary.print()
|
||||||
|
|
||||||
|
|
||||||
@click.command('import')
|
@cli.command('import')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@add_options(_input_options)
|
@add_options(_input_options)
|
||||||
@add_options(_dry_run_options)
|
@add_options(_dry_run_options)
|
||||||
|
@ -333,11 +356,6 @@ def _import(**kwargs):
|
||||||
|
|
||||||
src_paths, root = _get_paths(kwargs['src'], kwargs['dest'])
|
src_paths, root = _get_paths(kwargs['src'], kwargs['dest'])
|
||||||
|
|
||||||
if kwargs['copy']:
|
|
||||||
import_mode = 'copy'
|
|
||||||
else:
|
|
||||||
import_mode = 'move'
|
|
||||||
|
|
||||||
collection = Collection(
|
collection = Collection(
|
||||||
root,
|
root,
|
||||||
{
|
{
|
||||||
|
@ -351,19 +369,16 @@ def _import(**kwargs):
|
||||||
'glob': kwargs['glob'],
|
'glob': kwargs['glob'],
|
||||||
'dry_run': kwargs['dry_run'],
|
'dry_run': kwargs['dry_run'],
|
||||||
'interactive': kwargs['interactive'],
|
'interactive': kwargs['interactive'],
|
||||||
|
'path_format': kwargs['path_format'],
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO retrieve collection.opt
|
if kwargs['copy']:
|
||||||
# Use loc function
|
import_mode = 'copy'
|
||||||
geocoder='Nominatim'
|
else:
|
||||||
prefer_english_names=False
|
import_mode = 'move'
|
||||||
timeout=1
|
summary = _cli_sort(collection, src_paths, import_mode, kwargs['remove_duplicates'])
|
||||||
loc = GeoLocation(geocoder, prefer_english_names, timeout)
|
|
||||||
|
|
||||||
summary = collection.sort_files(
|
|
||||||
src_paths, kwargs['path_format'], loc, import_mode, kwargs['remove_duplicates']
|
|
||||||
)
|
|
||||||
|
|
||||||
if log_level < 30:
|
if log_level < 30:
|
||||||
summary.print()
|
summary.print()
|
||||||
|
@ -371,7 +386,8 @@ def _import(**kwargs):
|
||||||
if summary.errors:
|
if summary.errors:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@click.command('sort')
|
|
||||||
|
@cli.command('sort')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@add_options(_input_options)
|
@add_options(_input_options)
|
||||||
@add_options(_dry_run_options)
|
@add_options(_dry_run_options)
|
||||||
|
@ -414,15 +430,7 @@ def _sort(**kwargs):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO retrieve collection.opt
|
summary = _cli_sort(collection, paths, False, kwargs['remove_duplicates'])
|
||||||
geocoder='Nominatim'
|
|
||||||
prefer_english_names=False
|
|
||||||
timeout=1
|
|
||||||
loc = GeoLocation(geocoder, prefer_english_names, timeout)
|
|
||||||
|
|
||||||
summary = collection.sort_files(
|
|
||||||
paths, kwargs['path_format'], loc, kwargs['remove_duplicates']
|
|
||||||
)
|
|
||||||
|
|
||||||
if kwargs['clean']:
|
if kwargs['clean']:
|
||||||
collection.remove_empty_folders(root)
|
collection.remove_empty_folders(root)
|
||||||
|
@ -434,7 +442,7 @@ def _sort(**kwargs):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@click.command('update')
|
@cli.command('update')
|
||||||
@add_options(_logger_options)
|
@add_options(_logger_options)
|
||||||
@click.argument('path', required=True, nargs=1, type=click.Path())
|
@click.argument('path', required=True, nargs=1, type=click.Path())
|
||||||
def _update(**kwargs):
|
def _update(**kwargs):
|
||||||
|
@ -445,26 +453,13 @@ def _update(**kwargs):
|
||||||
log_level = log.get_level(kwargs['verbose'])
|
log_level = log.get_level(kwargs['verbose'])
|
||||||
log.console(LOG, level=log_level)
|
log.console(LOG, level=log_level)
|
||||||
|
|
||||||
geocoder='Nominatim'
|
|
||||||
prefer_english_names=False
|
|
||||||
timeout=1
|
|
||||||
loc = GeoLocation(geocoder, prefer_english_names, timeout)
|
|
||||||
collection = Collection(root)
|
collection = Collection(root)
|
||||||
|
loc = _cli_get_location(collection)
|
||||||
summary = collection.update(loc)
|
summary = collection.update(loc)
|
||||||
|
|
||||||
if log_level < 30:
|
if log_level < 30:
|
||||||
summary.print()
|
summary.print()
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
if __name__ == '__main__':
|
||||||
def main(**kwargs):
|
cli()
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
main.add_command(_clean)
|
|
||||||
main.add_command(_check)
|
|
||||||
main.add_command(_compare)
|
|
||||||
main.add_command(_init)
|
|
||||||
main.add_command(_import)
|
|
||||||
main.add_command(_sort)
|
|
||||||
main.add_command(_update)
|
|
||||||
|
|
|
@ -58,9 +58,9 @@ class FPath:
|
||||||
def get_early_morning_photos_date(self, date, mask):
|
def get_early_morning_photos_date(self, date, mask):
|
||||||
"""check for early hour photos to be grouped with previous day"""
|
"""check for early hour photos to be grouped with previous day"""
|
||||||
|
|
||||||
for i in '%H', '%M', '%S','%I', '%p', '%f':
|
for i in '%H', '%M', '%S', '%I', '%p', '%f':
|
||||||
|
# D'ont change date format if datestring contain hour, minutes or seconds.
|
||||||
if i in mask:
|
if i in mask:
|
||||||
# D'ont change date format if datestring contain hour, minutes or seconds...
|
|
||||||
return date.strftime(mask)
|
return date.strftime(mask)
|
||||||
|
|
||||||
if date.hour < self.day_begins:
|
if date.hour < self.day_begins:
|
||||||
|
@ -127,6 +127,7 @@ class FPath:
|
||||||
# Each item has its own custom logic and we evaluate a single item and return
|
# Each item has its own custom logic and we evaluate a single item and return
|
||||||
# the evaluated string.
|
# the evaluated string.
|
||||||
part = ''
|
part = ''
|
||||||
|
|
||||||
filename = metadata['filename']
|
filename = metadata['filename']
|
||||||
stem = os.path.splitext(filename)[0]
|
stem = os.path.splitext(filename)[0]
|
||||||
if item == 'stem':
|
if item == 'stem':
|
||||||
|
@ -515,7 +516,6 @@ class SortMedias:
|
||||||
else:
|
else:
|
||||||
self.summary.append('sort', False, src_path, dest_path)
|
self.summary.append('sort', False, src_path, dest_path)
|
||||||
|
|
||||||
|
|
||||||
def sort_file(self, src_path, dest_path, metadata, imp=False):
|
def sort_file(self, src_path, dest_path, metadata, imp=False):
|
||||||
"""Sort file and register it to db"""
|
"""Sort file and register it to db"""
|
||||||
if imp == 'copy':
|
if imp == 'copy':
|
||||||
|
@ -545,7 +545,7 @@ class SortMedias:
|
||||||
directory_path = self.root / relpath
|
directory_path = self.root / relpath
|
||||||
parts = directory_path.relative_to(self.root).parts
|
parts = directory_path.relative_to(self.root).parts
|
||||||
for i, _ in enumerate(parts):
|
for i, _ in enumerate(parts):
|
||||||
dir_path = self.root / Path(*parts[0 : i + 1])
|
dir_path = self.root / Path(*parts[0: i + 1])
|
||||||
if dir_path.is_file():
|
if dir_path.is_file():
|
||||||
self.log.warning(f'Target directory {dir_path} is a file')
|
self.log.warning(f'Target directory {dir_path} is a file')
|
||||||
# Rename the src_file
|
# Rename the src_file
|
||||||
|
@ -664,8 +664,9 @@ class SortMedias:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if conflicts != []:
|
if conflicts != []:
|
||||||
for files_data, conflict in self._solve_conflicts(conflicts,
|
for files_data, conflict in self._solve_conflicts(
|
||||||
remove_duplicates):
|
conflicts, remove_duplicates
|
||||||
|
):
|
||||||
|
|
||||||
src_path, dest_path, metadata = files_data
|
src_path, dest_path, metadata = files_data
|
||||||
if not conflict:
|
if not conflict:
|
||||||
|
@ -746,7 +747,7 @@ class Collection(SortMedias):
|
||||||
|
|
||||||
def get_config_options(self):
|
def get_config_options(self):
|
||||||
"""Get collection config"""
|
"""Get collection config"""
|
||||||
config = Config(self.root.joinpath('.ordigi', 'ordigi.conf'))
|
config = Config(self.root.joinpath('.ordigi', 'ordigi.conf'))
|
||||||
|
|
||||||
return config.get_config_options()
|
return config.get_config_options()
|
||||||
|
|
||||||
|
@ -760,7 +761,7 @@ class Collection(SortMedias):
|
||||||
exclude = self.exclude
|
exclude = self.exclude
|
||||||
|
|
||||||
paths = Paths(
|
paths = Paths(
|
||||||
filters = {
|
filters={
|
||||||
'exclude': exclude,
|
'exclude': exclude,
|
||||||
'extensions': None,
|
'extensions': None,
|
||||||
'glob': '**/*',
|
'glob': '**/*',
|
||||||
|
@ -839,7 +840,7 @@ class Collection(SortMedias):
|
||||||
metadata['src_path'] = row['SrcPath']
|
metadata['src_path'] = row['SrcPath']
|
||||||
# Check if row FilePath is a subpath of relpath
|
# Check if row FilePath is a subpath of relpath
|
||||||
if relpath.startswith(row['FilePath']):
|
if relpath.startswith(row['FilePath']):
|
||||||
path = os.path.relpath(relpath, row['FilePath'])
|
path = os.path.relpath(rlpath, row['FilePath'])
|
||||||
metadata['subdirs'] = row['Subdirs'] + path
|
metadata['subdirs'] = row['Subdirs'] + path
|
||||||
metadata['Filename'] = row['Filename']
|
metadata['Filename'] = row['Filename']
|
||||||
break
|
break
|
||||||
|
@ -859,7 +860,7 @@ class Collection(SortMedias):
|
||||||
checksum = utils.checksum(file_path)
|
checksum = utils.checksum(file_path)
|
||||||
relpath = file_path.relative_to(self.root)
|
relpath = file_path.relative_to(self.root)
|
||||||
if checksum == self.db.sqlite.get_checksum(relpath):
|
if checksum == self.db.sqlite.get_checksum(relpath):
|
||||||
self.summary.append('check',True, file_path)
|
self.summary.append('check', True, file_path)
|
||||||
else:
|
else:
|
||||||
self.log.error('{file_path} is corrupted')
|
self.log.error('{file_path} is corrupted')
|
||||||
self.summary.append('check', False, file_path)
|
self.summary.append('check', False, file_path)
|
||||||
|
@ -933,9 +934,9 @@ class Collection(SortMedias):
|
||||||
return self.summary
|
return self.summary
|
||||||
|
|
||||||
def sort_files(
|
def sort_files(
|
||||||
self, src_dirs, path_format, loc,
|
self, src_dirs, path_format, loc,
|
||||||
imp=False, remove_duplicates=False
|
imp=False, remove_duplicates=False
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Sort files into appropriate folder
|
Sort files into appropriate folder
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2,12 +2,10 @@ import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from configparser import RawConfigParser
|
from configparser import RawConfigParser
|
||||||
from os import path
|
|
||||||
from ordigi import constants
|
from ordigi import constants
|
||||||
from geopy.geocoders import options as gopt
|
from geopy.geocoders import options as gopt
|
||||||
|
|
||||||
|
|
||||||
# TODO make one method???
|
|
||||||
def check_option(getoption):
|
def check_option(getoption):
|
||||||
"""Check option type int or boolean"""
|
"""Check option type int or boolean"""
|
||||||
try:
|
try:
|
||||||
|
@ -18,6 +16,7 @@ def check_option(getoption):
|
||||||
else:
|
else:
|
||||||
return getoption
|
return getoption
|
||||||
|
|
||||||
|
|
||||||
def check_json(getoption):
|
def check_json(getoption):
|
||||||
"""Check if json string is valid"""
|
"""Check if json string is valid"""
|
||||||
try:
|
try:
|
||||||
|
@ -28,6 +27,7 @@ def check_json(getoption):
|
||||||
else:
|
else:
|
||||||
return getoption
|
return getoption
|
||||||
|
|
||||||
|
|
||||||
def check_re(getoption):
|
def check_re(getoption):
|
||||||
"""Check if regex string is valid"""
|
"""Check if regex string is valid"""
|
||||||
try:
|
try:
|
||||||
|
@ -165,9 +165,9 @@ class Config:
|
||||||
if option == 'geocoder' and value in ('Nominatim',):
|
if option == 'geocoder' and value in ('Nominatim',):
|
||||||
return self.conf[section][option]
|
return self.conf[section][option]
|
||||||
if option == 'glob':
|
if option == 'glob':
|
||||||
return self.conf[section][option]
|
|
||||||
if option == 'path_format':
|
|
||||||
return self.getre(section, option)
|
return self.getre(section, option)
|
||||||
|
if option == 'path_format':
|
||||||
|
return self.conf[section][option]
|
||||||
if option in multi_options:
|
if option in multi_options:
|
||||||
return set(self.getjson(section, option))
|
return set(self.getjson(section, option))
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from pathlib import Path
|
||||||
#: If True, debug messages will be printed.
|
#: If True, debug messages will be printed.
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
|
|
||||||
# Ordigi settings directory.
|
# Ordigi settings directory.
|
||||||
def get_config_dir(name):
|
def get_config_dir(name):
|
||||||
if 'XDG_CONFIG_HOME' in environ:
|
if 'XDG_CONFIG_HOME' in environ:
|
||||||
|
@ -19,6 +20,7 @@ def get_config_dir(name):
|
||||||
|
|
||||||
return confighome / name
|
return confighome / name
|
||||||
|
|
||||||
|
|
||||||
APPLICATION_DIRECTORY = get_config_dir('ordigi')
|
APPLICATION_DIRECTORY = get_config_dir('ordigi')
|
||||||
|
|
||||||
DEFAULT_PATH = '{%Y-%m-%b}/{album}|{city}'
|
DEFAULT_PATH = '{%Y-%m-%b}/{album}|{city}'
|
||||||
|
|
|
@ -30,4 +30,10 @@ exclude =
|
||||||
|
|
||||||
[options.entry_points]
|
[options.entry_points]
|
||||||
console_scripts =
|
console_scripts =
|
||||||
ordigi = ordigi.cli:main
|
ordigi = ordigi.cli:cli
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
|
||||||
|
[pycodestyle]
|
||||||
|
max-line-length = 88
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ class TestCollection:
|
||||||
src_checksum = utils.checksum(src_path)
|
src_checksum = utils.checksum(src_path)
|
||||||
summary = collection.sort_file(
|
summary = collection.sort_file(
|
||||||
src_path, dest_path, media.metadata, imp=imp
|
src_path, dest_path, media.metadata, imp=imp
|
||||||
)
|
)
|
||||||
assert not summary.errors
|
assert not summary.errors
|
||||||
# Ensure files remain the same
|
# Ensure files remain the same
|
||||||
assert collection._checkcomp(dest_path, src_checksum)
|
assert collection._checkcomp(dest_path, src_checksum)
|
||||||
|
|
Loading…
Reference in New Issue