Skip to content

Instantly share code, notes, and snippets.

@kirkegaard
Last active February 12, 2020 22:50
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 kirkegaard/aa4e2da5fb5562378f1e69dab062ce93 to your computer and use it in GitHub Desktop.
Save kirkegaard/aa4e2da5fb5562378f1e69dab062ce93 to your computer and use it in GitHub Desktop.
import argparse
import os
import re
import string
import subprocess
import sys
from shutil import which, copyfileobj
from urllib import request
from html.parser import HTMLParser
class BonanzaParser(HTMLParser):
playlist_url = None
meta = {}
def handle_starttag(self, tag, attrs):
attr = dict(attrs)
if tag == "source":
self.playlist_url = attr["src"]
elif tag == "meta":
for k in ("name", "property"):
if k in attr and "content" in attr:
self.meta[attr[k]] = attr["content"]
def progress_bar(iteration, total, prefix="", suffix="", decimals=1, length=100):
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = "█" * filledLength + "-" * (length - filledLength)
print("\r%s |%s| %s%% %s" % (prefix, bar, percent, suffix), end="\r")
if iteration == total:
print()
def format_filename(s):
valid_chars = "-_() %s%s" % (string.ascii_letters, string.digits)
filename = "".join(c for c in s if c in valid_chars)
filename = filename.replace(" ", "_")
return filename
def req(url):
with request.urlopen(url) as response:
return response.read().decode("utf-8")
def parse_url(url):
parser = BonanzaParser()
parser.feed(req(url))
playlist_url = parser.playlist_url
title = parser.meta["og:title"]
return (playlist_url, title)
def get_chunks(playlist_url):
playlist = req(playlist_url)
chunklist_url = re.search(".*m3u8", playlist).group()
base_url = chunklist_url[: chunklist_url.rfind("/")]
chunks_data = req(chunklist_url)
chunks = re.findall(".*\.ts", chunks_data)
chunks = ["%s/%s" % (base_url, chunk) for chunk in chunks]
return chunks
def write_file(chunks, filename):
with open(filename, "wb") as output_file:
chunks_total = len(chunks)
zfill = len(str(chunks_total))
progress_bar(0, chunks_total, prefix="Progress:", length=50)
for i, chunk in enumerate(chunks, start=1):
suffix = "[{i:0{len}d}/{total}]".format(i=i, total=chunks_total, len=zfill)
progress_bar(i, chunks_total, prefix="Progress:", suffix=suffix, length=50)
with request.urlopen("%s" % chunk) as chunk_data:
copyfileobj(chunk_data, output_file)
def has_ffmpeg():
return which("ffmpeg") is not None
def convert(file_input, file_output):
cmd = [
"ffmpeg",
"-y",
"-i",
file_input,
"-acodec",
"copy",
"-vcodec",
"copy",
file_output,
]
try:
proc = subprocess.run(cmd, check=True, capture_output=True)
except subprocess.CalledProcessError:
return False
return True
def get_args(args):
description = "Bonanza - Downloads episodes off https://dr.dk/bonanza"
arg = argparse.ArgumentParser(description=description)
arg.add_argument(
"-c",
"--convert",
metavar="bool",
type=bool,
default=False,
help="Convert ts to mp4. Requires ffmpeg",
)
arg.add_argument("url", type=str, help="The url to from https://dr.dk/bonanza")
return arg.parse_args(args)
def main():
args = get_args(sys.argv[1:])
(playlist_url, title) = parse_url(args.url)
print("Downloading: %s" % title)
chunks = get_chunks(playlist_url)
filename = "%s.ts" % format_filename(title)
write_file(chunks, filename)
if args.convert:
if has_ffmpeg() == False:
print("FFMpeg is not installed :(")
return False
print("Converting: %s" % filename)
filename_out = os.path.splitext(filename)[0] + ".mp4"
convert(filename, filename_out)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment