Skip to content

Releases: coconautilus17/LibraForge

v0.2.4

Choose a tag to compare

@coconautilus17 coconautilus17 released this 15 Jul 20:03
2a12118

New Features

  • Fix Series -- a cross-book bulk-edit dialog for correcting series metadata (name, author, genre, narrator, explicit, language) across every book in a detected series group at once. Two detection passes group books by title pattern (no series tag yet) or by normalizing existing series-tag variants (trailing space, ", Book N", reading-order qualifiers like "(Chronological Order)"/"(Publication Order)"), surfaced as group cards in both the Suspicion Report and Match Report widgets.
  • Enrichment Forge -- a new page that finds a series already in your Audiobookshelf library, pulls genre and narrator from Audible and Goodreads across every book in it, and applies the compiled result to the whole series at once. Explicit content evidence is shown alongside but never pre-checked, since neither provider's signal is reliable proof a book is clean, only a hint that it might not be.
  • Folder Forge: customizable naming template -- an optional template controlling how the organizer names destination folders and, for single-file books, the audio filename, via tokens for author, series, order/number, title, edition, narrator, publisher, year, and ASIN. It stays on "Use ABS default structure scheme" by default -- destination folders are laid out exactly as before -- and turning it off lets you define your own layout, with a live preview and worked example scenarios (fetched in parallel, so switching between them is instant). Loose single-file names now also get a tidy-up under either scheme: a name that is pure release junk or a jumbled restatement of the metadata (a doubled series name, an underscore-mangled dump) is rebuilt as a clean "Book N - Title" while already-clean names are left untouched. For full control, two filename tokens cover the "keep the file's own name, just tidy it" workflow: {filename} cleans the source name while {original} keeps it verbatim -- and anything placed after either token is appended, so stamping an ASIN onto a messy filename is a single edit. An ASIN that conflicts with one already in the name is flagged for review instead of being silently duplicated.
  • Manual Review: search for any book -- a new search box in Manual Review's "Load any book" section finds any book anywhere in your library by name and opens it directly, instead of being limited to the books flagged in the current Suspicion/Match report. It's backed by a filesystem index that builds in the background on startup and refreshes when the library changes, so results come up live as you type.
  • Collapsible advanced run settings, plus side navigation on every tool page -- the less-common run options on Metadata Forge, Folder Forge, and the M4B Tool now sit behind an "Advanced settings" toggle so the common path stays uncluttered, and the M4B Tool gained the same in-page side navigation as the other tool pages (with section jumps that land the heading just below the fixed header instead of behind it).
  • Refreshed, crisper UI -- tightened border-radius, spacing, and the type scale across the whole app onto a shared set of design tokens; recolored the default dark/light theme to a warmer palette; added a new "Wood" dark surface option alongside the existing theme choices.
  • M4B Tool: discovery-cache status indicator -- a persistent marker shows whether the cached multipart/non-M4B search for the current root and fixer script is ready (with a file count), stale (the fixer script changed since it was last built), or still building/updating, instead of only finding out after clicking Find and waiting.

Fixes

  • Security: removed a debug toggle that silently disabled connection and auth gating -- a "Show developer links" debug mode added one developer link, but also silently bypassed every "no metadata provider connected" redirect and the page-load auth check across the whole app. Left enabled in a browser from earlier testing, it would quietly turn those guards off; it has been removed entirely.
  • Security: patched known CVEs -- updated the Alpine base image and Python dependencies to close known vulnerabilities.
  • Security: hardened file and URL handling -- book cover lookups are now restricted to the configured audiobook library; file:// cover URLs are only accepted from LibraForge-managed uploads; cover images are capped at 10 MiB and validated as real JPEG/PNG; ABS/abs-agg/abs-tract service URLs must use http:///https://. Closes off unintended local file access and unsafe URL schemes in cover/service-URL handling.
  • Organizer: title corruption from bracketed annotations -- fixed a family of bugs where bracketed narrator/series annotations leaked into the cleaned title instead of being stripped (a 3-segment bracketed filename, a redundant "(Series Book N)" parenthetical, one level of nested parenthetical, a bare "(Book N)"/"(Vol. N)" annotation). Also fixed a stray ampersand-truncation regression from the same title-cleaning pass.
  • Fixer: batch runs silently reprocessing manually-applied books -- the marker-skip check trusted an incomplete written_fields list for grouped/json-sidecar books, so a book you'd already manually applied could get silently reprocessed on the next batch run. Fixed at the source instead of special-casing the check.
  • Fixer: wrong recovery target for grouped books -- grouped (multi-part) books' recovery flow now resolves the correct meta_target from the multi-part group map instead of a wrong/partial one.
  • Light-theme contrast/readability -- the default accent color and the success/warning/danger status colors had no light-theme-specific variants and were reusing dark-theme hex values verbatim, making several text/background combinations (especially the default accent's button text, and status badges throughout the app) fail basic readability in light mode. Audited every theme x surface x accent combination and fixed all of them.
  • Match Report: series-grouping cards vanished after changing the status filter -- selecting any status filter (including switching back to "All statuses") permanently dropped the series-group suggestion cards from the list, since they were inserted outside the normal filtered render cycle. Also added a "Series groups" filter option to view them on their own.
  • Match Report: failed books mislabeled "Not Matched" -- the status badge checked for a status string the backend never actually sends, so genuinely failed/errored books were silently shown as "Not Matched" instead of "Error" (invisible in practice since both badges happened to share identical styling).
  • Manual Review: duplicate "Manually Applied" badge -- Manual Review rendered its own separate reason chip for a fact already covered by the Match Report card's badge (both come from the same marker field); it now reuses that same badge instead of showing it twice, differently styled.
  • Start Here: reworked and completed the badge legend -- restructured into one table with labeled sections, fixed a stale/incorrect cross-reference between two badges, and added the previously-undocumented Multi-file, Suspect Report severity/trigger, and series-group ("no series"/"series drift") badges. Also added CSS for the "critical" suspect severity, which had no styling at all.
  • Settings redirect for a missing Audible/ABS connection lacked clarity -- clicking Start run or a search action with no metadata provider connected used to fail unclear, or land you on Settings with no explanation of what was missing. Now shows a clear notice explaining what to fix and highlights the relevant Settings section. Where there's a sensible fallback (Audible and ABS can substitute for each other), it automatically switches to whichever one is actually connected instead of failing; GraphicAudio/SoundBooth Theater and Goodreads/Kindle selections get the same clear redirect-and-explain treatment, without a false auto-switch since neither has an equivalent fallback.
  • A hidden "Batch provider" setting silently overrode the visible "Metadata provider" picker -- whole-library runs actually used a separate field tucked away in Advanced settings, easy to never notice, instead of the "Metadata provider" picker already visible on the page. Removed it; "Metadata provider" now drives both single-book search and whole-library runs consistently.
  • Cancel button did nothing for most of a run's lifetime -- the fixer only actually checked for a cancel request once it reached the write phase; clicking Cancel during the search/match phase (the search-per-book pass that makes up the large majority of a whole-library run's total time) was silently ignored and the run just kept going to completion, with no way to stop it short of killing the process directly on the server. Now checked in the search/match loop too, so Cancel takes effect within one in-flight search call, typically a few seconds, no matter which phase the run is in.
  • abs-agg (GraphicAudio, SoundBooth Theater, and more) had no Settings section -- unlike Goodreads/Kindle (abs-tract), there was nowhere to configure or verify its URL from Settings despite the backend already supporting it. Added one with the same live "Save and verify" check, and documented its full real provider list (11 total, including Goodreads and Hardcover once the abs-agg service itself is configured for them).
  • Unified library scanning across Manual Review, M4B, and Folder Forge -- Manual Review's "Load any book" search, the M4B Tool's multipart/non-M4B discovery, and Folder Forge's dashboard scan now share one folder-existence and per-folder-signature index instead of three separate, inconsistent staleness checks. Fixes two real bugs this uncovered: Folder Forge's scan trusted a too-coarse fingerprint that could keep serving stale dashboard tiles for up to an hour after a real change, and that same coarse fingerprint was blind to a book added or changed in a deep subfolder, so it silently never showed up. Folder Forge's...
Read more

v0.2.3

Choose a tag to compare

@coconautilus17 coconautilus17 released this 08 Jul 23:30
4a2169e

