jmathai / elodie Goto Github PK
View Code? Open in Web Editor NEWAn EXIF-based photo assistant, organizer and workflow automation tool.
Home Page: https://bit.ly/introducing-elodie
License: Apache License 2.0
An EXIF-based photo assistant, organizer and workflow automation tool.
Home Page: https://bit.ly/introducing-elodie
License: Apache License 2.0
constants.debug is used in module photo.py but 'import constants' is missing.
I tried to execute this command:
./elodie.py import --source="~/Desktop/chris" --destination="/Volumes/Data/Pictures/elodie-photos" --album="Aniversario Chris"
but it always return Usage message:
Usage: main.py import --source=<s> --destination=<d>
main.py import --file=<f> --destination=<d>
main.py update [--time=<t>] [--location=<l>] [--album=<a>] [--title=<t>] INPUT ...
If I remove the --album it does work.
It looks like LatLon has a GPL (not LGPL) license: https://pypi.python.org/pypi/LatLon/1.0.2 (see the bottom)
IANAL, but I'm pretty sure that requires software linked to it to be licensed GPL, too?
Would be interesting to create a page for that.
http://elodie.photos is available. :-)
The conversion from decimal to degrees loses precision. This was caught in a unit test.
Is it in this repository or another one? Don't see how to install.
When you run ./elodie.py update --title="my new title" /path/to/2015-01-01_12-00-00-my-old-file.jpg
It will name the file /path/to/2015-01-01_12-00-00-my-old-file-my-new-file.jpg
.
This seems to only be happening for videos.
I couldn't find the command ./elodie.py
in the root, as suggested in the README.
To test I used the import.py
I would like to use another format for date like dd/MM/yyyy
@patricksan @srynot4sale @ibizaman Do you all mind signing the CLA for your contributions? I used the online contributor agreements website which was funded by the Shuttleworth Foundation which provided me a 2 year fellowship.
You can sign it easily by signing in with your github account. It's been wired up to automatically scan PRs to ensure all contributors have signed.
When running a simple import, I get the following error:
Traceback (most recent call last):
File "./elodie.py", line 157, in <module>
_import(params)
File "./elodie.py", line 37, in _import
media = Media.get_class_by_file(current_file, [Photo, Video])
File "./elodie/elodie/media/media.py", line 298, in get_class_by_file
if(extension in Media.photo_extensions):
AttributeError: type object 'Media' has no attribute 'photo_extensions'
I'm on master - 5818978
and all tests seem to pass fine:
nosetests -s
..............S.S....S...********************.S********************.S......................
----------------------------------------------------------------------
Ran 51 tests in 10.250s
OK (SKIP=5)
I outputted some values if that can help:
>>> Media.__class__
<class 'elodie.media.media.Media'>
>>> dir(Media)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', 'get_album', 'get_class_by_file', 'get_exif', 'get_exiftool',
'get_exiftool_attributes', 'get_extension', 'get_file_path', 'get_metadata',
'get_mimetype', 'get_title', 'is_valid', 'set_album', 'set_album_from_folder',
'set_metadata', 'set_metadata_basename']
Some UTC problem ?
./elodie.py update --time="2010-05-01" /Users/flap/Pictures/elodie/2004-12-Dec/Unknown\ Location/2004-12-31_23-0*
{"source":"/Users/flap/Pictures/elodie/2004-12-Dec/Unknown Location/2004-12-31_23-01-39-imgp4530.jpg",
"destination":"/Users/flap/Pictures/elodie/2010-04-Apr/Unknown Location/2010-04-30_22-00-00-imgp4530.jpg"}
destination folder should be 2010-05-May
, not 2010-04-Apr
It would be nice to have a package that could be pip-installed. Here is a decent setup.py. The layout of the app would need some changing to support that, though.
Not strictly a problem with your app - but MapQuest are having issues automating the generation of API keys.
See the discussion at https://developer.mapquest.com/forum/free-api-key
I've previously had an API key with them, but now the site looks like this:
Wondering if there are any other suitable geo-coding services which are available? Perhaps http://wiki.openstreetmap.org/wiki/Nominatim ?
When looking up a geolocation coordinate we can cache the value to limit the number of lookups needed. A few considerations to make...
lat/lon pairs within a certain radius of a pair that's already stored should return the stored location name. (see gelocation.place_name
). When a pair is not within a certain radius of a stored lat/lon pair it should be looked up against an API and stored.
// cc @zingo
TL;DR: what would you think about using fuse?
First of all THANK YOU. This is the project I always wanted to do - in the exact same way.
So for now, the only way to update pictures is to run the elodie.py
command. I would propose to make importing and updating even more intuitive by adding fuse into the mix. This way, making a modification on the filesystem - renaming a directory, moving a file, etc. - would trigger elodie.py
and automatically change the EXIF information.
The UI could then be very inuitive. Assuming:
├── 2015-06-Jun
│ ├── California
│ │ ├── 2015-06-29_16-34-14-img_3900.jpg
│ │ └── 2015-06-29_17-07-06-img_3901.jpg
│ └── Paris
│ └── 2015-06-30_02-40-43-img_3903.jpg
├── 2015-07-Jul
│ ├── Mountain View
│ │ ├── 2015-07-19_17-16-37-img_9426.jpg
│ │ └── 2015-07-24_19-06-33-img_9432.jpg
Renaming California
to Silicon Valley
would trigger:
./elodie.py update --location="Silicon Valley" \
2015-06-Jun/California/2015-06-29_16-34-14-img_3900.jpg \
2015-06-Jun/California/2015-06-29_16-34-14-img_3901.jpg
Renaming 2015-07-Jul
to 2015-08
would trigger, with a bit of magick:
./elodie.py update --time="2015-08-19" 2015-07-Jul/Mountain View/2015-07-19_17-16-37-img_9426.jpg
./elodie.py update --time="2015-08-24" 2015-07-Jul/Mountain View/2015-07-24_19-06-33-img_9432.jpg
And of course, editing the EXIF information directly would also trigger corresponding ./elodie.py
commands.
Python bindings for fuse can be installed with pip too: pip install fuse-python
.
What do you think of this?
I am at this stage:
pip install LatLon
I am at the root of my Mac, but have this error:
running install_lib
creating /Library/Python/2.7/site-packages/pyproj
error: could not create '/Library/Python/2.7/site-packages/pyproj': Permission denied
Thanks for your help :)
Johan
The import/update script recursively gets a listing of files and checks the extension against a list of supported extensions. If a file has a supported extension but does not contain valid data (i.e. is not a picture or movie) then the script exits.
Traceback (most recent call last):
File "<string>", line 150, in <module>
File "<string>", line 44, in _import
File "/......../filesystem.py", line 137, in process_file
File "/......../media.py", line 243, in get_metadata
File "/......../media.py", line 143, in get_date_taken
File "/......../media.py", line 175, in get_exif
File "/usr/local/Cellar/pyexiv2/0.3.2_1/lib/python2.7/site-packages/pyexiv2/metadata.py", line 107, in read
self.__image = self._instantiate_image(self.filename)
File "/usr/local/Cellar/pyexiv2/0.3.2_1/lib/python2.7/site-packages/pyexiv2/metadata.py", line 79, in _instantiate_image
return libexiv2python._Image(filename)
IOError: /......../Photos/._2012-04-21 17.59.46.jpg: The file contains data of an unknown image type
elodie returned -1
I tried to run this command and it didn't work:
$ ./elodie.py import --source="~/Desktop/chris" --destination="/Volumes/Data/Pictures/elodie-photos"
I had to convert to:
$ ./elodie.py import --source="/Users/patrick/Desktop/chris" --destination="/Volumes/Data/Pictures/elodie-photos"
Hi again,
I have this error:
./elodie.py", line 4, in
import pyexiv2
ImportError: No module named pyexiv2
But everything is well installed.(pyexiv2-0.3.2_1 already installed)
Thanks
I was just about to shuffle some stuff around for #41 and I realized... there's no LICENSE file. I didn't see anything in the README about it, either. Are you planning to release this under the BSD License (like epiphany: https://github.com/jmathai/epiphany/blob/master/LICENSE) or something else?
FAIL: elodie.tests.media.video_test.test_get_date_taken
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/travis/virtualenv/python2.7_with_system_site_packages/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/home/travis/build/jmathai/elodie/elodie/tests/media/video_test.py", line 58, in test_get_date_taken
assert date_taken == (2015, 1, 19, 12, 45, 11, 0, 19, 0), date_taken
AssertionError: time.struct_time(tm_year=2015, tm_mon=12, tm_mday=12, tm_hour=8, tm_min=59, tm_sec=26, tm_wday=5, tm_yday=346, tm_isdst=0)
The latitude and longitude ref indicate the direction. We should not have the numeric component be signed.
It seems like error in photo.py line 82:
if(key == 'latitude'):
should be:
if(type == 'latitude'):
I am new with Hazel script stuff. Do you mind to describe the rule you made in Hazel to notify Elodie to do this:
"to set up a Hazel rule to notify me when photos arrive in ~/Downloads
so I can import them."
Thanks
Sometimes MapQuest returns an undesired location name for input location and that name is then used in the destination dir name.
User should be informed a priori so he can cancel the operation.
So far this is the list of pep8 issues.
# pep8 elodie
elodie/arguments.py:3:11: E401 multiple imports on one line
elodie/arguments.py:6:1: E302 expected 2 blank lines, found 1
elodie/arguments.py:12:1: W293 blank line contains whitespace
elodie/filesystem.py:17:1: E302 expected 2 blank lines, found 0
elodie/filesystem.py:21:80: E501 line too long (86 > 79 characters)
elodie/filesystem.py:38:80: E501 line too long (93 > 79 characters)
elodie/filesystem.py:38:94: W291 trailing whitespace
elodie/filesystem.py:41:80: E501 line too long (86 > 79 characters)
elodie/filesystem.py:63:31: E711 comparison to None should be 'if cond is None:'
elodie/filesystem.py:63:80: E501 line too long (80 > 79 characters)
elodie/filesystem.py:78:80: E501 line too long (86 > 79 characters)
elodie/filesystem.py:89:21: E711 comparison to None should be 'if cond is None:'
elodie/filesystem.py:92:80: E501 line too long (103 > 79 characters)
elodie/filesystem.py:94:80: E501 line too long (86 > 79 characters)
elodie/filesystem.py:94:87: W291 trailing whitespace
elodie/filesystem.py:95:80: E501 line too long (94 > 79 characters)
elodie/filesystem.py:98:80: E501 line too long (97 > 79 characters)
elodie/filesystem.py:103:80: E501 line too long (127 > 79 characters)
elodie/filesystem.py:128:80: E501 line too long (85 > 79 characters)
elodie/filesystem.py:129:80: E501 line too long (92 > 79 characters)
elodie/filesystem.py:137:9: E265 block comment should start with '# '
elodie/filesystem.py:159:21: E711 comparison to None should be 'if cond is None:'
elodie/filesystem.py:160:32: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/filesystem.py:164:80: E501 line too long (85 > 79 characters)
elodie/filesystem.py:165:27: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
elodie/filesystem.py:166:32: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/filesystem.py:167:80: E501 line too long (93 > 79 characters)
elodie/filesystem.py:172:17: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/filesystem.py:194:80: E501 line too long (117 > 79 characters)
elodie/filesystem.py:197:80: E501 line too long (84 > 79 characters)
elodie/filesystem.py:201:80: E501 line too long (82 > 79 characters)
elodie/filesystem.py:205:80: E501 line too long (97 > 79 characters)
elodie/filesystem.py:208:80: E501 line too long (91 > 79 characters)
elodie/filesystem.py:210:80: E501 line too long (80 > 79 characters)
elodie/filesystem.py:211:1: W293 blank line contains whitespace
elodie/geolocation.py:14:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:25:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:39:80: E501 line too long (86 > 79 characters)
elodie/geolocation.py:39:87: W291 trailing whitespace
elodie/geolocation.py:40:80: E501 line too long (121 > 79 characters)
elodie/geolocation.py:42:80: E501 line too long (92 > 79 characters)
elodie/geolocation.py:43:80: E501 line too long (83 > 79 characters)
elodie/geolocation.py:44:80: E501 line too long (86 > 79 characters)
elodie/geolocation.py:47:80: E501 line too long (154 > 79 characters)
elodie/geolocation.py:50:1: W293 blank line contains whitespace
elodie/geolocation.py:55:1: W293 blank line contains whitespace
elodie/geolocation.py:58:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:59:80: E501 line too long (82 > 79 characters)
elodie/geolocation.py:71:15: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
elodie/geolocation.py:76:80: E501 line too long (153 > 79 characters)
elodie/geolocation.py:78:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:80:23: E221 multiple spaces before operator
elodie/geolocation.py:81:28: E221 multiple spaces before operator
elodie/geolocation.py:85:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:89:1: W293 blank line contains whitespace
elodie/geolocation.py:97:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:102:54: E231 missing whitespace after ','
elodie/geolocation.py:106:29: E703 statement ends with a semicolon
elodie/geolocation.py:133:80: E501 line too long (110 > 79 characters)
elodie/geolocation.py:136:28: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/geolocation.py:140:28: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/geolocation.py:145:1: E302 expected 2 blank lines, found 1
elodie/geolocation.py:153:28: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/geolocation.py:154:80: E501 line too long (98 > 79 characters)
elodie/geolocation.py:155:80: E501 line too long (106 > 79 characters)
elodie/geolocation.py:158:28: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/geolocation.py:162:28: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/localstorage.py:9:1: E302 expected 2 blank lines, found 1
elodie/localstorage.py:11:80: E501 line too long (82 > 79 characters)
elodie/localstorage.py:23:80: E501 line too long (82 > 79 characters)
elodie/localstorage.py:38:80: E501 line too long (82 > 79 characters)
elodie/localstorage.py:47:18: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/localstorage.py:91:18: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/localstorage.py:94:52: E231 missing whitespace after ','
elodie/localstorage.py:99:80: E501 line too long (140 > 79 characters)
elodie/localstorage.py:102:80: E501 line too long (99 > 79 characters)
elodie/localstorage.py:105:37: E201 whitespace after '('
elodie/localstorage.py:105:53: E202 whitespace before ')'
elodie/localstorage.py:107:26: E201 whitespace after '('
elodie/localstorage.py:107:36: E202 whitespace before ')'
elodie/localstorage.py:110:17: E265 block comment should start with '# '
elodie/localstorage.py:111:36: E703 statement ends with a semicolon
elodie/plist_parser.py:15:1: E302 expected 2 blank lines, found 0
elodie/media/media.py:23:1: E302 expected 2 blank lines, found 0
elodie/media/media.py:33:80: E501 line too long (106 > 79 characters)
elodie/media/media.py:33:82: E261 at least two spaces before inline comment
elodie/media/media.py:33:83: E262 inline comment should start with '# '
elodie/media/media.py:54:1: W293 blank line contains whitespace
elodie/media/media.py:68:80: E501 line too long (81 > 79 characters)
elodie/media/media.py:74:5: E303 too many blank lines (2)
elodie/media/media.py:91:80: E501 line too long (108 > 79 characters)
elodie/media/media.py:98:1: W293 blank line contains whitespace
elodie/media/media.py:117:80: E501 line too long (111 > 79 characters)
elodie/media/media.py:134:26: E703 statement ends with a semicolon
elodie/media/media.py:144:5: E303 too many blank lines (2)
elodie/media/media.py:166:55: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
elodie/media/media.py:184:1: W293 blank line contains whitespace
elodie/media/media.py:196:21: E711 comparison to None should be 'if cond is None:'
elodie/media/media.py:200:1: W293 blank line contains whitespace
elodie/media/media.py:235:28: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/media.py:236:80: E501 line too long (107 > 79 characters)
elodie/media/media.py:237:80: E501 line too long (170 > 79 characters)
elodie/media/media.py:270:5: E303 too many blank lines (2)
elodie/media/media.py:271:80: E501 line too long (92 > 79 characters)
elodie/media/media.py:273:80: E501 line too long (121 > 79 characters)
elodie/media/media.py:276:80: E501 line too long (82 > 79 characters)
elodie/media/photo.py:26:1: E302 expected 2 blank lines, found 0
elodie/media/photo.py:38:1: W293 blank line contains whitespace
elodie/media/photo.py:51:13: E128 continuation line under-indented for visual indent
elodie/media/photo.py:51:19: E251 unexpected spaces around keyword / parameter equals
elodie/media/photo.py:51:21: E251 unexpected spaces around keyword / parameter equals
elodie/media/photo.py:51:45: E251 unexpected spaces around keyword / parameter equals
elodie/media/photo.py:51:47: E251 unexpected spaces around keyword / parameter equals
elodie/media/photo.py:54:80: E501 line too long (87 > 79 characters)
elodie/media/photo.py:66:80: E501 line too long (94 > 79 characters)
elodie/media/photo.py:73:80: E501 line too long (91 > 79 characters)
elodie/media/photo.py:75:80: E501 line too long (93 > 79 characters)
elodie/media/photo.py:78:23: E225 missing whitespace around operator
elodie/media/photo.py:78:80: E501 line too long (94 > 79 characters)
elodie/media/photo.py:83:80: E501 line too long (113 > 79 characters)
elodie/media/photo.py:85:80: E501 line too long (114 > 79 characters)
elodie/media/photo.py:100:80: E501 line too long (85 > 79 characters)
elodie/media/photo.py:102:80: E501 line too long (93 > 79 characters)
elodie/media/photo.py:103:80: E501 line too long (102 > 79 characters)
elodie/media/photo.py:105:80: E501 line too long (104 > 79 characters)
elodie/media/photo.py:110:80: E501 line too long (96 > 79 characters)
elodie/media/photo.py:111:80: E501 line too long (86 > 79 characters)
elodie/media/photo.py:112:30: E703 statement ends with a semicolon
elodie/media/photo.py:114:36: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/photo.py:124:80: E501 line too long (89 > 79 characters)
elodie/media/photo.py:125:1: W293 blank line contains whitespace
elodie/media/photo.py:134:25: E703 statement ends with a semicolon
elodie/media/photo.py:175:80: E501 line too long (95 > 79 characters)
elodie/media/photo.py:176:80: E501 line too long (132 > 79 characters)
elodie/media/photo.py:177:80: E501 line too long (97 > 79 characters)
elodie/media/photo.py:178:80: E501 line too long (135 > 79 characters)
elodie/media/video.py:26:1: E302 expected 2 blank lines, found 0
elodie/media/video.py:28:24: E231 missing whitespace after ','
elodie/media/video.py:28:30: E231 missing whitespace after ','
elodie/media/video.py:28:36: E231 missing whitespace after ','
elodie/media/video.py:28:42: E231 missing whitespace after ','
elodie/media/video.py:46:80: E501 line too long (95 > 79 characters)
elodie/media/video.py:52:5: E303 too many blank lines (2)
elodie/media/video.py:74:80: E501 line too long (100 > 79 characters)
elodie/media/video.py:92:80: E501 line too long (102 > 79 characters)
elodie/media/video.py:94:80: E501 line too long (85 > 79 characters)
elodie/media/video.py:102:80: E501 line too long (123 > 79 characters)
elodie/media/video.py:114:1: W293 blank line contains whitespace
elodie/media/video.py:127:13: E128 continuation line under-indented for visual indent
elodie/media/video.py:127:19: E251 unexpected spaces around keyword / parameter equals
elodie/media/video.py:127:21: E251 unexpected spaces around keyword / parameter equals
elodie/media/video.py:127:45: E251 unexpected spaces around keyword / parameter equals
elodie/media/video.py:127:47: E251 unexpected spaces around keyword / parameter equals
elodie/media/video.py:130:80: E501 line too long (87 > 79 characters)
elodie/media/video.py:135:80: E501 line too long (87 > 79 characters)
elodie/media/video.py:145:80: E501 line too long (111 > 79 characters)
elodie/media/video.py:149:80: E501 line too long (89 > 79 characters)
elodie/media/video.py:150:1: W293 blank line contains whitespace
elodie/media/video.py:171:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:172:80: E501 line too long (97 > 79 characters)
elodie/media/video.py:188:80: E501 line too long (82 > 79 characters)
elodie/media/video.py:213:80: E501 line too long (89 > 79 characters)
elodie/media/video.py:215:80: E501 line too long (84 > 79 characters)
elodie/media/video.py:224:80: E501 line too long (118 > 79 characters)
elodie/media/video.py:225:32: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:231:32: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:237:80: E501 line too long (87 > 79 characters)
elodie/media/video.py:239:80: E501 line too long (102 > 79 characters)
elodie/media/video.py:241:80: E501 line too long (115 > 79 characters)
elodie/media/video.py:242:80: E501 line too long (122 > 79 characters)
elodie/media/video.py:245:36: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:250:80: E501 line too long (106 > 79 characters)
elodie/media/video.py:261:80: E501 line too long (92 > 79 characters)
elodie/media/video.py:263:80: E501 line too long (82 > 79 characters)
elodie/media/video.py:264:80: E501 line too long (88 > 79 characters)
elodie/media/video.py:280:80: E501 line too long (84 > 79 characters)
elodie/media/video.py:285:80: E501 line too long (82 > 79 characters)
elodie/media/video.py:286:21: E265 block comment should start with '# '
elodie/media/video.py:299:36: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:304:80: E501 line too long (81 > 79 characters)
elodie/media/video.py:305:80: E501 line too long (82 > 79 characters)
elodie/media/video.py:313:80: E501 line too long (111 > 79 characters)
elodie/media/video.py:314:80: E501 line too long (108 > 79 characters)
elodie/media/video.py:317:36: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:318:80: E501 line too long (86 > 79 characters)
elodie/media/video.py:321:80: E501 line too long (84 > 79 characters)
elodie/media/video.py:324:80: E501 line too long (207 > 79 characters)
elodie/media/video.py:325:36: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/media/video.py:329:80: E501 line too long (99 > 79 characters)
elodie/media/video.py:346:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:8:80: E501 line too long (114 > 79 characters)
elodie/tests/filesystem_test.py:10:1: E402 module level import not at top of file
elodie/tests/filesystem_test.py:11:1: E402 module level import not at top of file
elodie/tests/filesystem_test.py:12:1: E402 module level import not at top of file
elodie/tests/filesystem_test.py:13:1: E402 module level import not at top of file
elodie/tests/filesystem_test.py:14:1: E402 module level import not at top of file
elodie/tests/filesystem_test.py:27:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/filesystem_test.py:30:1: W293 blank line contains whitespace
elodie/tests/filesystem_test.py:37:80: E501 line too long (97 > 79 characters)
elodie/tests/filesystem_test.py:43:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/filesystem_test.py:49:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:51:80: E501 line too long (92 > 79 characters)
elodie/tests/filesystem_test.py:53:19: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
elodie/tests/filesystem_test.py:55:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:68:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:70:80: E501 line too long (97 > 79 characters)
elodie/tests/filesystem_test.py:88:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:120:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:124:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:131:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:136:80: E501 line too long (82 > 79 characters)
elodie/tests/filesystem_test.py:138:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:150:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:157:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:164:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:171:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:178:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:186:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:196:80: E501 line too long (99 > 79 characters)
elodie/tests/filesystem_test.py:198:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:206:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:216:80: E501 line too long (110 > 79 characters)
elodie/tests/filesystem_test.py:218:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:226:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:236:80: E501 line too long (92 > 79 characters)
elodie/tests/filesystem_test.py:238:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:246:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:256:80: E501 line too long (103 > 79 characters)
elodie/tests/filesystem_test.py:258:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:266:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:276:80: E501 line too long (93 > 79 characters)
elodie/tests/filesystem_test.py:278:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:286:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:296:80: E501 line too long (104 > 79 characters)
elodie/tests/filesystem_test.py:298:1: E302 expected 2 blank lines, found 1
elodie/tests/filesystem_test.py:303:80: E501 line too long (85 > 79 characters)
elodie/tests/filesystem_test.py:306:80: E501 line too long (95 > 79 characters)
elodie/tests/filesystem_test.py:316:80: E501 line too long (104 > 79 characters)
elodie/tests/geolocation_test.py:7:80: E501 line too long (114 > 79 characters)
elodie/tests/geolocation_test.py:9:1: E402 module level import not at top of file
elodie/tests/geolocation_test.py:10:1: E402 module level import not at top of file
elodie/tests/geolocation_test.py:14:1: E302 expected 2 blank lines, found 1
elodie/tests/geolocation_test.py:20:1: W293 blank line contains whitespace
elodie/tests/geolocation_test.py:22:80: E501 line too long (91 > 79 characters)
elodie/tests/geolocation_test.py:27:80: E501 line too long (112 > 79 characters)
elodie/tests/geolocation_test.py:29:1: E302 expected 2 blank lines, found 1
elodie/tests/geolocation_test.py:33:1: W293 blank line contains whitespace
elodie/tests/geolocation_test.py:35:80: E501 line too long (91 > 79 characters)
elodie/tests/geolocation_test.py:42:80: E501 line too long (120 > 79 characters)
elodie/tests/helper.py:8:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:19:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:21:80: E501 line too long (82 > 79 characters)
elodie/tests/helper.py:26:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:30:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:33:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:45:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:46:80: E501 line too long (111 > 79 characters)
elodie/tests/helper.py:48:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:51:1: E302 expected 2 blank lines, found 1
elodie/tests/helper.py:55:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:5:80: E501 line too long (114 > 79 characters)
elodie/tests/localstorage_test.py:7:1: E402 module level import not at top of file
elodie/tests/localstorage_test.py:8:1: E402 module level import not at top of file
elodie/tests/localstorage_test.py:9:1: E402 module level import not at top of file
elodie/tests/localstorage_test.py:13:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:19:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:28:80: E501 line too long (83 > 79 characters)
elodie/tests/localstorage_test.py:33:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:34:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:43:80: E501 line too long (83 > 79 characters)
elodie/tests/localstorage_test.py:48:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:49:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:58:80: E501 line too long (83 > 79 characters)
elodie/tests/localstorage_test.py:63:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:64:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:73:80: E501 line too long (83 > 79 characters)
elodie/tests/localstorage_test.py:74:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:75:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:80:80: E501 line too long (100 > 79 characters)
elodie/tests/localstorage_test.py:82:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:91:80: E501 line too long (102 > 79 characters)
elodie/tests/localstorage_test.py:92:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:93:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:98:80: E501 line too long (103 > 79 characters)
elodie/tests/localstorage_test.py:100:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:109:80: E501 line too long (83 > 79 characters)
elodie/tests/localstorage_test.py:121:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:127:80: E501 line too long (129 > 79 characters)
elodie/tests/localstorage_test.py:129:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:139:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:145:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:146:5: E303 too many blank lines (2)
elodie/tests/localstorage_test.py:151:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:165:80: E501 line too long (105 > 79 characters)
elodie/tests/localstorage_test.py:167:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:181:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:183:1: W293 blank line contains whitespace
elodie/tests/localstorage_test.py:198:1: E302 expected 2 blank lines, found 1
elodie/tests/localstorage_test.py:200:1: W293 blank line contains whitespace
elodie/tests/media/media_test.py:13:80: E501 line too long (131 > 79 characters)
elodie/tests/media/media_test.py:14:80: E501 line too long (97 > 79 characters)
elodie/tests/media/media_test.py:16:1: E402 module level import not at top of file
elodie/tests/media/media_test.py:17:1: E402 module level import not at top of file
elodie/tests/media/media_test.py:18:1: E402 module level import not at top of file
elodie/tests/media/media_test.py:19:1: E402 module level import not at top of file
elodie/tests/media/media_test.py:23:1: E302 expected 2 blank lines, found 1
elodie/tests/media/media_test.py:29:1: E302 expected 2 blank lines, found 1
elodie/tests/media/media_test.py:35:1: E302 expected 2 blank lines, found 1
elodie/tests/media/media_test.py:36:80: E501 line too long (81 > 79 characters)
elodie/tests/media/media_test.py:40:1: E302 expected 2 blank lines, found 1
elodie/tests/media/media_test.py:41:80: E501 line too long (81 > 79 characters)
elodie/tests/media/media_test.py:45:1: E302 expected 2 blank lines, found 1
elodie/tests/media/media_test.py:46:80: E501 line too long (80 > 79 characters)
elodie/tests/media/media_test.py:50:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:13:80: E501 line too long (131 > 79 characters)
elodie/tests/media/photo_test.py:14:80: E501 line too long (97 > 79 characters)
elodie/tests/media/photo_test.py:16:1: E402 module level import not at top of file
elodie/tests/media/photo_test.py:17:1: E402 module level import not at top of file
elodie/tests/media/photo_test.py:18:1: E402 module level import not at top of file
elodie/tests/media/photo_test.py:22:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:36:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:40:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:46:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:51:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:56:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:62:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:68:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:74:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:80:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:86:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:94:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:100:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:105:80: E501 line too long (95 > 79 characters)
elodie/tests/media/photo_test.py:109:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:114:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:119:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:128:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/photo_test.py:137:80: E501 line too long (82 > 79 characters)
elodie/tests/media/photo_test.py:139:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:140:80: E501 line too long (80 > 79 characters)
elodie/tests/media/photo_test.py:155:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/photo_test.py:166:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:177:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/photo_test.py:186:1: E302 expected 2 blank lines, found 1
elodie/tests/media/photo_test.py:198:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/video_test.py:13:80: E501 line too long (131 > 79 characters)
elodie/tests/media/video_test.py:14:80: E501 line too long (97 > 79 characters)
elodie/tests/media/video_test.py:16:1: E402 module level import not at top of file
elodie/tests/media/video_test.py:17:1: E402 module level import not at top of file
elodie/tests/media/video_test.py:18:1: E402 module level import not at top of file
elodie/tests/media/video_test.py:22:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:36:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:42:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:48:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:54:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:61:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:67:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:72:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:77:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:89:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/video_test.py:98:80: E501 line too long (82 > 79 characters)
elodie/tests/media/video_test.py:100:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:104:80: E501 line too long (80 > 79 characters)
elodie/tests/media/video_test.py:114:5: E265 block comment should start with '# '
elodie/tests/media/video_test.py:115:5: E265 block comment should start with '# '
elodie/tests/media/video_test.py:119:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/video_test.py:130:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:144:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/video_test.py:153:1: E302 expected 2 blank lines, found 1
elodie/tests/media/video_test.py:168:19: E712 comparison to True should be 'if cond is True:' or 'if cond:'
elodie/tests/media/video_test.py:177:1: E302 expected 2 blank lines, found 1
when open the app, would be nice to have a link to github.
I would like to be able to move the folder .elodie to another place, for example my Google Drive. Like this way it would be easier to backup.
If .elodie not found in the user name, look for a environment variable ELODIE_HOME or ELODIE_CONF.
In cases like date_taken
we will fall back to the earlier of the modified or access time of the file if it is not available in EXIF. For these scenarios we should write the time we are using back into the EXIF.
When importing from a read-only source, I get the following error:
$ ./elodie.py import --source=~/Pictures/source --destination=~/Pictures/organized --album-from-folder
/usr/local/bin/exiftool -config "./elodie/configs/ExifTool_config" -xmp-elodie:Album="2015-08 MyEvent" "~/Pictures/source/2015/2015-08 MyEvent/P8242306.JPG"
Error: Error creating file: ~/Pictures/source/2015/2015-08 MyEvent/P8242306.JPG_exiftool_tmp - ~/Pictures/source/2015/2015-08 MyEvent/P8242306.JPG
And nothing is imported in the destination folder.
gh-47 by @zingo added caching for location coordinates. We can leverage the same cache to lookup a name and return its corresponding name.
In addition to a performance boost this lets us further customize location labels and folders as a result. If the location db contains a name
, lat
, long
set you can update a set of photos with that name. That means you can explicitly set labels and use ./elodie.py update --location="Home" /path/to/file.jpg
which would assign it the exact location from the cache and place the photo(s) into a folder named Home
instead of the normal "city name".
{"lat": 39.387227, "name": "Home", "long": -115.026129}
TODO: We need to come up with a way to backup/store the databases/caches that we're storing.
Since updating EXIF rewrites the file and can cause corruption we should consider copying the previous version of the file to some known location.
Taken from this comment on Medium.
https://medium.com/@sacherjj/with-exif-you-are-rewriting-the-file-every-time-you-change-anything-6aa25c5835fa#.4wjcrzpcg
ie why not provide a single --source
option and handle the "the source is a file" edge case in the code.
Hi, discovered your project on HN, looks like something I could use :)
Regarding the problem of photos with unknown location, the current solution consist to run the update
subcommand on them.
But say I have this folder tree :
├── 2015-06-Jun
│ ├── California
│ │ ├── 2015-06-29_16-34-14-img_3900.jpg
and an unknown location photo named 2015-06-29_17-07-06-img_3901.jpg
I think it would make the workflow even more painless, if I could ./elodie.py import --propagate ...
or something that would deduce that the photo has been taken in Cali since one half hour I took another one in this place.
A little magic/dangerous so should probably be turned off by default but does it make sense to you ?
Regards
(#46) I've made the image 'with-location-inv.jpg' that have the сoordinates inverted relative to 'with-location.jpg' and couple of tests. Tests added was failed. zserg/elodie@ea04b77
The following fix made test passed: zserg/elodie@95923e7
Marking a test as skipped for this by adding # -*- coding: utf-8
to the top of the file.
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/Users/jmathai/elodie/elodie/tests/media/photo.py", line 168, in test_set_title_non_ascii
status = photo.set_title('形声字 / 形聲字')
File "/Users/jmathai/elodie/elodie/media/photo.py", line 165, in set_title
exif_metadata['Xmp.dc.title'] = title
File "/usr/local/lib/python2.7/site-packages/pyexiv2/metadata.py", line 271, in __setitem__
return getattr(self, '_set_%s_tag' % family)(key, tag_or_value)
File "/usr/local/lib/python2.7/site-packages/pyexiv2/metadata.py", line 244, in _set_xmp_tag
tag = XmpTag(key, tag_or_value)
File "/usr/local/lib/python2.7/site-packages/pyexiv2/xmp.py", line 114, in __init__
self._set_value(value)
File "/usr/local/lib/python2.7/site-packages/pyexiv2/xmp.py", line 235, in _set_value
raw_value[k.encode('utf-8')] = v.encode('utf-8')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
I just tried to run the commands but they don't exist anymore. I guess it was renamed to ./elodie
There is no way to quit the app today. I have to kill the pid.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.