Rename Strategy (rename_strategy)
After a download completes, AB calls the Provider that the setting "rename method" (plugins.slots.rename_strategy) selects, for each media file and subtitle in the torrent. The host has only none (keep the name). The built-in plugin rename provides pn, advance and template. The id that a plugin registers appears in the list in Settings → Series management → Rename method.
from ab_sdk import Plugin, points, provider
from ab_sdk.rename import RenameInput, RenameSkipped, pad
class JellyfinStyle:
def target_name(self, f: RenameInput) -> str:
language = f".{f.language}" if f.kind == "subtitle" else ""
if f.episode_type == "movie":
return f"{f.bangumi_name}{language}{f.suffix}"
if not f.bangumi_name:
raise RenameSkipped("the series folder name is missing")
return f"{f.bangumi_name} - S{pad(f.season)}E{pad(f.episode)}{language}{f.suffix}"
class MyRename(Plugin):
@provider(points.RENAME_STRATEGY, id="jellyfin-style")
def jellyfin(self):
return JellyfinStyle()RenameInput
A frozen snapshot.
| Field | Description |
|---|---|
kind | media or subtitle (subtitles have no separate method; use kind) |
media_path | The original relative path in the torrent |
title | The title parsed from the file name |
bangumi_name | The series folder name of the save directory (Title (Year) for a movie) |
season, episode | Season and episode. episode already has the episode offset |
suffix | The extension with the dot, for example .mkv |
episode_type | episode, movie or special |
language | The subtitle language, for example zh, zh-tw |
group | The release group; can be None |
title and bangumi_name come from file names and folder names that already exist on disk. Each is one path component. AB does not remove reserved characters from them.
Return values and errors
- Return the new relative path in the torrent. Usually this is only a file name. The strategy adds the extension and the subtitle language. Return
f.media_pathfor no rename. pad(n, width=2)pads with zeros and keeps the fraction:pad(9.5) == "09.5". Half episodes such as recap episodes must keep the fraction. Otherwise they overwrite the whole episode of the same season.- Raise
RenameSkipped(reason): the file keeps its name, the torrent does not get the "renamed" tag, and AB sends onerename_skippednotification per torrent with the reason. AB retries in the next round after you fix the problem. This exception means that the input or the configuration has a problem. It does not count toward the breaker. Do not fall back to another naming method on failure. - Another exception, an empty string or a value that is not a string: the file also keeps its name and AB sends a notification, and the failure counts toward the breaker.
target_nameis a synchronous call with no timeout. Do not do network or disk IO in it.- If the
idin the settings is not registered (the plugin is disabled or tripped), AB writes one log line and acts asnone.
Tests
from ab_sdk.testing import RenameStrategyContract, create_plugin
class TestStrategy(RenameStrategyContract):
def create(self):
plugin, _ = create_plugin(MyRename)
return plugin.jellyfin()The suite checks: a non-empty relative path, no .., the suffix is kept, the result is deterministic. If your strategy fits only some inputs, override samples().
Example: examples/plugins/template-rename (a template with its own filters).