import os
import subprocess

def calculate_bitrate(target_size_mb, duration, audio_bitrate_kbps=96, override_target_mb=None):
    if override_target_mb is not None:
        target_size_mb = override_target_mb
    target_size_kb = target_size_mb * 1024
    total_bitrate_kbps = (target_size_kb / duration) * 8 - audio_bitrate_kbps
    return max(total_bitrate_kbps, 0)

def get_video_duration(filename):
    cmd = f"ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \"{filename}\""
    try:
        return float(subprocess.check_output(cmd, shell=True).decode('utf-8').strip())
    except subprocess.CalledProcessError as e:
        print(f"Error getting duration of {filename}: {e}")
        return 0

def adjust_audio_bitrate(original_video, encoded_video, target_size_mb, lower_tolerance_mb=0.01):
    target_size_bytes = target_size_mb * 1024 * 1024
    lower_tolerance_bytes = lower_tolerance_mb * 1024 * 1024
    current_audio_bitrate_kbps = 96
    extracted_audio = "extracted_audio.opus"

    # Extract audio from the original video
    os.system(f"ffmpeg -y -i \"{original_video}\" -vn -c:a libopus \"{extracted_audio}\"")

    for _ in range(20):  # Limit the number of adjustments to prevent infinite loops
        # Re-encode audio with the current bitrate and mux with video
        temp_output = f"temp_{os.path.basename(encoded_video)}"
        cmd_adjust_audio = f"ffmpeg -y -i \"{encoded_video}\" -i \"{extracted_audio}\" -c:v copy -c:a libopus -b:a {current_audio_bitrate_kbps}k -map 0:v:0 -map 1:a:0 \"{temp_output}\""
        os.system(cmd_adjust_audio)

        current_size_bytes = os.path.getsize(temp_output)
        if current_size_bytes <= target_size_bytes and current_size_bytes >= (target_size_bytes - lower_tolerance_bytes):
            # Target size within lower tolerance, stop adjusting
            os.replace(temp_output, encoded_video)
            break

        if current_size_bytes > target_size_bytes:
            current_audio_bitrate_kbps -= 2  # Decrease bitrate if file is too large
        elif current_size_bytes < (target_size_bytes - lower_tolerance_bytes):
            current_audio_bitrate_kbps += 2  # Increase bitrate if file is too small

        os.replace(temp_output, encoded_video)  # Replace the original file with the adjusted one

    # Clean up extracted audio file
    os.remove(extracted_audio)
    return current_audio_bitrate_kbps

def main():
    print(f"Current directory: {os.getcwd()}")
    resolution = input("Enter the desired resolution (e.g., 1920x1080) or leave blank for no change: ")
    fps = input("Enter the FPS to lock the video at or leave blank to keep original: ")
    target_size_mb = float(input("Enter the target file size in MB (e.g., 4 for 4096KB): "))
    override_target_mb = input("Enter an override target size in MB for initial bitrate calculation (leave blank for no override): ")
    override_target_mb = float(override_target_mb) if override_target_mb else None
    
    scale_option = f"scale={resolution}" if resolution else ""
    fps_option = f"fps={fps}" if fps else ""
    vf_options = f"-vf \"{scale_option},{fps_option}\"" if scale_option and fps_option else (f"-vf \"{scale_option}\"" if scale_option else (f"-vf \"{fps_option}\"" if fps_option else ""))

    file_processed = False

    for filename in os.listdir('.'):
        if filename.lower().endswith(('.mp4', '.avi', '.mov', '.mkv', '.mpg', '.ogm', '.wmv', '.mpeg', '.vob', '.m2ts')):
            file_processed = True
            print(f"Processing {filename}...")
            duration = get_video_duration(filename)
            if duration == 0:
                continue
            video_bitrate = calculate_bitrate(target_size_mb, duration, override_target_mb=override_target_mb)

            encoded_video = f"newfiles\\{os.path.splitext(filename)[0]}.webm"
            cmd_pass1 = f"ffmpeg -y -i \"{filename}\" -c:v libvpx-vp9 -pix_fmt yuv420p10le -quality good -threads 8 "\
                        f"-profile:v 2 -crf 30 -b:v {video_bitrate}k -c:a libopus -b:a 96k -cpu-used 0 -auto-alt-ref 1 "\
                        f"-arnr-maxframes 15 -arnr-strength 0 -aq-mode 0 -tile-rows 0 -tile-columns 1 "\
                        f"-tune-content default -enable-tpl 1 -row-mt 1 {vf_options} -pass 1 -f webm nul"
            cmd_pass2 = f"ffmpeg -y -i \"{filename}\" -c:v libvpx-vp9 -pix_fmt yuv420p10le -quality good -threads 8 "\
                        f"-profile:v 2 -crf 30 -b:v {video_bitrate}k -c:a libopus -b:a 96k -cpu-used 0 -auto-alt-ref 1 "\
                        f"-arnr-maxframes 15 -arnr-strength 0 -aq-mode 0 -tile-rows 0 -tile-columns 1 "\
                        f"-tune-content default -enable-tpl 1 -row-mt 1 {vf_options} -pass 2 \"{encoded_video}\""

            os.system(cmd_pass1)
            os.system(cmd_pass2)

            # Adjust audio bitrate if necessary
            final_audio_bitrate = adjust_audio_bitrate(filename, encoded_video, target_size_mb)

            print(f"Finished processing {filename}. Final audio bitrate: {final_audio_bitrate}kbps, file: {encoded_video}")

    if not file_processed:
        print("No video files found for processing.")

if __name__ == "__main__":
    main()
