111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
import os
|
|
import csv
|
|
import shutil
|
|
import argparse
|
|
from tqdm import tqdm
|
|
import ctypes
|
|
|
|
|
|
def is_windows():
|
|
return os.name == 'nt'
|
|
|
|
|
|
def hide_windows_console():
|
|
if is_windows():
|
|
try:
|
|
ctypes.windll.user32.ShowWindow(
|
|
ctypes.windll.kernel32.GetConsoleWindow(), 0)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def process_files(csv_path, dry_run=False):
|
|
# Constants
|
|
MAX_DISPLAY_LEN = 90
|
|
RED = "\033[91m"
|
|
RESET = "\033[0m"
|
|
|
|
# Read all rows
|
|
with open(csv_path, newline='', encoding='utf-8') as f:
|
|
reader = csv.DictReader(f)
|
|
rows = list(reader)
|
|
fieldnames = reader.fieldnames
|
|
|
|
# Compute max length for padding (after truncation if needed)
|
|
def safe_name(name):
|
|
return name if len(name) <= MAX_DISPLAY_LEN else name[:MAX_DISPLAY_LEN - 3] + "..."
|
|
|
|
all_filenames = [safe_name(os.path.basename(row['original_file'])) for row in rows if 'original_file' in row]
|
|
max_filename_len = max(len(name) for name in all_filenames)
|
|
|
|
updated = False
|
|
|
|
for row in (pbar := tqdm(rows, desc="Processing files", unit="file")):
|
|
status = row.get('accepted', '').strip()
|
|
orig = row['original_file']
|
|
trans = row['transcoded_file']
|
|
orig_dir = os.path.dirname(orig)
|
|
base, _ = os.path.splitext(os.path.basename(orig))
|
|
target = os.path.join(orig_dir, base + '.mkv')
|
|
|
|
# Format filename for display
|
|
filename = os.path.basename(orig)
|
|
if len(filename) > MAX_DISPLAY_LEN:
|
|
display_name = filename[:MAX_DISPLAY_LEN - 3] + "..."
|
|
display_name_colored = f"{RED}{display_name}{RESET}"
|
|
else:
|
|
display_name = filename
|
|
display_name_colored = display_name
|
|
padded_name = display_name_colored.ljust(max_filename_len + len(RED) + len(RESET)) # pad including ANSI
|
|
|
|
# Update progress bar
|
|
pbar.set_description(f"Processing: {padded_name}")
|
|
|
|
if status == 'o':
|
|
if not os.path.exists(trans):
|
|
continue
|
|
|
|
if not dry_run:
|
|
try:
|
|
if os.path.exists(orig):
|
|
os.remove(orig)
|
|
shutil.move(trans, target)
|
|
row['accepted'] = 'D'
|
|
updated = True
|
|
except Exception:
|
|
pass
|
|
|
|
elif status == 'x':
|
|
if os.path.exists(trans):
|
|
if not dry_run:
|
|
try:
|
|
os.remove(trans)
|
|
updated = True
|
|
except Exception:
|
|
pass
|
|
|
|
if updated and not dry_run:
|
|
backup = csv_path + '.bak'
|
|
shutil.copy(csv_path, backup)
|
|
with open(csv_path, 'w', newline='', encoding='utf-8') as f:
|
|
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
|
writer.writeheader()
|
|
writer.writerows(rows)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(
|
|
description='Replace original videos with AV1 transcodes based on CSV accepted column'
|
|
)
|
|
parser.add_argument('csvfile', help='Path to the CSV result file')
|
|
parser.add_argument('--dry-run', action='store_true',
|
|
help='Show actions without making changes')
|
|
parser.add_argument('--hide-console', action='store_true',
|
|
help='Hide Windows console window (GUI mode)')
|
|
args = parser.parse_args()
|
|
|
|
if args.hide_console:
|
|
hide_windows_console()
|
|
|
|
process_files(args.csvfile, dry_run=args.dry_run)
|