-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsplit_now.py
More file actions
150 lines (120 loc) · 4.71 KB
/
Copy pathsplit_now.py
File metadata and controls
150 lines (120 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
r"""
split_now.py
CLI tool: splits an already-extracted single-audio-track MKV (the
intermediate file the GUI app normally deletes after a successful run)
into named track files, without going through the GUI. Uses the same
extractor.py logic the app itself uses, so behaviour matches exactly.
Track names come from a text file, one name per line, in chapter order.
Leading numbering like "1.", "01 -", "1)" is stripped automatically, so
you can paste a tracklist straight from wherever you found it.
Usage:
python split_now.py EXTRACTED_MKV OUTPUT_FOLDER --names-file tracks.txt
Example:
python split_now.py "E:\Music Videos\Album\_work\_audio_extracted.mkv" ^
"E:\Music Videos\Album" --names-file tracks.txt
If you just want to see the chapters found in a file without splitting
anything yet, pass --list-only and skip --names-file.
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
import extractor
def _strip_leading_number(line: str) -> str:
return re.sub(r"^\s*\d+[\.\)\-]?\s*", "", line).strip()
def read_track_names(names_file: Path) -> dict[int, str]:
lines = names_file.read_text(encoding="utf-8").splitlines()
names: dict[int, str] = {}
chapter_index = 0
for line in lines:
line = line.strip()
if not line:
continue
chapter_index += 1
names[chapter_index] = _strip_leading_number(line)
return names
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Split an already-extracted single-audio-track MKV into named track files.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument(
"extracted_mkv",
type=Path,
help="Path to the extracted MKV (video + one chosen audio track, with chapters).",
)
parser.add_argument(
"output_folder",
type=Path,
nargs="?",
help="Folder to write the split track files into. Required unless --list-only.",
)
parser.add_argument(
"--names-file",
type=Path,
help="Text file with one track name per line, in chapter order. "
"Leading numbering (e.g. '1.', '01 -') is stripped automatically.",
)
parser.add_argument(
"--container",
default="mkv",
help="Output container extension (default: mkv).",
)
parser.add_argument(
"--list-only",
action="store_true",
help="Just print the chapters found in the file and exit, without splitting.",
)
args = parser.parse_args(argv)
if not args.list_only:
if args.output_folder is None:
parser.error("output_folder is required unless --list-only is given")
if args.names_file is None:
parser.error("--names-file is required unless --list-only is given")
return args
def main(argv: list[str] | None = None) -> int:
args = parse_args(sys.argv[1:] if argv is None else argv)
missing = [name for name, ok in extractor.check_tools().items() if not ok]
if missing:
print("Warning: the following required tools were not found on PATH:", file=sys.stderr)
for name in missing:
url = extractor.TOOL_DOWNLOAD_URLS.get(name, "")
print(f" - {name} ({url})", file=sys.stderr)
print("Continuing anyway - this will fail if they're actually needed.\n", file=sys.stderr)
if not args.extracted_mkv.is_file():
print(f"Error: {args.extracted_mkv} does not exist.", file=sys.stderr)
return 1
print(f"Reading chapters from {args.extracted_mkv.name} ...")
chapters = extractor.read_chapters(args.extracted_mkv)
print(f"Found {len(chapters)} chapters.")
if args.list_only:
for ch in chapters:
print(f" Chapter {ch.index}: starts at {ch.start_seconds:.1f}s")
return 0
track_names = read_track_names(args.names_file)
if len(track_names) != len(chapters):
print(
f"Warning: {args.names_file.name} has {len(track_names)} name(s) "
f"but the file has {len(chapters)} chapter(s). Unmatched chapters "
f"will use a default 'Track NN' name.",
file=sys.stderr,
)
for ch in chapters:
if ch.index in track_names:
ch.name = track_names[ch.index]
print(f"Splitting into {args.output_folder} ...")
results = extractor.split_chapters(
args.extracted_mkv,
chapters,
args.output_folder,
container=args.container,
progress_cb=print,
)
print(f"\nDone. Wrote {len(results)} files:")
for p in results:
print(f" {p}")
return 0
if __name__ == "__main__":
raise SystemExit(main())