Add support for episode names

This commit is contained in:
2022-01-16 09:11:00 +03:00
parent 58b1606a62
commit 463e5b4c9f
2 changed files with 266 additions and 85 deletions

View File

@@ -25,6 +25,7 @@ PATTERNS = (
r"|noir[-.]edition"
r"|black[-.]chrome[-.]edition"
r"|extended[-.]edition"
r"|hq[-.]edition"
r"|theatrical)"),
("restrictions", r"(unrated)"),
("resolution", r"[0-9]{3,4}[pi]"),
@@ -37,6 +38,7 @@ PATTERNS = (
("audio", r"%s?(dts(-es)?|ac3|flac|dd5\.1|aac2\.0|dub-line)" % LANGUAGES),
("subtitles", r"%s?sub" % LANGUAGES),
("language", r"(\d{1,2}x)?%s" % LANGUAGES),
("file_extension", r"mkv|avi"),
("unknown", r".*")
)
@@ -99,83 +101,130 @@ def process_file(fpath):
_lg.warning("%s -> %s", fname, result)
def _get_parsed_title_dict(chunk_list, chunk_map):
p_title = collections.defaultdict(list)
for idx, chunk in enumerate(chunk_list):
chunk_type = chunk_map[idx]
p_title[chunk_type].append(chunk)
return p_title
def _guess_combined(chunk_values, chunk_map):
""" Try to combine unknown chunks in pairs and parse them """
is_changed = False
p_title = _get_parsed_title_dict(chunk_values, chunk_map)
if len(p_title["unknown"]) < 2:
return is_changed, chunk_values, chunk_map
# i - begin of slice, j - end of slice
i = 0
# process up to second-to-last element
while i < len(chunk_map) - 1:
# we need slice with at least two elements
j = i + 2
# we need only unknown elements
while set(chunk_map[i:j]) == {"unknown"} and j <= len(chunk_map):
# create combined chunk
cmb_chunk = ".".join(chunk_values[i:j])
cmb_chunk_type = guess_part(cmb_chunk)
# add new combined chunk in lists
# first subelement gets new chunk, rest - None
# (will be removed later)
if cmb_chunk_type != "unknown":
is_changed = True
chunk_values[i] = cmb_chunk
chunk_map[i] = cmb_chunk_type
for idx in range(i+1, j):
chunk_values[idx] = None
chunk_map[idx] = None
# to start checking next chunks right after the end of slice
i = idx
break
# try add more elements to combined chunk
else:
j += 1
# start checking next value
i += 1
# clean up from None values
chunk_values = list(filter(None, chunk_values))
chunk_map = list(filter(None, chunk_map))
return is_changed, chunk_values, chunk_map
def parse_title(title):
""" Split media title to components. """
chunks = list(filter(None, re.split(SEPARATORS, title)))
p_title = collections.defaultdict(list)
chunk_values = filter(None, re.split(SEPARATORS, title))
# remove non-word chunks (like single hyphens)
chunks = list(filter(lambda ch: re.search(r"\w+", ch), chunks))
chunk_values = list(filter(lambda ch: re.search(r"\w+", ch), chunk_values))
# parse each chunk
unknown_chunks = {}
for idx, chunk in enumerate(chunks):
pat_type = guess_part(chunk)
if pat_type != "unknown":
p_title[pat_type].append(chunk)
else:
unknown_chunks[idx] = chunk
chunk_map = []
for ch_value in chunk_values:
chunk_map.append(guess_part(ch_value))
# try to combine unknown chunks in pairs and parse them
if len(unknown_chunks) > 1:
prev_idx = -1
for idx in sorted(unknown_chunks.keys()):
_, chunk_values, chunk_map = _guess_combined(chunk_values, chunk_map)
# first unknown chunk, skip
if prev_idx < 0:
prev_idx = idx
# # try to parse unknown chunks, replacing all hyphens in them with dots
p_title = _get_parsed_title_dict(chunk_values, chunk_map)
is_changed = False
if p_title.get("unknown"):
spl_ch_values = []
spl_ch_map = []
for idx, ch_value in enumerate(chunk_values):
ch_type = chunk_map[idx]
if ch_type == "unknown" and "-" in ch_value:
spl_values = ch_value.split("-")
for spl_val in spl_values:
if not spl_val:
continue
spl_type = guess_part(spl_val)
if spl_type != "unknown":
is_changed = True
spl_ch_values.append(spl_val)
spl_ch_map.append(spl_type)
else:
spl_ch_values.append(ch_value)
spl_ch_map.append(ch_type)
is_combined, spl_ch_values, spl_ch_map = _guess_combined(spl_ch_values, spl_ch_map)
if is_changed or is_combined:
chunk_values = spl_ch_values
chunk_map = spl_ch_map
# parse name and episode name
# only if there is something except unknown chunks
p_title = _get_parsed_title_dict(chunk_values, chunk_map)
if len(p_title["unknown"]) != len(chunk_values):
idx = 0
while idx < len(chunk_map) and chunk_map[idx] == "unknown":
chunk_map[idx] = "name"
idx += 1
# if episode number is found, next unknown chunks are episode name
if p_title.get("episode"):
idx = chunk_map.index("episode") + 1
while idx < len(chunk_map) and chunk_map[idx] == "unknown":
chunk_map[idx] = "episode_name"
idx += 1
# at last, strip hyphens from unknown chunks
# only if there is something except unknown chunks
p_title = _get_parsed_title_dict(chunk_values, chunk_map)
if len(p_title["unknown"]) != len(chunk_values):
for idx, chunk_type in enumerate(chunk_map):
if chunk_type != "unknown":
continue
# previous unknown chunk does not border with current, skip
if (prev_idx + 1) != idx:
prev_idx = idx
chunk_value = chunk_values[idx]
if chunk_value[0] != "-" and chunk_value[-1] != "-":
continue
chunk_values[idx] = chunk_value.strip("-")
# create combined chunk
cmb_chunk = ".".join([unknown_chunks[prev_idx], unknown_chunks[idx]])
cmb_chunk_type = guess_part(cmb_chunk)
# check next pair if nothing
if cmb_chunk_type == "unknown":
prev_idx = idx
continue
# if combined chunk matches pattern, add it to found type
# and remove from unknown chunks its parts
p_title[cmb_chunk_type].append(cmb_chunk)
del unknown_chunks[prev_idx]
del unknown_chunks[idx]
prev_idx = -1
# try to parse unknown chunks, replacing all hyphens in them with dots
if unknown_chunks:
# create string from unknown_chunks with dots instead of hyphens
u_chunks_str = ".".join(unknown_chunks.values())
uc_title = ".".join(filter(None, re.split(SEPARATORS_HYPHEN, u_chunks_str)))
# recursion exit condition
if uc_title != title:
p_uc_title = parse_title(uc_title)
# if parsed uc_title has smth else than "unknown", update p_title
if list(p_uc_title.keys()) != ["unknown"]:
p_title.update(p_uc_title)
# unknown_chunks should be cleared,
# because it was processed in nested function call
unknown_chunks = {}
# cut name from unknown chunks
# name is the first n consequent chunks
# only if amount of unknown chunks differs from overall amount of chunks
if len(unknown_chunks) != len(chunks):
i = 0
for idx in sorted(unknown_chunks.keys()):
if idx != i:
break
p_title["name"].append(unknown_chunks[idx])
del unknown_chunks[idx]
i += 1
for idx in sorted(unknown_chunks.keys()):
p_title["unknown"].append(unknown_chunks[idx])
p_title = _get_parsed_title_dict(chunk_values, chunk_map)
return dict(p_title)