New Features

  • Suspicion Report search + filter -- added a search box and flag-type filter to the Suspicion Report list, shared by both the Metadata Forge and Folder Forge report pages.
  • Manual Review Edit dialog overhaul -- widened to 75% of viewport width and given a settings-style side nav on the Metadata Forge page for jumping between sections. Cover search simplified to a clickable cover + title (no more separate "Use this cover" button), packing 4-7 covers per row instead of 2. Added Language and Explicit tag fields (written to metadata.json only -- no existing tag convention covers them), and a uniform Fill/Overwrite field policy across every dialog field.
  • Organizer: exclude items from a run -- each planned-move card now has an "Exclude from organizer run" button that adds the item to the skip-pattern list.
  • Goodreads circuit-breaker visibility -- when the abs-tract circuit breaker trips, affected books now show a "GR LIMITED" badge instead of looking like a genuine no-match, plus an end-of-run warning explaining what happened and suggesting a lower search-worker count.
  • Suspicion Report: missing-field flags -- flags a technically-correct match/move that's just missing its title, author, or series (high severity), separate from write-risk checks.
  • Cross-item suspect cards -- duplicate-identity cards (same ASIN, or same author/series/sequence across separate files) now show real identifying titles and paths instead of an empty "(cross-item)" placeholder.
  • Library Downloader: activation-bytes status -- a status indicator shows whether the account's activation bytes are cached, with a one-click-copy recovery command when they're not.
  • Library Downloader: concurrent downloads + structured report -- downloads now run 3-at-a-time like audible-cli instead of one at a time, and the end-of-run report shows each item's actual decrypt method and outcome instead of just aggregate counts.
  • Sticky header, version tag, Settings About -- the top header now stays attached while scrolling, shows the current release version linked to its GitHub notes, and Settings gained a short About section.

Fixes

  • Report vs. Manual Review metadata consistency -- the report's "local"/current display (Suspicion Report, Match Report) has been fixed at its root, closing out several related bugs found over the course of this release:
    • "Current" was partly built from matcher-only clues (title/series/author/book_number after path- and folder-name overrides meant only to help find the right catalog match), so a rejected or stale match could show a guessed identity instead of the file's real tags. Replaced with a pure tag-only reader used everywhere current state is displayed or persisted.
    • Genre, subtitle, summary, isbn, asin, and publisher were silently dropped or misreported blank in the marker (genre alone was wrong on 85 of 99 real books tested), because the writer's own "leave tag alone if the match has nothing" behavior wasn't mirrored when recording what got written; fill-missing mode also overwrote genre/subtitle instead of respecting existing values.
    • A cleanly-skipped file showed stale pre-fix data as if it were current, and grouped multi-file books' representative file could be a bonus non-content track (e.g. "Opening Credits"), leaking its own chapter title and track number as if they were the book's title and series sequence.
    • Root cause of the last remaining gap: the report and Manual Review read through two independently-written lookups that mostly agreed. The report now delegates to the exact same sidecar/marker lookup Manual Review uses.
    • Separately, the Match Report card had hardcoded blank "Local" values for Year/ASIN/ISBN since the card was first built -- unrelated bug, same visible symptom, now wired to the real data like every other field.
  • Manual Review: field clears silently ignored -- clearing a dialog field and applying wrote the old matched value back into the tag instead of clearing it. Also fixed multi-genre input (e.g. "Fantasy, LitRPG") collapsing into one malformed combined tag instead of two separate values.
  • Organizer: run settings silently ignored -- the Start button was sending its own click event as the request body instead of the form's collected values, so every setting (Progress every N items, skip patterns, Apply moves, and more) was silently replaced with its backend default on every run.
  • Organizer: multi-part grouping -- ported the fixer's part-sequence/leading-ordinal grouping so a folder holding both a real chapter sequence and a leftover merged edition (e.g. an M4B Tool output whose source files were never cleaned up) groups correctly instead of exploding every chapter into its own move.
  • Organizer: stale run after reload -- a page-reload race could silently swap in a stale prior run's progress and log after a fresh run was already started.
  • Library Downloader: CloudFront blocking -- downloads now prefer a per-book decryption voucher over account activation bytes, since the account's activation bytes are blocked at the source and the voucher path never touches that endpoint.
  • Side nav hidden behind sticky header -- the sticky side nav (Settings and Metadata Forge) rendered partly hidden behind the sticky header at every scroll position.
  • Suspicion Report: "latest report" filter no-op -- a structural bug meant the filter could never actually exclude organizer reports from the fixer's own "latest report" view.
  • Suspicion Report: false error on first load -- the suspect-review probe returned a 404 (logged as a browser console error) for the completely normal "not generated yet" state, on every single report load.

