Changelog

vNext

Breaking changes

A new key in the configuration has been added, viewableimages, which represents what file extensions are directly viewable by the browser and don't need to be converted. Previously this was hard-coded, but it is likely that modern browsers support more formats, so it is now configurable. Moreover, it has to be configured. A starting point can be seen in the sample configuration file.

New features

The camera and lens information pages now have two more graphs: per the paired item (for a camera, the lenses, and vice-versa) statistics (bar chart) and timeline, per-paired item trends (line chart). This should show better the actual usage of a camera or lens, and including the pairings. Of course, these are only useful in terms of timeline for fixed-lens cameras.

Additionally, all the timeline graphs (either on global camera and lens stats, or in the individual pages) have been switched to bars for better readability, and even more, correctness. The previous method of line+markers was connecting across gaps, which was misleading, and was significantly complicating the shape of the graph. Will have to see if this is indeed better.

Changed behaviour

The complex 5 view modes (image list, image grid, folder list, folder grid and image view) are being reworked. The longer goal is to make moving around the site more natural and to simplify it.

Currently two main changes have been done.

On the navigation side, using the "chips" to go to a year, or location-based attribute, will directly jump to a folder list, whereas the others will obey the "view mode".

On the view modes, there was a difference between "folder browse"—which navigated to the first folder image in "view" mode—and image browsing, which opened an inline view of the image (using the fancybox library). This latter inline view mode has been replaced with the standard view mode of the application, which is now the only image/movie viewer model.

Furthermore, the above-mentioned folder browse mode, which looked similar but behaved different from the image browse mode, has been entirely removed. For folders, the only remaining mode is listing, which makes more sense as showing just a picture was not representative for a folder.

In the movie play mode, if the end of the movie is reached, pressing spacebar once again will advance to the next item, instead of replaying the movie.

Fixed bugs

When going from any other page to the image viewer, and then moving to another image (still inside the image viewer), navigating back in history to the first image was not working. This has been fixed.

The picture cache had a bug in that for small pictures, they would be upscaled instead of left as-is. With many small pictures and with high maximum size auto-render, this could lead to significant cache usage. This has now been fixed, but the "too-large" thumbnails will not be automatically cleaned, it's recommended to wipe the cache manually.

Deployment changes

The secure sessions setting will no longer enforce also an HSTS header, but instead only set the secure bit on cookies; there is a new strict-transport-security config setting to control the header, defaulting to the https setting. However, even in https mode, the header can now be skipped, since usually the header is emitted in front-line applications, and thus when Corydalis is being reverse proxied, it should not be emitted from it too; duplicate HSTS headers are technically incorrect and will prevent sites from reaching an A+ score on SSL tests.

Additionally, it is now possible to bind the app to a Unix socket, instead of a host:port TCP connection, in order to improve performance and security of reverse-proxied deployments. This is controlled via the new unix-socket configuration key.

Internal changes

The remaining (trivial) corydalis JS code has been converted to TypeScript, and the entire codebase has been converted to modules, and is using esbuild as a bundler. This has plusses and minuses, but brings the code into a more modern era and should simplify use/integration of new libraries.

Dependencies

The dependencies have been updated as follows:

  • The graphing library plotly has been updated to version 3.0.

v2025.21.0 - "Zooming for all"

Released: Sat, 24 May 2025.

Major improvement: image zooming and panning

After many years, finally add image zooming to the main image viewer, together with mouse and gesture support for panning and pinch-zooming. This was on the cards since movie support was implemented, but my previous efforts failed to work well, for various reasons, one of them being the HammerJS library not being flexible enough. I used Claude (3.7 Sonnet) to help me implement fully-manual gesture handling, and then reverse engineer my code - at which it was not so good. I spent then a lot of time to understand the old viewer code, and it resulted in a significant simplification as well.

The zoom was tested on both small images, and large images, up to a ~96 Megapixel image from NASA (~200MiB disk size). It takes a while to load that, but afterwards panning and zooming is smooth.

As a side effect of the changes, I redid the way the HTML elements are laid out in order to remove manual state management, and this uncovered something that seems to be a bug in Safari iOS on iPads related to fullscreen corrupting viewport sizing - https://bugs.webkit.org/show_bug.cgi?id=293514. There's no workaround for it, except either don't enter full-screen, or close the tab and open a new one - page reload doesn't help.

Additional new feature: Added simple yearly and monthly timeline graphs to the curate page, to help understand the growth of the collection over time.

Bug fixes

  • When going to image view from a search, preserve (as intended) the search parameters; before it was going to the first image that matches the search, but the search filter was dropped, so it was simply jumping into all image search at a specific position.
  • In the image viewer, when the navigation bar changes height due to wrapping (which in itself is a UI bug), the canvas was not resized correctly, as the positioning was done manually. Fix that by switching to a flex columnar layout, which automatically triggers a CSS resize of the page layout, including the image canvas. That, coupled with switching the method used to observe size changes (from window resize to ResizeObserver) fixes the issue. In the new model, the canvas will resize automatically with the navigation bar, which in some cases is more jarring than the over or underflow, but it's more correct, as it doesn't leave permanent wrong positioning, just a one-time visible change.
  • Cover image generation for movies has been made more reliable, as sometimes ffmpeg was trying and failing to read from standard input, leading to no cover images.

Small improvements

  • The breadcrumbs are now so styled, that they will not wrap, but instead be clipped (and show an ellipsis on overflow), to keep the page structure constant no matter the folder/image names. Before, the wrapping could cause reflow when navigating between images.
  • Furthermore, the breadcrumb has been customised for the viewer specifically, to not show the "Viewer" final item, and on small sizes, show only the folder name, since that's most representative of the context, on medium sizes the image name too, and on large size also the top level folder. This should result in more meaningful context of the picture being viewed, as the viewer only shows (briefly) the image name.
  • The image viewer (the full page one) has been sped up by skipping some expensive CSS computations in the call path for every image drawing; this leads to a small performance improvement, but also potential visual bugs if display changes are missed.
  • The image viewer's image navigation bar is now centred on small screens, which finally solves a very old UI annoyance (on small screens in portrait mode, it was consuming ~70% of the screen width, but not centred). Additionally, move the nav bar a bit higher, so that on iOS phones or tablets, it doesn't conflict with the bottom "swipe-up" element (the black bar used to go to the home screen).
  • Make all plotly graphs responsive, as it seems this is not the default, even in 2024+.

v2024.12.0 - "No accidental zooming"

Released: Wed, 20 Mar 2024.

For me, the highlight of this release is the disabling of unintended, and accidental zooming in the image viewer, when using the navigation bar with fast tapping. The viewer zoom level is now stable, except when (intentionally) double tapping on the top navigation bar or search entry.

Features

A new "presentation" mode is available, where the image viewer is directly entered from any search. Previously, this was only either grid or list mode (for images or folders, respectively), and this additional mode enters the image viewer mode directly (without going through either grid or list first). This mode is activated whenever the image view is selected, which might not be optimal, so there might be tweaking to this in the future.

Improvements

