Skip to content

Instantly share code, notes, and snippets.

@natyusha
Last active May 14, 2025 21:15
Show Gist options
  • Save natyusha/2a658b04bab69bffdbf136a6f5a8cc28 to your computer and use it in GitHub Desktop.
Save natyusha/2a658b04bab69bffdbf136a6f5a8cc28 to your computer and use it in GitHub Desktop.
Shoko Anime Lua Renamer Config
-- ###### Shoko LuaRenamer NN ######
-- ### Table Manipulation Functions ###
function append(t, s)
s = string.lower(s)
custom_tags = {}
for i = 1,#t do
if(s:match("%[" .. t[i] .. "%]")) then table.insert(custom_tags, s:match("%[" .. t[i] .. "%]")) end
end
return " " .. table.concat(custom_tags, " ")
end
function search(t, s)
for i = 1,#t do
if (s:find("^" .. t[i])) then return t[i] end
end
return false
end
-- ### Anime Title Overrrides -- Replace titles for special cases like crossover series manually using anidb ids
local title = anime.preferredname
if anime.id == 2840 or anime.id == 2841 then title = "Akahori Gedou Hour Rabuge" end
-- ### Anime Title Cleaner ### -- Replace problematic or ugly characters with similar Unicode counterparts
-- Replace leading periods for Unix
title = title:gsub("^%.", "")
-- Replace special cases for aesthetics (half sign, arrows)
local StyledCharacters = { {"1/2", "½"}, {"1/6", ""}, {"%-%->", ""}, {"<%-%-", ""}, {"%->", ""}, {"<%-", ""} }
for _, v in ipairs(StyledCharacters) do title = title:gsub(v[1], v[2]) end
-- Replace characters not allowed in Windows filenames
title = title:gsub(".", { ["\\"] = "", ["/"] = "", [":"] = "", ["*"] = "", ["?"] = "", ["<"] = "", [">"] = "", ["|"] = "" })
title = title:gsub("\"(.+)\"", "“%1”") -- Replace double quotes around text separately with left and right quotes
-- Replace multiple spaces in a row with a single space and check for trailing whitespace
title = title:gsub("%s+", " "):gsub("%s+$", "")
-- ### Filename Tag Catcher ### -- Append custom file tags from the original filename back onto it
-- These are entered at the end of the filename in square brackets
local CustomFileTags = { "ptcen", "unc", "cut", "uncut", "director's cut", "original", "rebroadcast", "recap", "%l%l%l documentary", "documentary", "silent", "native %l%l%l",
"raw", "p?t?hardsubs %l%l%l", "p?t?hardsubs", "vertical", "uhd", "lq", "watermark", "logo", "test", "movie part%d%d?", "part%d%d?" } -- Table of custom file tags to keep and append (in display order)
local file_tags = append(CustomFileTags, file.name):gsub("%s+$", "") -- Append any custom file tags then remove trailing whitespace
-- ### Episode Number Modification ### -- Add episode numbers if the episode isn't a single entry
if episode.type ~= "Episode" then zeros = 1 else zeros = 2 end -- Remove padding for non standard episodes as they are naturally padded with the episode type
local ep_number = episode_numbers(math.max(#tostring(anime.episodecounts[episode.type]), zeros)) -- Apply padding based on the total episode count per type
ep_number = ep_number:gsub("^(.+) O(%d+)$", "O%2 (E%1)") -- Check if there are AniDB episode relations for "Other" episodes reverse them and put the related episode numbers in brackets
ep_number = ep_number:gsub("^(.+) S(%d+)$", "%1 (S%2)") -- Check if there are AniDB episode relations for "Special" episodes and put the related episode numbers in brackets
-- OPTION(A): ep_number = ep_number .. (file.anidb and file.anidb.version > 1 and "v" .. file.anidb.version or "") -- Append the file version if available
-- Replace the episode number with single entry titles if it isn't a special (due to several named "Music Video" on AniDB)
local ep_name = episode:getname(Language.English) or "" -- Grab the Main title for the episode
local SingleEntryTitles = { "Complete Movie$", "Short Movie$", "Music Video$", "Special$", "TV Special$", "OAD$", "OVA$", "Web$" } -- Table of ambiguous single entry titles
local SingleEntryOverrideIDs = { "284749" } -- Table of anidb episode ids to ignore SingleEntryTitle rules
if not search(SingleEntryOverrideIDs, tostring(episode.id)) then
if episode.type ~= "Special" and search(SingleEntryTitles, ep_name) then ep_number = "(" .. ep_name .. ")" end -- Place in brackets so they appear before episodes of other types
end
-- Override the numbering for normal episode relations that are "Parts" to match the format of "Other" type episodes above
if episode.type == "Episode" and #episodes > 1 and episodes[1]:getname(Language.English):match("Part %d of %d") then
ep_number = "0" .. episodes[1].number - 1 .. " (E" .. episodes[2].number .. ")"
end
-- ### Folder Name Modification ###
local folder_name = title
local CommonTitlePrefixes = { "Gekijou Henshuuban ", "Gekijou Soushuuhen ", "Gekijou Remix Ban ", "Gekijou Tanpen ", "Gekijouban 3D ", "Gekijouban ", "Eiga ", "OVA " } -- Table of common title prefixes
if search(CommonTitlePrefixes, folder_name) then folder_name = folder_name:gsub("^(" .. search(CommonTitlePrefixes, folder_name) .. ")(.+)$","%2 — %1") end -- Append common title prefixes to the folder names for ease of locating alphabetically sorted folders
-- Replace trailing ellipses/periods for windows, replace multiple spaces in a row with a single space and check for trailing whitespace
folder_name = folder_name:gsub("%.%.%.%.%.%.$", "……"):gsub("%.%.%.$", ""):gsub("%.%.$", ""):gsub("%.$", ""):gsub("%s+$", "")
-- ### Final Operation -- Move and rename the files
if anime.restricted then destination = "Hentai" else destination = "Anime" end -- Make sure 18 Restricted content is segregated
filename = table.concat({ title, " - ", ep_number, file_tags })
subfolder = { folder_name }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment