home / github

Menu
  • GraphQL API

issue_comments

Table actions
  • GraphQL API for issue_comments

7,983 rows sorted by html_url

✎ View and edit SQL

This data as json, CSV (advanced)

created_at (date) >30 ✖

  • 2021-03-22 66
  • 2021-11-19 60
  • 2020-10-15 52
  • 2020-09-22 51
  • 2020-10-30 49
  • 2022-03-21 46
  • 2020-12-18 43
  • 2020-06-09 42
  • 2020-06-18 41
  • 2020-10-20 40
  • 2022-01-09 40
  • 2020-05-27 39
  • 2021-11-16 39
  • 2021-12-16 39
  • 2020-12-30 38
  • 2020-10-09 36
  • 2021-11-20 36
  • 2022-01-20 36
  • 2022-03-19 36
  • 2020-09-15 34
  • 2021-11-29 34
  • 2020-06-08 33
  • 2021-01-04 33
  • 2021-05-27 33
  • 2022-02-06 33
  • 2020-06-01 32
  • 2022-03-05 32
  • 2019-06-24 31
  • 2021-08-13 31
  • 2022-04-28 31
  • …
id html_url ▼ issue_url node_id user created_at updated_at author_association body reactions issue performed_via_github_app
624284539 https://github.com/dogsheep/dogsheep-photos/issues/17#issuecomment-624284539 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/17 MDEyOklzc3VlQ29tbWVudDYyNDI4NDUzOQ== RhetTbull 41546558 2020-05-05T20:20:05Z 2020-05-05T20:20:05Z CONTRIBUTOR FYI, I've got an [issue](https://github.com/RhetTbull/osxphotos/issues/25) to make osxphotos cross-platform but it's low on my priority list. About 90% of the functionality could be done cross-platform but right now the MacOS specific stuff is embedded throughout and would take some work. Though I try to minimize it, there's sprinklings of ObjC & Applescript throughout osxphotos. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Only install osxphotos if running on macOS 612860531  
624364557 https://github.com/dogsheep/dogsheep-photos/issues/18#issuecomment-624364557 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/18 MDEyOklzc3VlQ29tbWVudDYyNDM2NDU1Nw== simonw 9599 2020-05-05T23:49:18Z 2020-05-05T23:49:18Z MEMBER Label is `macos-latest` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Switch CI solution to GitHub Actions with a macOS runner 612860758  
624406285 https://github.com/dogsheep/dogsheep-photos/issues/19#issuecomment-624406285 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/19 MDEyOklzc3VlQ29tbWVudDYyNDQwNjI4NQ== simonw 9599 2020-05-06T02:10:03Z 2020-05-06T02:10:03Z MEMBER Most annoying part of this is the difficulty of actually showing a photo. Maybe I need to run a local proxy that I can link to? A custom Datasette plugin perhaps? {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} apple-photos command should work even if upload has not run 613002220  
615931488 https://github.com/dogsheep/dogsheep-photos/issues/2#issuecomment-615931488 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/2 MDEyOklzc3VlQ29tbWVudDYxNTkzMTQ4OA== simonw 9599 2020-04-18T19:24:02Z 2020-04-18T19:24:02Z MEMBER I made a start on this last week with a https://github.com/simonw/heic-to-jpeg proxy. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to convert HEIC images to JPEG 602533352  
624408220 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-624408220 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYyNDQwODIyMA== simonw 9599 2020-05-06T02:18:47Z 2020-05-06T02:18:47Z MEMBER The `apple_photos` table has an indexed `uuid` column and a `path` column which stores the full path to that photo file on disk. I can write a custom Datasette plugin which takes the `uuid` from the URL, looks up the path, then serves up a thumbnail of the jpeg or heic image file. I'll prototype this is a one-off plugin first, then package it on PyPI for other people to install. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
624408370 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-624408370 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYyNDQwODM3MA== simonw 9599 2020-05-06T02:19:27Z 2020-05-06T02:19:27Z MEMBER The plugin can be generalized: it can be configured to know how to take the URL path, look it up in ANY table (via a custom SQL query) to get a path on disk and then serve that. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
624408738 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-624408738 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYyNDQwODczOA== simonw 9599 2020-05-06T02:21:05Z 2020-05-06T02:21:32Z MEMBER Here's rendering code from my hacked-together not-yet-released S3 image proxy: ```python from starlette.responses import Response from PIL import Image, ExifTags import pyheif for ORIENTATION_TAG in ExifTags.TAGS.keys(): if ExifTags.TAGS[ORIENTATION_TAG] == "Orientation": break ... # Load it into Pillow if ext == "heic": heic = pyheif.read_heif(image_response.content) image = Image.frombytes(mode=heic.mode, size=heic.size, data=heic.data) else: image = Image.open(io.BytesIO(image_response.content)) # Does EXIF tell us to rotate it? try: exif = dict(image._getexif().items()) if exif[ORIENTATION_TAG] == 3: image = image.rotate(180, expand=True) elif exif[ORIENTATION_TAG] == 6: image = image.rotate(270, expand=True) elif exif[ORIENTATION_TAG] == 8: image = image.rotate(90, expand=True) except (AttributeError, KeyError, IndexError): pass # Resize based on ?w= and ?h=, if set width, height = image.size w = request.query_params.get("w") h = request.query_params.get("h") if w is not None or h is not None: if h is None: # Set h based on w w = int(w) h = int((float(height) / width) * w) elif w is None: h = int(h) # Set w based on h w = int((float(width) / height) * h) w = int(w) h = int(h) image.thumbnail((w, h)) # ?bw= converts to black and white if request.query_params.get("bw"): image = image.convert("L") # ?q= sets the quality - defaults to 75 quality = 75 q = request.query_params.get("q") if q and q.isdigit() and 1 <= int(q) <= 100: quality = int(q) # Output as JPEG or PNG output_image = io.BytesIO() image_type = "JPEG" kwargs = {"quality": quality} if image.format == "PNG": image_type = "PNG" kwargs = {} … {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
625947133 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-625947133 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYyNTk0NzEzMw== simonw 9599 2020-05-08T18:13:06Z 2020-05-08T18:13:06Z MEMBER `datasette-media` will be able to handle this once I implement https://github.com/simonw/datasette-media/issues/3 {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
633234781 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-633234781 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYzMzIzNDc4MQ== dmd 41439 2020-05-24T13:56:13Z 2020-05-24T13:56:13Z NONE As that seems to be closed, can you give a hint on how to make this work? {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
633626741 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-633626741 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYzMzYyNjc0MQ== simonw 9599 2020-05-25T15:38:55Z 2020-05-25T15:38:55Z MEMBER Sure, I should absolutely document this! {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
633629944 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-633629944 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYzMzYyOTk0NA== simonw 9599 2020-05-25T15:47:42Z 2020-05-25T15:47:42Z MEMBER I'll add a proper section to the README, but for the moment here's how I do this. First, install `datasette` and the `datasette-media` plugin. Create a `metadata.yaml` file with the following content: ```yaml plugins: datasette-media: photo: sql: |- select path as filepath, 200 as resize_height from apple_photos where uuid = :key photo-big: sql: |- select path as filepath, 1024 as resize_height from apple_photos where uuid = :key ``` Now run `datasette -m metadata.yaml photos.db` - thumbnails will be served at http://127.0.0.1:8001/-/media/photo/F4469918-13F3-43D8-9EC1-734C0E6B60AD and larger sizes of the image at http://127.0.0.1:8001/-/media/photo-big/A8B02C7D-365E-448B-9510-69F80C26304D I also made myself two custom pages, one showing recent images and one showing random images. To do this, install the `datasette-template-sql` plugin and then create a `templates/pages` directory and add these files: `recent-photos.html` ```html <h1>Recent photos</h1> <div> {% for photo in sql("select * from apple_photos order by date desc limit 100") %} <img src="/-/media/photo/{{ photo['uuid'] }}"> {% endfor %} </div> ``` `random-photos.html` ```html <h1>Random photos</h1> <div> {% for photo in sql("with foo as (select * from apple_photos order by date desc limit 5000) select * from foo order by random() limit 100") %} <img src="/-/media/photo/{{ photo['uuid'] }}"> {% endfor %} </div> ``` Now run `datasette -m metadata.yaml photos.db --template-dir=templates/` Visit http://127.0.0.1:8001/random-photos to see some random photos or http://127.0.0.1:8002/recent-photos for recent photos. This is using this mechanism: https://datasette.readthedocs.io/en/stable/custom_templates.html#custom-pages {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
633643921 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-633643921 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYzMzY0MzkyMQ== simonw 9599 2020-05-25T16:29:44Z 2020-05-25T16:29:44Z MEMBER https://github.com/dogsheep/dogsheep-photos/blob/dc43fa8653cb9c7238a36f52239b91d1ec916d5c/README.md#serving-photos-locally-with-datasette-media {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
633644225 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-633644225 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYzMzY0NDIyNQ== simonw 9599 2020-05-25T16:30:44Z 2020-05-25T16:30:44Z MEMBER I'll add docs on using `datasette-json-html` too. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
633704127 https://github.com/dogsheep/dogsheep-photos/issues/20#issuecomment-633704127 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/20 MDEyOklzc3VlQ29tbWVudDYzMzcwNDEyNw== simonw 9599 2020-05-25T20:14:22Z 2020-05-25T20:14:22Z MEMBER https://github.com/dogsheep/dogsheep-photos/blob/0.4.1/README.md#serving-photos-locally-with-datasette-media {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Ability to serve thumbnailed Apple Photo from its place on disk 613006393  
626388764 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626388764 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM4ODc2NA== simonw 9599 2020-05-10T20:58:52Z 2020-05-10T20:58:52Z MEMBER More from the debugger: ``` > /Users/simon/.local/share/virtualenvs/photos-to-sqlite-0uGSHd6e/lib/python3.8/site-packages/osxphotos/photoinfo.py(614)place() -> self._place = PlaceInfo5(self._info["reverse_geolocation"]) ``` And: ``` > /Users/simon/Dropbox/Development/photos-to-sqlite/photos_to_sqlite/utils.py(91)osxphoto_to_row() -> place = photo.place ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626388837 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626388837 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM4ODgzNw== simonw 9599 2020-05-10T20:59:32Z 2020-05-10T20:59:32Z MEMBER So it appears it's possible for `photo.place` to raise that exception. A workaround could be to catch that and treat those photos as not having a place. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626390317 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626390317 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5MDMxNw== RhetTbull 41546558 2020-05-10T21:11:24Z 2020-05-10T21:50:58Z CONTRIBUTOR Ugh....Yeah, I think easiest is to catch the exception and return no place as you suggest. This particular bit of code involves un-archiving a serialized NSKeyedArchiver which uses an object table and it is certainly possible to create a circular reference that way. Because this is happening in the decode, the circular reference must be in the original data. Does Photos show valid reverse geolocation info for the photo in question? If so, Photos may be doing something beyond a simple decode of the binary plist. For now, I'll push a patch to catch the exception. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626394989 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626394989 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NDk4OQ== simonw 9599 2020-05-10T21:50:36Z 2020-05-10T21:50:36Z MEMBER https://github.com/Marketcircle/bpylist/pull/2 looks relevant here. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626395103 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626395103 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NTEwMw== simonw 9599 2020-05-10T21:51:36Z 2020-05-10T21:51:36Z MEMBER @RhetTbull I tried that workaround and it turns out I'm getting this error on ALL of my photos now! It's weird: a few day ago this wasn't happening. Now it's happening to everything. I'm not sure what I might have changed. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626395209 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626395209 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NTIwOQ== simonw 9599 2020-05-10T21:52:42Z 2020-05-10T21:52:42Z MEMBER Aha! It looks like I accidentally installed the old bplist into the same environment: ``` $ pip freeze | grep bpylist bpylist==0.1.4 bpylist2==3.0.0 ``` {"total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626395507 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626395507 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NTUwNw== RhetTbull 41546558 2020-05-10T21:54:45Z 2020-05-10T21:54:45Z CONTRIBUTOR @simonw does Photos show valid reverse geolocation info? Are you sure you're using [bpylist2](https://github.com/xa4a/bpylist2) and not bpylist? They're both unfortunately imported as "bpylist" so if you somehow got the wrong (original bpylist) version installed, it could be the issue. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626395641 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626395641 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NTY0MQ== RhetTbull 41546558 2020-05-10T21:55:54Z 2020-05-10T21:55:54Z CONTRIBUTOR Did removing old bpylist solve the original problem or do you still have a photo that throws circular reference? {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626395781 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626395781 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NTc4MQ== simonw 9599 2020-05-10T21:57:09Z 2020-05-10T21:57:09Z MEMBER Yes, I just recreated my virtual environment from scratch and the error went away. The problem occurred when I ran `pip install datasette-bplist` in the same virtual environment - https://github.com/simonw/datasette-bplist/blob/master/setup.py depends on `bpylist` which is incompatible with `bpylist2`. {"total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626396379 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-626396379 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDYyNjM5NjM3OQ== RhetTbull 41546558 2020-05-10T22:01:48Z 2020-05-10T22:01:48Z CONTRIBUTOR Frustrates me when package authors create a "drop in" replacement with the same import name...this kind of thing has bitten me more than once! Would've been nicer I think for bpylist2 to do "import bpylist2 as bpylist" {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
748436195 https://github.com/dogsheep/dogsheep-photos/issues/21#issuecomment-748436195 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/21 MDEyOklzc3VlQ29tbWVudDc0ODQzNjE5NQ== nickvazz 8573886 2020-12-19T07:44:32Z 2020-12-19T07:44:49Z NONE I have also run into this a bit, would it be possible to post your `requirements.txt` so I can try and reproduce your [blog post](https://simonwillison.net/2020/May/21/dogsheep-photos/)? {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} bpylist.archiver.CircularReference: archive has a cycle with uid(13) 615474990  
626667235 https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-626667235 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22 MDEyOklzc3VlQ29tbWVudDYyNjY2NzIzNQ== RhetTbull 41546558 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} Try out ExifReader 615626118  
626941278 https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-626941278 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22 MDEyOklzc3VlQ29tbWVudDYyNjk0MTI3OA== simonw 9599 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} Try out ExifReader 615626118  
627007458 https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-627007458 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22 MDEyOklzc3VlQ29tbWVudDYyNzAwNzQ1OA== RhetTbull 41546558 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} Try out ExifReader 615626118  
628405453 https://github.com/dogsheep/dogsheep-photos/issues/22#issuecomment-628405453 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/22 MDEyOklzc3VlQ29tbWVudDYyODQwNTQ1Mw== RhetTbull 41546558 2020-05-14T05:59:53Z 2020-05-14T05:59:53Z CONTRIBUTOR I've added support for the above exif data to [v0.28.17](https://github.com/RhetTbull/osxphotos/releases/tag/v0.28.17) of osxphotos. `PhotoInfo.exif_info` will return an `ExifInfo` [dataclass](https://docs.python.org/3/library/dataclasses.html) object with the following properties: ```python flash_fired: bool iso: int metering_mode: int sample_rate: int track_format: int white_balance: int aperture: float bit_rate: float duration: float exposure_bias: float focal_length: float fps: float latitude: float longitude: float shutter_speed: float camera_make: str camera_model: str codec: str lens_model: str ``` It's not all the EXIF data available in most files but is the data Photos deems important to save. Of course, you can get all the exif_data Note: this only works in Photos 5. As best as I can tell, EXIF data is not stored in the database for earlier versions. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Try out ExifReader 615626118  
631120771 https://github.com/dogsheep/dogsheep-photos/issues/23#issuecomment-631120771 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/23 MDEyOklzc3VlQ29tbWVudDYzMTEyMDc3MQ== simonw 9599 2020-05-19T22:32:48Z 2020-05-19T22:32:48Z MEMBER Documentation: https://github.com/dogsheep/photos-to-sqlite/blob/e2fab012551eed05278040b5d57e7373a1b9a0bf/README.md#creating-a-subset-database {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} create-subset command for creating a publishable subset of a photos database 621280529  
631255206 https://github.com/dogsheep/dogsheep-photos/issues/24#issuecomment-631255206 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/24 MDEyOklzc3VlQ29tbWVudDYzMTI1NTIwNg== simonw 9599 2020-05-20T06:00:25Z 2020-05-20T06:00:25Z MEMBER This needs documentation. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Configurable URL for images 621323348  
631127454 https://github.com/dogsheep/dogsheep-photos/issues/25#issuecomment-631127454 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/25 MDEyOklzc3VlQ29tbWVudDYzMTEyNzQ1NA== simonw 9599 2020-05-19T22:48:00Z 2020-05-21T15:58:32Z MEMBER I built #23 to help with this. $ dogsheep-photos create-subset photos.db public.db \ "select sha256 from apple_photos where albums like '%Public%'" And publish with Vercel: $ datasette publish now public.db --project dogsheep-photos \ --about=dogsheep/dogsheep-photos \ --about_url="https://github.com/dogsheep/dogsheep-photos" \ --install=datasette-json-html \ --install=datasette-cluster-map {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Create a public demo 621332242  
631251707 https://github.com/dogsheep/dogsheep-photos/issues/25#issuecomment-631251707 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/25 MDEyOklzc3VlQ29tbWVudDYzMTI1MTcwNw== simonw 9599 2020-05-20T05:49:27Z 2020-05-21T15:58:42Z MEMBER Renaming this demo to `dogsheep-photos.dogsheep.net` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Create a public demo 621332242  
631253136 https://github.com/dogsheep/dogsheep-photos/issues/25#issuecomment-631253136 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/25 MDEyOklzc3VlQ29tbWVudDYzMTI1MzEzNg== simonw 9599 2020-05-20T05:53:58Z 2020-05-20T05:53:58Z MEMBER Updated deploy command: ``` datasette publish now public.db --project dogsheep-photos \ --about=dogsheep/dogsheep-photos \ --about_url="https://github.com/dogsheep/dogsheep-photos" \ --install=datasette-json-html \ --install=datasette-cluster-map \ --title "Dogsheep Photos demo" ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Create a public demo 621332242  
631253248 https://github.com/dogsheep/dogsheep-photos/issues/25#issuecomment-631253248 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/25 MDEyOklzc3VlQ29tbWVudDYzMTI1MzI0OA== simonw 9599 2020-05-20T05:54:18Z 2020-05-20T05:54:18Z MEMBER https://dogsheep-photos.dogsheep.net/ {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Create a public demo 621332242  
631253852 https://github.com/dogsheep/dogsheep-photos/issues/25#issuecomment-631253852 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/25 MDEyOklzc3VlQ29tbWVudDYzMTI1Mzg1Mg== simonw 9599 2020-05-20T05:56:17Z 2020-05-21T22:26:16Z MEMBER I have a `deploy-demo.sh` script now: ```bash #!/bin/bash if [ -f public.db ]; then rm public.db fi pipenv run dogsheep-photos create-subset photos.db public.db \ "select sha256 from apple_photos where albums like '%Public%'" pipenv run sqlite-utils create-view public.db photos_on_a_map \ "select date, latitude, longitude, apple_photos.sha256, uploads.ext, json_object( 'title', 'Taken on ' || date, 'image', 'https://photos.simonwillison.net/i/' || uploads.sha256 || '.' || uploads.ext || '?w=400', 'link', 'https://photos.simonwillison.net/i/' || uploads.sha256 || '.' || uploads.ext || '?w=1200' ) as popup from apple_photos join uploads on apple_photos.sha256 = uploads.sha256 where latitude is not null order by date desc" \ --replace pipenv run datasette publish now public.db --project dogsheep-photos \ --about=dogsheep/dogsheep-photos \ --about_url="https://github.com/dogsheep/dogsheep-photos" \ --install=datasette-json-html \ --install=datasette-pretty-json \ --install=datasette-cluster-map>=0.10 \ --title "Dogsheep Photos demo" ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Create a public demo 621332242  
631226481 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631226481 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyNjQ4MQ== simonw 9599 2020-05-20T04:18:29Z 2020-05-20T04:18:29Z MEMBER I just renamed the repository. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631226572 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631226572 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyNjU3Mg== simonw 9599 2020-05-20T04:18:52Z 2020-05-20T04:18:52Z MEMBER Need to reconfigure Circle CI. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631226953 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631226953 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyNjk1Mw== simonw 9599 2020-05-20T04:20:34Z 2020-05-20T04:20:34Z MEMBER Huh, it looks like Circle CI picked up the name change automatically. https://app.circleci.com/pipelines/github/dogsheep/dogsheep-photos {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631227020 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631227020 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyNzAyMA== simonw 9599 2020-05-20T04:20:48Z 2020-05-20T04:21:16Z MEMBER Next time I push a release it will create `dogsheep-photos` on PyPI. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631227105 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631227105 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyNzEwNQ== simonw 9599 2020-05-20T04:21:06Z 2020-05-20T04:21:06Z MEMBER Then I just need to push a final photos-to-sqlite release that updates the README to tell people about the name change. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631227245 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631227245 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyNzI0NQ== simonw 9599 2020-05-20T04:21:38Z 2020-05-20T04:21:38Z MEMBER I'm going to release 0.4 now. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631229409 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631229409 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyOTQwOQ== simonw 9599 2020-05-20T04:30:40Z 2020-05-20T04:30:40Z MEMBER https://pypi.org/project/photos-to-sqlite/ now links to dogsheep-photos. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
631229485 https://github.com/dogsheep/dogsheep-photos/issues/26#issuecomment-631229485 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/26 MDEyOklzc3VlQ29tbWVudDYzMTIyOTQ4NQ== simonw 9599 2020-05-20T04:31:02Z 2020-05-20T04:31:02Z MEMBER https://pypi.org/project/dogsheep-photos/ is live. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Rename project to dogsheep-photos 621444763  
751125270 https://github.com/dogsheep/dogsheep-photos/issues/28#issuecomment-751125270 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/28 MDEyOklzc3VlQ29tbWVudDc1MTEyNTI3MA== jmelloy 129786 2020-12-24T22:26:22Z 2020-12-24T22:26:22Z NONE This comes around if you’ve run the photo export without running an s3 upload. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Invalid SQL no such table: main.uploads 624490929  
934207940 https://github.com/dogsheep/dogsheep-photos/issues/3#issuecomment-934207940 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/3 IC_kwDOD079W843ruHE jratike80 1751612 2021-10-05T08:57:41Z 2021-10-05T08:57:41Z NONE Maybe the exif-loader from the SpatiaLite project could be useful as a reference even it is written in C and it also saves images as blobs https://www.gaia-gis.it/fossil/spatialite-tools/file?name=exif_loader.c&ci=tip. The tool is also integrated into the spatialite-gui application. I found some user documentation from the web archive http://web.archive.org/web/20180629041238/https://www.gaia-gis.it/spatialite-2.3.1/spatialite-exif-2.3.1.html. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Import EXIF data into SQLite - lens used, ISO, aperture etc 602533481  
934372104 https://github.com/dogsheep/dogsheep-photos/issues/3#issuecomment-934372104 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/3 IC_kwDOD079W843sWMI RhetTbull 41546558 2021-10-05T12:38:24Z 2021-10-05T12:38:24Z CONTRIBUTOR As dogsheep-photos already uses [osxphotos](https://github.com/RhetTbull/osxphotos) to load photos you can access the EXIF data via osxphotos. Apple Photos imports a small subset of EXIF data at the time the photo is imported and osxphotos provides this via the [exif_info](https://github.com/RhetTbull/osxphotos#exifinfo) property. If you want the full EXIF data, osxphotos also provides a wrapper around [exiftool](https://github.com/RhetTbull/osxphotos#exiftool). {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Import EXIF data into SQLite - lens used, ISO, aperture etc 602533481  
791053721 https://github.com/dogsheep/dogsheep-photos/issues/32#issuecomment-791053721 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/32 MDEyOklzc3VlQ29tbWVudDc5MTA1MzcyMQ== dsisnero 6213 2021-03-05T00:31:27Z 2021-03-05T00:31:27Z NONE I am getting the same thing for US West (N. California) us-west-1 {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} KeyError: 'Contents' on running upload 803333769  
882091516 https://github.com/dogsheep/dogsheep-photos/issues/32#issuecomment-882091516 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/32 IC_kwDOD079W840k6X8 aaronyih1 10793464 2021-07-18T17:29:39Z 2021-07-18T17:33:02Z NONE Same here for US West (N. California) us-west-1. Running on Catalina. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} KeyError: 'Contents' on running upload 803333769  
884688833 https://github.com/dogsheep/dogsheep-photos/issues/32#issuecomment-884688833 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/32 IC_kwDOD079W840u0fB aaronyih1 10793464 2021-07-22T06:40:25Z 2021-07-22T06:40:25Z NONE The solution here is to upload an image to the bucket first. It is caused because it does not properly handle the case when there are no images in the bucket. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} KeyError: 'Contents' on running upload 803333769  
777951854 https://github.com/dogsheep/dogsheep-photos/issues/33#issuecomment-777951854 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/33 MDEyOklzc3VlQ29tbWVudDc3Nzk1MTg1NA== leafgarland 675335 2021-02-12T03:54:39Z 2021-02-12T03:54:39Z NONE I think that is a typo in the docs, you can use > dogsheep-photos apple-photos photos.db {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} photo-to-sqlite: command not found 803338729  
778002092 https://github.com/dogsheep/dogsheep-photos/issues/33#issuecomment-778002092 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/33 MDEyOklzc3VlQ29tbWVudDc3ODAwMjA5Mg== robmarkcole 11855322 2021-02-12T06:19:32Z 2021-02-12T06:19:32Z NONE hi @leafgarland that results in a new error: ``` (venv) (base) Robins-MacBook:datasette robin$ dogsheep-photos apple-photos photos.db Traceback (most recent call last): File "/Users/robin/datasette/venv/bin/dogsheep-photos", line 8, in <module> sys.exit(cli()) File "/Users/robin/datasette/venv/lib/python3.8/site-packages/click/core.py", line 829, in __call__ return self.main(*args, **kwargs) File "/Users/robin/datasette/venv/lib/python3.8/site-packages/click/core.py", line 782, in main rv = self.invoke(ctx) File "/Users/robin/datasette/venv/lib/python3.8/site-packages/click/core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/Users/robin/datasette/venv/lib/python3.8/site-packages/click/core.py", line 1066, in invoke return ctx.invoke(self.callback, **ctx.params) File "/Users/robin/datasette/venv/lib/python3.8/site-packages/click/core.py", line 610, in invoke return callback(*args, **kwargs) File "/Users/robin/datasette/venv/lib/python3.8/site-packages/dogsheep_photos/cli.py", line 206, in apple_photos db.conn.execute( sqlite3.OperationalError: no such table: attached.ZGENERICASSET ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} photo-to-sqlite: command not found 803338729  
778014990 https://github.com/dogsheep/dogsheep-photos/issues/33#issuecomment-778014990 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/33 MDEyOklzc3VlQ29tbWVudDc3ODAxNDk5MA== leafgarland 675335 2021-02-12T06:54:14Z 2021-02-12T06:54:14Z NONE Ahh, that might be because macOS Big Sur has changed the structure of the photos db. Might need to wait for a later release, there is a PR which adds support for Big Sur. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} photo-to-sqlite: command not found 803338729  
778246347 https://github.com/dogsheep/dogsheep-photos/issues/33#issuecomment-778246347 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/33 MDEyOklzc3VlQ29tbWVudDc3ODI0NjM0Nw== RhetTbull 41546558 2021-02-12T15:00:43Z 2021-02-12T15:00:43Z CONTRIBUTOR Yes, Big Sur Photos database doesn't have `ZGENERICASSET` table. PR #31 will fix this. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} photo-to-sqlite: command not found 803338729  
813249000 https://github.com/dogsheep/dogsheep-photos/issues/35#issuecomment-813249000 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/35 MDEyOklzc3VlQ29tbWVudDgxMzI0OTAwMA== ligurio 1151557 2021-04-05T07:37:57Z 2021-04-05T07:37:57Z NONE There are trained ML models used in Photoprism: - https://dl.photoprism.org/tensorflow/nasnet.zip - https://dl.photoprism.org/tensorflow/nsfw.zip {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Support to annotate photos on other than macOS OSes 842695374  
615932007 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615932007 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTkzMjAwNw== simonw 9599 2020-04-18T19:27:55Z 2020-04-18T19:27:55Z MEMBER Research thread: https://twitter.com/simonw/status/1249049694984011776 > I want to build some software that lets people store their own data in their own S3 bucket, but if possible I'd like not to have to teach people the incantations needed to get their bucket setup and minimum-permission credentials figures out https://testdriven.io/blog/storing-django-static-and-media-files-on-amazon-s3/ looks useful {"total_count": 2, "+1": 2, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615932204 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615932204 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTkzMjIwNA== simonw 9599 2020-04-18T19:29:22Z 2020-04-18T19:34:44Z MEMBER I'm going to call my bucket `dogsheep-photos-simon`. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615933273 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615933273 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTkzMzI3Mw== simonw 9599 2020-04-18T19:37:33Z 2020-04-18T19:37:33Z MEMBER https://console.aws.amazon.com/s3/bucket/create?region=us-west-1 ![S3_Management_Console](https://user-images.githubusercontent.com/9599/79669552-33e2a380-8171-11ea-9ab5-5785d34f652a.png) I created it with no public read-write access. I plan to use signed URLs via a transforming proxy to access images for display on the web. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615935577 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615935577 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTkzNTU3Nw== simonw 9599 2020-04-18T19:54:59Z 2020-04-18T19:55:30Z MEMBER Creating IAM groups called `dogsheep-photos-simon-read-write` and `dogsheep-photos-simon-read`: https://console.aws.amazon.com/iam/home#/groups - I created them with no attached policies. Now I can attach an "inline policy" to each one. For the read-write group I go here: https://console.aws.amazon.com/iam/home#/groups/dogsheep-photos-simon-read-write ![IAM_Management_Console](https://user-images.githubusercontent.com/9599/79669703-2d086080-8172-11ea-9597-83e0b155193e.png) Example policies are here: https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html For the read-write one I went with: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": [ "arn:aws:s3:::dogsheep-photos-simon/*" ] } ] } ``` For the read-only policy I'm going to guess that this is appropriate: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject*", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::dogsheep-photos-simon/*" ] } ] } ``` I tried the policy simulator to test this out: https://policysim.aws.amazon.com/home/index.jsp?#groups/dogsheep-photos-simon-read - this worked: ![IAM_Policy_Simulator](https://user-images.githubusercontent.com/9599/79669893-cd12b980-8173-11ea-8dfb-5660ce3652da.png) {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615936880 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615936880 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTkzNjg4MA== simonw 9599 2020-04-18T20:04:31Z 2020-04-18T20:04:31Z MEMBER Next step: create two IAM users, one for each of those groups. https://console.aws.amazon.com/iam/home#/users$new?step=details ![IAM_Management_Console](https://user-images.githubusercontent.com/9599/79669931-1bc05380-8174-11ea-9657-0e0c6a692d42.png) ![IAM_Management_Console](https://user-images.githubusercontent.com/9599/79669941-27137f00-8174-11ea-8ce7-249f0d4f96f6.png) I copied the keys into a secure note in 1password. Couldn't get into Transmit with them though! https://library.panic.com/transmit/transmit5/iam-roles/ may help. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615941746 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615941746 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0MTc0Ng== simonw 9599 2020-04-18T20:29:36Z 2020-04-18T20:29:36Z MEMBER I'm going to create another user just for Transmit, with full S3 access. name: `dogsheep-photos-simon-s3-all-access` Rather than creating a group for that user, I'm trying the "Attach existing policies directly" option: ![IAM_Management_Console](https://user-images.githubusercontent.com/9599/79670182-03513880-8176-11ea-811a-c80aefb4538a.png) That user DID work with Transmit. I uploaded a test HEIC image. I used Transmit to copy a signed URL for it. ``` ~ $ curl -i 'https://dogsheep-photos-simon.s3.us-west-1.amazonaws.com/IMG_7195.HEIC?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAWXFXAI...' | head -n 100 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0HTTP/1.1 200 OK x-amz-id-2: gBOCYqZfbNAnv0R/uJ++qm2NbW5SgD4TapgF9RQjzzeDIThcCz/BkKU+YoxlG4NJHlcmMgAHyh4= x-amz-request-id: C2FE7FCC3BD53A84 Date: Sat, 18 Apr 2020 20:28:54 GMT Last-Modified: Sat, 18 Apr 2020 20:13:49 GMT ETag: "fe3e081239a123ef745517878c53b854" Accept-Ranges: bytes Content-Type: image/heic Content-Length: 1913097 Server: AmazonS3 ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615942116 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615942116 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0MjExNg== simonw 9599 2020-04-18T20:30:56Z 2020-04-18T20:30:56Z MEMBER Next step: attempt a programmatic upload using the `dogsheep-photos-simon-read-write` credentials from a Jupyter notebook. Also attempt a programmatic bucket listing and read using `dogsheep-photos-simon-read` credentials. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615944806 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615944806 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0NDgwNg== simonw 9599 2020-04-18T20:41:39Z 2020-04-18T20:41:39Z MEMBER This worked! ![Dogsheep_Photos_S3_access](https://user-images.githubusercontent.com/9599/79670712-d868e380-8179-11ea-82a5-5dfd17356113.png) And this worked: ![Dogsheep_Photos_S3_access](https://user-images.githubusercontent.com/9599/79670777-50370e00-817a-11ea-83cd-18ebf5702878.png) {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615945056 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615945056 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0NTA1Ng== simonw 9599 2020-04-18T20:42:41Z 2020-04-18T20:42:41Z MEMBER But... `list_objects` failed for both of my keys (read and write): ![Dogsheep_Photos_S3_access](https://user-images.githubusercontent.com/9599/79670798-75c41780-817a-11ea-9907-2cbc4a2e497c.png) {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615946537 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615946537 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0NjUzNw== simonw 9599 2020-04-18T20:48:13Z 2020-04-18T20:48:13Z MEMBER How about generating a signed URL? ```python read_client.generate_presigned_url( "get_object", Params={ "Bucket": "dogsheep-photos-simon", "Key": "this_is_fine.jpg", }, ExpiresIn=600 ) ``` Gave me https://dogsheep-photos-simon.s3.amazonaws.com/this_is_fine.jpg?AWSAccessKeyId=AKIAWXFXAIOZNZ3JFO7I&Signature=x1zrS4w4OTGAACd7yHp9mYqXvN8%3D&Expires=1587243398 Which does this: ``` ~ $ curl -i 'https://dogsheep-photos-simon.s3.amazonaws.com/this_is_fine.jpg?AWSAccessKeyId=AKIAWXFXAIOZNZ3JFO7I&Signature=x1zrS4w4OTGAACd7yHp9mYqXvN8%3D&Expires=1587243398' HTTP/1.1 307 Temporary Redirect x-amz-bucket-region: us-west-1 x-amz-request-id: E78CD859AEE21D33 x-amz-id-2: 648mx+1+YSGga7NDOU7Q6isfsKnEPWOLC+DI4+x2o9FCc6pSCdIaoHJUbFMI8Vsuh1ADtx46ymU= Location: https://dogsheep-photos-simon.s3-us-west-1.amazonaws.com/this_is_fine.jpg?AWSAccessKeyId=AKIAWXFXAIOZNZ3JFO7I&Signature=x1zrS4w4OTGAACd7yHp9mYqXvN8%3D&Expires=1587243398 Content-Type: application/xml Transfer-Encoding: chunked Date: Sat, 18 Apr 2020 20:47:21 GMT Server: AmazonS3 <?xml version="1.0" encoding="UTF-8"?> <Error><Code>TemporaryRedirect</Code><Message>Please re-send this request to the specified temporary endpoint. Continue to use the original request endpoint for future requests.</Message><Endpoint>dogsheep-photos-simon.s3-us-west-1.amazonaws.com</Endpoint><Bucket>dogsheep-photos-simon</Bucket><RequestId>E78CD859AEE21D33</RequestId><HostId>648mx+1+YSGga7NDOU7Q6isfsKnEPWOLC+DI4+x2o9FCc6pSCdIaoHJUbFMI8Vsuh1ADtx46ymU=</HostId></Error>~ $ ``` So it redirects to another URL... which returns this: ``` ~ $ curl -i 'https://dogsheep-photos-simon.s3-us-west-1.amazonaws.com/this_is_fine.jpg?AWSAccessKeyId=AKIAWXFXAIOZNZ3JFO7I&Signature=x1zrS4w4OTGAACd7yHp9mYqXvN8%3D&Expires=1587243398' HTTP/1.1 200 OK x-amz-id-2: XafOl6mswj3yz0GJC9+Ptot1ll5sROVwqsMc10CUUfgpaUANTdIx2GhnONb5d1GVFJ6wlS2j3UY= x-amz-request-id: 258387C180411AFE Date: Sat, 18 Apr 2020 20:47:52 GMT Last-Modified: Sat, 18 Apr 2020 20:37:35 GMT E… {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615947229 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615947229 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0NzIyOQ== simonw 9599 2020-04-18T20:51:26Z 2020-04-18T20:51:26Z MEMBER Running the upload again like this resulted in the correct content-type: ```python client.upload_file( "/Users/simonw/Desktop/this_is_fine.jpg", "dogsheep-photos-simon", "this_is_fine.jpg", ExtraArgs={ "ContentType": "image/jpeg" } ) ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615947370 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615947370 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0NzM3MA== simonw 9599 2020-04-18T20:52:13Z 2020-04-18T20:52:13Z MEMBER This is great! I now have a key that can upload photos, and a separate key that can download photos OR generate signed URLs to access those photos. Next step: a script that starts uploading my photos. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615948102 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615948102 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk0ODEwMg== simonw 9599 2020-04-18T20:56:59Z 2020-04-18T20:56:59Z MEMBER I'm going to start with this: `photos-to-sqlite upload photos.db ~/path/to/directory` This will scan the provided directory (and all sub-directories) for image files. It will then: * Calculate a sha256 of the contents of that file * Upload the file to a key that's `sha256.jpg` or `.heic` * Upload a `sha256.json` file with the original path to the image * Add that image to a `uploads` table in `photos.db` Stretch goal: grab the EXIF data and include that in the `.json` upload AND the `uploads` database table. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615957385 https://github.com/dogsheep/dogsheep-photos/issues/4#issuecomment-615957385 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/4 MDEyOklzc3VlQ29tbWVudDYxNTk1NzM4NQ== simonw 9599 2020-04-18T21:56:16Z 2020-04-18T21:58:11Z MEMBER Got this working! I'll do EXIF in a separate ticket #3. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Upload all my photos to a secure S3 bucket 602533539  
615949574 https://github.com/dogsheep/dogsheep-photos/issues/5#issuecomment-615949574 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/5 MDEyOklzc3VlQ29tbWVudDYxNTk0OTU3NA== simonw 9599 2020-04-18T21:06:07Z 2020-04-18T21:06:07Z MEMBER ``` $ photos-to-sqlite s3-auth Create S3 credentials and paste them here: Access key ID: xxx Secret access key: yyy $ cat auth.json { "access_key_id": "xxx", "secret_access_key": "yyy" } ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} photos-to-sqlite s3-auth command 602551638  
615979923 https://github.com/dogsheep/dogsheep-photos/issues/6#issuecomment-615979923 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/6 MDEyOklzc3VlQ29tbWVudDYxNTk3OTkyMw== simonw 9599 2020-04-18T23:36:02Z 2020-04-18T23:36:02Z MEMBER I'll use a Click progress bar. To do this I need to first calculate the sum number of bytes in the photos that are going to be uploaded, then run the upload. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Add progress bar to upload command 602575575  
615983393 https://github.com/dogsheep/dogsheep-photos/issues/6#issuecomment-615983393 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/6 MDEyOklzc3VlQ29tbWVudDYxNTk4MzM5Mw== simonw 9599 2020-04-18T23:53:10Z 2020-04-18T23:53:10Z MEMBER ``` $ photos-to-sqlite upload photos3.db ~/Pictures/Photos\ Library.photoslibrary/Masters/2020 Uploading 2.09 GB [##----------------------------------] 6% 00:36:37 ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Add progress bar to upload command 602575575  
615993178 https://github.com/dogsheep/dogsheep-photos/issues/7#issuecomment-615993178 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/7 MDEyOklzc3VlQ29tbWVudDYxNTk5MzE3OA== simonw 9599 2020-04-19T00:37:08Z 2020-04-19T00:37:08Z MEMBER https://pypi.org/project/ImageHash/ Is one option. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Integrate image content hashing 602585497  
906015471 https://github.com/dogsheep/dogsheep-photos/issues/7#issuecomment-906015471 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/7 IC_kwDOD079W842ALLv dkam 18232 2021-08-26T02:01:01Z 2021-08-26T02:01:01Z NONE Perceptual hashes might be what you're after : http://phash.org {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Integrate image content hashing 602585497  
618100434 https://github.com/dogsheep/dogsheep-photos/issues/8#issuecomment-618100434 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/8 MDEyOklzc3VlQ29tbWVudDYxODEwMDQzNA== simonw 9599 2020-04-23T00:02:53Z 2020-04-23T00:02:53Z MEMBER I don't think it matters one way or the other - I'm storing the sha256 in the filename, so the fact that I could read the MD5 back from the list bucket operation doesn't give me any benefits. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Should I have used MD5 instead of SHA256? 605147638  
618100658 https://github.com/dogsheep/dogsheep-photos/issues/8#issuecomment-618100658 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/8 MDEyOklzc3VlQ29tbWVudDYxODEwMDY1OA== simonw 9599 2020-04-23T00:03:35Z 2020-04-23T00:03:35Z MEMBER Also MD5 isn't guaranteed for the ETag: > If an object is created by either the Multipart Upload or Part Copy operation, the ETag is not an MD5 digest, regardless of the method of encryption. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Should I have used MD5 instead of SHA256? 605147638  
618724149 https://github.com/dogsheep/dogsheep-photos/issues/9#issuecomment-618724149 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/9 MDEyOklzc3VlQ29tbWVudDYxODcyNDE0OQ== simonw 9599 2020-04-23T23:35:29Z 2020-04-23T23:35:29Z MEMBER ``` % photos-to-sqlite upload photos.db ~/Pictures/Photos\ Library.photoslibrary/originals Fetching existing keys from S3... Got 22,446 existing keys Calculating hashes [####--------------------------------] 13% 00:04:14 ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} upload command should be resumable, should only upload photos not already uploaded 605938063  
618725155 https://github.com/dogsheep/dogsheep-photos/issues/9#issuecomment-618725155 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/9 MDEyOklzc3VlQ29tbWVudDYxODcyNTE1NQ== simonw 9599 2020-04-23T23:39:14Z 2020-04-23T23:39:14Z MEMBER A few minutes later... ``` Fetching existing keys from S3... Got 22,446 existing keys Calculating hashes [####################################] 100% 22,441 hashed files, 610 are not yet in S3 Uploading 0.99 GB Uploading 610 photos [------------------------------------] 1/610 03:10:35 ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} upload command should be resumable, should only upload photos not already uploaded 605938063  
739058820 https://github.com/dogsheep/dogsheep-photos/pull/29#issuecomment-739058820 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/29 MDEyOklzc3VlQ29tbWVudDczOTA1ODgyMA== simonw 9599 2020-12-04T22:32:35Z 2020-12-04T22:32:35Z MEMBER Thanks for this! {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Fixed bug in SQL query for photo scores 638375985  
1035717429 https://github.com/dogsheep/dogsheep-photos/pull/31#issuecomment-1035717429 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/31 IC_kwDOD079W849u8s1 harperreed 18504 2022-02-11T01:55:38Z 2022-02-11T01:55:38Z NONE I would love this merged! {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Update for Big Sur 771511344  
748562330 https://github.com/dogsheep/dogsheep-photos/pull/31#issuecomment-748562330 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/31 MDEyOklzc3VlQ29tbWVudDc0ODU2MjMzMA== RhetTbull 41546558 2020-12-20T04:45:08Z 2020-12-20T04:45:08Z CONTRIBUTOR Fixes the issue mentioned here: https://github.com/dogsheep/dogsheep-photos/issues/15#issuecomment-748436115 {"total_count": 1, "+1": 0, "-1": 0, "laugh": 0, "hooray": 1, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Update for Big Sur 771511344  
811362316 https://github.com/dogsheep/dogsheep-photos/pull/31#issuecomment-811362316 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/31 MDEyOklzc3VlQ29tbWVudDgxMTM2MjMxNg== PabloLerma 871250 2021-03-31T19:14:39Z 2021-03-31T19:14:39Z NONE 👋 could I help somehow for this to be merged? As Big Sur is going to be more used as the time goes I think it would be nice to merge and publish a new version. Nice work! {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Update for Big Sur 771511344  
1006708046 https://github.com/dogsheep/dogsheep-photos/pull/36#issuecomment-1006708046 https://api.github.com/repos/dogsheep/dogsheep-photos/issues/36 IC_kwDOD079W848ASVO scoates 71983 2022-01-06T16:04:46Z 2022-01-06T16:04:46Z NONE This one got me, today, too. 👍 {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Correct naming of tool in readme 988493790  
1021264135 https://github.com/dogsheep/dogsheep.github.io/pull/6#issuecomment-1021264135 https://api.github.com/repos/dogsheep/dogsheep.github.io/issues/6 IC_kwDODMzF1s4830EH ligurio 1151557 2022-01-25T14:52:40Z 2022-01-25T14:52:40Z NONE @simonw, could you review? {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Add testres-db tool 842765105  
706775706 https://github.com/dogsheep/evernote-to-sqlite/issues/1#issuecomment-706775706 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/1 MDEyOklzc3VlQ29tbWVudDcwNjc3NTcwNg== simonw 9599 2020-10-11T22:14:00Z 2020-10-11T22:14:00Z MEMBER A live demo would be good too. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Documentation on how to use this with Datasette 718934942  
777690332 https://github.com/dogsheep/evernote-to-sqlite/issues/11#issuecomment-777690332 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/11 MDEyOklzc3VlQ29tbWVudDc3NzY5MDMzMg== dskrad 3613583 2021-02-11T18:16:01Z 2021-02-11T18:16:01Z NONE I solved this issue by modifying line 31 of utils.py content = ET.tostring(ET.fromstring(content_xml.strip())).decode("utf-8") {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} XML parse error 792851444  
777798330 https://github.com/dogsheep/evernote-to-sqlite/issues/11#issuecomment-777798330 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/11 MDEyOklzc3VlQ29tbWVudDc3Nzc5ODMzMA== simonw 9599 2021-02-11T21:18:58Z 2021-02-11T21:18:58Z MEMBER Thanks for the fix! {"total_count": 1, "+1": 1, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} XML parse error 792851444  
905203570 https://github.com/dogsheep/evernote-to-sqlite/issues/13#issuecomment-905203570 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/13 IC_kwDOEhK-wc419E9y simonw 9599 2021-08-25T05:51:22Z 2021-08-25T05:53:27Z MEMBER The debugger showed me that it broke on a string that looked like this: ```xml <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"> <en-note> <h1 title="Q3 2018 Reflection & Development"> <span title=Q3 2018 Reflection & Development"> Q3 2018 Reflection & Development </span> </h1> ... ``` Yeah that is not valid XML! {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} xml.etree.ElementTree.ParseError: not well-formed (invalid token) 978743426  
905206234 https://github.com/dogsheep/evernote-to-sqlite/issues/13#issuecomment-905206234 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/13 IC_kwDOEhK-wc419Fna simonw 9599 2021-08-25T05:58:42Z 2021-08-25T05:58:42Z MEMBER https://github.com/dogsheep/evernote-to-sqlite/blob/36a466f142e5bad52719851c2fbda0c05cd35b99/evernote_to_sqlite/utils.py#L34-L42 Not sure why I was round-tripping the `content_xml` like that - I will try not doing that. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} xml.etree.ElementTree.ParseError: not well-formed (invalid token) 978743426  
906635938 https://github.com/dogsheep/evernote-to-sqlite/issues/13#issuecomment-906635938 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/13 IC_kwDOEhK-wc42Ciqi simonw 9599 2021-08-26T18:18:27Z 2021-08-26T18:18:27Z MEMBER It looks like I was using the round-trip to dump the `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` and `<!DOCTYPE` prefixes. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} xml.etree.ElementTree.ParseError: not well-formed (invalid token) 978743426  
906646452 https://github.com/dogsheep/evernote-to-sqlite/issues/13#issuecomment-906646452 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/13 IC_kwDOEhK-wc42ClO0 simonw 9599 2021-08-26T18:34:34Z 2021-08-26T18:35:20Z MEMBER I tried this ampersand fix: https://regex101.com/r/ojU2H9/1 ```python # https://regex101.com/r/ojU2H9/1 _invalid_ampersand_re = re.compile(r'&(?![a-z0-9]+;)') def fix_bad_xml(xml): # More fixes for things like '&' not as part of an entity return _invalid_ampersand_re.sub('&amp;', xml) ``` Even with that I'm still getting total garbage in the `<en-note>` content - it's just HTML, not even trying to be XML. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} xml.etree.ElementTree.ParseError: not well-formed (invalid token) 978743426  
911772943 https://github.com/dogsheep/evernote-to-sqlite/issues/14#issuecomment-911772943 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/14 IC_kwDOEhK-wc42WI0P step21 46968 2021-09-02T14:53:11Z 2021-09-02T14:53:11Z NONE Additionally, assuming the line numbers match up with the provided enenx file, the mentioned line plus one before and after is as follows: ``` <![CDATA[>]]> </span></div> <div style="padding: 0px; font-family: Arial, sans-serif; font-size: 12px; line-height: 16px; white-space: pre-wrap;"><br style=" padding: 0px;"/> ``` {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} xml.etree.ElementTree.Parse Error - mismatched tag 986829194  
706784028 https://github.com/dogsheep/evernote-to-sqlite/issues/4#issuecomment-706784028 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/4 MDEyOklzc3VlQ29tbWVudDcwNjc4NDAyOA== simonw 9599 2020-10-11T23:20:32Z 2020-10-11T23:20:32Z MEMBER I haven't done the FTS on OCR yet. I'm going to move that to another ticket because it requires more thought. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Configure FTS + add an index on the date columns 718938508  
706786548 https://github.com/dogsheep/evernote-to-sqlite/issues/4#issuecomment-706786548 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/4 MDEyOklzc3VlQ29tbWVudDcwNjc4NjU0OA== simonw 9599 2020-10-11T23:39:46Z 2020-10-11T23:39:46Z MEMBER Should have used porter stemming for this. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Configure FTS + add an index on the date columns 718938508  
706776180 https://github.com/dogsheep/evernote-to-sqlite/issues/5#issuecomment-706776180 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/5 MDEyOklzc3VlQ29tbWVudDcwNjc3NjE4MA== simonw 9599 2020-10-11T22:17:55Z 2020-10-11T22:17:55Z MEMBER We could even do server-side thumbnailing for some of these images, but I'm inclined to serve up the full size ones and set a width on the image element based on the `width` attribute on `<en-media>`. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Figure out how to display images from <en-media> tags inline in Datasette 718938889  
706776242 https://github.com/dogsheep/evernote-to-sqlite/issues/5#issuecomment-706776242 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/5 MDEyOklzc3VlQ29tbWVudDcwNjc3NjI0Mg== simonw 9599 2020-10-11T22:18:30Z 2020-10-11T22:19:48Z MEMBER Alternatively, rather than relying on `datasette-media` this could base64-embed the images. `evernote-to-sqlite` could register itself as a Datasette plugin that knows how to do this. Maybe rename the column to `evernote_content` and register a render cell hook that knows how to rewrite those note bodies so that they are visible? Might need to feed them through Bleach too, just in case any nasty code can get into them. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Figure out how to display images from <en-media> tags inline in Datasette 718938889  
706776447 https://github.com/dogsheep/evernote-to-sqlite/issues/5#issuecomment-706776447 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/5 MDEyOklzc3VlQ29tbWVudDcwNjc3NjQ0Nw== simonw 9599 2020-10-11T22:20:32Z 2020-10-11T22:20:32Z MEMBER Or... I could do this client-side. JavaScript that looks for `<en-media>` tags and fetches the data using `fetch()` wouldn't be too hard to write. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Figure out how to display images from <en-media> tags inline in Datasette 718938889  
706776680 https://github.com/dogsheep/evernote-to-sqlite/issues/5#issuecomment-706776680 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/5 MDEyOklzc3VlQ29tbWVudDcwNjc3NjY4MA== simonw 9599 2020-10-11T22:22:16Z 2020-10-11T22:22:16Z MEMBER Maybe the best way do this is with a custom route, `/-/evernote/note-id` - that way I can clean the HTML and resolve the other things in the `<en-note>` structure without using `render_cell()` and the like. My concern about using `render_cell()` is that it could lead to weird security problems when combined with `?sql=` queries. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Figure out how to display images from <en-media> tags inline in Datasette 718938889  
706776808 https://github.com/dogsheep/evernote-to-sqlite/issues/5#issuecomment-706776808 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/5 MDEyOklzc3VlQ29tbWVudDcwNjc3NjgwOA== simonw 9599 2020-10-11T22:23:14Z 2020-10-11T22:23:14Z MEMBER ... but it's still important to be able to get to the rendered note directly from the browse notes `/evernote/notes` page. Maybe use a simple `render_cell()` hook that just knows how to generate the link to the rendered note page? {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Figure out how to display images from <en-media> tags inline in Datasette 718938889  
706834800 https://github.com/dogsheep/evernote-to-sqlite/issues/5#issuecomment-706834800 https://api.github.com/repos/dogsheep/evernote-to-sqlite/issues/5 MDEyOklzc3VlQ29tbWVudDcwNjgzNDgwMA== simonw 9599 2020-10-12T03:24:57Z 2020-10-16T20:16:28Z MEMBER Here's my first attempt at a plugin for this: ```python from datasette import hookimpl import jinja2 START = "<en-note" END = "</en-note>" TEMPLATE = """ <div style="max-width: 500px; white-space: normal; overflow-wrap: break-word;">{}</div> """.strip() EN_MEDIA_SCRIPT = """ Array.from(document.querySelectorAll('en-media')).forEach(el => { let hash = el.getAttribute('hash'); let type = el.getAttribute('type'); let path = `/evernote/resources_data/${hash}.json?_shape=array`; fetch(path).then(r => r.json()).then(rows => { let b64 = rows[0].data.encoded; let data = `data:${type};base64,${b64}`; el.innerHTML = `<img style="max-width: 300px" src="${data}">`; }); }); """ @hookimpl def render_cell(value, table): if not table: # Don't render content from arbitrary SQL queries, could be XSS hole return if not value or not isinstance(value, str): return value = value.strip() if value.startswith(START) and value.endswith(END): trimmed = value[len(START) : -len(END)] trimmed = trimmed.split(">", 1)[1] # Replace those horrible double newlines trimmed = trimmed.replace("<div><br /></div>", "<br>") return jinja2.Markup(TEMPLATE.format(trimmed)) @hookimpl def extra_body_script(): return EN_MEDIA_SCRIPT ``` It works! It does however demonstrate that Evernote's "clip this webpage" feature means there is a LOT of weird HTML that can get into a note. It looks like they've filtered out the scripts but I wouldn't bet on it - they certainly don't filter out many of the inline styles. So running Bleach is almost certainly a good idea. {"total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0} Figure out how to display images from <en-media> tags inline in Datasette 718938889  

Next page

Advanced export

JSON shape: default, array, newline-delimited, object

CSV options:

CREATE TABLE [issue_comments] (
   [html_url] TEXT,
   [issue_url] TEXT,
   [id] INTEGER PRIMARY KEY,
   [node_id] TEXT,
   [user] INTEGER REFERENCES [users]([id]),
   [created_at] TEXT,
   [updated_at] TEXT,
   [author_association] TEXT,
   [body] TEXT,
   [reactions] TEXT,
   [issue] INTEGER REFERENCES [issues]([id])
, [performed_via_github_app] TEXT);
CREATE INDEX [idx_issue_comments_issue]
                ON [issue_comments] ([issue]);
CREATE INDEX [idx_issue_comments_user]
                ON [issue_comments] ([user]);
Powered by Datasette · Queries took 40.57ms · About: simonw/datasette-graphql