Naut/examples/README.md
ookami125 8dde48c05a webui: replace nautctl web server with a loadable plugin
Drop the web UI that was compiled into nautctl and serve the
torrent-ui front end (../torrent-ui/public) from a native plugin
(plugins/webui) loaded via `nautd --plugin`. The plugin talks to the
engine only through the host call_rpc ABI and adapts the daemon's RPC
surface to the qBittorrent-style contract the UI expects (snapshot/SSE,
torrent detail tabs, add/delete, cookie auth).

Also folds in the daemon refactor that owns per-torrent worker threads
and the swarm engine (naut_swarm) used by the plugin's data source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 00:21:48 -04:00

3 KiB

Examples

Drop-in Lua scripts for the nautd scripting layer (see ../docs/scripting.md).

anime_sort.lua — sort anime into a library as it downloads

Files each episode into a clean, media-server-friendly tree the moment its file finishes verifying — before the rest of the torrent completes — using Naut-Torrent's on_file_complete hook + naut.move_file():

<SORTED_ROOT>/<Anime Title>/Season NN/<Anime Title> - SNNENN.<ext>

Movies (no detectable episode) go to <SORTED_ROOT>/<Title>/<Title> (year).<ext>.

Use it

# Start the engine, load the script, and add a download.
nautd --socket /tmp/nautd.sock
nautctl --socket /tmp/nautd.sock script examples/anime_sort.lua
nautctl --socket /tmp/nautd.sock add show.torrent /downloads/1

As each file completes you'll see, e.g.:

[anime_sort] [SubsPlease] Frieren - 12 [1080p].mkv  ->  /library/Frieren/Season 01/Frieren - S01E12.mkv

Options (top of the script)

Option Default Effect
SORTED_ROOT /sorted destination library root
ONLY_VIDEO true skip non-video files (subtitles, .nfo, samples) and leave them in place
KEEP_ORIGINAL_NAME false true keeps the original filename instead of Title - SNNENN.ext

anitomy.lua — the anime filename parser

A compact, dependency-free reimplementation of the ideas in Anitomy: given a scene/fansub filename it returns the anime title, season, episode (plus release group, resolution, year, extension). Pure Lua, no require/io/os, so it can be embedded verbatim in a sandboxed script — which is exactly what anime_sort.lua does.

local anitomy = require("anitomy")
local p = anitomy.parse("[Erai-raws] Jujutsu Kaisen 2nd Season - 17 [1080p].mkv")
-- p.title = "Jujutsu Kaisen", p.season = 2, p.episode = 17, p.extension = "mkv"

anime_sort.lua carries a verbatim copy of this parser (the sandbox can't require); test_anime_sort.lua asserts the two stay in agreement.

What it recognizes

  • [Group] Title - 12 [1080p].mkv (dash-delimited episode)
  • Title S04E28, Title S2 - 03, Title 2nd Season - 17, Title Season 2 - 14
  • Title.S03E11.1080p.x264.mkv (dotted delimiters)
  • Title_-_01v2_[720p].mkv (underscores, version suffix)
  • Episode 25, Ep5, #07, absolute numbering (- 500)
  • ranges (01-12), release-group and CRC/resolution stripping, movie years

Heuristic limitations (honest)

  • A title that ends in a number with no episode marker (Mob Psycho 100.mkv) treats the number as the episode — same as Anitomy.
  • Absolute episode numbering reports season 1 (there is no season marker to read).
  • Episode titles after the number (- 05 - The Battle) are dropped.

Tests

lua examples/test_anitomy.lua      # parser battery
lua examples/test_anime_sort.lua   # end-to-end path building + drift guard

These also run under ctest (as example_anitomy / example_anime_sort) when a lua interpreter is on PATH.