The install.pl script is essentially a sequence of commands executed to install the backend and frontend dependencies needed to run LRR, as well as basic environment checks.
Those variables were introduced for the Homebrew package, but they can be declared at anytime on any type of install; LRR will try to use them.
LRR_DATA_DIRECTORY - Data directory override. If this variable is set to a path, said path will house the content folder.
LRR_THUMB_DIRECTORY - Thumbnail directory override. If this variable is set to a path, said path will house the generated archive thumbnails.
LRR_TEMP_DIRECTORY - Temporary directory override. If this variable is set to a path, the temporary folder will be there instead of
LRR_LOG_DIRECTORY - Log directory override. Changes the location of the
LRR_FORCE_DEBUG - Debug Mode override. This will force Debug Mode to be enabled regardless of the user setting.
LRR_NETWORK - Network Interface. See the dedicated page in Advanced Operations.
While Perl's mantra is "There's more than one way to do it", I try to make LRR follow the PBP, aka Perl Best Practices.
This is done by the use of the Perl::Critic module, which reports PBP violations.
If installed, you can run the critic on the entire LRR source tree through the
npm run critic shortcut command.
Critic is automatically run on every commit made to LRR at the level 5 thanks to Github Actions.
I also run perltidy on the source tree every now and then for consistency. The rules used in perltidy passes are stored in the .perltidyrc file at the source root.
Code width limit is stupid for long strings and comments (ie the base64 pngs in plugin metadata), which is perltidy's default behavior.
The visual indentation when setting a bunch of variables at once a perltidy thing, but I actually really like it! I leave it in and try to repro it whenever it makes sense.
The codebase does have issues with variable naming -- perl packages usually go for snakecase buuut short variables are ok in flatcase (as per perlstyle )
''s should only be used for escaping
" easily and vice-versa but I don't really care about that one. 😐
A small practice I try to keep on my own for LRR's packages is to use methods (arrow notation,
Class::Name->do_thing) to call subroutines that take no arguments, and functions (namespace notation,
Class::Name::do_thing($param)) to call subs with arguments. It doesn't really matter much, but it looks cleaner to me!
Also makes it easier if one day I take the OOP pill for this project, as methods always get the current object (or class name) as the first parameter of their call.
Packages in the
Utils folder export most of their functions, as those are used by Plugins as well.
I recommend trying to only use exported functions in your code, and consider the rest as internal API suspect to change/breakage.
The Shinobu File Watcher runs in parallel of the LRR Mojolicious Server and handles various tasks:
Scanning the content folder for new archives at start
Keeping track of new/deleted archives using inotify watches
Adding new archives to the database and executing Plugins on them if enabled
It's a second process spawned through the Proc::Simple Perl Module. Heavier tasks are handled by a Minion Job Queue, which is much more closely linked to Mojo and basically just werks™
When you perform a search in LRR, that search is saved to a cache in order to be served faster the next time it's queried. This cache is busted as soon as the archive index is modified in any way.(be it editing metadata or adding/removing archives)
In Debug Mode:
The Mojolicious server auto-restarts on every file modification,
Logs are way more detailed,
You get access to Mojolicious logs in LRR's built-in Log View,
A Status dashboard becomes available at
You can look inside the LRR Redis database at any moment through the
The base architecture is as follows:
-Redis Database|- **************************************** <- 40-character long ID for every logged archive| |- tags <- Saved tags| |- name <- Name of the archive file, kept for filesystem checks| |- title <- Title of the archive, as set by the User| |- file <- Filesystem path to archive| |- isnew <- Whether the archive has been opened in LRR once or not| +- thumbhash <- SHA-1 hash of the first image of the archive||- LRR_PLUGIN_xxxxxxx <- Settings for a plugin with namespace xxxxxxx||- LRR_TOTALPAGESTAT <- Total pages read||- LRR_FILEMAP <- Shinobu Filemap, maps IDs in the database to their location on the filesystem||- SET_xxxxxxxxxx <- A Category.||- LRR_CONFIG <- Configuration keys, usually set through the LRR Configuration page.| |- htmltitle| |- motd| |- dirname <- Content directory| |- thumbdir <- Thumbnail directory| |- tempmaxsize <- Temp folder max size| |- enableresize <- Whether automatic image resizing is enabled| |- sizethreshold <- Auto-resizing threshold| |- readerquality <- Auto-resizing quality| |- enablecors <- Whether CORS headers are enabled| |- blacklist <- Tag blacklist| |- blackliston <- Whether tag blacklisting is enabled| |- devmode <- Whether debug mode is enabled| |- enablepass <- Enable/Disable Password Authentication.| |- nofunmode <- Whether No-Fun Mode is enabled| |- pagesize <- Amount of archives per Index page| +- apikey <- Key for API requests|+- LRR_SEARCHCACHE <- Search Cache|- $columnfilter-$filter-$sortkey-$sortorder-$newonly <- Unique ID for a search. The search result is serialized and saved as the value for this ID.+- --title-asc-0 <- Example ID for a search made on titles with no filters.