Skip to content

Instantly share code, notes, and snippets.

@lvm
Last active August 18, 2020 01:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lvm/9b031086ad26bea77323cb517cfd4eec to your computer and use it in GitHub Desktop.
Save lvm/9b031086ad26bea77323cb517cfd4eec to your computer and use it in GitHub Desktop.
youtube-dl a portion of a video.
#!/usr/bin/env python3
import shlex
import argparse
import youtube_dl
import subprocess as sp
from pathlib import Path
from youtube_dl.utils import sanitize_filename
USER_AGENT = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
def ffmpeg(args: list) -> None:
"Base ffmpeg call."
sp.call(shlex.split(f"ffmpeg -v quiet -y {args}"))
def slice_video(video_url, start, end, output="/tmp/ytslice.mp4", intact=False):
"Get video info and then download and slice it"
assert video_url, "Missing video, can't continue"
assert start, "Missing `start`, can't continue"
assert end, "Missing `end`, can't continue"
title = ""
output_dir = Path(output).parent
YTDL_OPTS = {
"quiet": True,
"restrictfilenames": True,
"writethumbnail": False,
"ignoreerrors": True,
"geo_bypass": True,
"format": "mp4",
"outtmpl": f"{str(output_dir)}/%(title)s.%(ext)s"
}
ext = "mp4"
if output.endswith(".mp3"):
YTDL_OPTS.update({
"format": "bestaudio/best",
"postprocessors": [
{
"key": "FFmpegExtractAudio",
"preferredcodec": "mp3",
"preferredquality": "192",
}
]
})
ext = "mp3"
with youtube_dl.YoutubeDL(YTDL_OPTS) as ydl:
youtube_dl.utils.std_headers["User-Agent"] = USER_AGENT
ytdl_info = ydl.extract_info(video_url, download=False)
title = ytdl_info.get("title")
yt_file = sanitize_filename(title, True, False)
yt_file = output_dir / f'{yt_file}.{ext}'
tmp_output = output_dir / f'{yt_file}.tmp.{ext}'
ydl.download([video_url])
ffmpeg(
f"-i '{yt_file}' -ss '{start}' -to '{end}' -async 1 -acodec copy '{tmp_output}'"
)
if intact or ext == "mp3":
Path(tmp_output).rename(output)
else:
ffmpeg(
f"-i '{tmp_output}' "
"-pix_fmt yuv420p -vcodec libx264 "
"-vf scale=640:-1 -acodec aac -vb 1024k "
"-minrate 1024k -maxrate 1024k -bufsize 1024k "
"-ar 44100 -ac 2 "
"-strict experimental -max_muxing_queue_size 1024 -r 30 "
f"'{output}'"
)
Path(tmp_output).unlink()
Path(yt_file).unlink()
return title, output
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("video", type=str, default="", help="Video URL")
parser.add_argument(
"-ss", type=str, default="00:00:00", required=True, help="Start time"
)
parser.add_argument(
"-to", type=str, default="", help="End time"
)
parser.add_argument(
"-o",
"--output",
type=str,
default="/tmp/ytslice.mp4",
required=False,
help="Output file (Default: /tmp/ytslice.mp4",
)
parser.add_argument(
"--intact",
action="store_true",
help="Don't re-encode the video."
)
args = parser.parse_args()
if args.video:
title, output = slice_video(args.video, args.ss, args.to, args.output, args.intact)
print (f"Title: {title}\nFile: {output}")
else:
parser.print_help()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment