Last active
February 12, 2020 22:50
-
-
Save kirkegaard/aa4e2da5fb5562378f1e69dab062ce93 to your computer and use it in GitHub Desktop.
$ python bonanza.py https://www.dr.dk/bonanza/serie/121/casper--mandrilafta/25670/casper--mandrilaftalen-0948
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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