|
@@ -15,16 +15,9 @@ import ntpath |
|
|
import yaml |
|
|
import yaml |
|
|
from pathlib import Path |
|
|
from pathlib import Path |
|
|
import logging |
|
|
import logging |
|
|
from systemd.journal import JournalHandler |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger('demotape') |
|
|
|
|
|
log.addHandler(JournalHandler()) |
|
|
|
|
|
|
|
|
|
|
|
log.setLevel(logging.INFO) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.basicConfig(filename='demotape.log', level=logging.INFO) |
|
|
|
|
|
logging.info("Starting demotape service at " + str(datetime.utcnow())) |
|
|
|
|
|
|
|
|
config_path = Path(__file__).parent / './config.yaml' |
|
|
config_path = Path(__file__).parent / './config.yaml' |
|
|
with config_path.open() as file: |
|
|
with config_path.open() as file: |
|
@@ -33,13 +26,13 @@ with config_path.open() as file: |
|
|
try: |
|
|
try: |
|
|
if sys.argv[1] and os.path.exists(sys.argv[1]): |
|
|
if sys.argv[1] and os.path.exists(sys.argv[1]): |
|
|
ROOT_PATH = sys.argv[1] |
|
|
ROOT_PATH = sys.argv[1] |
|
|
log('Root path for downloaded streams: ' + ROOT_PATH) |
|
|
|
|
|
|
|
|
logging.info('Root path for downloaded streams: ' + ROOT_PATH) |
|
|
else: |
|
|
else: |
|
|
log('destination path does not exist') |
|
|
|
|
|
|
|
|
logging.info('destination path does not exist') |
|
|
sys.exit() |
|
|
sys.exit() |
|
|
except IndexError: |
|
|
except IndexError: |
|
|
log('Script needs a valid destination path for recorded videos as argument') |
|
|
|
|
|
log('For example: \ndemotape.py /path/to/videos') |
|
|
|
|
|
|
|
|
logging.info('Script needs a valid destination path for recorded videos as argument') |
|
|
|
|
|
logging.info('For example: \ndemotape.py /path/to/videos') |
|
|
sys.exit() |
|
|
sys.exit() |
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -61,9 +54,9 @@ def generate_channellist(): |
|
|
'url': 'https://stream.wien.gv.at/live/ngrp:bv' + district_str_lz + '.stream_all/playlist.m3u8' |
|
|
'url': 'https://stream.wien.gv.at/live/ngrp:bv' + district_str_lz + '.stream_all/playlist.m3u8' |
|
|
} |
|
|
} |
|
|
channels.append(channel) |
|
|
channels.append(channel) |
|
|
log('channels:') |
|
|
|
|
|
|
|
|
logging.info('channels:') |
|
|
for channel in channels: |
|
|
for channel in channels: |
|
|
log(channel['name'] + ' ' + channel['url']) |
|
|
|
|
|
|
|
|
logging.info(channel['name'] + ' ' + channel['url']) |
|
|
return channels |
|
|
return channels |
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -77,33 +70,33 @@ def check_stream(url): |
|
|
# no livestream |
|
|
# no livestream |
|
|
return False |
|
|
return False |
|
|
except (ValueError, KeyError): |
|
|
except (ValueError, KeyError): |
|
|
log('some connection error or so') |
|
|
|
|
|
|
|
|
logging.info('some connection error or so') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyLogger(object): |
|
|
class MyLogger(object): |
|
|
def debug(self, msg): |
|
|
def debug(self, msg): |
|
|
#pass |
|
|
#pass |
|
|
log(msg) |
|
|
|
|
|
|
|
|
logging.info(msg) |
|
|
|
|
|
|
|
|
def warning(self, msg): |
|
|
def warning(self, msg): |
|
|
#pass |
|
|
#pass |
|
|
log(msg) |
|
|
|
|
|
|
|
|
logging.info(msg) |
|
|
|
|
|
|
|
|
def error(self, msg): |
|
|
def error(self, msg): |
|
|
log(msg) |
|
|
|
|
|
|
|
|
logging.info(msg) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def my_ytdl_hook(d): |
|
|
def my_ytdl_hook(d): |
|
|
if d['status'] == 'finished': |
|
|
if d['status'] == 'finished': |
|
|
log(timestamp() + 'Done downloading!') |
|
|
|
|
|
|
|
|
logging.info(timestamp() + 'Done downloading!') |
|
|
else: |
|
|
else: |
|
|
log(timestamp() + 'sth went wrong' + d['status']) |
|
|
|
|
|
log(d) |
|
|
|
|
|
|
|
|
logging.info(timestamp() + 'sth went wrong' + d['status']) |
|
|
|
|
|
logging.info(d) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def download_stream(channel, dest_path): |
|
|
def download_stream(channel, dest_path): |
|
|
log('download_stream') |
|
|
|
|
|
|
|
|
logging.info('download_stream') |
|
|
ytdl_opts = { |
|
|
ytdl_opts = { |
|
|
'logger': MyLogger(), |
|
|
'logger': MyLogger(), |
|
|
'outtmpl': dest_path, |
|
|
'outtmpl': dest_path, |
|
@@ -122,42 +115,42 @@ def download_stream(channel, dest_path): |
|
|
ytdl = youtube_dl.YoutubeDL(ytdl_opts) |
|
|
ytdl = youtube_dl.YoutubeDL(ytdl_opts) |
|
|
|
|
|
|
|
|
try: |
|
|
try: |
|
|
log(timestamp() + " Downloading: " + channel['url']) |
|
|
|
|
|
|
|
|
logging.info(timestamp() + " Downloading: " + channel['url']) |
|
|
ytdl.download([channel['url']]) |
|
|
ytdl.download([channel['url']]) |
|
|
except (youtube_dl.utils.DownloadError) as e: |
|
|
except (youtube_dl.utils.DownloadError) as e: |
|
|
log(timestamp() + " Download error: " + str(e)) |
|
|
|
|
|
|
|
|
logging.info(timestamp() + " Download error: " + str(e)) |
|
|
except (youtube_dl.utils.SameFileError) as e: |
|
|
except (youtube_dl.utils.SameFileError) as e: |
|
|
log("Download error: " + str(e)) |
|
|
|
|
|
|
|
|
logging.info("Download error: " + str(e)) |
|
|
except (UnicodeDecodeError) as e: |
|
|
except (UnicodeDecodeError) as e: |
|
|
log("UnicodeDecodeError: " + str(e)) |
|
|
|
|
|
|
|
|
logging.info("UnicodeDecodeError: " + str(e)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_channel(channel): |
|
|
def process_channel(channel): |
|
|
#log('entered function process_channel with ' + channel['name']) |
|
|
|
|
|
|
|
|
#logging.info('entered function process_channel with ' + channel['name']) |
|
|
while True: |
|
|
while True: |
|
|
|
|
|
|
|
|
log(timestamp() + ' checking ' + channel['name']) |
|
|
|
|
|
|
|
|
logging.info(timestamp() + ' checking ' + channel['name']) |
|
|
if check_stream(channel['url']): |
|
|
if check_stream(channel['url']): |
|
|
log(channel['name'] + ': stream online! Downloading ...') |
|
|
|
|
|
|
|
|
logging.info(channel['name'] + ': stream online! Downloading ...') |
|
|
dest_dir = ROOT_PATH + '/' + channel['name'] +'/' |
|
|
dest_dir = ROOT_PATH + '/' + channel['name'] +'/' |
|
|
# create directory if it doesn't exist |
|
|
# create directory if it doesn't exist |
|
|
if not os.path.exists(dest_dir): |
|
|
if not os.path.exists(dest_dir): |
|
|
log('creating directory ' + dest_dir) |
|
|
|
|
|
|
|
|
logging.info('creating directory ' + dest_dir) |
|
|
os.makedirs(dest_dir) |
|
|
os.makedirs(dest_dir) |
|
|
dest_path = get_destpath(channel) # dirctory + filename |
|
|
dest_path = get_destpath(channel) # dirctory + filename |
|
|
download_stream(channel, dest_path) # also converts video |
|
|
download_stream(channel, dest_path) # also converts video |
|
|
log(timestamp() + " Uploading video " + dest_path) |
|
|
|
|
|
|
|
|
logging.info(timestamp() + " Uploading video " + dest_path) |
|
|
upload_video(dest_path) |
|
|
upload_video(dest_path) |
|
|
else: |
|
|
else: |
|
|
waitingtime = random.randint(50,60) |
|
|
waitingtime = random.randint(50,60) |
|
|
time.sleep(waitingtime) |
|
|
time.sleep(waitingtime) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log('end processing ' + channel['name'] + ' ... (shouldn\'t happen!)') |
|
|
|
|
|
|
|
|
logging.info('end processing ' + channel['name'] + ' ... (shouldn\'t happen!)') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def upload_video(videofile_path): |
|
|
def upload_video(videofile_path): |
|
|
log('uploading %s' % (videofile_path)) |
|
|
|
|
|
|
|
|
logging.info('uploading %s' % (videofile_path)) |
|
|
credentials = config['webdav']['username'] + ':' + config['webdav']['password'] |
|
|
credentials = config['webdav']['username'] + ':' + config['webdav']['password'] |
|
|
webdav_baseurl = config['webdav']['base_url'] |
|
|
webdav_baseurl = config['webdav']['base_url'] |
|
|
filename = ntpath.basename(videofile_path) |
|
|
filename = ntpath.basename(videofile_path) |
|
@@ -169,7 +162,7 @@ def upload_video(videofile_path): |
|
|
delete_video(videofile_path) |
|
|
delete_video(videofile_path) |
|
|
return true |
|
|
return true |
|
|
except: |
|
|
except: |
|
|
log('Error while uploading %s to %s' % (file, webdav_url)) |
|
|
|
|
|
|
|
|
logging.info('Error while uploading %s to %s' % (file, webdav_url)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def delete_video(file): |
|
|
def delete_video(file): |
|
@@ -177,7 +170,7 @@ def delete_video(file): |
|
|
os.system('rm -rf "%s"' % (file)) |
|
|
os.system('rm -rf "%s"' % (file)) |
|
|
return true |
|
|
return true |
|
|
except: |
|
|
except: |
|
|
log('Error while deleting %s' % (file)) |
|
|
|
|
|
|
|
|
logging.info('Error while deleting %s' % (file)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_destpath(channel): |
|
|
def get_destpath(channel): |
|
@@ -198,12 +191,12 @@ def main(): |
|
|
try: |
|
|
try: |
|
|
data = future.result() |
|
|
data = future.result() |
|
|
except Exception as exc: |
|
|
except Exception as exc: |
|
|
log('%r generated an exception: %s' % (channel, exc)) |
|
|
|
|
|
|
|
|
logging.info('%r generated an exception: %s' % (channel, exc)) |
|
|
else: |
|
|
else: |
|
|
log('%r page is %d bytes' % (channel, len(data))) |
|
|
|
|
|
|
|
|
logging.info('%r page is %d bytes' % (channel, len(data))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log('end main (this shouldn\'t happen!)') |
|
|
|
|
|
|
|
|
logging.info('end main (this shouldn\'t happen!)') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main() |
|
|
main() |
|
|