Package: dogsheep-photos
dogsheep-photosSave details of your photos to a SQLite database and upload them to S3.SeeUsing SQL to find my best photo of a pelican according to Apple Photosfor background information on this project.What these tools doThese tools are a work-in-progress mechanism for taking full ownership of your photos. The core idea is to help implement the following:Every photo you have taken lives in a single, private Amazon S3 bucketYou have a single SQLite database file which stores metadata about those photos - potentially pulled from multiple different places. This may include EXIF data, Apple Photos, the results of running machine learning APIs against photos and much more besides.You can then useDatasetteto explore your own photos.I'm a heavy user of Apple Photos so the initial releases of this tool will have a bias towards that, but ideally I would like a subset of these tools to be useful to people no matter which core photo solution they are using.Installation$ pip install dogsheep-photosAuthentication (if using S3)If you want to use S3 to store your photos, you will need to first create S3 credentials for a new, dedicated bucket.This is a big pain. Here'show I did it.Run this command and paste in your credentials. You will need three values: the name of your S3 bucket, your Access key ID and your Secret access key.$ dogsheep-photos s3-authThis will create a file calledauth.jsonin your current directory containing the required values. To save the file at a different path or filename, use the--auth=myauth.jsonoption.Uploading photosRun this command to upload every photo in a specific directory to your S3 bucket:$ dogsheep-photos upload photos.db \
    ~/Pictures/Photos\ Library.photoslibrary/originalThe command will only upload photos that have not yet been uploaded, based on their sha256 hash.photos.dbwill be created with anuploadstable containing details of which files were uploaded.To see what the command would do without uploading any files, use the--dry-runoption.The sha256 hash of the photo contents will be used as the name of the file in the bucket, with an extension matching the type of file. This is an implementation of theContent addressable storagepattern.Importing Apple Photos metadataTheapple-photoscommand imports metadata from your Apple Photos library.$ photo-to-sqlite apple-photos photos.dbImported metadata includes places, people, albums, quality scores and machine learning labels for the photo contents.Creating a subset databaseYou can create a new, subset database of photos using thecreate-subsetcommand.This is useful for creating a shareable SQLite database that only contains metadata for a selected set of photos.Since photo metadata contains latitude and longitude you may not want to share a database that includes photos taken at your home address.create-subsettakes three arguments: an existing database file created using theapple-photoscommand, the name of the new, shareable database file you would like to create and a SQL query that returns thesha256hash values of the photos you would like to include in that database.For example, here's how to create a shareable database of just the photos that have been added to albums containing the word "Public":$ dogsheep-photos create-subset \
    photos.db \
    public.db \
    "select sha256 from apple_photos where albums like '%Public%'"Serving photos locally with datasette-mediaIf you don't want to upload your photos to S3 but you still want to browse them using Datasette you can do so using thedatasette-mediaplugin. This plugin adds the ability to serve images and other static files directly from disk, configured using a SQL query.To use it, first install Datasette and the plugin:$ pip install datasette datasette-mediaIf any of your photos are.HEICimages taken by an iPhone you should also install the optionalpyheifdependency:$ pip install pyheifNow create ametadata.yamlfile configuring the plugin:plugins:datasette-media:thumbnail:sql:|-select path as filepath, 200 as resize_height from apple_photos where uuid = :keylarge:sql:|-select path as filepath, 1024 as resize_height from apple_photos where uuid = :keyThis will configure two URL endpoins - one for 200 pixel high thumbnails and one for 1024 pixel hight larger images.Create yourphotos.dbdatabase using theapple-photoscommand, then run Datasette like this:$ datasette -m metadata.yamlYour photos will be served on URLs that look like this:http://127.0.0.1:8001/-/media/thumbnail/F4469918-13F3-43D8-9EC1-734C0E6B60AD
http://127.0.0.1:8001/-/media/large/F4469918-13F3-43D8-9EC1-734C0E6B60ADYou can find the UUIDs for use in these URLs by runningselect uuid from photos_with_apple_metadata.Displaying images using datasette-json-htmlIf you are usingdatasette-mediato serve photos you can include images directly in Datasette query results using thedatasette-json-htmlplugin.Runpip install datasette-json-htmlto install the plugin, then use queries like this to view your images:selectjson_object('img_src','/-/media/thumbnail/'||uuid)asphoto,uuid,datefromapple_photosorderbydatedesclimit10;Thephotocolumn returned by this query should render as image tags that display the correct images.Displaying images using custom template pagesDatasette'scustom pagesfeature lets you create custom pages for a Datasette instance by dropping HTML templates into atemplates/pagesdirectory and then running Datasette usingdatasette --template-dir=templates/.You can combine that ability with thedatasette-template-sqlplugin to create custom template pages that directly display photos served bydatasette-media.Install the plugin usingpip install datasette-template-sql.Create atemplates/pagesfolder and add the following files:recent-photos.html<h1>Recent photos</h1><div>{%forphotoinsql("select * from apple_photos order by date desc limit 20")%}<imgsrc="/-/media/photo/{{photo['uuid']}}">{%endfor%}</div>random-photos.html<h1>Random photos</h1><div>{%forphotoinsql("with foo as (select * from apple_photos order by date desc limit 5000) select * from foo order by random() limit 20")%}<imgsrc="/-/media/photo/{{photo['uuid']}}">{%endfor%}</div>Now run Datasette like this:$ datasette photos.db -m metadata.yaml --template-dir=templates/Visitinghttp://localhost:8001/recent-photoswill display 20 recent photos. Visitinghttp://localhost:8001/random-photoswill display 20 photos randomly selected from your 5,000 most recent.