checkdupes cli function, add readme

This commit is contained in:
dave 2019-06-21 09:22:42 -07:00
parent 4f218f068a
commit 6530d86617
5 changed files with 83 additions and 14 deletions

54
README.md Normal file
View File

@ -0,0 +1,54 @@
photolib
========
Cloud-native photo and related media library software, with a focus for photography hobbyists.
TODO longer description
Installation
------------
TODO
Usage
-----
After installation, photolib provides a CLI tool, `photocli`. It can be used as follows:
* `photocli checkdupes` - scan files and print those not already in the library:
```
$ find source -type f -exec shasum -a 256 {} \; | tee shas.txt
544b5a4f3898abae73260930ee70931a3992c048649692cef89b37576e886f69 source/2018-12-09 13.52.22.jpg
d2c2c30ca4986d364026644881d667162031008e60aac6a69d7b18230b7ea98c source/2019-04-08 20.05.02.jpg
9d42859ed92d7fb978cf73b41293480e1eab03d2d3a14c185c4daf3a49d324ab source/2019-06-19 16.28.07.png
...
$ photocli -s http://localhost:8080 checkdupes --sha-files shas.txt
```
TODO: support not using `--sha-files`
* `photocli ingest` - import new photos into the library:
```
$ photocli -s http://localhost:8080 ingest photos/*.jpg raws/*.cr2
...
```
TODO: implement this
There is some non-obvious behavior in the ingest process that is important to understand. Many photographers shoot in
multiple formats, in the sense that one click of the shutter produces multiple formats. Jpeg and Raw is common. During
ingest, photocli assumes that files with the same filename are multiple formats of the same image. E.g., if you have
both `IMG_1234.JPG` and `IMG_1234.cr2`, the two images will be grouped in the library. This combination action is only
applied during ingest; images already in the library that happen to share a filename with a file being imported will
not be merged. To add a format to a photo already in the library, see `photocli addformat`.

View File

@ -1,6 +1,8 @@
import argparse
import requests
from requests.exceptions import HTTPError
from photoapp.utils import get_extension
from photoapp.types import known_extensions
class PhotoApiClient(object):
@ -32,7 +34,6 @@ def main():
p_ingest.add_argument("-c", "--copy-of", help="existing uuid the imported images will be placed under")
args = parser.parse_args()
print(args)
client = PhotoApiClient(args.host)
@ -48,20 +49,24 @@ def main():
if not line:
continue
sha, path = line.split(maxsplit=1)
hashes[sha] = path.rstrip("\n")
path = path.rstrip("\n")
if get_extension(path) not in known_extensions:
continue
hashes[sha] = path
else:
raise NotImplementedError("must pass --sha-files for now")
for sha, path in hashes.items():
# hit http://localhost:8080/api/v1/byhash?sha=afe49172f709725a4503c9219fb4c6a9db8ad0354fc493f2f500269ac6faeaf6
# if the file is a dupe, do nothing
# if the file is original, print its path
try:
print(client.byhash(sha))
client.byhash(sha)
# if the file is a dupe, do nothing
except HTTPError as he:
print(repr(he.response.status_code))
# print(hashes)
# if the file is original, print its path
if he.response.status_code == 404:
print(path)
else:
raise
if __name__ == "__main__":

View File

@ -4,9 +4,10 @@ import traceback
from photoapp.library import PhotoLibrary
from photoapp.image import get_jpg_info, get_hash, get_mtime
from itertools import chain
from photoapp.types import Photo, PhotoSet
from photoapp.types import Photo, PhotoSet, known_extensions, regular_images, files_raw, files_video
import os
"""
Photo sorting rules:
@ -20,11 +21,6 @@ mov, video, or other
modification date
"""
known_extensions = ["jpg", "png", "cr2", "xmp", "mp4", "mov"]
regular_images = ["jpg", "png"]
files_raw = ["cr2", "xmp"]
files_video = ["mp4", "mov"]
def pprogress(done, total=None):
print(" complete: {}{}\r".format(done, " / {} ".format(total) if total else ''), end='')

View File

@ -7,6 +7,12 @@ import uuid
import enum
known_extensions = ["jpg", "png", "cr2", "xmp", "mp4", "mov"]
regular_images = ["jpg", "png"]
files_raw = ["cr2", "xmp"]
files_video = ["mp4", "mov"]
class PhotoStatus(enum.Enum):
private = 0
public = 1

View File

@ -1,3 +1,4 @@
import os
import cherrypy
from photoapp.types import PhotoSet, PhotoStatus
@ -15,6 +16,13 @@ def mime2ext(mime):
"video/quicktime": "mov"}[mime]
def get_extension(fname):
parts = os.path.basename(fname).split(".")
if len(parts) == 1:
return None
return parts[-1].lower()
def auth():
"""
Return the currently authorized username (per request) or None