first commit

This commit is contained in:
Philipp Rauch 2020-06-30 21:51:10 +02:00
commit b7934e09cc
6 changed files with 193 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.vscode
mediathek.code-workspace

16
Dockerfile Normal file
View file

@ -0,0 +1,16 @@
FROM python:3-alpine
WORKDIR /app
COPY requirements.txt ./
RUN apk update && apk add mkvtoolnix && apk add --no-cache tzdata
RUN pip install --no-cache-dir -r requirements.txt
ENV TZ Europe/Berlin
COPY main.py ./
RUN crontab -l | { cat; echo "15 03 * * * cd /app && python -u /app/main.py"; } | crontab -
VOLUME ["/download"]
CMD ["/usr/sbin/crond", "-f", "-l", "0"]

19
config.ini Normal file
View file

@ -0,0 +1,19 @@
[DEFAULT]
save_path = /download
default_language = ger
[Hubert und Staller]
rss = https://mediathekviewweb.de/feed?query=%23Hubert%2Bund%2BStaller%20!ARD
languages = ger
ger = ^(?P<titel>.*)\s+\(S(?P<season>\d+)/E(?P<episod>\d+)\)$
[Hubert ohne Staller]
rss = https://mediathekviewweb.de/feed?query=%23Hubert%2Bohne%2BStaller%20!ARD
languages = ger
ger = ^(?P<titel>.*)\s+\(S(?P<season>\d+)/E(?P<episod>\d+)\)$
[Doctor Who]
rss = https://mediathekviewweb.de/feed?query=%23Doctor%20!ARD
languages = ger,eng
ger = ^(?P<titel>.*)\s+\(S(?P<season>\d+)/E?(?P<episod>\d+|Weihnachtsspecial)\)$
eng = ^(?P<titel>.*)\s+\(S(?P<season>\d+)/E?(?P<episod>\d+|Weihnachtsspecial)\).*Originalversion.*$

10
docker-compose.yaml Normal file
View file

@ -0,0 +1,10 @@
version: '3'
services:
app:
build: .
image: mediathekdownload:latest
volumes:
- "/home/smokephil/Videos:/download"
- "./config.ini:/app/config.ini"
environment:
- "TZ=Europe/Berlin"

143
main.py Executable file
View file

@ -0,0 +1,143 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import os
import re
import shutil
import tempfile
import urllib.request
from configparser import ConfigParser
from pprint import pp
import feedparser
import requests
from pymkv import MKVFile, MKVTrack
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
config = ConfigParser(interpolation=None)
config.read('config.ini')
def build_filename(name, titel_dict):
if titel_dict == []:
return None
if titel_dict[0]['episod'].isdigit():
filename = '{name} S{season:>02}E{episod:>02} {titel}'.format(
name=name, **titel_dict[0])
else:
filename = '{name} S{season:>02}.{episod} {titel}'.format(
name=name, **titel_dict[0])
return filename.strip().replace(' ', '.')
def make_mkv(data):
series_name = data['series']
default_lang = config[series_name]['default_language']
lang_sort = config[series_name]['languages'].split(',')
def add_video(lang, path):
logging.debug('[MKV] add video (%s, %s)', lang, path)
video = MKVTrack(path, track_id=0, language=lang, default_track=True)
mkv.add_track(video)
def add_audio(lang, path):
logging.debug('[MKV] add audio (%s, %s)', lang, path)
audio = MKVTrack(path,
track_id=1,
language=lang,
default_track=lang == default_lang)
mkv.add_track(audio)
mkv = MKVFile()
add_video(default_lang, data['lang'][default_lang])
for lang in lang_sort:
mp4_file = data['lang'].pop(lang, None)
if mp4_file is not None:
add_audio(lang, mp4_file)
mkv.mux(data['mkvpath'])
def parse_feed(series_name):
d = feedparser.parse(config[series_name]['rss'])
episodes = dict()
for item in d['entries']:
title = item['title']
link = item['link']
for lang in config[series_name]['languages'].split(','):
pattern = config[series_name][lang]
groups = [x.groupdict() for x in re.finditer(pattern, title, re.M)]
if len(groups) == 1:
break
filename = build_filename(series_name, groups)
if filename is None:
logging.warning('skip %s', title)
continue
if filename not in episodes:
episodes[filename] = dict()
episodes[filename]['lang'] = dict()
episodes[filename]['lang'][lang] = link
season = '{season:>02}'.format(**groups[0])
episod = '{episod:>02}'.format(**groups[0])
basepath = os.path.join(config[series_name]['save_path'], series_name,
f'Season {season:>02}')
mkvpath = os.path.join(basepath, filename + '.mkv')
episodes[filename]['season'] = season
episodes[filename]['episod'] = episod
episodes[filename]['series'] = series_name
episodes[filename]['basepath'] = basepath
episodes[filename]['mkvpath'] = mkvpath
return episodes
def download_files(episodes):
for episod in sorted(episodes.keys()):
item = episodes[episod]
if os.path.exists(item['mkvpath']):
continue
basepath = item['basepath']
os.makedirs(basepath, exist_ok=True)
temp = tempfile.TemporaryDirectory(dir=basepath)
for lang in item['lang']:
link = item['lang'][lang]
filepath = os.path.join(temp.name, os.path.basename(link))
logging.info('start downloading...')
logging.debug('source: %s', link)
logging.debug('destination: %s', filepath)
try:
response = urllib.request.urlopen(link)
with requests.get(link, stream=True) as r:
with open(filepath, 'wb') as f:
shutil.copyfileobj(r.raw, f)
item['lang'][lang] = filepath
except:
logging.error("download")
pass
make_mkv(item)
temp.cleanup()
def run():
logging.info('====== START ======')
for series_name in config.sections():
episodes = parse_feed(series_name)
download_files(episodes)
logging.info('====== END ======')
if __name__ == "__main__":
run()

3
requirements.txt Normal file
View file

@ -0,0 +1,3 @@
feedparser==5.2.1
requests==2.24.0
pymkv==1.0.5