epicyon/webapp_podcast.py

307 lines
11 KiB
Python
Raw Normal View History

2022-01-11 18:25:13 +00:00
__filename__ = "webapp_podcast.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2022-02-03 13:58:20 +00:00
__version__ = "1.3.0"
2022-01-11 18:25:13 +00:00
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Web Interface Columns"
import os
2022-01-12 19:40:12 +00:00
import html
2022-01-12 20:01:28 +00:00
import urllib.parse
2022-01-11 18:25:13 +00:00
from shutil import copyfile
from utils import get_config_param
from utils import remove_html
from media import path_is_audio
2022-01-14 10:20:37 +00:00
from content import safe_web_text
2022-01-11 18:25:13 +00:00
from webapp_utils import get_broken_link_substitute
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import html_keyboard_navigation
2022-02-12 20:37:15 +00:00
def _html_podcast_social_interactions(podcast_properties: {},
translate: {},
nickname: str) -> str:
"""Returns html for social interactions with a podcast
"""
if not podcast_properties:
return ''
2022-04-29 13:54:13 +00:00
key = 'discussion'
if not podcast_properties.get(key):
key = 'socialInteract'
if not podcast_properties.get(key):
return ''
if podcast_properties[key].get('uri'):
episode_post_url = podcast_properties[key]['uri']
elif podcast_properties[key].get('url'):
episode_post_url = podcast_properties[key]['url']
elif podcast_properties[key].get('text'):
episode_post_url = podcast_properties[key]['text']
else:
2022-02-12 20:37:15 +00:00
return ''
2022-02-13 11:30:11 +00:00
actor_str = ''
podcast_account_id = None
2022-04-29 13:54:13 +00:00
if podcast_properties[key].get('accountId'):
podcast_account_id = podcast_properties[key]['accountId']
elif podcast_properties[key].get('podcastAccountUrl'):
podcast_account_id = \
2022-04-29 13:54:13 +00:00
podcast_properties[key]['podcastAccountUrl']
if podcast_account_id:
actor_handle = podcast_account_id
2022-02-13 11:30:11 +00:00
if actor_handle.startswith('@'):
actor_handle = actor_handle[1:]
actor_str = '?actor=' + actor_handle
2022-02-12 20:37:15 +00:00
podcast_str = \
'<center>\n' + \
' <a href="/users/' + nickname + \
2022-02-13 11:30:11 +00:00
'?replyto=' + episode_post_url + actor_str + '" target="_blank" ' + \
2022-02-12 20:37:15 +00:00
'rel="nofollow noopener noreferrer">💬 ' + \
translate['Leave a comment'] + '</a>\n' + \
' <a href="' + episode_post_url + '" target="_blank" ' + \
2022-02-12 20:37:15 +00:00
'rel="nofollow noopener noreferrer">' + \
translate['View comments'] + '</a>\n' + \
'</center>\n'
return podcast_str
2022-01-11 18:25:13 +00:00
def _html_podcast_performers(podcast_properties: {}) -> str:
"""Returns html for performers of a podcast
"""
2022-01-13 23:06:04 +00:00
if not podcast_properties:
return ''
2022-01-11 18:25:13 +00:00
if not podcast_properties.get('persons'):
return ''
# list of performers
podcast_str = '<div class="performers">\n'
podcast_str += ' <center>\n'
podcast_str += '<ul>\n'
for performer in podcast_properties['persons']:
if not performer.get('text'):
continue
performer_name = performer['text']
performer_title = performer_name
if performer.get('role'):
performer_title += ' (' + performer['role'] + ')'
if performer.get('group'):
performer_title += ', <i>' + performer['group'] + '</i>'
performer_title = remove_html(performer_title)
performer_url = ''
if performer.get('href'):
performer_url = performer['href']
performer_img = ''
if performer.get('img'):
performer_img = performer['img']
podcast_str += ' <li>\n'
podcast_str += ' <figure>\n'
podcast_str += ' <a href="' + performer_url + '">\n'
podcast_str += \
2022-03-28 08:47:53 +00:00
' <img loading="lazy" decoding="async" ' + \
'src="' + performer_img + '" alt="" />\n'
2022-01-11 18:25:13 +00:00
podcast_str += \
' <figcaption>' + performer_title + '</figcaption>\n'
podcast_str += ' </a>\n'
podcast_str += ' </figure>\n'
podcast_str += ' </li>\n'
podcast_str += '</ul>\n'
podcast_str += '</div>\n'
return podcast_str
def _html_podcast_soundbites(link_url: str, extension: str,
podcast_properties: {},
translate: {}) -> str:
"""Returns html for podcast soundbites
"""
2022-01-13 23:06:04 +00:00
if not podcast_properties:
return ''
2022-01-11 18:25:13 +00:00
if not podcast_properties.get('soundbites'):
return ''
podcast_str = '<div class="performers">\n'
podcast_str += ' <center>\n'
podcast_str += '<ul>\n'
ctr = 1
for performer in podcast_properties['soundbites']:
if not performer.get('startTime'):
continue
if not performer['startTime'].isdigit():
continue
if not performer.get('duration'):
continue
if not performer['duration'].isdigit():
continue
end_time = str(float(performer['startTime']) +
float(performer['duration']))
podcast_str += ' <li>\n'
preview_url = \
link_url + '#t=' + performer['startTime'] + ',' + end_time
soundbite_title = translate['Preview']
if ctr > 0:
soundbite_title += ' ' + str(ctr)
podcast_str += \
' <audio controls>\n' + \
' <p>' + soundbite_title + '</p>\n' + \
' <source src="' + preview_url + '" type="audio/' + \
extension.replace('.', '') + '">' + \
translate['Your browser does not support the audio element.'] + \
'</audio>\n'
podcast_str += ' </li>\n'
ctr += 1
podcast_str += '</ul>\n'
podcast_str += '</div>\n'
return podcast_str
def html_podcast_episode(css_cache: {}, translate: {},
base_dir: str, nickname: str, domain: str,
newswire_item: [], theme: str,
default_timeline: str,
text_mode_banner: str, access_keys: {}) -> str:
"""Returns html for a podcast episode, giebn an item from the newswire
"""
css_filename = base_dir + '/epicyon-podcast.css'
if os.path.isfile(base_dir + '/podcast.css'):
css_filename = base_dir + '/podcast.css'
if os.path.isfile(base_dir + '/accounts/podcast-background-custom.jpg'):
if not os.path.isfile(base_dir + '/accounts/podcast-background.jpg'):
copyfile(base_dir + '/accounts/podcast-background.jpg',
base_dir + '/accounts/podcast-background.jpg')
instance_title = get_config_param(base_dir, 'instanceTitle')
podcast_str = \
html_header_with_external_style(css_filename, instance_title, None)
podcast_properties = newswire_item[8]
image_url = ''
image_src = 'src'
if podcast_properties.get('images'):
if podcast_properties['images'].get('srcset'):
image_url = podcast_properties['images']['srcset']
image_src = 'srcset'
if not image_url and podcast_properties.get('image'):
image_url = podcast_properties['image']
link_url = newswire_item[1]
podcast_str += html_keyboard_navigation(text_mode_banner, {}, {})
podcast_str += '<br><br>\n'
podcast_str += '<div class="options">\n'
podcast_str += ' <div class="optionsAvatar">\n'
podcast_str += ' <center>\n'
podcast_str += ' <a href="' + link_url + '">\n'
if image_src == 'srcset':
2022-03-28 08:47:53 +00:00
podcast_str += ' <img loading="lazy" decoding="async" ' + \
'srcset="' + image_url + \
2022-01-11 18:25:13 +00:00
'" alt="" ' + get_broken_link_substitute() + '/></a>\n'
else:
2022-03-28 08:47:53 +00:00
podcast_str += ' <img loading="lazy" decoding="async" ' + \
'src="' + image_url + \
2022-01-11 18:25:13 +00:00
'" alt="" ' + get_broken_link_substitute() + '/></a>\n'
2022-01-12 19:21:12 +00:00
podcast_str += ' </center>\n'
2022-01-11 18:25:13 +00:00
podcast_str += ' </div>\n'
2022-01-12 19:21:12 +00:00
podcast_str += ' <center>\n'
2022-01-12 18:35:15 +00:00
audio_extension = None
2022-01-11 18:25:13 +00:00
if path_is_audio(link_url):
if '.mp3' in link_url:
2022-01-12 18:35:15 +00:00
audio_extension = 'mpeg'
2022-04-18 13:21:45 +00:00
elif '.opus' in link_url:
audio_extension = 'opus'
2022-04-18 13:44:08 +00:00
elif '.flac' in link_url:
audio_extension = 'flac'
2022-01-11 18:25:13 +00:00
else:
2022-01-12 18:35:15 +00:00
audio_extension = 'ogg'
else:
if podcast_properties.get('linkMimeType'):
if 'audio' in podcast_properties['linkMimeType']:
audio_extension = \
podcast_properties['linkMimeType'].split('/')[1]
# show widgets for soundbites
if audio_extension:
podcast_str += _html_podcast_soundbites(link_url, audio_extension,
2022-01-11 18:25:13 +00:00
podcast_properties,
translate)
# podcast player widget
podcast_str += \
2022-01-12 19:21:12 +00:00
' <audio controls>\n' + \
' <source src="' + link_url + '" type="audio/' + \
2022-01-12 18:35:15 +00:00
audio_extension.replace('.', '') + '">' + \
2022-01-11 18:25:13 +00:00
translate['Your browser does not support the audio element.'] + \
2022-01-12 19:21:12 +00:00
'\n </audio>\n'
2022-01-13 11:11:18 +00:00
elif podcast_properties.get('linkMimeType'):
2022-01-14 19:08:01 +00:00
if '/youtube' in podcast_properties['linkMimeType']:
url = link_url.replace('/watch?v=', '/embed/')
if '&' in url:
url = url.split('&')[0]
if '?utm_' in url:
url = url.split('?utm_')[0]
2022-01-14 18:48:43 +00:00
podcast_str += \
2022-03-28 08:47:53 +00:00
" <iframe loading=\"lazy\" decoding=\"async\" src=\"" + \
2022-01-14 20:04:39 +00:00
url + "\" width=\"400\" height=\"300\" " + \
2022-04-06 10:23:46 +00:00
"frameborder=\"0\" allow=\"fullscreen\" " + \
2022-01-14 18:48:43 +00:00
"allowfullscreen>\n </iframe>\n"
elif 'video' in podcast_properties['linkMimeType']:
2022-01-13 11:19:52 +00:00
video_mime_type = podcast_properties['linkMimeType']
2022-01-13 11:11:18 +00:00
video_msg = 'Your browser does not support the video element.'
podcast_str += \
2022-01-13 11:24:15 +00:00
' <figure id="videoContainer" ' + \
'data-fullscreen="false">\n' + \
2022-01-13 11:19:52 +00:00
' <video id="video" controls preload="metadata">\n' + \
'<source src="' + link_url + '" ' + \
2022-01-13 11:24:15 +00:00
'type="' + video_mime_type + '">' + \
translate[video_msg] + '</video>\n </figure>\n'
2022-01-11 18:25:13 +00:00
2022-01-12 20:01:28 +00:00
podcast_title = \
2022-01-12 20:40:14 +00:00
remove_html(html.unescape(urllib.parse.unquote_plus(newswire_item[0])))
2022-01-11 18:25:13 +00:00
if podcast_title:
podcast_str += \
2022-01-12 20:53:32 +00:00
'<p><label class="podcast-title">' + podcast_title + \
2022-01-11 18:25:13 +00:00
'</label></p>\n'
if newswire_item[4]:
2022-01-12 19:21:12 +00:00
podcast_description = \
2022-01-12 20:01:28 +00:00
html.unescape(urllib.parse.unquote_plus(newswire_item[4]))
2022-01-14 10:20:37 +00:00
podcast_description = safe_web_text(podcast_description)
2022-01-11 18:25:13 +00:00
if podcast_description:
podcast_str += '<p>' + podcast_description + '</p>\n'
# donate button
if podcast_properties.get('funding'):
if podcast_properties['funding'].get('url'):
donate_url = podcast_properties['funding']['url']
podcast_str += \
'<p><a href="' + donate_url + \
'"><button class="donateButton">' + translate['Donate'] + \
'</button></a></p>\n'
if podcast_properties['categories']:
podcast_str += '<p>'
tags_str = ''
for tag in podcast_properties['categories']:
tag_link = '/users/' + nickname + '/tags/' + tag.replace('#', '')
tags_str += '<a href="' + tag_link + '">' + tag + '</a> '
podcast_str += tags_str.strip() + '</p>\n'
2022-01-11 18:25:13 +00:00
podcast_str += _html_podcast_performers(podcast_properties)
2022-02-12 20:37:15 +00:00
podcast_str += \
_html_podcast_social_interactions(podcast_properties, translate,
nickname)
2022-01-11 18:25:13 +00:00
podcast_str += ' </center>\n'
podcast_str += '</div>\n'
podcast_str += html_footer()
return podcast_str