mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of gitlab.com:bashrc2/epicyon
commit
3c1866c40b
26
content.py
26
content.py
|
@ -11,9 +11,9 @@ import os
|
||||||
import email.parser
|
import email.parser
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
from utils import valid_hash_tag
|
||||||
from utils import dangerous_svg
|
from utils import dangerous_svg
|
||||||
from utils import remove_domain_port
|
from utils import remove_domain_port
|
||||||
from utils import is_valid_language
|
|
||||||
from utils import get_image_extensions
|
from utils import get_image_extensions
|
||||||
from utils import load_json
|
from utils import load_json
|
||||||
from utils import save_json
|
from utils import save_json
|
||||||
|
@ -33,17 +33,6 @@ MUSIC_SITES = ('soundcloud.com', 'bandcamp.com')
|
||||||
|
|
||||||
MAX_LINK_LENGTH = 40
|
MAX_LINK_LENGTH = 40
|
||||||
|
|
||||||
VALID_HASHTAG_CHARS = \
|
|
||||||
set('0123456789' +
|
|
||||||
'abcdefghijklmnopqrstuvwxyz' +
|
|
||||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
|
|
||||||
'¡¿ÄäÀàÁáÂâÃãÅåǍǎĄąĂăÆæĀā' +
|
|
||||||
'ÇçĆćĈĉČčĎđĐďðÈèÉéÊêËëĚěĘęĖėĒē' +
|
|
||||||
'ĜĝĢģĞğĤĥÌìÍíÎîÏïıĪīĮįĴĵĶķ' +
|
|
||||||
'ĹĺĻļŁłĽľĿŀÑñŃńŇňŅņÖöÒòÓóÔôÕõŐőØøŒœ' +
|
|
||||||
'ŔŕŘřẞߌśŜŝŞşŠšȘșŤťŢţÞþȚțÜüÙùÚúÛûŰűŨũŲųŮůŪū' +
|
|
||||||
'ŴŵÝýŸÿŶŷŹźŽžŻż')
|
|
||||||
|
|
||||||
REMOVE_MARKUP = (
|
REMOVE_MARKUP = (
|
||||||
'b', 'i', 'ul', 'ol', 'li', 'em', 'strong',
|
'b', 'i', 'ul', 'ol', 'li', 'em', 'strong',
|
||||||
'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5'
|
'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5'
|
||||||
|
@ -497,19 +486,6 @@ def add_web_links(content: str) -> str:
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def valid_hash_tag(hashtag: str) -> bool:
|
|
||||||
"""Returns true if the give hashtag contains valid characters
|
|
||||||
"""
|
|
||||||
# long hashtags are not valid
|
|
||||||
if len(hashtag) >= 32:
|
|
||||||
return False
|
|
||||||
if set(hashtag).issubset(VALID_HASHTAG_CHARS):
|
|
||||||
return True
|
|
||||||
if is_valid_language(hashtag):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _add_hash_tags(word_str: str, http_prefix: str, domain: str,
|
def _add_hash_tags(word_str: str, http_prefix: str, domain: str,
|
||||||
replace_hashtags: {}, post_hashtags: {}) -> bool:
|
replace_hashtags: {}, post_hashtags: {}) -> bool:
|
||||||
"""Detects hashtags and adds them to the replacements dict
|
"""Detects hashtags and adds them to the replacements dict
|
||||||
|
|
|
@ -71,6 +71,10 @@ body, html {
|
||||||
image-rendering: var(--rendering);
|
image-rendering: var(--rendering);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audio {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
a, u {
|
a, u {
|
||||||
color: var(--options-fg-color);
|
color: var(--options-fg-color);
|
||||||
}
|
}
|
||||||
|
|
2
inbox.py
2
inbox.py
|
@ -61,6 +61,7 @@ from utils import undo_reaction_collection_entry
|
||||||
from utils import has_group_type
|
from utils import has_group_type
|
||||||
from utils import local_actor_url
|
from utils import local_actor_url
|
||||||
from utils import has_object_stringType
|
from utils import has_object_stringType
|
||||||
|
from utils import valid_hash_tag
|
||||||
from categories import get_hashtag_categories
|
from categories import get_hashtag_categories
|
||||||
from categories import set_hashtag_category
|
from categories import set_hashtag_category
|
||||||
from httpsig import get_digest_algorithm_from_headers
|
from httpsig import get_digest_algorithm_from_headers
|
||||||
|
@ -119,7 +120,6 @@ from announce import is_self_announce
|
||||||
from announce import create_announce
|
from announce import create_announce
|
||||||
from notifyOnPost import notify_when_person_posts
|
from notifyOnPost import notify_when_person_posts
|
||||||
from conversation import update_conversation
|
from conversation import update_conversation
|
||||||
from content import valid_hash_tag
|
|
||||||
from webapp_hashtagswarm import html_hash_tag_swarm
|
from webapp_hashtagswarm import html_hash_tag_swarm
|
||||||
from person import valid_sending_actor
|
from person import valid_sending_actor
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ from newswire import get_dict_from_newswire
|
||||||
# from posts import send_signed_json
|
# from posts import send_signed_json
|
||||||
from posts import create_news_post
|
from posts import create_news_post
|
||||||
from posts import archive_posts_for_person
|
from posts import archive_posts_for_person
|
||||||
from content import valid_hash_tag
|
from utils import valid_hash_tag
|
||||||
from utils import get_base_content_from_post
|
from utils import get_base_content_from_post
|
||||||
from utils import remove_html
|
from utils import remove_html
|
||||||
from utils import get_full_domain
|
from utils import get_full_domain
|
||||||
|
|
99
newswire.py
99
newswire.py
|
@ -18,6 +18,7 @@ from datetime import timezone
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from utils import valid_post_date
|
from utils import valid_post_date
|
||||||
from categories import set_hashtag_category
|
from categories import set_hashtag_category
|
||||||
|
from utils import valid_hash_tag
|
||||||
from utils import dangerous_svg
|
from utils import dangerous_svg
|
||||||
from utils import get_fav_filename_from_url
|
from utils import get_fav_filename_from_url
|
||||||
from utils import get_base_content_from_post
|
from utils import get_base_content_from_post
|
||||||
|
@ -225,6 +226,10 @@ def _add_newswire_dict_entry(base_dir: str, domain: str,
|
||||||
# extract hashtags from the text of the feed post
|
# extract hashtags from the text of the feed post
|
||||||
post_tags = get_newswire_tags(all_text, max_tags)
|
post_tags = get_newswire_tags(all_text, max_tags)
|
||||||
|
|
||||||
|
# Include tags from podcast categories
|
||||||
|
if podcast_properties:
|
||||||
|
post_tags += podcast_properties['categories']
|
||||||
|
|
||||||
# combine the tags into a single list
|
# combine the tags into a single list
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
if tag in post_tags:
|
if tag in post_tags:
|
||||||
|
@ -384,13 +389,59 @@ def _xml2str_to_hashtag_categories(base_dir: str, xml_str: str,
|
||||||
False, force)
|
False, force)
|
||||||
|
|
||||||
|
|
||||||
def xml_podcast_to_dict(xml_str: str) -> {}:
|
def _get_podcast_categories(xml_item: str, xml_str: str) -> str:
|
||||||
|
""" get podcast categories if they exist. These can be turned into hashtags
|
||||||
|
"""
|
||||||
|
podcast_categories = []
|
||||||
|
episode_category_tags = ['<itunes:category', '<category']
|
||||||
|
|
||||||
|
for category_tag in episode_category_tags:
|
||||||
|
item_str = xml_item
|
||||||
|
if category_tag not in xml_item:
|
||||||
|
if category_tag not in xml_str:
|
||||||
|
continue
|
||||||
|
item_str = xml_str
|
||||||
|
|
||||||
|
category_list = item_str.split(category_tag)
|
||||||
|
first_category = True
|
||||||
|
for episode_category in category_list:
|
||||||
|
if first_category:
|
||||||
|
first_category = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
if 'text="' in episode_category:
|
||||||
|
episode_category = episode_category.split('text="')[1]
|
||||||
|
if '"' in episode_category:
|
||||||
|
episode_category = episode_category.split('"')[0]
|
||||||
|
episode_category = \
|
||||||
|
episode_category.lower().replace(' ', '')
|
||||||
|
episode_category = episode_category.replace('#', '')
|
||||||
|
if episode_category not in podcast_categories:
|
||||||
|
if valid_hash_tag(episode_category):
|
||||||
|
podcast_categories.append('#' + episode_category)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '>' in episode_category:
|
||||||
|
episode_category = episode_category.split('>')[1]
|
||||||
|
if '<' in episode_category:
|
||||||
|
episode_category = episode_category.split('<')[0]
|
||||||
|
episode_category = \
|
||||||
|
episode_category.lower().replace(' ', '')
|
||||||
|
episode_category = episode_category.replace('#', '')
|
||||||
|
if episode_category not in podcast_categories:
|
||||||
|
if valid_hash_tag(episode_category):
|
||||||
|
podcast_categories.append('#' + episode_category)
|
||||||
|
|
||||||
|
return podcast_categories
|
||||||
|
|
||||||
|
|
||||||
|
def xml_podcast_to_dict(xml_item: str, xml_str: str) -> {}:
|
||||||
"""podcasting extensions for RSS feeds
|
"""podcasting extensions for RSS feeds
|
||||||
See https://github.com/Podcastindex-org/podcast-namespace/
|
See https://github.com/Podcastindex-org/podcast-namespace/
|
||||||
blob/main/docs/1.0.md
|
blob/main/docs/1.0.md
|
||||||
"""
|
"""
|
||||||
if '<podcast:' not in xml_str:
|
if '<podcast:' not in xml_item:
|
||||||
if '<itunes:' not in xml_str:
|
if '<itunes:' not in xml_item:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
podcast_properties = {
|
podcast_properties = {
|
||||||
|
@ -402,7 +453,7 @@ def xml_podcast_to_dict(xml_str: str) -> {}:
|
||||||
"trailers": []
|
"trailers": []
|
||||||
}
|
}
|
||||||
|
|
||||||
pod_lines = xml_str.split('<podcast:')
|
pod_lines = xml_item.split('<podcast:')
|
||||||
ctr = 0
|
ctr = 0
|
||||||
for pod_line in pod_lines:
|
for pod_line in pod_lines:
|
||||||
if ctr == 0 or '>' not in pod_line:
|
if ctr == 0 or '>' not in pod_line:
|
||||||
|
@ -453,9 +504,13 @@ def xml_podcast_to_dict(xml_str: str) -> {}:
|
||||||
podcast_episode_image = None
|
podcast_episode_image = None
|
||||||
episode_image_tags = ['<itunes:image']
|
episode_image_tags = ['<itunes:image']
|
||||||
for image_tag in episode_image_tags:
|
for image_tag in episode_image_tags:
|
||||||
if image_tag not in xml_str:
|
item_str = xml_item
|
||||||
continue
|
if image_tag not in xml_item:
|
||||||
episode_image = xml_str.split(image_tag)[1]
|
if image_tag not in xml_str:
|
||||||
|
continue
|
||||||
|
item_str = xml_str
|
||||||
|
|
||||||
|
episode_image = item_str.split(image_tag)[1]
|
||||||
if 'href="' in episode_image:
|
if 'href="' in episode_image:
|
||||||
episode_image = episode_image.split('href="')[1]
|
episode_image = episode_image.split('href="')[1]
|
||||||
if '"' in episode_image:
|
if '"' in episode_image:
|
||||||
|
@ -471,17 +526,21 @@ def xml_podcast_to_dict(xml_str: str) -> {}:
|
||||||
podcast_episode_image = episode_image
|
podcast_episode_image = episode_image
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# get categories if they exist. These can be turned into hashtags
|
||||||
|
podcast_categories = _get_podcast_categories(xml_item, xml_str)
|
||||||
|
|
||||||
if podcast_episode_image:
|
if podcast_episode_image:
|
||||||
podcast_properties['image'] = podcast_episode_image
|
podcast_properties['image'] = podcast_episode_image
|
||||||
|
podcast_properties['categories'] = podcast_categories
|
||||||
|
|
||||||
if '<itunes:explicit>Y' in xml_str or \
|
if '<itunes:explicit>Y' in xml_item or \
|
||||||
'<itunes:explicit>T' in xml_str or \
|
'<itunes:explicit>T' in xml_item or \
|
||||||
'<itunes:explicit>1' in xml_str:
|
'<itunes:explicit>1' in xml_item:
|
||||||
podcast_properties['explicit'] = True
|
podcast_properties['explicit'] = True
|
||||||
else:
|
else:
|
||||||
podcast_properties['explicit'] = False
|
podcast_properties['explicit'] = False
|
||||||
else:
|
else:
|
||||||
if '<podcast:' not in xml_str:
|
if '<podcast:' not in xml_item:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return podcast_properties
|
return podcast_properties
|
||||||
|
@ -537,7 +596,11 @@ def _xml2str_to_dict(base_dir: str, domain: str, xml_str: str,
|
||||||
rss_items = xml_str.split('<item>')
|
rss_items = xml_str.split('<item>')
|
||||||
post_ctr = 0
|
post_ctr = 0
|
||||||
max_bytes = max_feed_item_size_kb * 1024
|
max_bytes = max_feed_item_size_kb * 1024
|
||||||
|
first_item = True
|
||||||
for rss_item in rss_items:
|
for rss_item in rss_items:
|
||||||
|
if first_item:
|
||||||
|
first_item = False
|
||||||
|
continue
|
||||||
if not rss_item:
|
if not rss_item:
|
||||||
continue
|
continue
|
||||||
if len(rss_item) > max_bytes:
|
if len(rss_item) > max_bytes:
|
||||||
|
@ -589,7 +652,7 @@ def _xml2str_to_dict(base_dir: str, domain: str, xml_str: str,
|
||||||
if _valid_feed_date(pub_date_str):
|
if _valid_feed_date(pub_date_str):
|
||||||
post_filename = ''
|
post_filename = ''
|
||||||
votes_status = []
|
votes_status = []
|
||||||
podcast_properties = xml_podcast_to_dict(rss_item)
|
podcast_properties = xml_podcast_to_dict(rss_item, xml_str)
|
||||||
if podcast_properties:
|
if podcast_properties:
|
||||||
podcast_properties['linkMimeType'] = link_mime_type
|
podcast_properties['linkMimeType'] = link_mime_type
|
||||||
_add_newswire_dict_entry(base_dir, domain,
|
_add_newswire_dict_entry(base_dir, domain,
|
||||||
|
@ -630,7 +693,11 @@ def _xml1str_to_dict(base_dir: str, domain: str, xml_str: str,
|
||||||
rss_items = xml_str.split(item_str)
|
rss_items = xml_str.split(item_str)
|
||||||
post_ctr = 0
|
post_ctr = 0
|
||||||
max_bytes = max_feed_item_size_kb * 1024
|
max_bytes = max_feed_item_size_kb * 1024
|
||||||
|
first_item = True
|
||||||
for rss_item in rss_items:
|
for rss_item in rss_items:
|
||||||
|
if first_item:
|
||||||
|
first_item = False
|
||||||
|
continue
|
||||||
if not rss_item:
|
if not rss_item:
|
||||||
continue
|
continue
|
||||||
if len(rss_item) > max_bytes:
|
if len(rss_item) > max_bytes:
|
||||||
|
@ -682,7 +749,7 @@ def _xml1str_to_dict(base_dir: str, domain: str, xml_str: str,
|
||||||
if _valid_feed_date(pub_date_str):
|
if _valid_feed_date(pub_date_str):
|
||||||
post_filename = ''
|
post_filename = ''
|
||||||
votes_status = []
|
votes_status = []
|
||||||
podcast_properties = xml_podcast_to_dict(rss_item)
|
podcast_properties = xml_podcast_to_dict(rss_item, xml_str)
|
||||||
if podcast_properties:
|
if podcast_properties:
|
||||||
podcast_properties['linkMimeType'] = link_mime_type
|
podcast_properties['linkMimeType'] = link_mime_type
|
||||||
_add_newswire_dict_entry(base_dir, domain,
|
_add_newswire_dict_entry(base_dir, domain,
|
||||||
|
@ -713,7 +780,11 @@ def _atom_feed_to_dict(base_dir: str, domain: str, xml_str: str,
|
||||||
atom_items = xml_str.split('<entry>')
|
atom_items = xml_str.split('<entry>')
|
||||||
post_ctr = 0
|
post_ctr = 0
|
||||||
max_bytes = max_feed_item_size_kb * 1024
|
max_bytes = max_feed_item_size_kb * 1024
|
||||||
|
first_item = True
|
||||||
for atom_item in atom_items:
|
for atom_item in atom_items:
|
||||||
|
if first_item:
|
||||||
|
first_item = False
|
||||||
|
continue
|
||||||
if not atom_item:
|
if not atom_item:
|
||||||
continue
|
continue
|
||||||
if len(atom_item) > max_bytes:
|
if len(atom_item) > max_bytes:
|
||||||
|
@ -763,7 +834,7 @@ def _atom_feed_to_dict(base_dir: str, domain: str, xml_str: str,
|
||||||
if _valid_feed_date(pub_date_str):
|
if _valid_feed_date(pub_date_str):
|
||||||
post_filename = ''
|
post_filename = ''
|
||||||
votes_status = []
|
votes_status = []
|
||||||
podcast_properties = xml_podcast_to_dict(atom_item)
|
podcast_properties = xml_podcast_to_dict(atom_item, xml_str)
|
||||||
if podcast_properties:
|
if podcast_properties:
|
||||||
podcast_properties['linkMimeType'] = link_mime_type
|
podcast_properties['linkMimeType'] = link_mime_type
|
||||||
_add_newswire_dict_entry(base_dir, domain,
|
_add_newswire_dict_entry(base_dir, domain,
|
||||||
|
|
4
tests.py
4
tests.py
|
@ -82,6 +82,7 @@ from utils import copytree
|
||||||
from utils import load_json
|
from utils import load_json
|
||||||
from utils import save_json
|
from utils import save_json
|
||||||
from utils import get_status_number
|
from utils import get_status_number
|
||||||
|
from utils import valid_hash_tag
|
||||||
from utils import get_followers_of_person
|
from utils import get_followers_of_person
|
||||||
from utils import remove_html
|
from utils import remove_html
|
||||||
from utils import dangerous_markup
|
from utils import dangerous_markup
|
||||||
|
@ -132,7 +133,6 @@ from content import get_price_from_string
|
||||||
from content import limit_repeated_words
|
from content import limit_repeated_words
|
||||||
from content import switch_words
|
from content import switch_words
|
||||||
from content import extract_text_fields_in_post
|
from content import extract_text_fields_in_post
|
||||||
from content import valid_hash_tag
|
|
||||||
from content import html_replace_email_quote
|
from content import html_replace_email_quote
|
||||||
from content import html_replace_quote_marks
|
from content import html_replace_quote_marks
|
||||||
from content import dangerous_css
|
from content import dangerous_css
|
||||||
|
@ -6428,7 +6428,7 @@ def _test_xml_podcast_dict() -> None:
|
||||||
'address="someaddress2" split="99" />\n' + \
|
'address="someaddress2" split="99" />\n' + \
|
||||||
'</podcast:value>\n' + \
|
'</podcast:value>\n' + \
|
||||||
'</rss>'
|
'</rss>'
|
||||||
podcast_properties = xml_podcast_to_dict(xml_str)
|
podcast_properties = xml_podcast_to_dict(xml_str, xml_str)
|
||||||
assert podcast_properties
|
assert podcast_properties
|
||||||
# pprint(podcast_properties)
|
# pprint(podcast_properties)
|
||||||
assert podcast_properties.get('valueRecipients')
|
assert podcast_properties.get('valueRecipients')
|
||||||
|
|
28
utils.py
28
utils.py
|
@ -20,6 +20,17 @@ from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from followingCalendar import add_person_to_calendar
|
from followingCalendar import add_person_to_calendar
|
||||||
|
|
||||||
|
VALID_HASHTAG_CHARS = \
|
||||||
|
set('0123456789' +
|
||||||
|
'abcdefghijklmnopqrstuvwxyz' +
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
|
||||||
|
'¡¿ÄäÀàÁáÂâÃãÅåǍǎĄąĂăÆæĀā' +
|
||||||
|
'ÇçĆćĈĉČčĎđĐďðÈèÉéÊêËëĚěĘęĖėĒē' +
|
||||||
|
'ĜĝĢģĞğĤĥÌìÍíÎîÏïıĪīĮįĴĵĶķ' +
|
||||||
|
'ĹĺĻļŁłĽľĿŀÑñŃńŇňŅņÖöÒòÓóÔôÕõŐőØøŒœ' +
|
||||||
|
'ŔŕŘřẞߌśŜŝŞşŠšȘșŤťŢţÞþȚțÜüÙùÚúÛûŰűŨũŲųŮůŪū' +
|
||||||
|
'ŴŵÝýŸÿŶŷŹźŽžŻż')
|
||||||
|
|
||||||
# posts containing these strings will always get screened out,
|
# posts containing these strings will always get screened out,
|
||||||
# both incoming and outgoing.
|
# both incoming and outgoing.
|
||||||
# Could include dubious clacks or admin dogwhistles
|
# Could include dubious clacks or admin dogwhistles
|
||||||
|
@ -1798,7 +1809,7 @@ def delete_post(base_dir: str, http_prefix: str,
|
||||||
str(post_filename))
|
str(post_filename))
|
||||||
|
|
||||||
|
|
||||||
def is_valid_language(text: str) -> bool:
|
def _is_valid_language(text: str) -> bool:
|
||||||
"""Returns true if the given text contains a valid
|
"""Returns true if the given text contains a valid
|
||||||
natural language string
|
natural language string
|
||||||
"""
|
"""
|
||||||
|
@ -1900,7 +1911,7 @@ def valid_nickname(domain: str, nickname: str) -> bool:
|
||||||
return False
|
return False
|
||||||
if len(nickname) > 30:
|
if len(nickname) > 30:
|
||||||
return False
|
return False
|
||||||
if not is_valid_language(nickname):
|
if not _is_valid_language(nickname):
|
||||||
return False
|
return False
|
||||||
forbidden_chars = ('.', ' ', '/', '?', ':', ';', '@', '#', '!')
|
forbidden_chars = ('.', ' ', '/', '?', ':', ';', '@', '#', '!')
|
||||||
for char in forbidden_chars:
|
for char in forbidden_chars:
|
||||||
|
@ -3288,3 +3299,16 @@ def get_fav_filename_from_url(base_dir: str, favicon_url: str) -> str:
|
||||||
if '/favicon.' in favicon_url:
|
if '/favicon.' in favicon_url:
|
||||||
favicon_url = favicon_url.replace('/favicon.', '.')
|
favicon_url = favicon_url.replace('/favicon.', '.')
|
||||||
return base_dir + '/favicons/' + favicon_url.replace('/', '-')
|
return base_dir + '/favicons/' + favicon_url.replace('/', '-')
|
||||||
|
|
||||||
|
|
||||||
|
def valid_hash_tag(hashtag: str) -> bool:
|
||||||
|
"""Returns true if the give hashtag contains valid characters
|
||||||
|
"""
|
||||||
|
# long hashtags are not valid
|
||||||
|
if len(hashtag) >= 32:
|
||||||
|
return False
|
||||||
|
if set(hashtag).issubset(VALID_HASHTAG_CHARS):
|
||||||
|
return True
|
||||||
|
if _is_valid_language(hashtag):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
|
@ -184,6 +184,17 @@ def html_podcast_episode(css_cache: {}, translate: {},
|
||||||
audio_extension.replace('.', '') + '">' + \
|
audio_extension.replace('.', '') + '">' + \
|
||||||
translate['Your browser does not support the audio element.'] + \
|
translate['Your browser does not support the audio element.'] + \
|
||||||
'\n </audio>\n'
|
'\n </audio>\n'
|
||||||
|
elif podcast_properties.get('linkMimeType'):
|
||||||
|
if 'video' in podcast_properties['linkMimeType']:
|
||||||
|
video_mime_type = podcast_properties['linkMimeType']
|
||||||
|
video_msg = 'Your browser does not support the video element.'
|
||||||
|
podcast_str += \
|
||||||
|
' <figure id="videoContainer" ' + \
|
||||||
|
'data-fullscreen="false">\n' + \
|
||||||
|
' <video id="video" controls preload="metadata">\n' + \
|
||||||
|
'<source src="' + link_url + '" ' + \
|
||||||
|
'type="' + video_mime_type + '">' + \
|
||||||
|
translate[video_msg] + '</video>\n </figure>\n'
|
||||||
|
|
||||||
podcast_title = \
|
podcast_title = \
|
||||||
remove_html(html.unescape(urllib.parse.unquote_plus(newswire_item[0])))
|
remove_html(html.unescape(urllib.parse.unquote_plus(newswire_item[0])))
|
||||||
|
@ -210,6 +221,14 @@ def html_podcast_episode(css_cache: {}, translate: {},
|
||||||
'"><button class="donateButton">' + translate['Donate'] + \
|
'"><button class="donateButton">' + translate['Donate'] + \
|
||||||
'</button></a></p>\n'
|
'</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'
|
||||||
|
|
||||||
podcast_str += _html_podcast_performers(podcast_properties)
|
podcast_str += _html_podcast_performers(podcast_properties)
|
||||||
|
|
||||||
podcast_str += ' </center>\n'
|
podcast_str += ' </center>\n'
|
||||||
|
|
Loading…
Reference in New Issue