2020-11-09 19:41:01 +00:00
|
|
|
__filename__ = "webapp_media.py"
|
|
|
|
__author__ = "Bob Mottram"
|
|
|
|
__license__ = "AGPL3+"
|
2022-02-03 13:58:20 +00:00
|
|
|
__version__ = "1.3.0"
|
2020-11-09 19:41:01 +00:00
|
|
|
__maintainer__ = "Bob Mottram"
|
2021-09-10 16:14:50 +00:00
|
|
|
__email__ = "bob@libreserver.org"
|
2020-11-09 19:41:01 +00:00
|
|
|
__status__ = "Production"
|
2021-06-26 11:27:14 +00:00
|
|
|
__module_group__ = "Timeline"
|
2020-11-09 19:41:01 +00:00
|
|
|
|
2020-12-24 10:18:34 +00:00
|
|
|
import os
|
2021-12-26 18:10:53 +00:00
|
|
|
from utils import valid_url_prefix
|
2020-12-24 10:18:34 +00:00
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def load_peertube_instances(base_dir: str, peertube_instances: []) -> None:
|
2020-12-24 10:18:34 +00:00
|
|
|
"""Loads peertube instances from file into the given list
|
|
|
|
"""
|
2022-01-03 23:35:42 +00:00
|
|
|
peertube_list = None
|
|
|
|
peertube_instances_filename = base_dir + '/accounts/peertube.txt'
|
|
|
|
if os.path.isfile(peertube_instances_filename):
|
|
|
|
with open(peertube_instances_filename, 'r') as fp_inst:
|
|
|
|
peertube_str = fp_inst.read()
|
|
|
|
if peertube_str:
|
|
|
|
peertube_str = peertube_str.replace('\r', '')
|
|
|
|
peertube_list = peertube_str.split('\n')
|
|
|
|
if not peertube_list:
|
2020-12-24 11:42:23 +00:00
|
|
|
return
|
2022-01-03 23:35:42 +00:00
|
|
|
for url in peertube_list:
|
2021-12-25 23:38:53 +00:00
|
|
|
if url in peertube_instances:
|
2020-12-24 11:42:23 +00:00
|
|
|
continue
|
2021-12-25 23:38:53 +00:00
|
|
|
peertube_instances.append(url)
|
2020-12-24 11:42:23 +00:00
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def _add_embedded_video_from_sites(translate: {}, content: str,
|
|
|
|
peertube_instances: [],
|
|
|
|
width: int, height: int) -> str:
|
2020-11-09 19:41:01 +00:00
|
|
|
"""Adds embedded videos
|
|
|
|
"""
|
|
|
|
if '>vimeo.com/' in content:
|
|
|
|
url = content.split('>vimeo.com/')[1]
|
|
|
|
if '<' in url:
|
|
|
|
url = url.split('<')[0]
|
2022-01-14 18:48:43 +00:00
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
"<center>\n<span itemprop=\"video\">\n" + \
|
|
|
|
"<iframe loading=\"lazy\" decoding=\"async\" " + \
|
2020-11-09 19:41:01 +00:00
|
|
|
"src=\"https://player.vimeo.com/video/" + \
|
|
|
|
url + "\" width=\"" + str(width) + \
|
|
|
|
"\" height=\"" + str(height) + \
|
2022-04-06 10:18:43 +00:00
|
|
|
"\" frameborder=\"0\" allow=\"" + \
|
2022-05-02 13:08:55 +00:00
|
|
|
"fullscreen\" allowfullscreen></iframe>\n" + \
|
|
|
|
"</span>\n</center>\n"
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
2022-01-03 23:35:42 +00:00
|
|
|
video_site = 'https://www.youtube.com'
|
2022-02-22 10:08:56 +00:00
|
|
|
if 'https://m.youtube.com' in content:
|
|
|
|
content = content.replace('https://m.youtube.com', video_site)
|
2022-01-03 23:35:42 +00:00
|
|
|
if '"' + video_site in content:
|
|
|
|
url = content.split('"' + video_site)[1]
|
2022-02-24 19:03:11 +00:00
|
|
|
if '"' in url:
|
|
|
|
url = url.split('"')[0]
|
2022-03-08 16:09:11 +00:00
|
|
|
if '/channel/' not in url and '/playlist' not in url:
|
2022-02-24 19:03:11 +00:00
|
|
|
url = url.replace('/watch?v=', '/embed/')
|
|
|
|
if '&' in url:
|
|
|
|
url = url.split('&')[0]
|
|
|
|
if '?utm_' in url:
|
|
|
|
url = url.split('?utm_')[0]
|
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
"<center>\n<span itemprop=\"video\">\n" + \
|
|
|
|
"<iframe loading=\"lazy\" " + \
|
2022-03-28 08:47:53 +00:00
|
|
|
"decoding=\"async\" src=\"" + \
|
2022-02-24 19:03:11 +00:00
|
|
|
video_site + url + "\" width=\"" + str(width) + \
|
|
|
|
"\" height=\"" + str(height) + \
|
2022-04-06 10:18:43 +00:00
|
|
|
"\" frameborder=\"0\" allow=\"fullscreen\" " + \
|
2022-05-02 13:08:55 +00:00
|
|
|
"allowfullscreen></iframe>\n" + \
|
|
|
|
"</span></center>\n"
|
2022-02-24 19:03:11 +00:00
|
|
|
return content
|
2022-01-30 11:46:40 +00:00
|
|
|
|
|
|
|
video_site = 'https://youtu.be/'
|
|
|
|
if '"' + video_site in content:
|
|
|
|
url = content.split('"' + video_site)[1]
|
2022-02-24 19:03:11 +00:00
|
|
|
if '"' in url:
|
|
|
|
url = url.split('"')[0]
|
2022-03-08 16:09:11 +00:00
|
|
|
if '/channel/' not in url and '/playlist' not in url:
|
2022-02-24 19:03:11 +00:00
|
|
|
url = 'embed/' + url
|
|
|
|
if '&' in url:
|
|
|
|
url = url.split('&')[0]
|
|
|
|
if '?utm_' in url:
|
|
|
|
url = url.split('?utm_')[0]
|
|
|
|
video_site = 'https://www.youtube.com/'
|
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
"<center>\n<span itemprop=\"video\">\n" + \
|
|
|
|
"<iframe loading=\"lazy\" " + \
|
2022-03-28 08:47:53 +00:00
|
|
|
"decoding=\"async\" src=\"" + \
|
2022-02-24 19:03:11 +00:00
|
|
|
video_site + url + "\" width=\"" + str(width) + \
|
|
|
|
"\" height=\"" + str(height) + \
|
2022-04-06 10:18:43 +00:00
|
|
|
"\" frameborder=\"0\" allow=\"fullscreen\" " + \
|
2022-05-02 13:08:55 +00:00
|
|
|
"allowfullscreen></iframe>\n" + \
|
|
|
|
"</span></center>\n"
|
2022-02-24 19:03:11 +00:00
|
|
|
return content
|
2020-11-09 19:41:01 +00:00
|
|
|
|
2022-01-03 23:35:42 +00:00
|
|
|
invidious_sites = (
|
|
|
|
'https://invidious.snopyta.org',
|
|
|
|
'https://yewtu.be',
|
|
|
|
'https://tube.connect.cafe',
|
|
|
|
'https://invidious.kavin.rocks',
|
|
|
|
'https://invidiou.site',
|
|
|
|
'https://invidious.tube',
|
|
|
|
'https://invidious.xyz',
|
|
|
|
'https://invidious.zapashcanon.fr',
|
|
|
|
'http://c7hqkpkpemu6e7emz5b4vy' +
|
|
|
|
'z7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion',
|
|
|
|
'http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4' +
|
|
|
|
'bzzsg2ii4fv2iid.onion'
|
|
|
|
)
|
|
|
|
for video_site in invidious_sites:
|
|
|
|
if '"' + video_site in content:
|
|
|
|
url = content.split('"' + video_site)[1]
|
2020-11-09 19:41:01 +00:00
|
|
|
if '"' in url:
|
|
|
|
url = url.split('"')[0].replace('/watch?v=', '/embed/')
|
|
|
|
if '&' in url:
|
|
|
|
url = url.split('&')[0]
|
2021-01-14 09:38:51 +00:00
|
|
|
if '?utm_' in url:
|
|
|
|
url = url.split('?utm_')[0]
|
2022-04-06 10:44:48 +00:00
|
|
|
# explicitly turn off autoplay
|
|
|
|
if '?' in url:
|
|
|
|
if '&autoplay=' not in url:
|
|
|
|
url += '&autoplay=0'
|
|
|
|
else:
|
|
|
|
url = url.replace('&autoplay=1', '&autoplay=0')
|
|
|
|
else:
|
|
|
|
if '?autoplay=' not in url:
|
|
|
|
url += '?autoplay=0'
|
|
|
|
else:
|
|
|
|
url = url.replace('?autoplay=1', '?autoplay=0')
|
2022-01-14 18:48:43 +00:00
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
"<center>\n<span itemprop=\"video\">\n" + \
|
|
|
|
"<iframe loading=\"lazy\" " + \
|
2022-03-28 08:47:53 +00:00
|
|
|
"decoding=\"async\" src=\"" + \
|
2022-01-03 23:35:42 +00:00
|
|
|
video_site + url + "\" width=\"" + \
|
2020-11-09 19:41:01 +00:00
|
|
|
str(width) + "\" height=\"" + str(height) + \
|
2022-04-06 10:18:43 +00:00
|
|
|
"\" frameborder=\"0\" allow=\"fullscreen\" " + \
|
2022-05-02 13:08:55 +00:00
|
|
|
"allowfullscreen></iframe>\n" + \
|
|
|
|
"</span>\n</center>\n"
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
2022-01-03 23:35:42 +00:00
|
|
|
video_site = 'https://media.ccc.de'
|
|
|
|
if '"' + video_site in content:
|
|
|
|
url = content.split('"' + video_site)[1]
|
2020-11-09 19:41:01 +00:00
|
|
|
if '"' in url:
|
|
|
|
url = url.split('"')[0]
|
2022-02-23 12:22:33 +00:00
|
|
|
video_site_settings = ''
|
|
|
|
if '#' in url:
|
|
|
|
video_site_settings = '#' + url.split('#', 1)[1]
|
|
|
|
url = url.split('#')[0]
|
2020-11-09 19:41:01 +00:00
|
|
|
if not url.endswith('/oembed'):
|
|
|
|
url = url + '/oembed'
|
2022-02-23 12:22:33 +00:00
|
|
|
url += video_site_settings
|
2022-01-14 18:48:43 +00:00
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
"<center>\n<span itemprop=\"video\">\n" + \
|
|
|
|
"<iframe loading=\"lazy\" " + \
|
2022-03-28 08:47:53 +00:00
|
|
|
"decoding=\"async\" src=\"" + \
|
2022-01-03 23:35:42 +00:00
|
|
|
video_site + url + "\" width=\"" + \
|
2020-11-09 19:41:01 +00:00
|
|
|
str(width) + "\" height=\"" + str(height) + \
|
|
|
|
"\" frameborder=\"0\" allow=\"fullscreen\" " + \
|
2022-05-02 13:08:55 +00:00
|
|
|
"allowfullscreen></iframe>\n" + \
|
|
|
|
"</span>\n</center>\n"
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
|
|
|
if '"https://' in content:
|
2021-12-25 23:38:53 +00:00
|
|
|
if peertube_instances:
|
2021-07-06 09:44:45 +00:00
|
|
|
# only create an embedded video for a limited set of
|
|
|
|
# peertube sites.
|
2022-01-03 23:35:42 +00:00
|
|
|
peertube_sites = peertube_instances
|
2020-12-23 23:59:49 +00:00
|
|
|
else:
|
2021-09-07 16:29:59 +00:00
|
|
|
# A default minimal set of peertube instances
|
2020-12-24 10:13:21 +00:00
|
|
|
# Also see https://peertube_isolation.frama.io/list/ for
|
|
|
|
# adversarial instances. Nothing in that list should be
|
|
|
|
# in the defaults below.
|
2022-01-03 23:35:42 +00:00
|
|
|
peertube_sites = (
|
2021-12-29 21:55:09 +00:00
|
|
|
'share.tube',
|
|
|
|
'visionon.tv',
|
2022-03-23 14:29:55 +00:00
|
|
|
'anarchy.tube',
|
2021-12-29 21:55:09 +00:00
|
|
|
'peertube.fr',
|
2022-03-23 15:37:32 +00:00
|
|
|
'video.nerdcave.site',
|
2021-12-29 21:55:09 +00:00
|
|
|
'kolektiva.media',
|
|
|
|
'peertube.social',
|
|
|
|
'videos.lescommuns.org'
|
|
|
|
)
|
2022-01-03 23:35:42 +00:00
|
|
|
for site in peertube_sites:
|
2020-12-24 13:57:02 +00:00
|
|
|
site = site.strip()
|
|
|
|
if not site:
|
|
|
|
continue
|
|
|
|
if len(site) < 5:
|
|
|
|
continue
|
|
|
|
if '.' not in site:
|
|
|
|
continue
|
2022-01-03 23:35:42 +00:00
|
|
|
site_str = site
|
2020-12-24 13:13:03 +00:00
|
|
|
if site.startswith('http://'):
|
|
|
|
site = site.replace('http://', '')
|
|
|
|
elif site.startswith('https://'):
|
|
|
|
site = site.replace('https://', '')
|
|
|
|
if site.endswith('.onion') or site.endswith('.i2p'):
|
2022-01-03 23:35:42 +00:00
|
|
|
site_str = 'http://' + site
|
2020-12-24 13:13:03 +00:00
|
|
|
else:
|
2022-01-03 23:35:42 +00:00
|
|
|
site_str = 'https://' + site
|
|
|
|
site_str = '"' + site_str
|
|
|
|
if site_str not in content:
|
2021-07-06 09:44:45 +00:00
|
|
|
continue
|
2022-01-03 23:35:42 +00:00
|
|
|
url = content.split(site_str)[1]
|
2021-07-06 09:44:45 +00:00
|
|
|
if '"' not in url:
|
|
|
|
continue
|
2022-02-22 09:51:36 +00:00
|
|
|
url = url.split('"')[0]
|
2022-02-22 09:57:48 +00:00
|
|
|
if '/c/' in url:
|
|
|
|
# don't try to embed peertube channel page
|
|
|
|
continue
|
2022-04-10 08:56:29 +00:00
|
|
|
if '?sort=' in url:
|
|
|
|
# don't try to embed a sorted list
|
|
|
|
continue
|
2022-02-22 12:03:56 +00:00
|
|
|
if '/w/' in url:
|
|
|
|
if '/videos/' not in url:
|
|
|
|
url = url.replace('/w/', '/videos/embed/')
|
|
|
|
else:
|
|
|
|
url = url.replace('/w/', '/embed/')
|
2022-02-22 09:51:36 +00:00
|
|
|
url = url.replace('/watch/', '/embed/')
|
2022-02-22 12:03:56 +00:00
|
|
|
|
2022-01-14 18:48:43 +00:00
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
"<center>\n<span itemprop=\"video\">\n" + \
|
|
|
|
"<iframe loading=\"lazy\" decoding=\"async\" " + \
|
2021-07-06 09:44:45 +00:00
|
|
|
"sandbox=\"allow-same-origin " + \
|
|
|
|
"allow-scripts\" src=\"https://" + \
|
|
|
|
site + url + "\" width=\"" + str(width) + \
|
|
|
|
"\" height=\"" + str(height) + \
|
2022-04-06 10:18:43 +00:00
|
|
|
"\" frameborder=\"0\" allow=\"" + \
|
2022-05-02 13:08:55 +00:00
|
|
|
"fullscreen\" allowfullscreen></iframe>\n" + \
|
|
|
|
"</span>\n</center>\n"
|
2021-07-06 09:44:45 +00:00
|
|
|
return content
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def _add_embedded_audio(translate: {}, content: str) -> str:
|
2022-04-18 13:21:45 +00:00
|
|
|
"""Adds embedded audio for mp3/ogg/opus
|
2020-11-09 19:41:01 +00:00
|
|
|
"""
|
2022-04-18 13:44:08 +00:00
|
|
|
if not ('.mp3' in content or
|
|
|
|
'.ogg' in content or
|
|
|
|
'.opus' in content or
|
|
|
|
'.flac' in content):
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
|
|
|
if '<audio ' in content:
|
|
|
|
return content
|
|
|
|
|
|
|
|
extension = '.mp3'
|
|
|
|
if '.ogg' in content:
|
|
|
|
extension = '.ogg'
|
2022-04-18 13:21:45 +00:00
|
|
|
elif '.opus' in content:
|
|
|
|
extension = '.opus'
|
2022-04-18 13:44:08 +00:00
|
|
|
elif '.flac' in content:
|
|
|
|
extension = '.flac'
|
2020-11-09 19:41:01 +00:00
|
|
|
|
|
|
|
words = content.strip('\n').split(' ')
|
2022-01-03 23:35:42 +00:00
|
|
|
for wrd in words:
|
|
|
|
if extension not in wrd:
|
2020-11-09 19:41:01 +00:00
|
|
|
continue
|
2022-01-03 23:35:42 +00:00
|
|
|
wrd = wrd.replace('href="', '').replace('">', '')
|
|
|
|
if wrd.endswith('.'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if wrd.endswith('"'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if wrd.endswith(';'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if wrd.endswith(':'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if not wrd.endswith(extension):
|
2020-11-09 19:41:01 +00:00
|
|
|
continue
|
|
|
|
|
2022-01-03 23:35:42 +00:00
|
|
|
if not valid_url_prefix(wrd):
|
2020-11-09 19:41:01 +00:00
|
|
|
continue
|
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
'<center>\n<span itemprop="audio">' + \
|
|
|
|
'<audio controls>\n' + \
|
2022-01-03 23:35:42 +00:00
|
|
|
'<source src="' + wrd + '" type="audio/' + \
|
2021-07-06 09:44:45 +00:00
|
|
|
extension.replace('.', '') + '">' + \
|
|
|
|
translate['Your browser does not support the audio element.'] + \
|
2022-05-02 13:08:55 +00:00
|
|
|
'</audio>\n</span>\n</center>\n'
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def _add_embedded_video(translate: {}, content: str) -> str:
|
2020-11-09 19:41:01 +00:00
|
|
|
"""Adds embedded video for mp4/webm/ogv
|
|
|
|
"""
|
|
|
|
if not ('.mp4' in content or '.webm' in content or '.ogv' in content):
|
|
|
|
return content
|
|
|
|
|
|
|
|
if '<video ' in content:
|
|
|
|
return content
|
|
|
|
|
|
|
|
extension = '.mp4'
|
|
|
|
if '.webm' in content:
|
|
|
|
extension = '.webm'
|
|
|
|
elif '.ogv' in content:
|
|
|
|
extension = '.ogv'
|
|
|
|
|
|
|
|
words = content.strip('\n').split(' ')
|
2022-01-03 23:35:42 +00:00
|
|
|
for wrd in words:
|
|
|
|
if extension not in wrd:
|
2020-11-09 19:41:01 +00:00
|
|
|
continue
|
2022-01-03 23:35:42 +00:00
|
|
|
wrd = wrd.replace('href="', '').replace('">', '')
|
|
|
|
if wrd.endswith('.'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if wrd.endswith('"'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if wrd.endswith(';'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if wrd.endswith(':'):
|
|
|
|
wrd = wrd[:-1]
|
|
|
|
if not wrd.endswith(extension):
|
2020-11-09 19:41:01 +00:00
|
|
|
continue
|
2022-01-03 23:35:42 +00:00
|
|
|
if not valid_url_prefix(wrd):
|
2020-11-09 19:41:01 +00:00
|
|
|
continue
|
|
|
|
content += \
|
2022-05-02 13:08:55 +00:00
|
|
|
'<center><span itemprop="video">\n' + \
|
|
|
|
'<figure id="videoContainer" ' + \
|
2021-03-07 12:06:01 +00:00
|
|
|
'data-fullscreen="false">\n' + \
|
|
|
|
' <video id="video" controls ' + \
|
2021-07-06 09:44:45 +00:00
|
|
|
'preload="metadata">\n' + \
|
2022-01-03 23:35:42 +00:00
|
|
|
'<source src="' + wrd + '" type="video/' + \
|
2021-07-06 09:44:45 +00:00
|
|
|
extension.replace('.', '') + '">\n' + \
|
|
|
|
translate['Your browser does not support the video element.'] + \
|
2022-05-02 13:08:55 +00:00
|
|
|
'</video>\n</figure>\n</span>\n</center>\n'
|
2020-11-09 19:41:01 +00:00
|
|
|
return content
|
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def add_embedded_elements(translate: {}, content: str,
|
|
|
|
peertube_instances: []) -> str:
|
2020-11-09 19:41:01 +00:00
|
|
|
"""Adds embedded elements for various media types
|
|
|
|
"""
|
2021-12-29 21:55:09 +00:00
|
|
|
content = _add_embedded_video_from_sites(translate, content,
|
|
|
|
peertube_instances, 400, 300)
|
|
|
|
content = _add_embedded_audio(translate, content)
|
|
|
|
return _add_embedded_video(translate, content)
|