Docs

  • Expanded README with current features, added an issue-reporting guide.

v0.2.2

Choose a tag to compare

@coconautilus17 coconautilus17 released this 04 Jul 23:36
bd82dff

New Features

  • Organizer skip-pattern matcher -- ported the Metadata Forge skip-pattern mechanism into Folder Forge: a Skip patterns, one per line field (plus the "include persistent patterns from global policy" checkbox) that skips books whose source path or inferred metadata matches, same case-insensitive semantics as the fixer's version.

  • Organizer failure visibility -- the apply loop previously called shutil.move with no error handling at all: one bad move (a blocked destination path, permission error, or a source that vanished between planning and apply) crashed the entire run and silently dropped every remaining planned move, with no report of what did or didn't move. Failures are now isolated per move, with a prominent "N succeeded, M failed" summary banner and a Failed Moves section listing each failure's error, source, and target.

  • Organizer no-sidecars warning -- multi-file book handling (grouping split chapters, and title/author/series identity across them) leans on metadata the fixer writes to sidecars. If a scan root has nothing the fixer has ever touched, Folder Forge now warns ("Fixer was not applied -- multi-file book handling relies on the fixer script. Continue anyway?") instead of silently producing weak, filename-derived metadata for split books.

  • Start Here guide -- a collapsible legend on the landing page explaining Edit modes, Write modes, Match badges, the metadata.json vs. Audiobookshelf Scanner distinction (with a screenshot of ABS's 6 metadata sources), Report types, the Owned badge, and a step-by-step Suggested Workflow through the full Metadata Forge + Organizer pipeline.

Fixes

  • Matcher regressions from a real library run -- a full pass against a real, messy _unorganized folder surfaced several ways a wrong match could still reach an auto-write:

    • A candidate with no sequence data at all (empty series/sequence) could still hit the high-confidence write floors via title+duration+author agreement alone, even when the local file has an explicit, confident book number the candidate can't confirm or refute.
    • The parallel/companion-series leniency (for legitimate cases like a local omnibus-numbered book matching a differently-numbered sub-series) ignored a confirmed sequence disagreement regardless of how large the gap was, letting a recurring saga tagline shared across several volumes of the same series override a real 3-book sequence mismatch.
    • A coincidental substring series name (e.g. two different, unrelated series by the same prolific author, one name a substring of the other) let its raw text-similarity score carry an item past the write threshold on its own, even after the same-author cross-series protection blocked the more obvious inflation paths.
    • A common multi-file release convention (001 Author - Book N - Chapter X.mp3, a bare space after the zero-padded index) was never recognized as a chapter sequence, and once combined with a merged single-file edition sitting in the same folder, exploded every chapter into its own separate, wrong match instead of grouping into one book.
    • A loose file sitting directly in the scan root (no book-specific subfolder) could have its title corrupted into the literal name of the scan-root folder, following a backwards filename parse.

    All five verified against the real library that surfaced them, with 12 new regression tests.

  • Library Downloader activation-bytes rate limit -- root-caused the Amazon CloudFront rate-limiting affecting AAX downloads: account activation bytes were being fetched once per book instead of once per run, firing repeated live requests to Audible's activation endpoint in quick succession and tripping abuse protection. Now fetched once per run, cached (including a failed fetch), and persisted to the auth file.

  • Library Downloader run leak -- run_download_worker now pops from the in-memory runs dict and writes a final report on completion, matching the other three workers (fixer, M4B tool, organizer).

  • Settings anchor scroll -- /settings#accounts (linked from every tool page's "Set up auth" call-to-action, and the /auth-setup redirect target) landed users deep in the middle of the Publishers list instead of the Accounts section, because the browser's native hash-scroll fired before the async Publishers/Title-noise lists finished rendering and growing the page. Now re-applied after each list finishes loading.

  • Organizer: multi-file grouping and cross-contamination -- recognizes part numbers embedded mid-filename, not just trailing ones; fixed metadata cross-contamination between distinct books sharing a folder-level libraforge.json.

  • Manual Review cover extraction -- now reads the real embedded cover tag instead of ffmpeg's first video stream, fixing wrong covers shown for some files.

  • Organizer Suspicion Report visibility -- moved above Planned Moves in the UI; it was getting buried below a long list of planned moves after a real run.

Docs

  • CHANGELOG and README brought up to date against current features (Suspect Report, Settings-page consolidation, Goodreads/Kindle provider, Start Here guide); "Local agent advisory review" redacted from the README's Planned section, superseded by the Suspect Report (a resource-friendly, rule-based script pass over write matches, no LLM involved).

v0.2.1

Choose a tag to compare

@coconautilus17 coconautilus17 released this 01 Jul 23:24
4b947b1

New Features

  • Report retention (Settings > Reports): Prune old run reports automatically after each scan. Two independent opt-in rules: max age in days and max total reports kept. Also includes a manual "Prune now" button. Both rules are disabled by default.

  • Compare table: live applied metadata -- the "Current" column in manual review now shows the actual applied state from libraforge.json instead of a preset field list. ASIN is read from sidecar.audible.asin; single-file books (direct ID3 writes) read from marker.audible. All stored fields are shown, including year, subtitle, genre, and ASIN that were previously missing.

  • Search from original backup -- manual review includes a checkbox to search Audible using the pre-apply backup title instead of the live tag, with an explanatory note when active.

  • Multifile duration from file cache -- duration for grouped multifile books is now summed from the file_cache entries in libraforge.json. When the cache is missing or files have moved, a concurrent ffprobe fallback (16 workers) is used and results are saved to cache.

  • ABS-compatible metadata.json -- Audiobookshelf metadata.json is now written with authors as ["Name"] and series as ["Series #N"] (plain string arrays), matching the ABS import format.

Fixes

  • Single standalone mp3 books write direct ID3 tags -- books with a single mp3 file now write tags directly instead of producing a JSON sidecar. should_write_json_sidecar() only returns true for grouped multifile books.

  • "Voidknight Ascension - Book" wrong series -- the series_number_title regex was capturing trailing label words (Book, Volume, Part) as part of the series name before more-specific patterns could run. Added a guard to skip matches where the series ends with a label word.

  • Path override corrupting series when path merges title + series -- apply_structured_path_override was replacing a correct embedded series with a path-derived merge of title + series (e.g. "Magic Eater" -> "Courts Magic Eater"). Added a merge-detection guard so the embedded granular values are preserved.

  • Fractional prequel sequences rejected -- strong_identity_overrides_number_conflict was rejecting matches where the local book number was a fractional prequel (e.g. 0.5) vs. a catalog sequence of 0. Now allows differences smaller than 1.0.

  • Tests updated from v4_16 to v5 -- three test files referenced the archived audible-metadata-fixer-v4_16.py. Updated to v5 and fixed three pre-existing regressions the archived tests had been hiding (series label parsing, title+series merge detection, fractional sequence scoring).

  • audible-metadata-fixer-v4_16.py archived -- moved to scripts/archive/; auto-discovery now only finds the current v5 fixer.

v0.2.0

Choose a tag to compare

@coconautilus17 coconautilus17 released this 30 Jun 00:11
8310dac

New Features

Match Report Widget

  • Full per-book match report UI rendered after every run -- expandable cards in a 2-per-row grid showing local vs. matched metadata side by side
  • Each card shows: cover images (local + provider), title, author, narrator, series, sequence, genre, year, ASIN, duration comparison, the query used to find the match, and a score percentage badge
  • Searchable by title, author, series, or path; filterable by status (Matched, Goodreads, Manually Applied, Smart-skipped, Would write, Written, Skipped, Not Matched, Error)
  • Manually applied books show a dedicated badge and load their stored marker data so the report reflects what was actually written, not a re-matched result
  • Local cover loading now extracts the embedded cover from loose audio files directly via ffmpeg, so books without a folder-level cover.jpg get their own correct cover instead of sharing the parent folder's

Goodreads / Kindle Fallback (abs-tract)

  • Unmatched books automatically fall back to Goodreads via abs-tract for title, author, series, and sequence metadata
  • Kindle cover-only fallback for books that match on metadata but lack an Audible cover
  • Explicit opt-in flag in the UI (Goodreads fallback checkbox); manual provider selector also exposes Goodreads and Kindle for single-book review
  • Circuit breaker with cooldown protects against upstream Goodreads/Amazon rate-limit blocks; transient failures retry instead of failing silently
  • Goodreads matches are provider-aware: smart-skip only checks the fields Goodreads can actually supply (title, author, series, sequence) -- narrator, ASIN, year, and genre are never blanked by a Goodreads re-match

Settings Page

  • Dedicated /settings page consolidating preferences, Accounts, and cleanup controls into a left-nav sectioned layout
  • Publisher learning author/narrator guard: known author and narrator names are no longer incorrectly learned as publishers

Multi-file Grouping Improvements

  • Per-chapter .ogg books grouped as a single multi-file book
  • Leading-ordinal chapter splits (e.g. "01 - BookTitle Part 1.mp3") grouped correctly as one book
  • Sidecar cleanup endpoint: remove libraforge state files for a target folder

Fixes

Matching Quality

  • Cross-series matches blocked when series names share only a prefix word (e.g. Arena vs Arena Road)
  • Hard block on matches with a clearly different author
  • Four matching failures fixed: chapter-numbered titles, audio-author-prefixed filenames, format labels misread as immersion labels, Goodreads series queries
  • "Title - Series, N" filenames with a bare book number now parsed correctly
  • Grouped "Series N - Author" folder names no longer blocked from matching

Genre

  • Removed all "Audiobook" hardcodes from the fixer script -- genre now defaults to empty string instead of the format label
  • Genre field filtered through all candidate providers and surfaced in the match report card and manual review UI
  • _pick_genre() helper blocks format labels ("audiobook", "audiobooks") so they never appear as a real genre

Metadata Correctness

  • fill_missing no longer preserves stale fraction sequences (e.g. "1/1" from embedded MP4 track tags) when a fresh valid sequence is available
  • Relative target paths normalized correctly before being passed to the fixer
  • Target path validated before run starts with a clear 400 error instead of a silent failure

UI / UX

  • Score badge shows percentage (e.g. 87%) instead of a rounded 0 or 1
  • "Audiobook" genre no longer appears in manual review metadata fields
  • Path validation error surfaced clearly in the run UI

v0.1.3

Choose a tag to compare

@coconautilus17 coconautilus17 released this 27 Jun 22:34
4fd395b

Metadata recovery, scan accuracy, and sidecar conformance.

Highlights

  • Self-healing fill-missing - recovers missing tags from existing libraforge markers, so books that were already marked as processed now get reprocessed and filled instead of skipped (#65).
  • Smarter scan completeness - the scanner judges a book by the real file's ASIN plus core tags, and treats a fixer-confirmed NOREALASIN as ASIN-satisfied, so it stops flagging books that are actually done (#66).
  • Scanner conformance - honors ignored folders relative to the scan root and defers sidecar creation to the fixer, so it never adopts or clobbers a folder-level libraforge.json (#68).

Fixes

  • Manual apply sidecar placement - manual applies now write sidecars by alone/group like the rest of the fixer: folder-level when the book is alone in its folder, per-file when the folder is shared (#71).
  • Library owned detection clarity - made it explicit that Owned status comes from Audiobookshelf's indexed ASINs, and that Audiobookshelf must re-scan after tags are fixed before a title shows as Owned (#64, #72).

Full Changelog: v0.1.2...v0.1.3

v0.1.2

Choose a tag to compare

@coconautilus17 coconautilus17 released this 26 Jun 23:32
ee6bfad

What's Changed

  • fix(fixer): resolve duplicate-ASIN library scan from cheap sources first by @coconautilus17 in #60

Full Changelog: v0.1.1...v0.1.2

v0.1.1

Choose a tag to compare

@coconautilus17 coconautilus17 released this 26 Jun 21:59
b31e500

What's Changed

  • fix(library): owned-ASIN scan no longer times out or crashes by @coconautilus17 in #55
  • feat(library): owned-ASIN detection via Audiobookshelf by @coconautilus17 in #56
  • fix(organizer): no-series dramatized book naming + canonical author f… by @coconautilus17 in #57
  • feat(abs): one-click removal of the stored Audiobookshelf API key by @coconautilus17 in #58

Full Changelog: v0.1.0...v0.1.1

v0.1.0

Choose a tag to compare

@coconautilus17 coconautilus17 released this 26 Jun 19:03
7bcdebe

What's Changed

New Contributors

Full Changelog: https://github.com/coconautilus17/LibraForge/commits/v0.1.0