html_url,issue_url,id,node_id,user,user_label,created_at,updated_at,author_association,body,reactions,issue,issue_label,performed_via_github_app https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-626667235,https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22,626667235,MDEyOklzc3VlQ29tbWVudDYyNjY2NzIzNQ==,41546558,RhetTbull,2020-05-11T12:20:34Z,2020-05-11T12:20:34Z,CONTRIBUTOR,"@simonw FYI, osxphotos includes a built in ExifTool class that uses [exiftool](https://exiftool.org/) to read and write exif data. It's not exposed yet in the docs because I really only use it right now in the osphotos command line interface to write tags when exporting. In v0.28.16 (just pushed) I added an ExifTool.as_dict() method which will give you a dict with all the exif tags in a file. For example: ```python import osxphotos photos = osxphotos.PhotosDB().photos() exiftool = osxphotos.exiftool.ExifTool(photos[0].path) exifdata = exiftool.as_dict() tags = exifdata[""IPTC:Keywords""] ``` Not as elegant perhaps as a python only implementation because ExifTool has to make subprocess calls to an external tool but exiftool is by far the best tool available for reading and writing EXIF data and it does support HEIC. As for implementation, ExifTool uses a singleton pattern so the first time you instantiate it, it spawns an IPC to exiftool but then keeps it open and uses the same process for any subsequent calls (even on different files). ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",615626118,Try out ExifReader, https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-626941278,https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22,626941278,MDEyOklzc3VlQ29tbWVudDYyNjk0MTI3OA==,9599,simonw,2020-05-11T20:25:58Z,2020-05-11T20:25:58Z,MEMBER,"Interesting - do you know if there's anything the `exiftool` process handles that `ExifReader` doesn't? I'm actually just going to extract a subset of the EXIF data at first - since the original photo files will always be available I don't feel the need to get everything out for the first step. My plan is to use EXIF to help support photo collections that aren't in Apple Photos - I'm going to build a database table keyed by the `sha256` of each photo that extracts the camera make, lens, a few settings (ISO, aperture etc) and the GPS lat/lon.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",615626118,Try out ExifReader, https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-627007458,https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22,627007458,MDEyOklzc3VlQ29tbWVudDYyNzAwNzQ1OA==,41546558,RhetTbull,2020-05-11T22:51:52Z,2020-05-11T22:52:26Z,CONTRIBUTOR,"I'm not familiar with `ExifReader`. I wrote my own wrapper around `exiftool` because I wanted a simple way to write EXIF data when exporting photos (e.g. writing out to PersonInImage and keywords to IPTC:Keywords) and the existing python packages like [pyexiftool](https://github.com/smarnach/pyexiftool) didn't do quite what I wanted. If all you're after is the camera and shot info, that's available in `ZEXTENDEDATTRIBUTES` table. I've got an open issue [#11](https://github.com/RhetTbull/osxphotos/issues/11) to add this to osxphotos but it hasn't bubbled to the top of my backlog yet. osxphotos will give you the location info: `PhotoInfo.location` returns a tuple of (lat, lon) though this info is in ZEXTENDEDATTRIBUTES too (though it might not be correct as I believe Photos creates this table at import and the user might have changed the location of a photo, e.g. if camera didn't have GPS). ```sql CREATE TABLE ZEXTENDEDATTRIBUTES ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZFLASHFIRED INTEGER, ZISO INTEGER, ZMETERINGMODE INTEGER, ZSAMPLERATE INTEGER, ZTRACKFORMAT INTEGER, ZWHITEBALANCE INTEGER, ZASSET INTEGER, ZAPERTURE FLOAT, ZBITRATE FLOAT, ZDURATION FLOAT, ZEXPOSUREBIAS FLOAT, ZFOCALLENGTH FLOAT, ZFPS FLOAT, ZLATITUDE FLOAT, ZLONGITUDE FLOAT, ZSHUTTERSPEED FLOAT, ZCAMERAMAKE VARCHAR, ZCAMERAMODEL VARCHAR, ZCODEC VARCHAR, ZLENSMODEL VARCHAR ); ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",615626118,Try out ExifReader, https://github.com/simonw/datasette/issues/699#issuecomment-626807487,https://api.github.com/repos/simonw/datasette/issues/699,626807487,MDEyOklzc3VlQ29tbWVudDYyNjgwNzQ4Nw==,8431341,zeluspudding,2020-05-11T16:23:57Z,2020-05-11T16:24:59Z,NONE,`Authorization: bearer xxx` auth for API keys is a plus plus for me. Looked into just adding this into your `Flask` logic but learned this project doesn't use flask. Interesting 🤔,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,Authentication (and permissions) as a core concept, https://github.com/simonw/datasette/issues/699#issuecomment-626943809,https://api.github.com/repos/simonw/datasette/issues/699,626943809,MDEyOklzc3VlQ29tbWVudDYyNjk0MzgwOQ==,9599,simonw,2020-05-11T20:30:07Z,2020-05-11T20:31:18Z,OWNER,"I implemented bearer tokens in a private project of mine as a one-off plugin. I'm going to extract that out into a installable plugin soon. For the moment, my `plugins/token_auth.py` file looks like this: ```python from datasette import hookimpl import secrets class TokenAuth: def __init__( self, app, secret, auth, ): self.app = app self.secret = secret self.auth = auth async def __call__(self, scope, receive, send): if scope.get(""type"") != ""http"": return await self.app(scope, receive, send) authorization = dict(scope.get(""headers"") or {}).get(b""authorization"") or b"""" expected = ""Bearer {}"".format(self.secret).encode(""utf8"") if secrets.compare_digest(authorization, expected): scope = dict(scope, auth=self.auth) return await self.app(scope, receive, send) @hookimpl(trylast=True) def asgi_wrapper(datasette): config = datasette.plugin_config(""token-auth"") or {} secret = config.get(""secret"") auth = config.get(""auth"") def wrap_with_asgi_auth(app): return TokenAuth(app, secret=secret, auth=auth,) return wrap_with_asgi_auth ``` Then I have the following in `metadata.json`: ```json { ""plugins"": { ""token-auth"": { ""auth"": { ""name"": ""token-bot"" }, ""secret"": { ""$env"": ""TOKEN_SECRET"" } } } } ``` And a `TOKEN_SECRET` environment variable.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,Authentication (and permissions) as a core concept, https://github.com/simonw/datasette/issues/699#issuecomment-626945281,https://api.github.com/repos/simonw/datasette/issues/699,626945281,MDEyOklzc3VlQ29tbWVudDYyNjk0NTI4MQ==,9599,simonw,2020-05-11T20:32:33Z,2020-05-11T20:32:33Z,OWNER,"I did have a bit of trouble with this one-off plugin getting it to load in the correct order - since I need authentication to work if EITHER the one-off plugin spots a token or my `datasette-auth-github` plugin authenticates the user. That's why I want authentication as a core Datasette concept - so plugins like these can easily play together in a predictable manner.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,Authentication (and permissions) as a core concept, https://github.com/simonw/datasette/issues/699#issuecomment-626991001,https://api.github.com/repos/simonw/datasette/issues/699,626991001,MDEyOklzc3VlQ29tbWVudDYyNjk5MTAwMQ==,8431341,zeluspudding,2020-05-11T22:06:34Z,2020-05-11T22:06:34Z,NONE,Very nice! Thank you for sharing that :+1: :) Will try it out!,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",582526961,Authentication (and permissions) as a core concept, https://github.com/simonw/datasette/issues/764#issuecomment-626808805,https://api.github.com/repos/simonw/datasette/issues/764,626808805,MDEyOklzc3VlQ29tbWVudDYyNjgwODgwNQ==,9599,simonw,2020-05-11T16:26:17Z,2020-05-11T16:27:27Z,OWNER,"The keys here can be anything: https://packaging.python.org/guides/distributing-packages-using-setuptools/#project-urls So where do the icons come from? Turns out the PyPI site has special case rules for the icons here: https://github.com/pypa/warehouse/blob/2f00f4a9f208546ff0ebb6a6e61439021ca60a43/warehouse/templates/packaging/detail.html#L16-L60","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",616012427,Add PyPI project urls to setup.py, https://github.com/simonw/datasette/issues/764#issuecomment-626810129,https://api.github.com/repos/simonw/datasette/issues/764,626810129,MDEyOklzc3VlQ29tbWVudDYyNjgxMDEyOQ==,9599,simonw,2020-05-11T16:28:43Z,2020-05-11T16:28:43Z,OWNER,"For Datasette I'll go with: * Documentation * Changelog * Live demo * Source code * Issues * CI","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",616012427,Add PyPI project urls to setup.py, https://github.com/simonw/datasette/issues/764#issuecomment-626813924,https://api.github.com/repos/simonw/datasette/issues/764,626813924,MDEyOklzc3VlQ29tbWVudDYyNjgxMzkyNA==,9599,simonw,2020-05-11T16:36:06Z,2020-05-11T16:36:06Z,OWNER,Made a TIL: https://github.com/simonw/til/blob/master/pypi/project-links.md,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",616012427,Add PyPI project urls to setup.py, https://github.com/simonw/datasette/issues/765#issuecomment-626874374,https://api.github.com/repos/simonw/datasette/issues/765,626874374,MDEyOklzc3VlQ29tbWVudDYyNjg3NDM3NA==,9599,simonw,2020-05-11T18:25:43Z,2020-05-11T18:25:43Z,OWNER,"Trickiness here is what tag to use. Do we use the tag of the installed copy of Datasette that is running `datasette publish`? That would mean you don't get the latest features in your deployed release. Could hit an API to figure out the most recent version? Bit odd. Could we output the version of Datasette that was deployed and tell people they can run `--latest` to force the most recent release?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",616087149,publish heroku should default to currently tagged version, https://github.com/simonw/sqlite-utils/issues/110#issuecomment-626431484,https://api.github.com/repos/simonw/sqlite-utils/issues/110,626431484,MDEyOklzc3VlQ29tbWVudDYyNjQzMTQ4NA==,9599,simonw,2020-05-11T01:58:20Z,2020-05-11T01:58:20Z,OWNER,Released in 2.9 https://sqlite-utils.readthedocs.io/en/latest/changelog.html#v2-9,"{""total_count"": 1, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 1, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",613755043,Support decimal.Decimal type, https://github.com/simonw/sqlite-utils/issues/111#issuecomment-626417220,https://api.github.com/repos/simonw/sqlite-utils/issues/111,626417220,MDEyOklzc3VlQ29tbWVudDYyNjQxNzIyMA==,9599,simonw,2020-05-11T00:46:04Z,2020-05-11T00:46:04Z,OWNER,"Docs: * https://sqlite-utils.readthedocs.io/en/latest/cli.html#dropping-tables * https://sqlite-utils.readthedocs.io/en/latest/cli.html#dropping-views","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",615477131,sqlite-utils drop-table and drop-view commands, https://github.com/simonw/sqlite-utils/issues/111#issuecomment-626431562,https://api.github.com/repos/simonw/sqlite-utils/issues/111,626431562,MDEyOklzc3VlQ29tbWVudDYyNjQzMTU2Mg==,9599,simonw,2020-05-11T01:58:36Z,2020-05-11T01:58:36Z,OWNER,Released in 2.9 https://sqlite-utils.readthedocs.io/en/latest/changelog.html#v2-9,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",615477131,sqlite-utils drop-table and drop-view commands, https://github.com/simonw/sqlite-utils/issues/30#issuecomment-626903632,https://api.github.com/repos/simonw/sqlite-utils/issues/30,626903632,MDEyOklzc3VlQ29tbWVudDYyNjkwMzYzMg==,9599,simonw,2020-05-11T19:17:17Z,2020-05-11T19:17:17Z,OWNER,I don't think this is a useful feature.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",461215118,Option to open database in read-only mode,