V 1.0 - Only Prints

This commit is contained in:
Hannes committed 2026-03-20 00:46:36 +01:00
commit e00fa1ca80
15 files changed
+1045

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
# mkv/__init__.py
from .chapter import (
get_intro_outro,
get_chapters
)
from .intro_outro import (
check_intro_outro_sync
)
+67
View File
@@ -0,0 +1,67 @@
# for import needed
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).resolve().parent.parent))
from utils import run
### Regular Imports
from typing import Tuple, List
import json
def get_chapters(file: Path) -> List[Tuple[float, float]]:
"""Return list of (start_ti
from .intro_outro importme, duration) for each chapter."""
cmd = [
"ffprobe",
"-i", str(file),
"-print_format", "json",
"-show_chapters",
"-loglevel", "error"
]
result = run(cmd)
data = json.loads(result.stdout)
chapters = []
for ch in data.get("chapters", []):
start = float(ch["start_time"])
end = float(ch["end_time"])
duration = end - start
chapters.append((start, duration))
return chapters
def get_intro_outro(file: Path, length: float = 90.0) -> List[Tuple[float, float]]:
try:
chapters = get_chapters(Path(file))
except:
raise AttributeError(f"{file} has no chapter Marks")
multiplier = 2
min_len = length / multiplier
max_len = length * multiplier
filtered = [
(start, dur) for start, dur in chapters
if min_len <= dur <= max_len
]
while len(filtered) > 2 and multiplier <= 1.1:
multiplier -= 0.1
min_len = length / multiplier
max_len = length * multiplier
filtered = [
(start, dur) for start, dur in chapters
if min_len <= dur <= max_len
]
if len(filtered) == 2:
return filtered
elif len(filtered) == 1:
### Found only a Intro or Outro
raise ValueError(f"Could only find one intro or outro:\n{filtered}")
elif len(filtered) == 0:
raise ValueError(f"Found no outro or intro:\n{filtered}")
else:
raise ValueError(f"Found too many intros/outros:\n{filtered}")
if __name__ == '__main__':
file = "./output_dir/episode.mkv"
print(get_intro_outro(Path(file)))
+18
View File
@@ -0,0 +1,18 @@
import sys
import os
from pathlib import Path
from mkv import check_intro_outro_sync
if __name__ == '__main__':
if len(sys.argv) == 2:
if os.path.isfile(sys.argv[1]):
boolean, floater, stream = check_intro_outro_sync(Path(sys.argv[1]))
if boolean:
print("Video is syncable!")
print(f"With offset of {floater} at audio_stream {stream}")
else:
print("Video is not syncable!")
else:
raise FileExistsError(f"File does not exists: {sys.argv[1]}")
else:
print("python check_intro.py /path/to/file")
+55
View File
@@ -0,0 +1,55 @@
from mkv.chapter import get_intro_outro
from audio.audio_utils import extract_audio_segment_tmp, get_audio_streams
from audio.audio_cross_correlation import get_audio_offset
from pathlib import Path
import numpy as np
from typing import Tuple
def check_intro_outro_sync(file: Path, length: float = 90.0, uncertainty: float = 0.1, max_offset: float = 0.1) -> Tuple[bool, float|None, int|None]:
intro_outro = get_intro_outro(file, length)
if intro_outro[0][0]<intro_outro[1][0]:
intro = intro_outro[0]
outro = intro_outro[1]
else:
intro = intro_outro[1]
outro = intro_outro[0]
### Cut away any possible part that is not of the intro/outro
intro = (intro[0]+intro[1]*(uncertainty/2), intro[1]-intro[1]*uncertainty)
outro = (outro[0]+outro[1]*(uncertainty/2), outro[1]-outro[1]*uncertainty)
### Get the intro and outro Segments
audio_streams = get_audio_streams(file)
intros : list[Path] = []
outros : list[Path] = []
# for i in audio_streams:
# intros.append(extract_audio_segment_tmp(file, intro, None, i))
# outros.append(extract_audio_segment_tmp(file, outro, None, i))
intros.append(extract_audio_segment_tmp(file, intro, None, audio_streams[0]))
outros.append(extract_audio_segment_tmp(file, outro, None, audio_streams[0]))
intros.append(extract_audio_segment_tmp(file, intro, None, audio_streams[-1]))
outros.append(extract_audio_segment_tmp(file, outro, None, audio_streams[-1]))
### correlate
intro_offsets = []
outro_offsets = []
for intro_a, outro_a in zip(intros, outros):
idx = intros.index(intro_a)
odx = outros.index(outro_a)
for intro_b, outro_b in zip(intros[idx+1:], outros[odx+1:]):
intro_offset = get_audio_offset(intro_a, intro_b, intro[1])
intro_offsets.append(intro_offset)
# print(f"intro_offset between Audioline {intros.index(intro_a)} and {intros.index(intro_b)} is {intro_offset}")
outro_offset = get_audio_offset(outro_a, outro_b, outro[1])
outro_offsets.append(outro_offset)
# print(f"outro_offset between Audioline {outros.index(outro_a)} and {outros.index(outro_b)} is {outro_offset}")
# print(f"Offset of offsets: {(outro_offset - intro_offset)}")
mean_offset = float(np.mean([intro_offsets[0], outro_offsets[0]]))
# print(f"Mean Intro Offset: {round(np.mean(intro_offsets), 1)}")
# print(f"Mean Outro Offset: {round(np.mean(outro_offsets), 1)}")
# print(f"Offset of mean offsets: {round(np.mean(outro_offsets) - np.mean(intro_offsets)), 3}")
if np.abs(np.mean(outro_offsets) - np.mean(intro_offsets)) < max_offset:
return True, mean_offset, audio_streams[-1]
return False, None, None