Improvements to the image viewer:

  • enable the Tab key to navigate to random images, similar to existing r; the reason being that in full screen, some browsers restrict alphanumeric input, but whitespace keys (such as tab/enter) are allowed.
  • fix history navigation (backward/forward), by correctly tracking state; previous half-implementation didn't actually work.
  • add Backspace/Delete/< as history backward navigation, again useful in full screen mode, and > for forward navigation.
  • implement a small key shortcuts help page, activated by either ? or h.
  • disable "tap-to-zoom" on the navigation bar, since this was, in my own experience, one of the most confusing outcomes of trying to navigate fast by tapping (rather than swiping), and getting out of zoomed state was difficult since the canvas (which doesn't interact for this) takes 90% of the page.

Other improvements:

  • the image info page is now better organised, due to re-enabling the dynamic layout (via the masonry library); a CSS issue that prevented was finally identified and fixed.
  • slight improvement to formatting of filters for a date (day of the month).

Experimental features

Corydalis web endpoint now presents a manifest file, allowing installation as a Progressive Web App, running in "standalone" mode. This means that on small screens, more of the available screen space is used for Corydalis, even in normal mode, leading to a more pleasant experience. To enable this, use the normal action for your platform, for example on Apple devices, open the share menu, and select "Add to home screen" (iOS/iPadOS) or "Add to doc" (MacOS).

Note this feature is experimental, and it is lacking good a good user model, for example, forward/backward navigation on all pages.

v2024.9.0

Released: Sun, 03 Mar 2024.

A medium sized release, with both internal and user-visible changes.

New user features

The simple viewer (see view-vs-browse in the user manual) now has the ability to play videos inline, rather than simply opening the raw video in a new browser tab. This is new functionality, bugs are expected, and please report them.

On the home page, a new card is present that allows browsing all pictures, start at a random picture, "on this day" functionality, and on this day-of-the-week. This will likely be expanded in the future, I assume there are more interesting features to expose that are so to say "cross-section" in the repository, rather than "city X, location Y, person Z".

Server admin changes

Two new config settings were introduced and one was deprecated:

  • request-logging can now configure the HTTP logs as one of none, apache, and detailed; this replaces the old detailed_logging, which only toggled between apache and detailed;
  • log-level can no configure the level of application logging; this overlaps with should-log-all (which, when set to true, is equivalent to log-level: debug, and when unset, it was previously equivalent to info); there are not many application logs, but a switch between the default of info and warning might be appropriate unless one wants to debug the server behaviour;
  • it's likely that should-log-all will be removed in the future.

For installation, there's now an additional option to use pre-built amd64 binaries generated automatically by the GitHub Actions (at each commit). Of course, building from source is still best, as it will use the exact environment (rather than just Ubuntu latest).

Internal changes

I've switched my editor environment from Emacs to VSCode, and as a result, a lot of associated tooling has changed as well. This did result in quite a bit of code churn due to formatting changes, and this might continue a bit more as I investigate newer tooling.

Biggest miss: there's no meaningful unit test coverage improvement 🙁. I still need to come up with a strategy here, and especially one that can cover/integrates both Haskell and Typescript testing. On the slightly positive side, the new logging changes (were written for and) allow very clean test output, as all the logging noise is now hidden. This should allow a more positive attitude to tests 😁.

Very minor notice: the code now builds with GHC 9.6.

v2023.44.0

Released: Sat, 04 Nov 2023.

A new release (at a rather arbitrary point in time), and switching to calendar-based versioning since it makes more sense for this application.

HiDPI displays

Finally fixed image resolution handling for hi-dpi displays. Previously, Corydalis was completely oblivious to this, so the images were fuzzy in the native (built-in) image viewer (issue #10). Now they should show correctly.

Performance changes

Image thumbnails in image/folder list make use of the HTML-native lazy-loading mechanism, which (for browsers that implement it) makes large image lists actually usable. Not a proper replacement for a paged loading mechanism, but a working substitute.

Slight performance change for loading pages due to reduced and combined CSS/JS resource serving. This can lead to 10-20% page loaded speed-ups, depending on the page type and complexity.

Exif changes

Now parses the rating as written by (at least) Lightroom. Value '0' is unrated, otherwise the explicit rating.

Search changes

Added new search atoms season, month, day, rating, people-count, keyword-count.

Season is the usual English name for season, i.e. winter, spring, summer, autumn, and the season computation is based on month boundaries: winter lasts from December to January, and the rest follow.

Month is the usual English name for the month, or alternatively the numeric value (1-12).

Day is a bit more complex. It can take any of: day-of-week (English names), 'weekday', 'weekend', or numerical month day (e.g. '10th').

Rating is the exif rating as written by camera or image processing tools, usually using the values 1-5, with 0 being unrated.

People and keyword count atoms are what you'd expect, searching by how many people or keywords are in an image.

All the numeric search atoms (year, rating, counts, etc.) can use '<' and '>' in the quick search, e.g. keyword-count:>3.

UI interaction changes

Previously, searching for things, or clicking to various links was always going to either an image grid browsing view or folder grid browsing view, based on static conditions. Now, the preference of how to display search results has moved to a per-browser sticky (long-lived) cookies, so that multiple searches will remain on last view. The preference is updated whenever the view is manually changed (via the alternate links in the page).

In case of missing preferences, the default is same as before, image or folder grid.

Internal changes

The way image name URLs are built for multi-level paths changed; instead of encoded '%2F' elements in the path, with the image being a single path element, now image names are multi-path elements: a%2Fb%2Fc becomes a/b/c. This should help with reverse-proxying corydalis, and in general is a cleaner way to represent file-system paths in URLS.

The source tree no longer contains embedded libraries (yay!). They have been replaced by symlinks (or transformations) of upstream files as shipped in npm packages. This should simplify future development.

v0.4.0

Released: Sun, 26 May 2019.

This is yet another major release, getting closer to a friendly UI for photo viewing in parallel with the expansion of the library curation for people so interested. Around 380 commits, so even bigger than v0.3…

New features

A large number of new features, due to the long bake time. Will do better next time ☺

Movie support

It is now possible to view movies formats that are natively supported by the browser. This is not much, as many older cameras were creating things like AVI files, or some cameras still generate MOVs that are not well supported.

Nevertheless, for the formats that are supported, it is possible to:

  • view them as such, in the image viewer and the new browsing mode
  • search for movies by type
  • see statistics (in the 'curate' module)

When just looking at images (in the new browsing UI, or as thumbnails, etc.) the movie "cover" is taken either from an embedded thumbnail (if available), or from the first frame via ffmpeg, which is a new dependency.

A new alternative UI for browsing pictures

The existing image viewer, designed for fast sequential viewing, lack the ability to browse through images, without necessarily wanting to see them in detail. Furthermore, the existing image/folder views with their data-oriented tabular formats were really not user friendly, but more geared towards analysing the photo library.

There's now a new, parallel "browse" mode that is grid based, which allows scrolling through the pictures. It deals much better with large results as it's paginated and incrementally loading, and applies the same to folder views and to image views.

On the folder view, selecting an image leads into the image viewer for that folder, whereas for the image view, it just opens the image or the movie in a "light box", allowing to view the image in more detail (even at full resolution, which is better than the previous image view) without losing track of browsing position.

It is also possible to switch between folder and image views and between the list-based and the browse-based view for either.

Asynchronous repository scanning with progress report

The previous synchronous-scanning done in the reload handler was, of course, a big kludge, and it was finally time to retire it. The reload handler now just triggers the scan, and it's possible to see progress statistics for both the scanning phase, and for the rendering phase, which was completely hidden before.

The refactoring had a couple of nice side-effects:

  • the UI is fully usable during the scans; if this is a subsequent scan, the previous results are kept until the in-progress scan is finished, leading to no "down-time" of accessing the data;
  • rendering phase is better controlled and there's no significant duplicate work; previous implementation was forgetting the rendering thread and could lead to N parallel threads all doing the same work;

On top of all this, the repository state is cached at end of scanning, so initial load (after task restart) is much faster.

New search atoms

More search atoms, which means higher chance of confusion. Anyway ☺

  • added title and caption (string) atoms
  • added folder (string) atom which allow usual searches on folder name
  • added filename (string) atom which allows searching on image name, including any intermediate directories (such as day1/dsc_0590.jpg).
  • added image status (set) atom, which replaces the old by-status view.
  • added folder class (set) atom, which replaces the old by-folder-type view.
  • added a lens (string) search atom.

The addition of image status and folder class atoms allowed completely removing the old style "by-category" views, completing the unification of the search/browse/list paradigm onto searching (via filters).

Expanded library statistics (curate module)

Added camera statistics, including tracking of shutter count if available, and expanded the lens statistics. One can now look to see which cameras generate best keepers, or to track equipment use/last use, etc. Multiple cameras of the same model are handled now via serial info, which however breaks as many cameras don't store their serial in movie metadata, only in images.

The over-time usage for both cameras and lenses now show graphs, but I'm not sure they're very readable, so it's more like raw v1.

Improved handling of exif errors or (new) plain inconsistencies (e.g. location fields existing but empty). This should allow removing

There is so much more data that could be shown here, but not yet…

Performance improvements

Some folder statistics are now pre-computed and cached, leading to significant speed-ups (up to one order of magnitude) in some cases (e.g. the folder list view).

Quick search atoms now can be prefixed with an atom keyword followed by a colon to restrict searches to that specific atom, and not try all atoms that match. E.g. 'year:2018 country:Italy'.

As described above, repository state is cached, so application restart is much faster.

There have also been some overall performance improvements by changing the used types (some StringText migration, or list to sets, etc.), but with no hard data.

Bugs fixed

Folder cover display should now more consistently find an image to display, even if the first image(s) are not viewable or if the image filter doesn't actually select an image from the folder.

Master (as in 'soft master') images that are not proper raw files, but instead something like png/tiff/etc. are now directly viewable. The logic for this is hard coded for now, but finally one can see master bitmaps.

Quick searches for two (but exactly two) words which neither finds anything was triggering a but in the atom parser; this is was fixed by removing arbitrary-length operators in the parser.

Images are now viewed in capture time order, not alphabetical order. This could be called an improvement as well, but it was IMO a bug in the first place.

Full screen mode in the view library is now done via the screenfull javascript library, leading hopefully to expanded compatibility. On top of that, a fake full screen mode is there for browsers which don't support a native on - looking at you, Safari on iOS, why oh why?

Relaxed the parsing of some exif fields, hopefully allowing parsing of metadata generated by more exotic writers.

Miscellaneous

Folder search semantics

Changed semantics of folder search. Before, a folder search (almost) always meant "it contains at least one image that itself matches the exact filter". Now, a folder search for a composite filter (e.g. "A and B") means it contains an image matching "A" and also contains an image matching "B".

The rationale for this change is that some atoms only have meaning at folder level (e.g. folder class), and other have different meaning at folder and image level (e.g. year), so the handling of atoms should be as well different.

A (desired) side effect of the change is that many searches are faster on folders now, since we can look at aggregate folder statistics in many cases, rather than look at each individual image in turn.

Internal changes

The application state was moved from global variables (MVars) to a context structure, which unblocked testing of minimal repositories. As such, there's a tiny bit of coverage improvement, but this serious testing remains for the future.

Untracked files are now handled together with image files, which should lead hopefully to a better handling of files, but has potential for some bugs (e.g. one was found in list folder with regards to image statistics).

v0.3.0

Released: Fri, 09 Mar 2018.

A major release, with close to 300 commits.

Important: due to internal changes, all the cached exif metadata will be regenerated, so the first startup should be slower. This should proceed automatically, but as there is no versioning of the cache, it might be a good idea to remove the files manually (as there's no automated clean-up procedure yet):

find /path/to/cache/dir -name '*-bexif' -delete
find /path/to/cache/dir -name '*-exif' -delete

New features:

  • Rewritten search system; besides just location and people/keyword searches, a number of other atoms have been added, and now the search supports arbitrary combinations of these.
  • Image viewing/browsing have moved from folder-based (view all images in folder A, move to folder B, etc.) to the above search/filter based: show me (and view in order) all images with keyword flowers, no matter in which folders they are located.
  • Exif parsing has been reworked, and a number of new fields have been added (e.g. ISO, shutter speed; location fields are now split into country/province/city/etc.)
  • Exif parsing failures are recorded, can be viewed on the curate page and searched by the 'problem' atom.
  • The security requirements have been somewhat relaxed, allowing the application to run in non-secure (https) mode, recommended only when using behind a reverse proxy, and to allow non-logged in browsing, recommended for a website/demo site.

Improvements:

  • Directory scanning has been parallelised, leading to 2.5× and more speed-ups.
  • Exif metadata is now cached even in the case of failures, and is only regenerated in case the source file is updated; this should allow for (much) faster rescans if there are many images that fail parsing.
  • This might have been present in 0.2 too, but: exif metadata is now updated automatically if the source file is updated.
  • The CSS and part of JS dependencies are combined and served as single file; this (the CSS part) has eliminated some flickering when used with Firefox.
  • Added a lens statistics page.
  • Added an about page, pointing back to GitHub for the sources and explaining a bit the application.

Bugs fixed:

  • Exif parsing had significant issues with related to people parsing (at image level), and with folder-level aggregation (which was actually plain broken); these should be fixed now.
  • UI usability on small screens was very low, mostly fixed now (but this can be always improved).
  • Image viewer handles keystrokes better, eliminating their interception when modifiers are used; e.g. CTRL+r for reload was previously also triggering a r random image view.

UI changes/additions:

  • Moved to Bootstrap 4, which allowed fixing the UI responsiveness fixed.
  • Moved to Font Awesome 5 (new icon look).
  • Small updates to the other dependencies as well.

v0.2.0

Released: Thu, 08 Feb 2018.

Initial public release, after a very long bake time ☺