July 3
Hi all, hope you're doing well. Updates below!
AWS Reserved Instances
Deserted Chateau's test database and cache servers currently have 1 year reserved instances, paid fully upfront, that are due to expire towards the end of July. With the renewal coming up soon, I did some research into whether a 3 year option would be a better financial choice: I know I'll be using the servers for that long anyway where the test environments are concerned.
The 3 year reserved instances have two choices: paid fully upfront, or partially upfront (which is like 50% upfront, and the other 50% spread across the 3 years). Roughly speaking, the 1 year terms have about 33-35% savings vs normal instances, and the 3 year terms have 52-57% - the 3 year terms are like 3 years for the price of 2x 1 year terms, so it's a pretty big savings increase without any extra upfront payment needed. The 3 year saving is broadly similar whether it's paid fully upfront or not.
For the test environments I'll use 3 year partial upfront instances going forward for database servers, and 3 year no upfront for cache servers (that option isn't there for databases). For the live instances when those begin, the 1 year options are better until I can be sure the 3 year options are likely to be used for the full duration.
Image Resizing quality improvement
I made a major improvement to the image resizing code, in terms of the output quality of resized images. I'd been suspecting something wasn't right for a while, as images had a noticeable loss of quality compared to what would be expected from the encoding parameters (90% JPEG quality, no chroma subsampling). I realised it was likely due to a double encoding bug after testing on my local machine with a smaller project that's also using the Sharp library and getting different results there.
In the image resizing function, for code streamlining purposes I was first outputting resized images to a buffer, then encoding them to e.g. JPG or PNG. What I'd overlooked was that when outputting images to buffers in the Sharp library, it's not a temporary "middle stage" of processing the image before encoding the image and finalising it - the buffer is an output option of its own, and so images were getting encoded and thus compressed twice. Fixing it was simple, images have noticeably better quality now.
Improved Tooltip Standards
Until now, a lot of tooltip HTML was hardcoded into pages; in some ways this is fine, as the content of those tooltips is not expected to change, but it means that any change to the HTML structure of tooltips in future would mean changing all of them in every file. Not too convenient.
I've made a system whereby the structure for each tooltip is dynamically inserted into the page via PHP. This avoids janky loading that would happen if they were loaded via JavaScript when the page is ready, and means that changing tooltip structure just means changing two files: the PHP tooltip template, and the JavaScript one for tooltips rendered after load, such as for multiple submissions or for a modal popup window.
There's also a need for a standard "error popup" that can appear when the user takes an action, like clicking on a button. A lot of pages don't have space for errors to be displayed in the usual page flow, so tooltip errors could be useful in some cases here; a few edge cases might need a "snackbar-style" popup (similar to the ones you get on phones, where an area of the bottom or top of the phone shows an error on top of the rest of the display). That's on my todo list for the next update, as a lot of the user interface improvements for fixing things that otherwise just have debugging statements or JavaScript alert() calls will be changed to have more graceful error reporting once I've decided on the approach for that.
Profile page improvements
TinyMCE: Styling Overrides
To finish up the "Commission Info" and "About" profile pages, I need to finalise the TinyMCE editor behaviour for each of those pages, so that users can customise exactly what they want. For users who find it too complex, inserting an image is allowed, which makes it easier for people with e.g. premade commission sheets and whatnot.
TinyMCE: Image upload handling
I've implemented the image handling code for user-submitted TinyMCE content; it needed to be customised so that the quality of the image can be controlled, and also to ensure that images uploaded in the editor are only saved if the user actually saves the editor content. It's sort of similar to the normal upload process, where images are first uploaded to a temporary folder in S3 and then moved to a permanent one if they're saved, but as there's no easy way to track which images are in the editor it's a bit more complicated in the backend.
Reblogs and Likes tabs
I've finished up making separate "reblogs" and "likes" tabs in user profiles, so that it's possible to browse a user's reblog or like history. The reblogs tab will be enabled by default, and the likes tab disabled by default, and then users can decide in their profile settings which (if any) of them they want to be shown.
This also necessitated some minor refactoring of the gallery code to handle multiple galleries on pages, explained below.
Artwork Gallery changes
Up to now, a few gallery styling functions were making use of the .gallery-padding CSS class, which is applied to all gallery containers. A problem with that approach is that when changing the gallery styling for one gallery, it causes other galleries on the same page to have the same changes applied when they shouldn't; I've had to modify the gallery constructor and some styling methods to use a root element selector, that identifies a given gallery's root container and only makes modifications within that container for that gallery.
I still need to decide how a user changing a gallery's style in the sidepanel affects multiple galleries on a page, as there's two possible approaches. One is to change all galleries on the page to the given style, and another is to maintain separate styles for each gallery, which is probably a bit more complicated, but I'll need to do a bit of analysis to see what makes sense.
User Search
I've created a stored procedure to perform user searches, as opposed to artwork searches. I'll need to design the page that will show this, or ideally make it part of the existing search artworks page that can be viewed when the user clicks on it, so that it's easier to use the navigation bar to search for users.
I also discovered a pre-written SQL function for calculating the Levenshtein distance between two strings (basically calculating how similar two strings are), which will help a lot in user searches where minor typos or so forth can otherwise derail a search. I don't know if it will be suitable to use in artwork searches, as it would mean a huge number of functions calls that would make for an unacceptably slow SQL query. I'll look into it a bit more when I have the time.
Artwork Submission improvements
Commissioner Fields
I've implemented the commissioner fields for artwork submission, so that commissioners or artist+commissioner accounts are required to specify if an artwork was a commission they didn't make themselves, and both declare the artist and link to them. These fields only appear for those account types; artist accounts without the commissioner role don't have these fields shown.
I haven't yet implemented the extra stuff on the display artwork page (and possibly gallery pages) to signify when an artwork is a commission, and designed where to display that information, that's next on the todo list.
Styling Improvements
I've cleaned up a lot of the styling and animations for the artwork submission page, so that it's a lot easier to use and navigate. It currently looks like this:
The "multiple submission upload" option allows users to submit multiple artworks at once if they are subscribed (a normal user can still put multiple images or videos in one artwork, but can only submit one artwork at a time). Toggling the option, and options like commission fields and schedule date/time, now have graceful animations and don't show redundant fields. For instance, someone who hasn't ticked the "Schedule post" checkbox doesn't need the schedule date/time chooser on the page, so hiding it when not in use makes the page easier to read.
I still need to decide on things like the text layout, in case it's e.g. difficult for people to line up each of the options with their respective checkbox. It looks "neater" this way, since the text is all lined up on the left, but there might be better ways of achieving that. I'll think on it a bit more.
Database code refactoring
Some of the database classes (e.g. ArtworkDB and UserDB) were getting to a ridiculously large size. Even though many of the bigger SQL queries are separated out by way of stored procedures, these files were still thousands of lines long, which is unwieldy and annoying to go through.
I've refactored them so that the main ArtworkDB and UserDB classes are still there, but that related functionality is in its own folder of classes. You can see what I mean here:
This should also make debugging a bit easier in future.
Misc
Minor Improvements
- Un-bookmarking an artwork whilst browsing a bookmark folder now causes it to disappear from the gallery. I might need to consider making that a toggleable option, for users who e.g. find it annoying to fatfinger the bookmark button not wanting that behaviour, but it's useful when people want to manage a bookmarks folder and not have them cluttering the page.
- The GetArtworkGallery backend form has been improved and streamlined, so that it doesn't have one function for each gallery type (e.g. profile galleries, bookmark galleries and so on).
Bug Fixes
- Fixed a bug in the feed style display for galleries, where switching between different images/videos of an artwork would cause it to resize incorrectly when resizing the browser window.
- Fixed artwork comment notifications also being sent if the user was commenting on their own artwork, which shouldn't generate a notification for them.
- Fixed gallery feed style icons showing before their respective artworks do when browsing a user's bookmarks galleries.