|
#!/usr/bin/env python |
|
|
|
import argparse as ap |
|
from os import makedirs, remove |
|
import os.path as p |
|
import signal |
|
|
|
import feedparser as fp |
|
import requests as r |
|
from tqdm import tqdm |
|
|
|
########## exit gracefully ########## |
|
|
|
open_file = None |
|
def graceful_exit(sig, frame): |
|
if open_file: |
|
remove(open_file) |
|
exit() |
|
|
|
signal.signal(signal.SIGINT, graceful_exit) |
|
|
|
########## setup argparse ########## |
|
|
|
video_formats = ["mp4", "webm"] |
|
audio_formats = ["mp3", "opus"] |
|
|
|
parser = ap.ArgumentParser(prog="dl-ccc-feed", description="Download all elements from a CCC event feed", formatter_class=lambda prog: ap.ArgumentDefaultsHelpFormatter(prog, max_help_position=50)) |
|
parser.add_argument("event", help="e.g. '39c3'") |
|
parser.add_argument("-o", "--output", default=".", help="output directory") |
|
parser.add_argument("-q", "--quality", default="lq", choices=["lq", "hq"], help="only applicable for video") |
|
parser.add_argument("-f", "--format", default="mp4", choices=video_formats + audio_formats, help="file format to download") |
|
parser.add_argument("-l", "--list", default=False, action='store_true', help="list file links in feed and exit") |
|
parser.add_argument("-np", "--no-progress", default=False, action='store_true', help="don't show progress bars") |
|
|
|
########## parse args ########## |
|
|
|
args = parser.parse_args() |
|
|
|
pth = args.output |
|
event = args.event |
|
file_format = args.format |
|
quality = args.quality if file_format in video_formats else "" |
|
no_progress = args.no_progress |
|
show_list = args.list |
|
|
|
########## setup ########## |
|
|
|
url = f"https://media.ccc.de/c/{event}/podcast/{file_format}{('-' if quality else '') + quality}.xml" |
|
|
|
# create dir, if not exists |
|
makedirs(pth, exist_ok=True) |
|
|
|
entries = fp.parse(url).entries |
|
|
|
########## optional listing ########## |
|
|
|
if show_list: |
|
for entry in entries: |
|
print(entry.id) |
|
exit() |
|
|
|
########## run download ########## |
|
|
|
# for each element in feed |
|
for entry in tqdm(entries, colour="green", position=1, disable=no_progress): |
|
url = entry.id |
|
title = entry.title |
|
|
|
# get file name |
|
fname = p.basename(url).split("?")[0] |
|
fpth = p.join(pth, fname) |
|
|
|
if p.exists(fpth): |
|
continue |
|
|
|
# download |
|
res = r.get(url, stream=True) |
|
size = int(res.headers.get("content-length", 0)) |
|
with tqdm(total=size, unit="B", unit_scale=True, colour="red", position=0, leave=False, desc="{:.30}".format(title), disable=no_progress) as bar: |
|
with open(fpth, "wb") as f: |
|
open_file = fpth |
|
for chunk in res.iter_content(chunk_size=1024): |
|
f.write(chunk) |
|
bar.update(len(chunk)) |
|
|
|
open_file = None |