|
@@ -11,8 +11,11 @@ import m3u8 |
|
|
import youtube_dl |
|
|
import youtube_dl |
|
|
import asyncio |
|
|
import asyncio |
|
|
import concurrent.futures |
|
|
import concurrent.futures |
|
|
|
|
|
import ntpath |
|
|
|
|
|
import yaml |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with open(r'config.yaml') as file: |
|
|
|
|
|
config = yaml.load(file, Loader=yaml.FullLoader) |
|
|
|
|
|
|
|
|
try: |
|
|
try: |
|
|
if sys.argv[1] and os.path.exists(sys.argv[1]): |
|
|
if sys.argv[1] and os.path.exists(sys.argv[1]): |
|
@@ -27,7 +30,9 @@ except IndexError: |
|
|
sys.exit() |
|
|
sys.exit() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def timestamp(): |
|
|
|
|
|
dateTimeObj = datetime.now() |
|
|
|
|
|
return '[ ' + dateTimeObj.strftime("%F %H:%M:%S.%f") + ' ] ' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -36,13 +41,16 @@ def generate_channellist(): |
|
|
districts = range(1, 23 + 1) # districts of vienna |
|
|
districts = range(1, 23 + 1) # districts of vienna |
|
|
|
|
|
|
|
|
for district_num in districts: |
|
|
for district_num in districts: |
|
|
district_str = str(district_num) |
|
|
|
|
|
|
|
|
# district_str = str(district_num) |
|
|
district_str_lz = str(district_num).zfill(2) # leading zero |
|
|
district_str_lz = str(district_num).zfill(2) # leading zero |
|
|
channel = { |
|
|
channel = { |
|
|
'name': district_str+'. Bezirk', |
|
|
|
|
|
|
|
|
'name': '1' + district_str_lz + '0', # 1010 - 1230 |
|
|
'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) |
|
|
|
|
|
print('channels:') |
|
|
|
|
|
for channel in channels: |
|
|
|
|
|
print(channel['name'] + ' ' + channel['url']) |
|
|
return channels |
|
|
return channels |
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -75,60 +83,95 @@ class MyLogger(object): |
|
|
|
|
|
|
|
|
def my_ytdl_hook(d): |
|
|
def my_ytdl_hook(d): |
|
|
if d['status'] == 'finished': |
|
|
if d['status'] == 'finished': |
|
|
print('Done downloading!') |
|
|
|
|
|
print(d) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def download_stream(channel): |
|
|
|
|
|
now = datetime.now() # current date and time |
|
|
|
|
|
|
|
|
|
|
|
dest_dir = ROOT_PATH + '/' + channel['name'] +'/' |
|
|
|
|
|
dest_filename = now.strftime("%Y-%m-%d--%H.%M.%S") + '.mp4' |
|
|
|
|
|
|
|
|
print(timestamp() + 'Done downloading!') |
|
|
|
|
|
else: |
|
|
|
|
|
print(timestamp() + 'sth went wrong' + d['status']) |
|
|
|
|
|
print(d) |
|
|
|
|
|
|
|
|
# create directory if it doesn't exist |
|
|
|
|
|
if not os.path.exists(dest_dir): |
|
|
|
|
|
print('creating directory ' + dest_dir) |
|
|
|
|
|
os.makedirs(dest_dir) |
|
|
|
|
|
|
|
|
|
|
|
dest = dest_dir + dest_filename |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def download_stream(channel, dest_path): |
|
|
|
|
|
print('download_stream') |
|
|
ytdl_opts = { |
|
|
ytdl_opts = { |
|
|
'logger': MyLogger(), |
|
|
'logger': MyLogger(), |
|
|
'outtmpl': dest, |
|
|
|
|
|
|
|
|
'outtmpl': dest_path, |
|
|
'format': 'bestaudio/best', |
|
|
'format': 'bestaudio/best', |
|
|
'recodevideo': 'mp4', |
|
|
|
|
|
'progress_hooks': [my_ytdl_hook], |
|
|
|
|
|
|
|
|
# 'recodevideo': 'mp4', |
|
|
|
|
|
# 'postprocessors': [{ |
|
|
|
|
|
# 'key': 'FFmpegVideoConvertor', |
|
|
|
|
|
# 'preferedformat': 'mp4', |
|
|
|
|
|
# 'preferredquality': '25', |
|
|
|
|
|
# }], |
|
|
|
|
|
# should just stop after a few retries and start again instead of hanging in the loop of trying to download |
|
|
|
|
|
'retries': 3, |
|
|
|
|
|
'fragment-retries': 3, |
|
|
|
|
|
'progress_hooks': [my_ytdl_hook] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ytdl = youtube_dl.YoutubeDL(ytdl_opts) |
|
|
ytdl = youtube_dl.YoutubeDL(ytdl_opts) |
|
|
|
|
|
|
|
|
try: |
|
|
try: |
|
|
|
|
|
print(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: |
|
|
print("Download error: " + str(e)) |
|
|
|
|
|
|
|
|
print(timestamp() + " Download error: " + str(e)) |
|
|
except (youtube_dl.utils.SameFileError) as e: |
|
|
except (youtube_dl.utils.SameFileError) as e: |
|
|
print("Download error: " + str(e)) |
|
|
print("Download error: " + str(e)) |
|
|
except (UnicodeDecodeError) as e: |
|
|
except (UnicodeDecodeError) as e: |
|
|
print("UnicodeDecodeError: " + str(e)) |
|
|
print("UnicodeDecodeError: " + str(e)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_channel(channel): |
|
|
def process_channel(channel): |
|
|
#print('entered function process_channel with ' + channel['name']) |
|
|
#print('entered function process_channel with ' + channel['name']) |
|
|
while True: |
|
|
while True: |
|
|
#print('checking ' + channel['name']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print(timestamp() + ' checking ' + channel['name']) |
|
|
if check_stream(channel['url']): |
|
|
if check_stream(channel['url']): |
|
|
print(channel['name'] + ': stream online! Downloading ...') |
|
|
print(channel['name'] + ': stream online! Downloading ...') |
|
|
download_stream(channel) |
|
|
|
|
|
|
|
|
dest_dir = ROOT_PATH + '/' + channel['name'] +'/' |
|
|
|
|
|
# create directory if it doesn't exist |
|
|
|
|
|
if not os.path.exists(dest_dir): |
|
|
|
|
|
print('creating directory ' + dest_dir) |
|
|
|
|
|
os.makedirs(dest_dir) |
|
|
|
|
|
dest_path = get_destpath(channel) # dirctory + filename |
|
|
|
|
|
download_stream(channel, dest_path) # also converts video |
|
|
|
|
|
print(timestamp() + " Uploading video " + dest_path) |
|
|
|
|
|
upload_video(dest_path) |
|
|
else: |
|
|
else: |
|
|
# print(channel['name'] + ': stream offline') |
|
|
|
|
|
# wait between checks |
|
|
|
|
|
waitingtime = random.randint(20,30) |
|
|
|
|
|
|
|
|
waitingtime = random.randint(50,60) |
|
|
time.sleep(waitingtime) |
|
|
time.sleep(waitingtime) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print('end processing ' + channel['name'] + ' ... (shouldn\'t happen!)') |
|
|
print('end processing ' + channel['name'] + ' ... (shouldn\'t happen!)') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def upload_video(videofile_path): |
|
|
|
|
|
print('uploading %s' % (videofile_path)) |
|
|
|
|
|
credentials = config['webdav']['username'] + ':' + config['webdav']['password'] |
|
|
|
|
|
webdav_baseurl = config['webdav']['base_url'] |
|
|
|
|
|
filename = ntpath.basename(videofile_path) |
|
|
|
|
|
webdav_url = webdav_baseurl + filename |
|
|
|
|
|
try: |
|
|
|
|
|
# Upload to cloud using webdav |
|
|
|
|
|
result = os.system('curl -L -u %s -T "%s" "%s"' % (credentials, videofile_path, webdav_url)) |
|
|
|
|
|
if result == 0: # exit code |
|
|
|
|
|
delete_video(videofile_path) |
|
|
|
|
|
return true |
|
|
|
|
|
except: |
|
|
|
|
|
print('Error while uploading %s to %s' % (file, webdav_url)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def delete_video(file): |
|
|
|
|
|
try: |
|
|
|
|
|
os.system('rm -rf "%s"' % (file)) |
|
|
|
|
|
return true |
|
|
|
|
|
except: |
|
|
|
|
|
print('Error while deleting %s' % (file)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_destpath(channel): |
|
|
|
|
|
now = datetime.now() # current date and time |
|
|
|
|
|
dest_dir = ROOT_PATH + '/' + channel['name'] +'/' |
|
|
|
|
|
dest_filename = channel['name'] + "_" + now.strftime("%Y-%m-%d--%H.%M.%S") + '.mp4' |
|
|
|
|
|
return dest_dir + dest_filename |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
def main(): |
|
|