add local files
This commit is contained in:
parent
f5faa70bc8
commit
795ef36da5
|
@ -0,0 +1,119 @@
|
||||||
|
<map version="freeplane 1.7.0">
|
||||||
|
<!--To view this file, download free mind mapping software Freeplane from http://freeplane.sourceforge.net -->
|
||||||
|
<node TEXT="elodie" FOLDED="false" ID="ID_577640973" CREATED="1624709002278" MODIFIED="1624709019473" STYLE="oval"><hook NAME="MapStyle">
|
||||||
|
<conditional_styles>
|
||||||
|
<conditional_style ACTIVE="true" LOCALIZED_STYLE_REF="styles.connection" LAST="false">
|
||||||
|
<node_periodic_level_condition PERIOD="2" REMAINDER="1"/>
|
||||||
|
</conditional_style>
|
||||||
|
<conditional_style ACTIVE="true" LOCALIZED_STYLE_REF="styles.topic" LAST="false">
|
||||||
|
<node_level_condition VALUE="2" MATCH_CASE="false" MATCH_APPROXIMATELY="false" COMPARATION_RESULT="0" SUCCEED="true"/>
|
||||||
|
</conditional_style>
|
||||||
|
<conditional_style ACTIVE="true" LOCALIZED_STYLE_REF="styles.subtopic" LAST="false">
|
||||||
|
<node_level_condition VALUE="4" MATCH_CASE="false" MATCH_APPROXIMATELY="false" COMPARATION_RESULT="0" SUCCEED="true"/>
|
||||||
|
</conditional_style>
|
||||||
|
<conditional_style ACTIVE="true" LOCALIZED_STYLE_REF="styles.subsubtopic" LAST="false">
|
||||||
|
<node_level_condition VALUE="6" MATCH_CASE="false" MATCH_APPROXIMATELY="false" COMPARATION_RESULT="0" SUCCEED="true"/>
|
||||||
|
</conditional_style>
|
||||||
|
</conditional_styles>
|
||||||
|
<properties edgeColorConfiguration="#808080ff,#ff0000ff,#0000ffff,#00ff00ff,#ff00ffff,#00ffffff,#7c0000ff,#00007cff,#007c00ff,#7c007cff,#007c7cff,#7c7c00ff" fit_to_viewport="false" show_note_icons="true"/>
|
||||||
|
|
||||||
|
<map_styles>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.root_node" STYLE="oval" UNIFORM_SHAPE="true" VGAP_QUANTITY="24.0 pt">
|
||||||
|
<font SIZE="24"/>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.predefined" POSITION="right" STYLE="bubble">
|
||||||
|
<stylenode LOCALIZED_TEXT="default" ICON_SIZE="12.0 pt" COLOR="#000000" STYLE="fork">
|
||||||
|
<font NAME="Arial" SIZE="10" BOLD="false" ITALIC="false"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="defaultstyle.details"/>
|
||||||
|
<stylenode LOCALIZED_TEXT="defaultstyle.attributes">
|
||||||
|
<font SIZE="9"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="defaultstyle.note" COLOR="#000000" BACKGROUND_COLOR="#ffffff" TEXT_ALIGN="LEFT"/>
|
||||||
|
<stylenode LOCALIZED_TEXT="defaultstyle.floating">
|
||||||
|
<edge STYLE="hide_edge"/>
|
||||||
|
<cloud COLOR="#f0f0f0" SHAPE="ROUND_RECT"/>
|
||||||
|
</stylenode>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.user-defined" POSITION="right" STYLE="bubble">
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.topic" COLOR="#18898b" STYLE="fork">
|
||||||
|
<font NAME="Liberation Sans" SIZE="10" BOLD="true"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.subtopic" COLOR="#cc3300" STYLE="fork">
|
||||||
|
<font NAME="Liberation Sans" SIZE="10" BOLD="true"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.subsubtopic" COLOR="#669900">
|
||||||
|
<font NAME="Liberation Sans" SIZE="10" BOLD="true"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.connection" COLOR="#606060" STYLE="fork">
|
||||||
|
<font NAME="Arial" SIZE="8" BOLD="false"/>
|
||||||
|
</stylenode>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="styles.AutomaticLayout" POSITION="right" STYLE="bubble">
|
||||||
|
<stylenode LOCALIZED_TEXT="AutomaticLayout.level.root" COLOR="#000000" STYLE="oval">
|
||||||
|
<font SIZE="18"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="AutomaticLayout.level,1" COLOR="#0033ff">
|
||||||
|
<font SIZE="16"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="AutomaticLayout.level,2" COLOR="#00b439">
|
||||||
|
<font SIZE="14"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="AutomaticLayout.level,3" COLOR="#990000">
|
||||||
|
<font SIZE="12"/>
|
||||||
|
</stylenode>
|
||||||
|
<stylenode LOCALIZED_TEXT="AutomaticLayout.level,4" COLOR="#111111">
|
||||||
|
<font SIZE="10"/>
|
||||||
|
</stylenode>
|
||||||
|
</stylenode>
|
||||||
|
</stylenode>
|
||||||
|
</map_styles>
|
||||||
|
</hook>
|
||||||
|
<node TEXT="import" POSITION="right" ID="ID_1958811617" CREATED="1624709031603" MODIFIED="1624710428698"><richcontent TYPE="NOTE">
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Import from external source
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
</richcontent>
|
||||||
|
<node TEXT="--update" ID="ID_1408411362" CREATED="1624710635676" MODIFIED="1624710643751"/>
|
||||||
|
</node>
|
||||||
|
<node TEXT="update" POSITION="right" ID="ID_200299843" CREATED="1624709041259" MODIFIED="1624710451112"><richcontent TYPE="NOTE">
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Update metadata
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
</richcontent>
|
||||||
|
</node>
|
||||||
|
<node TEXT="sort" FOLDED="true" POSITION="right" ID="ID_474160274" CREATED="1624709213958" MODIFIED="1624710465196"><richcontent TYPE="NOTE">
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Sort photo
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
</richcontent>
|
||||||
|
<node TEXT="sort files" ID="ID_1215066925" CREATED="1624709364728" MODIFIED="1624709367203"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
</map>
|
|
@ -0,0 +1,241 @@
|
||||||
|
|
||||||
|
# Name ideas
|
||||||
|
dozo
|
||||||
|
fog
|
||||||
|
mtool
|
||||||
|
ordigi
|
||||||
|
|
||||||
|
# Geocoders
|
||||||
|
- Pelias
|
||||||
|
- Photon
|
||||||
|
- Nominatium
|
||||||
|
|
||||||
|
# TEST
|
||||||
|
|
||||||
|
def get_exif(filename):
|
||||||
|
image = Image.open(filename)
|
||||||
|
image.verify()
|
||||||
|
return image._getexif()
|
||||||
|
|
||||||
|
def get_geotagging(exif):
|
||||||
|
if not exif:
|
||||||
|
raise ValueError("No EXIF metadata found")
|
||||||
|
|
||||||
|
geotagging = {}
|
||||||
|
for (idx, tag) in TAGS.items():
|
||||||
|
if tag == 'GPSInfo':
|
||||||
|
if idx not in exif:
|
||||||
|
raise ValueError("No EXIF geotagging found")
|
||||||
|
|
||||||
|
for (key, val) in GPSTAGS.items():
|
||||||
|
if key in exif[idx]:
|
||||||
|
geotagging[val] = exif[idx][key]
|
||||||
|
|
||||||
|
return geotagging
|
||||||
|
get_geotagging(exif)
|
||||||
|
from PIL.ExifTags import TAGS
|
||||||
|
|
||||||
|
def get_labeled_exif(exif):
|
||||||
|
labeled = {}
|
||||||
|
for (key, val) in exif.items():
|
||||||
|
labeled[TAGS.get(key)] = val
|
||||||
|
|
||||||
|
return labeled
|
||||||
|
get_geotagging(exif)
|
||||||
|
from PIL.ExifTags import GPSTAGS
|
||||||
|
get_geotagging(exif)
|
||||||
|
geotags = get_geotagging(exif)
|
||||||
|
get_location(geotags)
|
||||||
|
|
||||||
|
def get_decimal_from_dms(dms, ref):
|
||||||
|
|
||||||
|
degrees = dms[0][0] / dms[0][1]
|
||||||
|
minutes = dms[1][0] / dms[1][1] / 60.0
|
||||||
|
seconds = dms[2][0] / dms[2][1] / 3600.0
|
||||||
|
|
||||||
|
if ref in ['S', 'W']:
|
||||||
|
degrees = -degrees
|
||||||
|
minutes = -minutes
|
||||||
|
seconds = -seconds
|
||||||
|
|
||||||
|
return round(degrees + minutes + seconds, 5)
|
||||||
|
|
||||||
|
def get_coordinates(geotags):
|
||||||
|
lat = get_decimal_from_dms(geotags['GPSLatitude'], geotags['GPSLatitudeRef'])
|
||||||
|
|
||||||
|
lon = get_decimal_from_dms(geotags['GPSLongitude'], geotags['GPSLongitudeRef'])
|
||||||
|
|
||||||
|
return (lat,lon)
|
||||||
|
|
||||||
|
def get_geotagging(exif):
|
||||||
|
if not exif:
|
||||||
|
raise ValueError("No EXIF metadata found")
|
||||||
|
|
||||||
|
geotagging = {}
|
||||||
|
for (idx, tag) in TAGS.items():
|
||||||
|
if tag == 'GPSInfo':
|
||||||
|
if idx not in exif:
|
||||||
|
raise ValueError("No EXIF geotagging found")
|
||||||
|
|
||||||
|
for (key, val) in GPSTAGS.items():
|
||||||
|
if key in exif[idx]:
|
||||||
|
geotagging[val] = exif[idx][key]
|
||||||
|
|
||||||
|
return geotagging
|
||||||
|
|
||||||
|
def get_decimal_from_dms(dms, ref):
|
||||||
|
|
||||||
|
degrees = dms[0]
|
||||||
|
minutes = dms[1] / 60.0
|
||||||
|
seconds = dms[2] / 3600.0
|
||||||
|
|
||||||
|
if ref in ['S', 'W']:
|
||||||
|
degrees = -degrees
|
||||||
|
minutes = -minutes
|
||||||
|
seconds = -seconds
|
||||||
|
|
||||||
|
return round(degrees + minutes + seconds, 5)
|
||||||
|
headers = {}
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['API_KEY'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
78/41: headers = {}
|
||||||
|
78/42:
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['API_KEY'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
78/43:
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['API_KEY'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
78/44: API_KEY=m5aGo8xGe4LLhxeKZYpHr2MPXGN2aDhe
|
||||||
|
78/45: API_KEY='m5aGo8xGe4LLhxeKZYpHr2MPXGN2aDhe'
|
||||||
|
78/46:
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['API_KEY'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
78/47: API_KEY='m5aGo8xGe4LLhxeKZYpHr2MPXGN2aDhe'
|
||||||
|
78/48:
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['API_KEY'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
78/49:
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['m5aGo8xGe4LLhxeKZYpHr2MPXGN2aDhe'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
78/50: %load_ext autotime
|
||||||
|
78/51:
|
||||||
|
import pandas as pd
|
||||||
|
import geopandas as gpd
|
||||||
|
import geopy
|
||||||
|
from geopy.geocoders import Nominatim
|
||||||
|
from geopy.extra.rate_limiter import RateLimiterimport matplotlib.pyplot as plt
|
||||||
|
import plotly_express as pximport tqdm
|
||||||
|
from tqdm._tqdm_notebook import tqdm_notebook
|
||||||
|
78/52:
|
||||||
|
import pandas as pd
|
||||||
|
import geopandas as gpd
|
||||||
|
import geopy
|
||||||
|
from geopy.geocoders import Nominatim
|
||||||
|
from geopy.extra.rate_limiter import RateLimiterimport matplotlib.pyplot as plt
|
||||||
|
import plotly_express as px
|
||||||
|
import pandas as pd
|
||||||
|
import geopandas as gpd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
filename='2021-02-24_09-33-29-20210305_081001_01.mp4'
|
||||||
|
def get_exif(filename):
|
||||||
|
image = Image.open(filename)
|
||||||
|
image.verify()
|
||||||
|
return image._getexif()
|
||||||
|
exif=get_exif(filename)
|
||||||
|
|
||||||
|
from PIL.ExifTags import TAGS
|
||||||
|
from PIL.ExifTags import GPSTAGS
|
||||||
|
def get_geotagging(exif):
|
||||||
|
if not exif:
|
||||||
|
raise ValueError("No EXIF metadata found")
|
||||||
|
|
||||||
|
geotagging = {}
|
||||||
|
for (idx, tag) in TAGS.items():
|
||||||
|
if tag == 'GPSInfo':
|
||||||
|
if idx not in exif:
|
||||||
|
raise ValueError("No EXIF geotagging found")
|
||||||
|
|
||||||
|
for (key, val) in GPSTAGS.items():
|
||||||
|
if key in exif[idx]:
|
||||||
|
geotagging[val] = exif[idx][key]
|
||||||
|
|
||||||
|
return geotagging
|
||||||
|
geotags = get_geotagging(exif)
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
|
||||||
|
def get_location(geotags):
|
||||||
|
coords = get_coordinates(geotags)
|
||||||
|
|
||||||
|
uri = 'https://revgeocode.search.hereapi.com/v1/revgeocode'
|
||||||
|
headers = {}
|
||||||
|
params = {
|
||||||
|
'apiKey': os.environ['API_KEY'],
|
||||||
|
'at': "%s,%s" % coords,
|
||||||
|
'lang': 'en-US',
|
||||||
|
'limit': 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.get(uri, headers=headers, params=params)
|
||||||
|
try:
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
print(str(e))
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_coordinates(geotags):
|
||||||
|
lat = get_decimal_from_dms(geotags['GPSLatitude'], geotags['GPSLatitudeRef'])
|
||||||
|
|
||||||
|
lon = get_decimal_from_dms(geotags['GPSLongitude'], geotags['GPSLongitudeRef'])
|
||||||
|
|
||||||
|
return (lat,lon)
|
||||||
|
coords = get_coordinates(geotags)
|
||||||
|
import geopy
|
||||||
|
from geopy.geocoders import Nominatim
|
||||||
|
locator = Nominatim(user_agent='myGeocoder')
|
||||||
|
# coordinates ='53.480837, -2.244914'
|
||||||
|
lat='45.58339'
|
||||||
|
lon='4.79823'
|
||||||
|
coords = lat + ',' + lon
|
||||||
|
locator.reverse(coords)
|
||||||
|
location =locator.reverse(coords)
|
||||||
|
location.address.split(',')
|
||||||
|
city=location.address.split(',')[1].strip()
|
||||||
|
country=location.address.split(',')[7].strip()
|
||||||
|
location.raw
|
||||||
|
rint
|
||||||
|
country=location.raw['address']['country']
|
||||||
|
city=location.raw['address']['village']
|
|
@ -0,0 +1,111 @@
|
||||||
|
# NOW
|
||||||
|
|
||||||
|
- db integrity have not to be checked in media but in collection??
|
||||||
|
|
||||||
|
- build structure to store file path and info with metadata
|
||||||
|
metadatas[file_path] = {'checksum': value}. Init must select same files than
|
||||||
|
get_metadatata
|
||||||
|
|
||||||
|
- check edit_metadata again test with valid doc
|
||||||
|
- show exif metadata
|
||||||
|
- print all values and select some to edit
|
||||||
|
- dry run = no changes
|
||||||
|
|
||||||
|
- compare custom output folder similar to?
|
||||||
|
- ordigi-gui
|
||||||
|
- add name and dirpath options???
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
Options:
|
||||||
|
--location --time
|
||||||
|
# -f overwrite metadata
|
||||||
|
--auto|-a: a set of option: geolocalisation, best match date, rename, album
|
||||||
|
from folder...
|
||||||
|
# --keep-folder option
|
||||||
|
# --rename
|
||||||
|
--confirm unsure operation
|
||||||
|
|
||||||
|
# Bugs
|
||||||
|
- summary
|
||||||
|
|
||||||
|
- set date original???, interactive mode...
|
||||||
|
|
||||||
|
- Faire en sorte que le programme ne plante pas...
|
||||||
|
- option to not update exif metadata...
|
||||||
|
## Exiftools
|
||||||
|
https://gitlab.com/TNThieding/exif
|
||||||
|
exiftool -akljklbum=tjkljkestjlj /tmp/pytest-of-cedric/pytest-12/test_sort_files0/2008-10-Oct/test_exif/2008-10-24_09-12-56-photo.nef
|
||||||
|
|
||||||
|
exiftool -album=tjkljkestjlj /tmp/pytest-of-cedric/pytest-12/test_sort_files0/2008-10-Oct/test_exif/2008-10-24_09-12-56-photo.nef
|
||||||
|
1 image files updated
|
||||||
|
|
||||||
|
Get result code....
|
||||||
|
|
||||||
|
|
||||||
|
## Doc use sphinx??
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
- ordigi view/show
|
||||||
|
- ordigi search
|
||||||
|
- use tree to show paths?
|
||||||
|
|
||||||
|
|
||||||
|
# Pylint
|
||||||
|
https://pythonspeed.com/articles/pylint/
|
||||||
|
use config file
|
||||||
|
|
||||||
|
# Media:
|
||||||
|
|
||||||
|
# Test:
|
||||||
|
|
||||||
|
# enhancement
|
||||||
|
- summary: replace success by copied/moved/deleted
|
||||||
|
|
||||||
|
## Alias
|
||||||
|
alias ogi=ordigi
|
||||||
|
|
||||||
|
## Image analysis
|
||||||
|
https://pypi.org/project/google-cloud-vision/
|
||||||
|
https://googleapis.dev/python/vision/latest/index.html
|
||||||
|
https://www.datacamp.com/community/tutorials/beginner-guide-google-vision-api
|
||||||
|
|
||||||
|
|
||||||
|
## Album form folder
|
||||||
|
|
||||||
|
# Update
|
||||||
|
|
||||||
|
https://github.com/JohannesBuchner/imagehash
|
||||||
|
https://github.com/cw-somil/Duplicate-Remover
|
||||||
|
https://leons.im/posts/a-python-implementation-of-simhash-algorithm/
|
||||||
|
|
||||||
|
Visualy check similar image
|
||||||
|
https://www.pluralsight.com/guides/importing-image-data-into-numpy-arrays
|
||||||
|
https://stackoverflow.com/questions/56056054/add-check-boxes-to-scrollable-image-in-python
|
||||||
|
https://wellsr.com/python/python-image-manipulation-with-pillow-library/
|
||||||
|
kitty gird image?
|
||||||
|
https://fr.wikibooks.org/wiki/PyQt/PyQt_versus_wxPython
|
||||||
|
https://docs.python.org/3/faq/gui.html
|
||||||
|
https://docs.opencv.org/3.4/d3/df2/tutorial_py_basic_ops.html
|
||||||
|
https://stackoverflow.com/questions/52727332/python-tkinter-create-checkbox-list-from-listbox
|
||||||
|
|
||||||
|
|
||||||
|
Image gird method:
|
||||||
|
matplot
|
||||||
|
https://gist.github.com/lebedov/7018889ba47668c64bcf96aee82caec0
|
||||||
|
|
||||||
|
Tkinter
|
||||||
|
https://python-forum.io/thread-22700.html
|
||||||
|
https://stackoverflow.com/questions/43326282/how-can-i-use-images-in-a-tkinter-grid
|
||||||
|
|
||||||
|
wxwidget
|
||||||
|
https://wxpython.org/Phoenix/docs/html/wx.lib.agw.thumbnailctrl.html
|
||||||
|
|
||||||
|
|
||||||
|
Ability to change metadata to selection
|
||||||
|
|
||||||
|
Fix: change versvalidion number to 0.x99
|
||||||
|
|
||||||
|
https://github.com/andrewning/sortphotos/blob/master/src/sortphotos.py
|
||||||
|
|
||||||
|
# AFTER
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Create virtual environment
|
||||||
|
nmkvirtualenv ordigi
|
||||||
|
|
||||||
|
# Work on it (activate and cd)
|
||||||
|
workon ordigi
|
||||||
|
|
||||||
|
# Install required dependencies
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Liked it to path
|
||||||
|
pip install -e .
|
||||||
|
|
||||||
|
# View file tree of path
|
||||||
|
tree /dest/path
|
||||||
|
|
||||||
|
# Test code
|
||||||
|
pylint ordigi/* -E
|
||||||
|
pylint ordigi/**
|
||||||
|
pytest --cov=ordigi --cov-report html tests/*.py
|
||||||
|
pip install --prefix=~/.local -e .
|
||||||
|
|
||||||
|
# config
|
||||||
|
|
||||||
|
## Path format
|
||||||
|
dirs_path=<%Y>/<%m-%b>-<city>-<folder>
|
||||||
|
name=<%Y%m%d-%H%M%S>-%u<original_name>|%u<basename>.%l<ext>
|
||||||
|
|
||||||
|
|
||||||
|
## run
|
||||||
|
ordigi import 220719.bkp -f -c -R collection
|
Loading…
Reference in New Issue