Skip to content

Instantly share code, notes, and snippets.

@rubenhortas
Last active February 16, 2026 17:47
Show Gist options
  • Select an option

  • Save rubenhortas/d0ccd46750dd009d0f3fbedec5a4ecc9 to your computer and use it in GitHub Desktop.

Select an option

Save rubenhortas/d0ccd46750dd009d0f3fbedec5a4ecc9 to your computer and use it in GitHub Desktop.
Utility to normalize TV show filenames
#!/usr/bin/env python3
"""
TV Show Renamer: A utility to normalize TV show filenames.
This script automates the tedious process of renaming video files from messy
tracker formats (e.g., 'Show.Name.S01E01.720p.x264-Group.mkv') into a clean,
standardized structure (e.g., 'Show Name S01E01.mkv').
KEY FEATURES:
* Format Normalization: Converts multiple episode formats (S01E01, 1x01,
[Cap.101]) into a single consistent output style (English or Spanish).
* Intelligent Cleanup: Automatically removes over 100+ common metadata
tags, including video quality (4K, 1080p), codecs (x264, HEVC),
platforms (NF, AMZN), and release group names.
* Recursive Processing: Can scan entire directory trees to find and
process video files (.mp4, .mkv, .avi).
* Safety First: Includes a 'Test Mode' (-t) to preview changes without
modifying any files, and prevents overwriting existing files.
* Clean Typography: Corrects capitalization and removes redundant
periods, underscores, and dashes from titles.
USAGE:
usage: tv_show_renamer.py [-h] [-t] [-of {en,es}] [-sf {en,es}] [-ts TITLE_SEPARATOR] [paths ...]
TV Show Renamer (Normalize 'S01E01' and '1x01' formats)
positional arguments:
paths Directories to process
options:
-h, --help show this help message and exit
-t, --test Test mode (no changes)
-of, --output-format {en,es}
Format: 'en' (S01E01) or 'es' (01x01). Default: 'en'
-sf, --skip-format {en,es}
Skip files that already have this format
-ts, --title-separator TITLE_SEPARATOR
Separating character between the episode and the title, e.g.: '-'
"""
import argparse
import re
import signal
import sys
from pathlib import Path
# Keywords to strip (Case insensitive)
# Don't add '[]'
_ACRONYMS = [
# Video qualities
"CAM",
"CAMRIP",
"HDCAM",
"BDSCR",
"DDC",
"DVDSCR",
"DVDSCREENER",
"SCR",
"SCREENER",
"WEBSCREENER",
"HDTC",
"TC",
"TELECINE",
"HDTS",
"TELESYNC",
"TS",
"TVRIP",
"VHSRIP",
"WP",
"WORKPRINT",
"BD5",
"BD9",
"BD25",
"BD50",
"BD66",
"BD100",
"BDISO",
"BDMV",
"BDR",
"BDRIP",
"DISC",
"BLU RAY",
"BLU RAY RIP",
"BLURAY",
"BRIP",
"BRRIP",
"COMPLETE.BLURAY",
"REMUX",
"PDTV",
"DVDMUX",
"DVDR",
"DVDRIP",
"DVD-5",
"DVD-9",
"DVD-FULL",
"FULL-RIP",
"ISO RIP",
"ISOLESS RIP",
"P_REDVDRIP",
"UNTOUCHED RIP",
"HD",
"HDRIP",
"HDTV",
"HDTVRIP",
"PPV",
"PPVRIP",
"WEB",
"WEB DL",
"WEB RIP",
"WEB (SCENE)",
"WEBDL",
"WEBRIP",
"WEB-DL",
"WEB-DLRIP",
"WEB-RIP",
# 4K
"DS4k",
"RM4K",
# Video resolutions
"m-720p",
"mini 720p",
"720p",
"m-1080p",
"mini 1080p",
"1080",
"1080p",
"m1080p",
"mHD",
"mini HD",
"μHD",
"micro HD",
# Video Codecs
"XVid",
"AV1",
"x264",
"AVC",
"h264",
"H.264",
"H-264",
"H 264",
"x265",
"h265",
"H.265",
"H 265",
"HEVC",
"10bit",
# Video bit rates
"CBR",
"VBR",
# Video dynamic range
"SDR",
"HDR",
# Audio languages
"Dual",
"MULTI",
"AA3",
"AAc",
"AAC2 0",
"AC3",
# Audio qualities
"2.0",
"2Ch",
"5.1",
"7.1",
"2 0",
"5 1",
"7 1",
# Audio Codecs
"AA3",
"AC3",
"DDP",
"DDP2.0",
"DDP2 0",
"DDP5.1",
"DDP5 1",
# Corrected versions
"(Proper)",
"(Repack)",
"PROPER",
"REPACK",
# Subtitles
"+Subs",
"HC",
"MULTISUBS",
"Subs",
"SUBTITLES",
# Platforfms
"A3P",
"ABC",
"ALL4",
"AMZ",
"AMZN",
"ARD",
"ATVP",
"APTV",
"BBC",
"CBC",
"CBS",
"CR",
"DSNP",
"DISNEY",
"HBO",
"HBOM",
"HMax",
"HULU",
"NBC",
"NF",
"NFLX",
"PARA",
"PMNT",
"PCOK",
"PCKL",
"SHOW",
"STZ",
# Groups and sites
"AFG",
"EZTV.to",
"EZTVx.to",
"eztv.re",
"www.AtomixHQ.com",
"www.AtomixHQ.link",
"www.AtomoHD.BEER",
"www.AtomoHD.CASA",
"www.AtomoHD.cloud",
"www.AtomoHD.FUTBOL",
"www.AtomoHD.LOVE",
"www.AtomoHD.ninja",
"www.AtomoHD.PLUS",
"www.descargas2020.com",
"www.descargas2020.org",
"www.maxitorrent.com",
"www.PCTmix.com",
"www.pctnew.com",
"www.newpct1.com",
"(wolfmax4k.com)",
"BONE",
"CBFM",
"DiRT",
"EDITH",
"ETHEL",
"FENiX",
"FLUX",
"FREQUENCY",
"GalaxyTV",
"glhf",
"ggwp",
"GRACE",
"HiggsBoson",
"ION10",
"JFF",
"lazycunts",
"MeGusta",
"MGHW",
"NTb",
"RAWR",
"STAN",
"STC",
"successfulcrab",
"SYNCOPY",
"TORRENTGALAXY",
"TRUFFLE",
# Languages
"Cast",
"Castellano",
]
_VIDEO_EXTENSIONS = {".mp4", ".avi", ".mkv"}
_RE_EPISODE = re.compile(
r"""
(?P<show_name>.*?)
(?:
s(?P<s_en>\d{1,2})e(?P<e_en>\d{2}) | # s01e01
(?P<s_es>\d{1,2})x(?P<e_es>\d{2}) | # 1x01
\[Cap.(?P<se_es>\d+)\] # [Cap.101]
)
[\s\.\-]*(?P<title>.*)$
""",
re.IGNORECASE | re.VERBOSE,
)
_RE_CLEANUP_TAGS = re.compile(r"\s*\[.*?\]\s*")
_RE_ACRONYMS_CLEANUP = re.compile(
r"(?:[\s\.\-]+|^)("
+ "|".join(map(re.escape, sorted(_ACRONYMS, key=len, reverse=True)))
+ r")(?=[\s\.\-]|$)",
re.IGNORECASE,
)
_RE_SPACES_CLEANUP = re.compile(r"[\s\.]+")
# ANSI colors
_RED = "\033[91m"
_GREEN = "\033[92m"
_RESET = "\033[0m"
class Video:
__slots__ = [
"original_name",
"new_name",
"_path",
"_output_format",
"_skip_format",
"_title_separator",
"_extension",
"_language",
]
def __init__(
self,
file_path: Path,
output_format: str,
skip_format: str | None,
title_separator: str,
):
self.original_name = file_path.name
self.new_name = None
self._path = file_path
self._output_format = output_format
self._skip_format = skip_format
self._title_separator = title_separator
self._extension = file_path.suffix
self._language = None
self._parse()
def _parse(self) -> None:
match = _RE_EPISODE.search(self._path.stem)
if not match:
return
s_en, e_en = match.group("s_en"), match.group("e_en")
s_es, e_es = match.group("s_es"), match.group("e_es")
se_es = match.group("se_es")
if s_en and e_en:
season, episode, self._language = s_en, e_en, "en"
elif s_es and e_es:
season, episode, self._language = s_es, e_es, "es"
elif se_es:
season = se_es[:-2] if len(se_es) > 2 else "01"
episode = se_es[-2:].zfill(2)
self._language = "es"
else:
return
if self._skip_format == self._language:
return
show_name = self._clean_text(match.group("show_name"))
show_name = " ".join(word.capitalize() for word in show_name.split())
ep_title = self._clean_text(match.group("title"))
season_int = int(season)
if self._output_format == "en":
formatted_id = f"S{season_int:02d}E{episode}"
else:
formatted_id = f"{season_int:02d}x{episode}"
parts = [show_name, formatted_id]
if ep_title:
if self._title_separator.strip():
parts.append(self._title_separator)
parts.append(ep_title)
self.new_name = " ".join(parts) + self._extension
def _clean_text(self, text: str) -> str:
if not text:
return ""
clean_text = _RE_CLEANUP_TAGS.sub("", text)
clean_text = _RE_ACRONYMS_CLEANUP.sub(" ", clean_text)
clean_text = _RE_SPACES_CLEANUP.sub(" ", clean_text).strip(" .-_")
return clean_text
def _rename_videos(
directory: Path,
output_format: str,
skip_format: str,
title_separator: str,
testing: bool,
) -> None:
videos = 0
renamed = 0
print(
f"\n{_GREEN + '(TEST) ' + _RESET if testing else ''}Processing: {_GREEN}{directory}{_RESET}"
)
video_files = (
f
for f in directory.rglob("*")
if f.suffix.lower() in _VIDEO_EXTENSIONS and f.is_file()
)
for video_file in sorted(video_files, key=lambda x: x.name):
videos += 1
video = Video(video_file, output_format, skip_format, title_separator)
if video.new_name and video.new_name != video.original_name:
target = video_file.with_name(video.new_name)
print(f"{video.original_name} -> {_GREEN}{video.new_name}{_RESET}")
if not testing:
if target.exists():
print(f"{_RED}Skip{_RESET}: '{target}' already exists")
continue
try:
video_file.rename(target)
renamed += 1
except Exception as e:
print(f"{_RED}Error{_RESET}: {e}")
print(f"\nRenamed {_GREEN}{renamed}{_RESET}/{videos} videos")
def _main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
description="TV Show Renamer (Normalize 'S01E01' and '1x01' formats)"
)
parser.add_argument("paths", nargs="*", help="Directories to process")
parser.add_argument(
"-t", "--test", action="store_true", help="Test mode (no changes)"
)
parser.add_argument(
"-of",
"--output-format",
choices=["en", "es"],
default="en",
help="Format: 'en' (S01E01) or 'es' (01x01). Default: 'en'",
)
parser.add_argument(
"-sf",
"--skip-format",
choices=["en", "es"],
help="Skip files that already have this format",
)
parser.add_argument(
"-ts",
"--title-separator",
default="",
help="Separating character between the episode and the title, e.g.: '-'",
)
args = parser.parse_args(argv)
if not args.paths:
parser.print_help()
return 0
try:
title_separator = args.title_separator
if title_separator:
if len(title_separator) > 1 and Path(title_separator).exists():
print(
f"Warning: The separator '{title_separator}' looks like a filename."
)
print('If you wanted to use "*", please use quotes: -ts "*"')
for p in args.paths:
path_obj = Path(p).resolve()
if path_obj.is_dir():
_rename_videos(
directory=path_obj,
output_format=args.output_format,
skip_format=args.skip_format,
title_separator=title_separator,
testing=args.test,
)
else:
print(f"{_RED}Error{_RESET}: '{p}' is not a directory")
return 0
except Exception as e:
print(f"{_RED}Error{_RESET}: {e}")
return 1
if __name__ == "__main__":
signal.signal(signal.SIGINT, lambda sig, frame: sys.exit(0))
sys.exit(_main(sys.argv[1:]))
#https://www.softzone.es/noticias/open-source/sistema-operativo-linux-kolibrios-1-4-mb/!/usr/bin/env python3
# Run from cli:
# python3 -m unittest nombre_de_tu_archivo.TvShowRenamerTest.test_name
import unittest
from tv_show_renamer import Video
class FakePath:
def __init__(self, filename: str):
self.name = filename
if '.' in filename:
self.stem = filename.rsplit('.', 1)[0]
self.suffix = f".{filename.rsplit('.', 1)[1]}"
else:
self.stem = filename
self.suffix = ""
def __repr__(self):
return f"FakePath('{self.name}')"
class TvShowRenamerTest(unittest.TestCase):
def setUp(self):
self.separator = ''
self.test_separator = f" {self.separator} " if self.separator.strip() else ' '
self.filenames = [
# ES Ok
'Test 1x02.mkv',
'Test 01x02.mkv',
'Test 1x02 - episode title.mkv',
'Test 33 1x02.mkv',
'Test 33 1x02 - episode title',
'Test (testing) 1x02.mkv',
'Test (testing) 1x02 - episode title.mkv',
'NotAshow.mkv',
'Crime 1x02 testing.mkv',
'Casting 1x02 testing.mkv',
# ES to format
'Test [HDTV 720p][Cap.102].mkv',
'Test 1x02 episode title [NF 1080p WEBDL AVC Dual DDP 5.1 + Subs].mkv',
'Test 1x02 episode title [NF 1080p WEBDL AVC Dual DDP 5.1 + Subs].mkv',
'Test.[Cap102].episode.title.mkv',
'Test.testing.1x02.mkv',
'Test.testing.01x02.mkv',
'T3st.testing.1x02.mkv',
'T3st.testing.01x02.mkv',
'T3st!.testing.1x02.mkv',
'T3st!.testing.01x02.mkv',
'Tests 1x02 testing[TS].mkv',
'Test 1x02 [remove this text.-].mkv',
# EN Ok
'Test s01e02.mkv',
'Test s01e02 - episode title.mkv',
'Test s02e02 episode title.mkv',
# EN to format
'Test.s01e02.1080p.WEB.h264-EDITH[EZTVx.to].mkv',
'Test.s01e02.720p.WEB.h264-EDITH[EZTVx.to].mkv',
'Test.s01e05.1to1.mkv',
'Test.2025.s01e02.Part1.1080p.AMZN.WEB-DL.DDP5.1.H-264-Ntb.mkv',
'Test s01e02 episode title 1080p HMax WEB-DL DDP2 0 H 264-STC[EZTVx.to].mkv'
]
def rename(self, of: str, sf: str|None, expected_results: list):
print('-'*130)
print(f"output format: '{of}' - skip format: '{sf}' - separator: '{self.test_separator}'")
print('-'*130)
for t in zip(self.filenames, expected_results):
fake_file = FakePath(t[0])
video = Video(fake_file, output_format=of, skip_format=sf, title_separator=self.separator)
new_name = video.new_name if video.new_name else video.original_name
if new_name:
print(f"* {t[0]} -> {new_name}")
self.assertEqual(new_name, t[1])
print()
def test_en_none(self):
of = 'en'
sf = None
expected_results = [
# ES Ok
'Test S01E02.mkv',
'Test S01E02.mkv',
f"Test S01E02{self.test_separator}episode title.mkv",
'Test 33 S01E02.mkv',
f"Test 33 S01E02{self.test_separator}episode title",
'Test (testing) S01E02.mkv',
f"Test (testing) S01E02{self.test_separator}episode title.mkv",
'NotAshow.mkv',
f"Crime S01E02{self.test_separator}testing.mkv",
f"Casting S01E02{self.test_separator}testing.mkv",
# ES to format
'Test S01E02.mkv',
f"Test S01E02{self.test_separator}episode title.mkv",
f"Test S01E02{self.test_separator}episode title.mkv",
f"Test S01E02{self.test_separator}episode title.mkv",
'Test Testing S01E02.mkv',
'Test Testing S01E02.mkv',
'T3st Testing S01E02.mkv',
'T3st Testing S01E02.mkv',
'T3st! Testing S01E02.mkv',
'T3st! Testing S01E02.mkv',
f"Tests S01E02{self.test_separator}testing.mkv",
'Test S01E02.mkv',
# EN Ok
'Test S01E02.mkv',
f"Test S01E02{self.test_separator}episode title.mkv",
f"Test S02E02{self.test_separator}episode title.mkv",
# EN to format
'Test S01E02.mkv',
'Test S01E02.mkv',
f"Test S01E05{self.test_separator}1to1.mkv",
f"Test 2025 S01E02{self.test_separator}Part1.mkv",
f"Test S01E02{self.test_separator}episode title.mkv"
]
self.rename(of, sf, expected_results)
def test_en_es(self):
of = 'en'
sf = 'es'
expected_results = [
# ES Ok
'Test 1x02.mkv',
'Test 01x02.mkv',
'Test 1x02 - episode title.mkv',
'Test 33 1x02.mkv',
'Test 33 1x02 - episode title',
'Test (testing) 1x02.mkv',
'Test (testing) 1x02 - episode title.mkv',
'NotAshow.mkv',
'Crime 1x02 testing.mkv',
'Casting 1x02 testing.mkv',
# ES to format
'Test [HDTV 720p][Cap.102].mkv',
'Test 1x02 episode title [NF 1080p WEBDL AVC Dual DDP 5.1 + Subs].mkv',
'Test 1x02 episode title [NF 1080p WEBDL AVC Dual DDP 5.1 + Subs].mkv',
'Test.[Cap102].episode.title.mkv',
'Test.testing.1x02.mkv',
'Test.testing.01x02.mkv',
'T3st.testing.1x02.mkv',
'T3st.testing.01x02.mkv',
'T3st!.testing.1x02.mkv',
'T3st!.testing.01x02.mkv',
'Tests 1x02 testing[TS].mkv',
'Test 1x02 [remove this text.-].mkv',
# EN Ok
'Test S01E02.mkv',
f"Test S01E02{self.test_separator}episode title.mkv",
f"Test S02E02{self.test_separator}episode title.mkv",
# EN to format
'Test S01E02.mkv',
'Test S01E02.mkv',
f"Test S01E05{self.test_separator}1to1.mkv",
f"Test 2025 S01E02{self.test_separator}Part1.mkv",
f"Test S01E02{self.test_separator}episode title.mkv"
]
self.rename(of, sf, expected_results)
def test_en_en(self):
of = 'en'
sf = 'en'
expected_results = [
# ES Ok
'Test S01E02.mkv',
'Test S01E02.mkv',
f"Test S01E02{self.test_separator}episode title.mkv",
'Test 33 S01E02.mkv',
f"Test 33 S01E02{self.test_separator}episode title",
'Test (testing) S01E02.mkv',
f"Test (testing) S01E02{self.test_separator}episode title.mkv",
'NotAshow.mkv',
f"Crime S01E02{self.test_separator}testing.mkv",
f"Casting S01E02{self.test_separator}testing.mkv",
# ES to format
'Test S01E02.mkv',
f"Test S01E02{self.test_separator}episode title.mkv",
f"Test S01E02{self.test_separator}episode title.mkv",
f"Test S01E02{self.test_separator}episode title.mkv",
'Test Testing S01E02.mkv',
'Test Testing S01E02.mkv',
'T3st Testing S01E02.mkv',
'T3st Testing S01E02.mkv',
'T3st! Testing S01E02.mkv',
'T3st! Testing S01E02.mkv',
f"Tests S01E02{self.test_separator}testing.mkv",
'Test S01E02.mkv',
# EN Ok
'Test s01e02.mkv',
'Test s01e02 - episode title.mkv',
'Test s02e02 episode title.mkv',
# EN to format
'Test.s01e02.1080p.WEB.h264-EDITH[EZTVx.to].mkv',
'Test.s01e02.720p.WEB.h264-EDITH[EZTVx.to].mkv',
'Test.s01e05.1to1.mkv',
'Test.2025.s01e02.Part1.1080p.AMZN.WEB-DL.DDP5.1.H-264-Ntb.mkv',
'Test s01e02 episode title 1080p HMax WEB-DL DDP2 0 H 264-STC[EZTVx.to].mkv'
]
self.rename(of, sf, expected_results)
def test_es_none(self):
of = 'es'
sf = None
expected_results = [
# ES Ok
'Test 01x02.mkv',
'Test 01x02.mkv',
f"Test 01x02{self.test_separator}episode title.mkv",
'Test 33 01x02.mkv',
f"Test 33 01x02{self.test_separator}episode title",
'Test (testing) 01x02.mkv',
f"Test (testing) 01x02{self.test_separator}episode title.mkv",
'NotAshow.mkv',
f"Crime 01x02{self.test_separator}testing.mkv",
f"Casting 01x02{self.test_separator}testing.mkv",
# ES to format
'Test 01x02.mkv',
f"Test 01x02{self.test_separator}episode title.mkv",
f"Test 01x02{self.test_separator}episode title.mkv",
f"Test 01x02{self.test_separator}episode title.mkv",
'Test Testing 01x02.mkv',
'Test Testing 01x02.mkv',
'T3st Testing 01x02.mkv',
'T3st Testing 01x02.mkv',
'T3st! Testing 01x02.mkv',
'T3st! Testing 01x02.mkv',
f"Tests 01x02{self.test_separator}testing.mkv",
'Test 01x02.mkv',
# EN Ok
'Test 01x02.mkv',
f"Test 01x02{self.test_separator}episode title.mkv",
f"Test 02x02{self.test_separator}episode title.mkv",
# EN to format
'Test 01x02.mkv',
'Test 01x02.mkv',
f"Test 01x05{self.test_separator}1to1.mkv",
f"Test 2025 01x02{self.test_separator}Part1.mkv",
f"Test 01x02{self.test_separator}episode title.mkv"
]
self.rename(of, sf, expected_results)
def test_es_en(self):
of = 'es'
sf = 'en'
expected_results = [
# ES Ok
'Test 01x02.mkv',
'Test 01x02.mkv',
f"Test 01x02{self.test_separator}episode title.mkv",
'Test 33 01x02.mkv',
f"Test 33 01x02{self.test_separator}episode title",
'Test (testing) 01x02.mkv',
f"Test (testing) 01x02{self.test_separator}episode title.mkv",
'NotAshow.mkv',
f"Crime 01x02{self.test_separator}testing.mkv",
f"Casting 01x02{self.test_separator}testing.mkv",
# ES to format
'Test 01x02.mkv',
f"Test 01x02{self.test_separator}episode title.mkv",
f"Test 01x02{self.test_separator}episode title.mkv",
f"Test 01x02{self.test_separator}episode title.mkv",
'Test Testing 01x02.mkv',
'Test Testing 01x02.mkv',
'T3st Testing 01x02.mkv',
'T3st Testing 01x02.mkv',
'T3st! Testing 01x02.mkv',
'T3st! Testing 01x02.mkv',
f"Tests 01x02{self.test_separator}testing.mkv",
'Test 01x02.mkv',
# EN Ok
'Test s01e02.mkv',
'Test s01e02 - episode title.mkv',
'Test s02e02 episode title.mkv',
# EN to format
'Test.s01e02.1080p.WEB.h264-EDITH[EZTVx.to].mkv',
'Test.s01e02.720p.WEB.h264-EDITH[EZTVx.to].mkv',
'Test.s01e05.1to1.mkv',
'Test.2025.s01e02.Part1.1080p.AMZN.WEB-DL.DDP5.1.H-264-Ntb.mkv',
'Test s01e02 episode title 1080p HMax WEB-DL DDP2 0 H 264-STC[EZTVx.to].mkv'
]
self.rename(of, sf, expected_results)
def test_es_es(self):
of = 'es'
sf = 'es'
expected_results = [
# ES Ok
'Test 1x02.mkv',
'Test 01x02.mkv',
'Test 1x02 - episode title.mkv',
'Test 33 1x02.mkv',
'Test 33 1x02 - episode title',
'Test (testing) 1x02.mkv',
'Test (testing) 1x02 - episode title.mkv',
'NotAshow.mkv',
'Crime 1x02 testing.mkv',
'Casting 1x02 testing.mkv',
# ES to format
'Test [HDTV 720p][Cap.102].mkv',
'Test 1x02 episode title [NF 1080p WEBDL AVC Dual DDP 5.1 + Subs].mkv',
'Test 1x02 episode title [NF 1080p WEBDL AVC Dual DDP 5.1 + Subs].mkv',
'Test.[Cap102].episode.title.mkv',
'Test.testing.1x02.mkv',
'Test.testing.01x02.mkv',
'T3st.testing.1x02.mkv',
'T3st.testing.01x02.mkv',
'T3st!.testing.1x02.mkv',
'T3st!.testing.01x02.mkv',
'Tests 1x02 testing[TS].mkv',
'Test 1x02 [remove this text.-].mkv',
# EN Ok
'Test 01x02.mkv',
f"Test 01x02{self.test_separator}episode title.mkv",
f"Test 02x02{self.test_separator}episode title.mkv",
# EN to format
'Test 01x02.mkv',
'Test 01x02.mkv',
f"Test 01x05{self.test_separator}1to1.mkv",
f"Test 2025 01x02{self.test_separator}Part1.mkv",
f"Test 01x02{self.test_separator}episode title.mkv"
]
self.rename(of, sf, expected_results)
if __name__ == '__main__':
unittest.main()
# Run one test
# suite = unittest.TestSuite()
# suite.addTest('test_name'))
# runner = unittest.TextTestRunner()
# runner.run(suite)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment