Skip to content

Instantly share code, notes, and snippets.

@FlyingFathead
Created January 24, 2025 07:56
Show Gist options
  • Save FlyingFathead/13cfe86196794f7f32c6530bfcc700b9 to your computer and use it in GitHub Desktop.
Save FlyingFathead/13cfe86196794f7f32c6530bfcc700b9 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# this is a simple script that allows you to use yt-dlp to get an audio file
# and recode it (if necessary) to fit within target size limitations.
import sys
import os
import subprocess
# ----------------------
# CONFIG
# ----------------------
DEFAULT_TARGET_MB = 20
MIN_BITRATE = 8 # kbps
MAX_BITRATE = 320 # kbps
def hz_line():
""" Print a line of dashes across the terminal width (or 80 fallback). """
try:
columns = int(os.environ.get("COLUMNS", 0))
if columns <= 0:
columns = int(subprocess.check_output(["tput", "cols"]).strip())
except:
columns = 80
print("-" * columns, flush=True)
def run_live(cmd):
""" Run a command so its stdout/stderr prints live. Return exit code. """
p = subprocess.Popen(cmd)
p.communicate()
return p.returncode
def run_capture(cmd):
""" Run a command capturing all output (stdout/stderr). Return (stdout, stderr, code). """
r = subprocess.run(cmd, capture_output=True, text=True)
return r.stdout.strip(), r.stderr.strip(), r.returncode
def file_size(path):
return os.path.getsize(path)
def usage():
print(f"Usage: {os.path.basename(sys.argv[0])} <YOUTUBE_URL> [TARGET_MB]", flush=True)
print(f"Default TARGET_MB={DEFAULT_TARGET_MB}", flush=True)
def main():
print("Starting yousqueeze single-pass script...", flush=True)
hz_line()
# ---------------------
# Step 0: Parse Args
# ---------------------
if len(sys.argv) < 2:
usage()
sys.exit(1)
url = sys.argv[1]
target_mb = float(sys.argv[2]) if len(sys.argv) > 2 else DEFAULT_TARGET_MB
target_bytes = int(target_mb * 1024 * 1024)
print(f"Target = {target_mb} MB => {target_bytes} bytes", flush=True)
hz_line()
# ---------------------
# Step 1: Fetch Title
# ---------------------
print("STEP 1: GET VIDEO TITLE (for naming)", flush=True)
hz_line()
title_cmd = ["yt-dlp", "--print", "title", "--skip-download", url]
out, err, code = run_capture(title_cmd)
if code != 0 or not out:
print("Could not retrieve title. Using fallback 'untitled_video'.", flush=True)
final_title = "untitled_video"
else:
final_title = out.strip()
final_mp3_name = f"{final_title}_recode_{int(target_mb)}.mp3"
print(f"Video title => {final_title}", flush=True)
hz_line()
# ---------------------
# Step 2: Download MP3
# ---------------------
print("STEP 2: DOWNLOAD AS MP3", flush=True)
hz_line()
if os.path.exists("temp.mp3"):
os.remove("temp.mp3")
dl_cmd = [
"yt-dlp",
"--extract-audio",
"--audio-format", "mp3",
"-f", "bestaudio",
"-o", "temp.%(ext)s",
url
]
print(f"Running: {' '.join(dl_cmd)}", flush=True)
rcode = run_live(dl_cmd)
if rcode != 0:
print("yt-dlp failed!", flush=True)
sys.exit(1)
if not os.path.exists("temp.mp3"):
print("No temp.mp3 created—something went wrong.", flush=True)
sys.exit(1)
size_now = file_size("temp.mp3")
print(f"Downloaded MP3 size => {size_now} bytes (~{size_now/(1024*1024):.2f} MB)", flush=True)
hz_line()
# ---------------------
# Step 3: Check If Under Target
# ---------------------
if size_now <= target_bytes:
print("Already under target => just rename & done!", flush=True)
if os.path.exists(final_mp3_name):
os.remove(final_mp3_name)
os.rename("temp.mp3", final_mp3_name)
print(f"Final => {final_mp3_name}", flush=True)
sys.exit(0)
# ---------------------
# Step 4: Single-Pass Squeeze
# ---------------------
print("STEP 4: SINGLE-PASS RE-ENCODE TO REACH TARGET", flush=True)
hz_line()
# 4a) get duration
ffprobe_cmd = [
"ffprobe",
"-v", "error",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
"-i", "temp.mp3"
]
dur_out, dur_err, dur_code = run_capture(ffprobe_cmd)
if dur_code != 0 or not dur_out:
print("Could not get duration from ffprobe! Bailing out.", flush=True)
sys.exit(1)
duration_sec = float(dur_out.strip())
print(f"Duration => {duration_sec:.2f} seconds", flush=True)
# 4b) approximate needed kbps
# total_bits_needed = target_bytes * 8
# bits_per_second = total_bits_needed / duration_sec
# kbps = bits_per_second / 1000
needed_kbps = int((target_bytes * 8) / (duration_sec * 1000))
if needed_kbps < MIN_BITRATE:
needed_kbps = MIN_BITRATE
if needed_kbps > MAX_BITRATE:
needed_kbps = MAX_BITRATE
print(f"Estimated needed bitrate => {needed_kbps} kbps", flush=True)
hz_line()
# 4c) re-encode at that bitrate
if os.path.exists(final_mp3_name):
os.remove(final_mp3_name)
ff_cmd = [
"ffmpeg",
"-y",
"-v", "info",
"-i", "temp.mp3",
"-vn",
"-c:a", "libmp3lame",
"-b:a", f"{needed_kbps}k",
"-f", "mp3",
final_mp3_name
]
print(f"Encoding once at {needed_kbps} kbps...", flush=True)
run_live(ff_cmd)
if not os.path.exists(final_mp3_name):
print("No final MP3 produced! Something went wrong with FFmpeg!", flush=True)
sys.exit(1)
final_size = file_size(final_mp3_name)
print(f"Final size => {final_size} bytes (~{final_size/(1024*1024):.2f} MB).", flush=True)
# Cleanup temp
if os.path.exists("temp.mp3"):
os.remove("temp.mp3")
print(f"Done => {final_mp3_name}", flush=True)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment