diff --git a/docs/ordigi.mm b/docs/ordigi.mm new file mode 100644 index 0000000..99ec606 --- /dev/null +++ b/docs/ordigi.mm @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Import from external source +

+ + + +
+ + + + + + + + + +

+ Update metadata +

+ + + +
+
+ + + + + + + +

+ Sort photo +

+ + + +
+ + +
+
diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..ff9215d --- /dev/null +++ b/notes.md @@ -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'] diff --git a/todo.md b/todo.md new file mode 100755 index 0000000..5c8889a --- /dev/null +++ b/todo.md @@ -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 + diff --git a/workflow.md b/workflow.md new file mode 100644 index 0000000..4c36741 --- /dev/null +++ b/workflow.md @@ -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>-- +name=<%Y%m%d-%H%M%S>-%u|%u.%l + + +## run +ordigi import 220719.bkp -f -c -R collection