mirror of https://gitlab.com/bashrc2/epicyon
Podcast episode screen
parent
3524117e9c
commit
39401222fe
29
daemon.py
29
daemon.py
|
@ -156,6 +156,7 @@ from blog import html_blog_page
|
|||
from blog import html_blog_post
|
||||
from blog import html_edit_blog
|
||||
from blog import get_blog_address
|
||||
from webapp_podcast import html_podcast_episode
|
||||
from webapp_theme_designer import html_theme_designer
|
||||
from webapp_minimalbutton import set_minimal
|
||||
from webapp_minimalbutton import is_minimal
|
||||
|
@ -14062,6 +14063,34 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self._write(msg)
|
||||
return
|
||||
|
||||
# show a podcast episode
|
||||
if authorized and users_in_path and html_getreq and \
|
||||
'?podepisode=' in self.path:
|
||||
nickname = self.path.split('/users/')[1]
|
||||
if '/' in nickname:
|
||||
nickname = nickname.split('/')[0]
|
||||
episode_timestamp = self.path.split('?podepisode=')[1]
|
||||
if self.server.newswire.get(episode_timestamp):
|
||||
pod_episode = self.server.newswire[episode_timestamp]
|
||||
html_str = \
|
||||
html_podcast_episode(self.server.css_cache,
|
||||
self.server.translate,
|
||||
self.server.base_dir,
|
||||
nickname,
|
||||
self.server.domain,
|
||||
pod_episode,
|
||||
self.server.themeName,
|
||||
self.server.default_timeline,
|
||||
self.server.text_mode_banner,
|
||||
self.server.access_keys)
|
||||
if html_str:
|
||||
msg = html_str.encode('utf-8')
|
||||
msglen = len(msg)
|
||||
self._set_headers('text/html', msglen,
|
||||
None, calling_domain, False)
|
||||
self._write(msg)
|
||||
return
|
||||
|
||||
# redirect to the welcome screen
|
||||
if html_getreq and authorized and users_in_path and \
|
||||
'/welcome' not in self.path:
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
:root {
|
||||
--avatar-rounding: 10%;
|
||||
--options-bg-color: #282c37;
|
||||
--options-link-bg-color: transparent;
|
||||
--options-fg-color: #dddddd;
|
||||
--options-main-link-color: #999;
|
||||
--options-main-visited-color: #888;
|
||||
--border-color: #505050;
|
||||
--font-size-header: 18px;
|
||||
--font-color-header: #ccc;
|
||||
--font-size: 40px;
|
||||
--font-size2: 24px;
|
||||
--font-size3: 38px;
|
||||
--font-size4: 22px;
|
||||
--font-size5: 20px;
|
||||
--text-entry-foreground: #ccc;
|
||||
--text-entry-background: #111;
|
||||
--time-color: #aaa;
|
||||
--button-text: #FFFFFF;
|
||||
--button-small-text: #FFFFFF;
|
||||
--button-background-hover: #777;
|
||||
--button-background: #999;
|
||||
--button-small-background: #999;
|
||||
--hashtag-margin: 2%;
|
||||
--hashtag-vertical-spacing1: 50px;
|
||||
--hashtag-vertical-spacing2: 100px;
|
||||
--hashtag-vertical-spacing3: 100px;
|
||||
--hashtag-vertical-spacing4: 150px;
|
||||
--hashtag-size1: 30px;
|
||||
--hashtag-size2: 40px;
|
||||
--follow-text-size1: 24px;
|
||||
--follow-text-size2: 40px;
|
||||
--follow-text-entry-width: 90%;
|
||||
--focus-color: white;
|
||||
--petname-width-chars: 16ch;
|
||||
--options-main-link-color-hover: #bbb;
|
||||
--rendering: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Bedstead';
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
font-display: block;
|
||||
src: url('./fonts/bedstead.otf') format('opentype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Bedstead';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-display: block;
|
||||
src: url('./fonts/bedstead.otf') format('opentype');
|
||||
}
|
||||
|
||||
body, html {
|
||||
background-image: url("podcast-background.jpg");
|
||||
background-size: cover;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: var(--options-bg-color);
|
||||
color: var(--options-fg-color);
|
||||
|
||||
height: 100%;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
max-width: 100%;
|
||||
min-width: 600px;
|
||||
image-rendering: var(--rendering);
|
||||
}
|
||||
|
||||
a, u {
|
||||
color: var(--options-fg-color);
|
||||
}
|
||||
|
||||
a:visited{
|
||||
color: var(--options-main-visited-color);
|
||||
background: var(--options-link-bg-color);
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: var(--options-main-link-color);
|
||||
background: var(--options-link-bg-color);
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:link:hover {
|
||||
color: var(--options-main-link-color-hover);
|
||||
}
|
||||
|
||||
a:visited:hover {
|
||||
color: var(--options-main-link-color-hover);
|
||||
}
|
||||
|
||||
a:focus {
|
||||
border: 2px solid var(--focus-color);
|
||||
}
|
||||
|
||||
.transparent {
|
||||
color: transparent;
|
||||
background: transparent;
|
||||
font-size: 0px;
|
||||
line-height: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.follow {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background-color: var(--options-bg-color);
|
||||
}
|
||||
|
||||
.followAvatar {
|
||||
margin: 0% 0;
|
||||
}
|
||||
|
||||
.followAvatar img {
|
||||
border-radius: 10%;
|
||||
width: 20%;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.imText {
|
||||
font-size: var(--font-size4);
|
||||
color: var(--options-main-link-color);
|
||||
}
|
||||
|
||||
.pgp {
|
||||
font-size: var(--font-size5);
|
||||
color: var(--options-main-link-color);
|
||||
background: var(--options-link-bg-color);
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: var(--button-background-hover);
|
||||
}
|
||||
|
||||
.options {
|
||||
font-size: var(--font-size);
|
||||
}
|
||||
|
||||
.options img {
|
||||
border-radius: var(--avatar-rounding);
|
||||
background-color: var(--options-bg-color);
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 400px) {
|
||||
textarea {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: var(--font-size4);
|
||||
width: 90%;
|
||||
background-color: var(--text-entry-background);
|
||||
color: var(--text-entry-foreground);
|
||||
}
|
||||
.followText {
|
||||
font-size: var(--follow-text-size1);
|
||||
}
|
||||
input[type=text] {
|
||||
width: var(--follow-text-entry-width);
|
||||
clear: both;
|
||||
max-width: 30%;
|
||||
min-width: var(--petname-width-chars);
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
color: var(--text-entry-foreground);
|
||||
background-color: var(--text-entry-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.button {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-text);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: 24px;
|
||||
width: 10ch;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
margin: 30px;
|
||||
}
|
||||
.buttonIcon {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-text);
|
||||
text-align: center;
|
||||
padding: 10px 65px;
|
||||
font-size: 24px;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.buttonsmall {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-small-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-small-text);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: 24px;
|
||||
width: 7ch;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
margin: 30px;
|
||||
}
|
||||
input[type=checkbox]
|
||||
{
|
||||
-ms-transform: scale(2);
|
||||
-moz-transform: scale(2);
|
||||
-webkit-transform: scale(2);
|
||||
-o-transform: scale(2);
|
||||
transform: scale(2);
|
||||
padding: 10px;
|
||||
margin: 20px 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
textarea {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: var(--font-size);
|
||||
width: 90%;
|
||||
background-color: var(--text-entry-background);
|
||||
color: var(--text-entry-foreground);
|
||||
}
|
||||
.followText {
|
||||
font-size: var(--follow-text-size2);
|
||||
}
|
||||
input[type=text] {
|
||||
width: var(--follow-text-entry-width);
|
||||
clear: both;
|
||||
font-size: var(--font-size);
|
||||
text-align: center;
|
||||
max-width: 50%;
|
||||
min-width: var(--petname-width-chars);
|
||||
color: var(--text-entry-foreground);
|
||||
background-color: var(--text-entry-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.button {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-text);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: var(--font-size);
|
||||
width: 10ch;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
margin: 30px;
|
||||
}
|
||||
.buttonIcon {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-text);
|
||||
text-align: center;
|
||||
padding: 6px 80px;
|
||||
font-size: var(--font-size);
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.buttonsmall {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-small-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-small-text);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: var(--font-size);
|
||||
width: 7ch;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
margin: 30px;
|
||||
}
|
||||
input[type=checkbox]
|
||||
{
|
||||
-ms-transform: scale(4);
|
||||
-moz-transform: scale(4);
|
||||
-webkit-transform: scale(4);
|
||||
-o-transform: scale(4);
|
||||
transform: scale(4);
|
||||
padding: 20px;
|
||||
margin: 30px 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
textarea {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: var(--font-size2);
|
||||
width: 90%;
|
||||
background-color: var(--text-entry-background);
|
||||
color: var(--text-entry-foreground);
|
||||
}
|
||||
.followText {
|
||||
font-size: var(--follow-text-size2);
|
||||
}
|
||||
input[type=text] {
|
||||
width: var(--follow-text-entry-width);
|
||||
clear: both;
|
||||
font-size: var(--font-size2);
|
||||
text-align: center;
|
||||
max-width: 50%;
|
||||
min-width: var(--petname-width-chars);
|
||||
color: var(--text-entry-foreground);
|
||||
background-color: var(--text-entry-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.button {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-text);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: var(--font-size2);
|
||||
width: 10ch;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
margin: 30px;
|
||||
}
|
||||
.buttonIcon {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-text);
|
||||
text-align: center;
|
||||
padding: 6px 80px;
|
||||
font-size: var(--font-size2);
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.buttonsmall {
|
||||
border-radius: 4px;
|
||||
background-color: var(--button-small-background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
color: var(--button-small-text);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: var(--font-size2);
|
||||
width: 7ch;
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
cursor: pointer;
|
||||
margin: 30px;
|
||||
}
|
||||
input[type=checkbox]
|
||||
{
|
||||
-ms-transform: scale(4);
|
||||
-moz-transform: scale(4);
|
||||
-webkit-transform: scale(4);
|
||||
-o-transform: scale(4);
|
||||
transform: scale(4);
|
||||
padding: 20px;
|
||||
margin: 30px 40px;
|
||||
}
|
||||
}
|
24
newswire.py
24
newswire.py
|
@ -445,6 +445,26 @@ def xml_podcast_to_dict(xml_str: str) -> {}:
|
|||
podcast_properties[pod_key] = pod_entry
|
||||
ctr += 1
|
||||
|
||||
# get the image for the podcast, if it exists
|
||||
episode_image_tags = ['<itunes:image']
|
||||
for image_tag in episode_image_tags:
|
||||
if image_tag not in xml_str:
|
||||
continue
|
||||
episode_image = xml_str.split(image_tag)[1]
|
||||
if 'href="' in episode_image:
|
||||
episode_image = episode_image.split('href="')[1]
|
||||
if '"' in episode_image:
|
||||
episode_image = episode_image.split('"')[0]
|
||||
podcast_properties['image'] = episode_image
|
||||
break
|
||||
else:
|
||||
if '>' in episode_image:
|
||||
episode_image = episode_image.split('>')[1]
|
||||
if '<' in episode_image:
|
||||
episode_image = episode_image.split('<')[0]
|
||||
if '://' in episode_image and '.' in episode_image:
|
||||
podcast_properties['image'] = episode_image
|
||||
break
|
||||
return podcast_properties
|
||||
|
||||
|
||||
|
@ -487,9 +507,11 @@ def _xml2str_to_dict(base_dir: str, domain: str, xml_str: str,
|
|||
continue
|
||||
if '</pubDate>' not in rss_item:
|
||||
continue
|
||||
|
||||
title = rss_item.split('<title>')[1]
|
||||
title = _remove_cdata(title.split('</title>')[0])
|
||||
title = remove_html(title)
|
||||
|
||||
description = ''
|
||||
if '<description>' in rss_item and '</description>' in rss_item:
|
||||
description = rss_item.split('<description>')[1]
|
||||
|
@ -500,11 +522,13 @@ def _xml2str_to_dict(base_dir: str, domain: str, xml_str: str,
|
|||
description = rss_item.split('<media:description>')[1]
|
||||
description = description.split('</media:description>')[0]
|
||||
description = remove_html(description)
|
||||
|
||||
link = rss_item.split('<link>')[1]
|
||||
link = link.split('</link>')[0]
|
||||
if '://' not in link:
|
||||
continue
|
||||
item_domain = link.split('://')[1]
|
||||
|
||||
if '/' in item_domain:
|
||||
item_domain = item_domain.split('/')[0]
|
||||
if is_blocked_domain(base_dir, item_domain):
|
||||
|
|
2
tests.py
2
tests.py
|
@ -6439,6 +6439,8 @@ def _test_xml_podcast_dict() -> None:
|
|||
assert podcast_properties.get('funding')
|
||||
assert int(podcast_properties['episode']) == 5
|
||||
assert podcast_properties['funding']['text'] == "Support the show"
|
||||
assert podcast_properties['funding']['url'] == \
|
||||
"https://whoframed.rodger/donate"
|
||||
assert len(podcast_properties['transcripts']) == 3
|
||||
assert len(podcast_properties['valueRecipients']) == 2
|
||||
assert len(podcast_properties['persons']) == 5
|
||||
|
|
|
@ -269,7 +269,8 @@ def _html_newswire(base_dir: str, newswire: {}, nickname: str, moderator: bool,
|
|||
if len(item) > 8:
|
||||
# change the link url to a podcast episode screen
|
||||
podcast_properties = item[8]
|
||||
if podcast_properties.get('persons'):
|
||||
if podcast_properties.get('persons') and \
|
||||
podcast_properties.get('image'):
|
||||
link_url = '/users/' + nickname + '/?podepisode=' + date_str
|
||||
|
||||
html_str += separator_str
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
__filename__ = "webapp_podcast.py"
|
||||
__author__ = "Bob Mottram"
|
||||
__license__ = "AGPL3+"
|
||||
__version__ = "1.2.0"
|
||||
__maintainer__ = "Bob Mottram"
|
||||
__email__ = "bob@libreserver.org"
|
||||
__status__ = "Production"
|
||||
__module_group__ = "Web Interface Columns"
|
||||
|
||||
import os
|
||||
from shutil import copyfile
|
||||
from utils import get_config_param
|
||||
from utils import remove_html
|
||||
from media import path_is_audio
|
||||
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
|
||||
|
||||
|
||||
def _html_podcast_performers(podcast_properties: {}) -> str:
|
||||
"""Returns html for performers of a podcast
|
||||
"""
|
||||
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 += \
|
||||
' <img loading="lazy" src="' + performer_img + \
|
||||
'" alt="" />\n'
|
||||
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
|
||||
"""
|
||||
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':
|
||||
podcast_str += ' <img loading="lazy" srcset="' + image_url + \
|
||||
'" alt="" ' + get_broken_link_substitute() + '/></a>\n'
|
||||
else:
|
||||
podcast_str += ' <img loading="lazy" src="' + image_url + \
|
||||
'" alt="" ' + get_broken_link_substitute() + '/></a>\n'
|
||||
podcast_str += ' </div>\n'
|
||||
|
||||
if path_is_audio(link_url):
|
||||
if '.mp3' in link_url:
|
||||
extension = 'mp3'
|
||||
else:
|
||||
extension = 'ogg'
|
||||
|
||||
podcast_str += _html_podcast_soundbites(link_url, extension,
|
||||
podcast_properties,
|
||||
translate)
|
||||
|
||||
# podcast player widget
|
||||
podcast_str += \
|
||||
'<audio controls>\n' + \
|
||||
'<source src="' + link_url + '" type="audio/' + \
|
||||
extension.replace('.', '') + '">' + \
|
||||
translate['Your browser does not support the audio element.'] + \
|
||||
'</audio>\n'
|
||||
|
||||
podcast_title = remove_html(newswire_item[0])
|
||||
if podcast_title:
|
||||
podcast_str += \
|
||||
'<p><label class="podcast-title">"' + podcast_title + \
|
||||
'</label></p>\n'
|
||||
if newswire_item[4]:
|
||||
podcast_description = remove_html(newswire_item[4])
|
||||
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'
|
||||
|
||||
podcast_str += _html_podcast_performers(podcast_properties)
|
||||
|
||||
podcast_str += ' </center>\n'
|
||||
podcast_str += '</div>\n'
|
||||
|
||||
podcast_str += html_footer()
|
||||
return podcast_str
|
Loading…
Reference in New Issue