Merge branch 'main' of gitlab.com:bashrc2/epicyon
85
daemon.py
|
|
@ -617,6 +617,17 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _request_ssml(self) -> bool:
|
||||||
|
"""Should a ssml response be given?
|
||||||
|
"""
|
||||||
|
if not self.headers.get('Accept'):
|
||||||
|
return False
|
||||||
|
accept_str = self.headers['Accept']
|
||||||
|
if 'application/ssml' in accept_str:
|
||||||
|
if 'text/html' not in accept_str:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _request_http(self) -> bool:
|
def _request_http(self) -> bool:
|
||||||
"""Should a http response be given?
|
"""Should a http response be given?
|
||||||
"""
|
"""
|
||||||
|
|
@ -11025,7 +11036,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._redirect_headers(actor_absolute, cookie, calling_domain)
|
self._redirect_headers(actor_absolute, cookie, calling_domain)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _show_individual_at_post(self, authorized: bool,
|
def _show_individual_at_post(self, ssml_getreq: bool, authorized: bool,
|
||||||
calling_domain: str, referer_domain: str,
|
calling_domain: str, referer_domain: str,
|
||||||
path: str,
|
path: str,
|
||||||
base_dir: str, http_prefix: str,
|
base_dir: str, http_prefix: str,
|
||||||
|
|
@ -11073,6 +11084,35 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if len(status_number) <= 10 or not status_number.isdigit():
|
if len(status_number) <= 10 or not status_number.isdigit():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if ssml_getreq:
|
||||||
|
ssml_filename = \
|
||||||
|
acct_dir(base_dir, nickname, domain) + '/outbox/' + \
|
||||||
|
http_prefix + ':##' + domain_full + '#users#' + nickname + \
|
||||||
|
'#statuses#' + status_number + '.ssml'
|
||||||
|
if not os.path.isfile(ssml_filename):
|
||||||
|
ssml_filename = \
|
||||||
|
acct_dir(base_dir, nickname, domain) + '/postcache/' + \
|
||||||
|
http_prefix + ':##' + domain_full + '#users#' + \
|
||||||
|
nickname + '#statuses#' + status_number + '.ssml'
|
||||||
|
if not os.path.isfile(ssml_filename):
|
||||||
|
self._404()
|
||||||
|
return True
|
||||||
|
ssml_str = None
|
||||||
|
try:
|
||||||
|
with open(ssml_filename, 'r') as fp_ssml:
|
||||||
|
ssml_str = fp_ssml.read()
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if ssml_str:
|
||||||
|
msg = ssml_str.encode('utf-8')
|
||||||
|
msglen = len(msg)
|
||||||
|
self._set_headers('application/ssml+xml', msglen,
|
||||||
|
cookie, calling_domain, False)
|
||||||
|
self._write(msg)
|
||||||
|
return True
|
||||||
|
self._404()
|
||||||
|
return True
|
||||||
|
|
||||||
post_filename = \
|
post_filename = \
|
||||||
acct_dir(base_dir, nickname, domain) + '/outbox/' + \
|
acct_dir(base_dir, nickname, domain) + '/outbox/' + \
|
||||||
http_prefix + ':##' + domain_full + '#users#' + nickname + \
|
http_prefix + ':##' + domain_full + '#users#' + nickname + \
|
||||||
|
|
@ -11346,7 +11386,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.getreq_busy = False
|
self.server.getreq_busy = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _show_individual_post(self, authorized: bool,
|
def _show_individual_post(self, ssml_getreq: bool, authorized: bool,
|
||||||
calling_domain: str, referer_domain: str,
|
calling_domain: str, referer_domain: str,
|
||||||
path: str,
|
path: str,
|
||||||
base_dir: str, http_prefix: str,
|
base_dir: str, http_prefix: str,
|
||||||
|
|
@ -11388,6 +11428,35 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if len(status_number) <= 10 or (not status_number.isdigit()):
|
if len(status_number) <= 10 or (not status_number.isdigit()):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if ssml_getreq:
|
||||||
|
ssml_filename = \
|
||||||
|
acct_dir(base_dir, nickname, domain) + '/outbox/' + \
|
||||||
|
http_prefix + ':##' + domain_full + '#users#' + nickname + \
|
||||||
|
'#statuses#' + status_number + '.ssml'
|
||||||
|
if not os.path.isfile(ssml_filename):
|
||||||
|
ssml_filename = \
|
||||||
|
acct_dir(base_dir, nickname, domain) + '/postcache/' + \
|
||||||
|
http_prefix + ':##' + domain_full + '#users#' + \
|
||||||
|
nickname + '#statuses#' + status_number + '.ssml'
|
||||||
|
if not os.path.isfile(ssml_filename):
|
||||||
|
self._404()
|
||||||
|
return True
|
||||||
|
ssml_str = None
|
||||||
|
try:
|
||||||
|
with open(ssml_filename, 'r') as fp_ssml:
|
||||||
|
ssml_str = fp_ssml.read()
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if ssml_str:
|
||||||
|
msg = ssml_str.encode('utf-8')
|
||||||
|
msglen = len(msg)
|
||||||
|
self._set_headers('application/ssml+xml', msglen,
|
||||||
|
cookie, calling_domain, False)
|
||||||
|
self._write(msg)
|
||||||
|
return True
|
||||||
|
self._404()
|
||||||
|
return True
|
||||||
|
|
||||||
post_filename = \
|
post_filename = \
|
||||||
acct_dir(base_dir, nickname, domain) + '/outbox/' + \
|
acct_dir(base_dir, nickname, domain) + '/outbox/' + \
|
||||||
http_prefix + ':##' + domain_full + '#users#' + nickname + \
|
http_prefix + ':##' + domain_full + '#users#' + nickname + \
|
||||||
|
|
@ -15387,12 +15456,15 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
'_GET', 'create session',
|
'_GET', 'create session',
|
||||||
self.server.debug)
|
self.server.debug)
|
||||||
|
|
||||||
# is this a html request?
|
# is this a html/ssml/icalendar request?
|
||||||
html_getreq = False
|
html_getreq = False
|
||||||
|
ssml_getreq = False
|
||||||
icalendar_getreq = False
|
icalendar_getreq = False
|
||||||
if self._has_accept(calling_domain):
|
if self._has_accept(calling_domain):
|
||||||
if self._request_http():
|
if self._request_http():
|
||||||
html_getreq = True
|
html_getreq = True
|
||||||
|
elif self._request_ssml():
|
||||||
|
ssml_getreq = True
|
||||||
elif self._request_icalendar():
|
elif self._request_icalendar():
|
||||||
icalendar_getreq = True
|
icalendar_getreq = True
|
||||||
else:
|
else:
|
||||||
|
|
@ -16184,7 +16256,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.translate,
|
self.server.translate,
|
||||||
access_keys,
|
access_keys,
|
||||||
self.server.access_keys,
|
self.server.access_keys,
|
||||||
self.server.default_timeline)
|
self.server.default_timeline,
|
||||||
|
self.server.theme_name)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._login_headers('text/html', msglen, calling_domain)
|
self._login_headers('text/html', msglen, calling_domain)
|
||||||
|
|
@ -17628,7 +17701,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.debug)
|
self.server.debug)
|
||||||
|
|
||||||
# get an individual post from the path /@nickname/statusnumber
|
# get an individual post from the path /@nickname/statusnumber
|
||||||
if self._show_individual_at_post(authorized,
|
if self._show_individual_at_post(ssml_getreq, authorized,
|
||||||
calling_domain, referer_domain,
|
calling_domain, referer_domain,
|
||||||
self.path,
|
self.path,
|
||||||
self.server.base_dir,
|
self.server.base_dir,
|
||||||
|
|
@ -17773,7 +17846,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
# get an individual post from the path
|
# get an individual post from the path
|
||||||
# /users/nickname/statuses/number
|
# /users/nickname/statuses/number
|
||||||
if '/statuses/' in self.path and users_in_path:
|
if '/statuses/' in self.path and users_in_path:
|
||||||
if self._show_individual_post(authorized,
|
if self._show_individual_post(ssml_getreq, authorized,
|
||||||
calling_domain, referer_domain,
|
calling_domain, referer_domain,
|
||||||
self.path,
|
self.path,
|
||||||
self.server.base_dir,
|
self.server.base_dir,
|
||||||
|
|
|
||||||
38
epicyon.py
|
|
@ -46,6 +46,7 @@ from session import create_session
|
||||||
from session import get_json
|
from session import get_json
|
||||||
from session import get_vcard
|
from session import get_vcard
|
||||||
from session import download_html
|
from session import download_html
|
||||||
|
from session import download_ssml
|
||||||
from newswire import get_rss
|
from newswire import get_rss
|
||||||
from filters import add_filter
|
from filters import add_filter
|
||||||
from filters import remove_filter
|
from filters import remove_filter
|
||||||
|
|
@ -341,6 +342,8 @@ parser.add_argument('--xmlvcard', dest='xmlvcard', type=str, default=None,
|
||||||
'activitypub actor url')
|
'activitypub actor url')
|
||||||
parser.add_argument('--json', dest='json', type=str, default=None,
|
parser.add_argument('--json', dest='json', type=str, default=None,
|
||||||
help='Show the json for a given activitypub url')
|
help='Show the json for a given activitypub url')
|
||||||
|
parser.add_argument('--ssml', dest='ssml', type=str, default=None,
|
||||||
|
help='Show the SSML for a given activitypub url')
|
||||||
parser.add_argument('--htmlpost', dest='htmlpost', type=str, default=None,
|
parser.add_argument('--htmlpost', dest='htmlpost', type=str, default=None,
|
||||||
help='Show the html for a given activitypub url')
|
help='Show the html for a given activitypub url')
|
||||||
parser.add_argument('--rss', dest='rss', type=str, default=None,
|
parser.add_argument('--rss', dest='rss', type=str, default=None,
|
||||||
|
|
@ -1040,6 +1043,31 @@ if args.json:
|
||||||
pprint(test_json)
|
pprint(test_json)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
if args.ssml:
|
||||||
|
session = create_session(None)
|
||||||
|
profile_str = 'https://www.w3.org/ns/activitystreams'
|
||||||
|
as_header = {
|
||||||
|
'Accept': 'application/ssml+xml; profile="' + profile_str + '"'
|
||||||
|
}
|
||||||
|
if not args.domain:
|
||||||
|
args.domain = get_config_param(base_dir, 'domain')
|
||||||
|
domain = ''
|
||||||
|
if args.domain:
|
||||||
|
domain = args.domain
|
||||||
|
signing_priv_key_pem = get_instance_actor_key(base_dir, domain)
|
||||||
|
if debug:
|
||||||
|
print('base_dir: ' + str(base_dir))
|
||||||
|
if signing_priv_key_pem:
|
||||||
|
print('Obtained instance actor signing key')
|
||||||
|
else:
|
||||||
|
print('Did not obtain instance actor key for ' + domain)
|
||||||
|
test_ssml = download_ssml(signing_priv_key_pem, session, args.ssml,
|
||||||
|
as_header, None, debug, __version__,
|
||||||
|
http_prefix, domain)
|
||||||
|
if test_ssml:
|
||||||
|
print(str(test_ssml))
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
if args.vcard:
|
if args.vcard:
|
||||||
session = create_session(None)
|
session = create_session(None)
|
||||||
if not args.domain:
|
if not args.domain:
|
||||||
|
|
@ -1084,11 +1112,11 @@ if args.htmlpost:
|
||||||
print('Obtained instance actor signing key')
|
print('Obtained instance actor signing key')
|
||||||
else:
|
else:
|
||||||
print('Did not obtain instance actor key for ' + domain)
|
print('Did not obtain instance actor key for ' + domain)
|
||||||
testHtml = download_html(signing_priv_key_pem, session, args.htmlpost,
|
test_html = download_html(signing_priv_key_pem, session, args.htmlpost,
|
||||||
as_header, None, debug, __version__,
|
as_header, None, debug, __version__,
|
||||||
http_prefix, domain)
|
http_prefix, domain)
|
||||||
if testHtml:
|
if test_html:
|
||||||
print(testHtml)
|
print(test_html)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# create cache for actors
|
# create cache for actors
|
||||||
|
|
|
||||||
6
inbox.py
|
|
@ -2282,7 +2282,8 @@ def _receive_announce(recent_posts_cache: {},
|
||||||
nickname, domain, domain_full,
|
nickname, domain, domain_full,
|
||||||
post_json_object, person_cache,
|
post_json_object, person_cache,
|
||||||
translate, lookup_actor,
|
translate, lookup_actor,
|
||||||
theme_name)
|
theme_name, system_language,
|
||||||
|
'inbox')
|
||||||
try:
|
try:
|
||||||
with open(post_filename + '.tts', 'w+') as ttsfile:
|
with open(post_filename + '.tts', 'w+') as ttsfile:
|
||||||
ttsfile.write('\n')
|
ttsfile.write('\n')
|
||||||
|
|
@ -4120,7 +4121,8 @@ def _inbox_after_initial(server, inbox_start_time,
|
||||||
update_speaker(base_dir, http_prefix,
|
update_speaker(base_dir, http_prefix,
|
||||||
nickname, domain, domain_full,
|
nickname, domain, domain_full,
|
||||||
post_json_object, person_cache,
|
post_json_object, person_cache,
|
||||||
translate, None, theme_name)
|
translate, None, theme_name,
|
||||||
|
system_language, boxname)
|
||||||
fitness_performance(inbox_start_time,
|
fitness_performance(inbox_start_time,
|
||||||
server.fitness,
|
server.fitness,
|
||||||
'INBOX', 'update_speaker',
|
'INBOX', 'update_speaker',
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ from delete import outbox_delete
|
||||||
from shares import outbox_share_upload
|
from shares import outbox_share_upload
|
||||||
from shares import outbox_undo_share_upload
|
from shares import outbox_undo_share_upload
|
||||||
from webapp_post import individual_post_as_html
|
from webapp_post import individual_post_as_html
|
||||||
|
from speaker import update_speaker
|
||||||
|
|
||||||
|
|
||||||
def _person_receive_update_outbox(recent_posts_cache: {},
|
def _person_receive_update_outbox(recent_posts_cache: {},
|
||||||
|
|
@ -400,6 +401,13 @@ def post_message_to_outbox(session, translate: {},
|
||||||
print('WARN: post not saved to outbox ' + outbox_name)
|
print('WARN: post not saved to outbox ' + outbox_name)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
update_speaker(base_dir, http_prefix,
|
||||||
|
post_to_nickname, domain, domain_full,
|
||||||
|
message_json, person_cache,
|
||||||
|
translate, message_json['actor'],
|
||||||
|
theme, system_language,
|
||||||
|
outbox_name)
|
||||||
|
|
||||||
# save all instance blogs to the news actor
|
# save all instance blogs to the news actor
|
||||||
if post_to_nickname != 'news' and outbox_name == 'tlblogs':
|
if post_to_nickname != 'news' and outbox_name == 'tlblogs':
|
||||||
if '/' in saved_filename:
|
if '/' in saved_filename:
|
||||||
|
|
|
||||||
39
session.py
|
|
@ -373,6 +373,45 @@ def download_html(signing_priv_key_pem: str,
|
||||||
None, quiet, debug, False)
|
None, quiet, debug, False)
|
||||||
|
|
||||||
|
|
||||||
|
def download_ssml(signing_priv_key_pem: str,
|
||||||
|
session, url: str, headers: {}, params: {}, debug: bool,
|
||||||
|
version: str = __version__, http_prefix: str = 'https',
|
||||||
|
domain: str = 'testdomain',
|
||||||
|
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
||||||
|
if not isinstance(url, str):
|
||||||
|
if debug and not quiet:
|
||||||
|
print('url: ' + str(url))
|
||||||
|
print('ERROR: download_ssml failed, url should be a string')
|
||||||
|
return None
|
||||||
|
session_params = {}
|
||||||
|
session_headers = {}
|
||||||
|
if headers:
|
||||||
|
session_headers = headers
|
||||||
|
if params:
|
||||||
|
session_params = params
|
||||||
|
session_headers['Accept'] = 'application/ssml+xml'
|
||||||
|
session_headers['User-Agent'] = 'Epicyon/' + version
|
||||||
|
if domain:
|
||||||
|
session_headers['User-Agent'] += \
|
||||||
|
'; +' + http_prefix + '://' + domain + '/'
|
||||||
|
if not session:
|
||||||
|
if not quiet:
|
||||||
|
print('WARN: download_ssml failed, no session specified')
|
||||||
|
return None
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
HTTPConnection.debuglevel = 1
|
||||||
|
|
||||||
|
if signing_priv_key_pem:
|
||||||
|
return _get_json_signed(session, url, domain,
|
||||||
|
session_headers, session_params,
|
||||||
|
timeout_sec, signing_priv_key_pem,
|
||||||
|
quiet, debug)
|
||||||
|
return _get_json_request(session, url, domain, session_headers,
|
||||||
|
session_params, timeout_sec,
|
||||||
|
None, quiet, debug, False)
|
||||||
|
|
||||||
|
|
||||||
def _set_user_agent(session, http_prefix: str, domain_full: str) -> None:
|
def _set_user_agent(session, http_prefix: str, domain_full: str) -> None:
|
||||||
"""Sets the user agent
|
"""Sets the user agent
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
52
speaker.py
|
|
@ -11,6 +11,7 @@ import os
|
||||||
import html
|
import html
|
||||||
import random
|
import random
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
from utils import get_cached_post_filename
|
||||||
from utils import remove_id_ending
|
from utils import remove_id_ending
|
||||||
from utils import is_dm
|
from utils import is_dm
|
||||||
from utils import is_reply
|
from utils import is_reply
|
||||||
|
|
@ -301,9 +302,11 @@ def _speaker_endpoint_json(display_name: str, summary: str,
|
||||||
return speaker_json
|
return speaker_json
|
||||||
|
|
||||||
|
|
||||||
def _ssm_lheader(system_language: str, instance_title: str) -> str:
|
def _ssml_header(system_language: str, box_name: str, summary: str) -> str:
|
||||||
"""Returns a header for an SSML document
|
"""Returns a header for an SSML document
|
||||||
"""
|
"""
|
||||||
|
if summary:
|
||||||
|
summary = ': ' + summary
|
||||||
return '<?xml version="1.0"?>\n' + \
|
return '<?xml version="1.0"?>\n' + \
|
||||||
'<speak xmlns="http://www.w3.org/2001/10/synthesis"\n' + \
|
'<speak xmlns="http://www.w3.org/2001/10/synthesis"\n' + \
|
||||||
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' + \
|
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' + \
|
||||||
|
|
@ -312,15 +315,14 @@ def _ssm_lheader(system_language: str, instance_title: str) -> str:
|
||||||
' version="1.1">\n' + \
|
' version="1.1">\n' + \
|
||||||
' <metadata>\n' + \
|
' <metadata>\n' + \
|
||||||
' <dc:title xml:lang="' + system_language + '">' + \
|
' <dc:title xml:lang="' + system_language + '">' + \
|
||||||
instance_title + ' inbox</dc:title>\n' + \
|
box_name + summary + '</dc:title>\n' + \
|
||||||
' </metadata>\n'
|
' </metadata>\n'
|
||||||
|
|
||||||
|
|
||||||
def _speaker_endpoint_ssml(display_name: str, summary: str,
|
def _speaker_endpoint_ssml(display_name: str, summary: str,
|
||||||
content: str, image_description: str,
|
content: str, image_description: str,
|
||||||
links: [], language: str,
|
links: [], language: str,
|
||||||
instance_title: str,
|
gender: str, box_name: str) -> str:
|
||||||
gender: str) -> str:
|
|
||||||
"""Returns an SSML endpoint for the TTS speaker
|
"""Returns an SSML endpoint for the TTS speaker
|
||||||
https://en.wikipedia.org/wiki/Speech_Synthesis_Markup_Language
|
https://en.wikipedia.org/wiki/Speech_Synthesis_Markup_Language
|
||||||
https://www.w3.org/TR/speech-synthesis/
|
https://www.w3.org/TR/speech-synthesis/
|
||||||
|
|
@ -342,7 +344,9 @@ def _speaker_endpoint_ssml(display_name: str, summary: str,
|
||||||
|
|
||||||
content = _add_ssm_lemphasis(content)
|
content = _add_ssm_lemphasis(content)
|
||||||
voice_params = 'name="' + display_name + '" gender="' + gender + '"'
|
voice_params = 'name="' + display_name + '" gender="' + gender + '"'
|
||||||
return _ssm_lheader(lang_short, instance_title) + \
|
if summary is None:
|
||||||
|
summary = ''
|
||||||
|
return _ssml_header(lang_short, box_name, summary) + \
|
||||||
' <p>\n' + \
|
' <p>\n' + \
|
||||||
' <s xml:lang="' + language + '">\n' + \
|
' <s xml:lang="' + language + '">\n' + \
|
||||||
' <voice ' + voice_params + '>\n' + \
|
' <voice ' + voice_params + '>\n' + \
|
||||||
|
|
@ -356,7 +360,6 @@ def _speaker_endpoint_ssml(display_name: str, summary: str,
|
||||||
def get_ssml_box(base_dir: str, path: str,
|
def get_ssml_box(base_dir: str, path: str,
|
||||||
domain: str,
|
domain: str,
|
||||||
system_language: str,
|
system_language: str,
|
||||||
instance_title: str,
|
|
||||||
box_name: str) -> str:
|
box_name: str) -> str:
|
||||||
"""Returns SSML for the given timeline
|
"""Returns SSML for the given timeline
|
||||||
"""
|
"""
|
||||||
|
|
@ -379,7 +382,7 @@ def get_ssml_box(base_dir: str, path: str,
|
||||||
speaker_json['imageDescription'],
|
speaker_json['imageDescription'],
|
||||||
speaker_json['detectedLinks'],
|
speaker_json['detectedLinks'],
|
||||||
system_language,
|
system_language,
|
||||||
instance_title, gender)
|
gender, box_name)
|
||||||
|
|
||||||
|
|
||||||
def speakable_text(base_dir: str, content: str, translate: {}) -> (str, []):
|
def speakable_text(base_dir: str, content: str, translate: {}) -> (str, []):
|
||||||
|
|
@ -544,7 +547,8 @@ def update_speaker(base_dir: str, http_prefix: str,
|
||||||
nickname: str, domain: str, domain_full: str,
|
nickname: str, domain: str, domain_full: str,
|
||||||
post_json_object: {}, person_cache: {},
|
post_json_object: {}, person_cache: {},
|
||||||
translate: {}, announcing_actor: str,
|
translate: {}, announcing_actor: str,
|
||||||
theme_name: str) -> None:
|
theme_name: str,
|
||||||
|
system_language: str, box_name: str) -> None:
|
||||||
""" Generates a json file which can be used for TTS announcement
|
""" Generates a json file which can be used for TTS announcement
|
||||||
of incoming inbox posts
|
of incoming inbox posts
|
||||||
"""
|
"""
|
||||||
|
|
@ -554,5 +558,35 @@ def update_speaker(base_dir: str, http_prefix: str,
|
||||||
post_json_object, person_cache,
|
post_json_object, person_cache,
|
||||||
translate, announcing_actor,
|
translate, announcing_actor,
|
||||||
theme_name)
|
theme_name)
|
||||||
speaker_filename = acct_dir(base_dir, nickname, domain) + '/speaker.json'
|
if not speaker_json:
|
||||||
|
return
|
||||||
|
account_dir = acct_dir(base_dir, nickname, domain)
|
||||||
|
speaker_filename = account_dir + '/speaker.json'
|
||||||
save_json(speaker_json, speaker_filename)
|
save_json(speaker_json, speaker_filename)
|
||||||
|
|
||||||
|
# save the ssml
|
||||||
|
cached_ssml_filename = \
|
||||||
|
get_cached_post_filename(base_dir, nickname,
|
||||||
|
domain, post_json_object)
|
||||||
|
if not cached_ssml_filename:
|
||||||
|
return
|
||||||
|
cached_ssml_filename = cached_ssml_filename.replace('.html', '.ssml')
|
||||||
|
if box_name == 'outbox':
|
||||||
|
cached_ssml_filename = \
|
||||||
|
cached_ssml_filename.replace('/postcache/', '/outbox/')
|
||||||
|
gender = None
|
||||||
|
if speaker_json.get('gender'):
|
||||||
|
gender = speaker_json['gender']
|
||||||
|
ssml_str = \
|
||||||
|
_speaker_endpoint_ssml(speaker_json['name'],
|
||||||
|
speaker_json['summary'],
|
||||||
|
speaker_json['say'],
|
||||||
|
speaker_json['imageDescription'],
|
||||||
|
speaker_json['detectedLinks'],
|
||||||
|
system_language,
|
||||||
|
gender, box_name)
|
||||||
|
try:
|
||||||
|
with open(cached_ssml_filename, 'w+') as fp_ssml:
|
||||||
|
fp_ssml.write(ssml_str)
|
||||||
|
except OSError:
|
||||||
|
print('EX: unable to write ssml ' + cached_ssml_filename)
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 981 B After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 980 B After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 980 B After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 1019 B After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 8.1 KiB |
19
utils.py
|
|
@ -1745,6 +1745,25 @@ def delete_cached_html(base_dir: str, nickname: str, domain: str,
|
||||||
'unable to delete cached post file ' +
|
'unable to delete cached post file ' +
|
||||||
str(cached_post_filename))
|
str(cached_post_filename))
|
||||||
|
|
||||||
|
cached_post_filename = cached_post_filename.replace('.html', '.ssml')
|
||||||
|
if os.path.isfile(cached_post_filename):
|
||||||
|
try:
|
||||||
|
os.remove(cached_post_filename)
|
||||||
|
except OSError:
|
||||||
|
print('EX: delete_cached_html ' +
|
||||||
|
'unable to delete cached ssml post file ' +
|
||||||
|
str(cached_post_filename))
|
||||||
|
|
||||||
|
cached_post_filename = \
|
||||||
|
cached_post_filename.replace('/postcache/', '/outbox/')
|
||||||
|
if os.path.isfile(cached_post_filename):
|
||||||
|
try:
|
||||||
|
os.remove(cached_post_filename)
|
||||||
|
except OSError:
|
||||||
|
print('EX: delete_cached_html ' +
|
||||||
|
'unable to delete cached outbox ssml post file ' +
|
||||||
|
str(cached_post_filename))
|
||||||
|
|
||||||
|
|
||||||
def _delete_hashtags_on_post(base_dir: str, post_json_object: {}) -> None:
|
def _delete_hashtags_on_post(base_dir: str, post_json_object: {}) -> None:
|
||||||
"""Removes hashtags when a post is deleted
|
"""Removes hashtags when a post is deleted
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from utils import get_config_param
|
||||||
from utils import acct_dir
|
from utils import acct_dir
|
||||||
from webapp_utils import html_header_with_external_style
|
from webapp_utils import html_header_with_external_style
|
||||||
from webapp_utils import html_footer
|
from webapp_utils import html_footer
|
||||||
|
from webapp_utils import get_banner_file
|
||||||
|
|
||||||
|
|
||||||
def load_access_keys_for_accounts(base_dir: str, key_shortcuts: {},
|
def load_access_keys_for_accounts(base_dir: str, key_shortcuts: {},
|
||||||
|
|
@ -43,7 +44,7 @@ def html_access_keys(css_cache: {}, base_dir: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
translate: {}, access_keys: {},
|
translate: {}, access_keys: {},
|
||||||
default_access_keys: {},
|
default_access_keys: {},
|
||||||
default_timeline: str) -> str:
|
default_timeline: str, theme: str) -> str:
|
||||||
"""Show and edit key shortcuts
|
"""Show and edit key shortcuts
|
||||||
"""
|
"""
|
||||||
access_keys_filename = \
|
access_keys_filename = \
|
||||||
|
|
@ -53,6 +54,9 @@ def html_access_keys(css_cache: {}, base_dir: str,
|
||||||
if access_keys_from_file:
|
if access_keys_from_file:
|
||||||
access_keys = access_keys_from_file
|
access_keys = access_keys_from_file
|
||||||
|
|
||||||
|
timeline_key = access_keys['menuTimeline']
|
||||||
|
submit_key = access_keys['submitButton']
|
||||||
|
|
||||||
access_keys_form = ''
|
access_keys_form = ''
|
||||||
css_filename = base_dir + '/epicyon-profile.css'
|
css_filename = base_dir + '/epicyon-profile.css'
|
||||||
if os.path.isfile(base_dir + '/epicyon.css'):
|
if os.path.isfile(base_dir + '/epicyon.css'):
|
||||||
|
|
@ -62,6 +66,20 @@ def html_access_keys(css_cache: {}, base_dir: str,
|
||||||
get_config_param(base_dir, 'instanceTitle')
|
get_config_param(base_dir, 'instanceTitle')
|
||||||
access_keys_form = \
|
access_keys_form = \
|
||||||
html_header_with_external_style(css_filename, instance_title, None)
|
html_header_with_external_style(css_filename, instance_title, None)
|
||||||
|
|
||||||
|
access_keys_form += \
|
||||||
|
'<header>\n' + \
|
||||||
|
'<a href="/users/' + nickname + '/' + \
|
||||||
|
default_timeline + '" title="' + \
|
||||||
|
translate['Switch to timeline view'] + '" alt="' + \
|
||||||
|
translate['Switch to timeline view'] + '">\n'
|
||||||
|
banner_file, _ = \
|
||||||
|
get_banner_file(base_dir, nickname, domain, theme)
|
||||||
|
access_keys_form += '<img loading="lazy" decoding="async" ' + \
|
||||||
|
'class="timeline-banner" alt="" ' + \
|
||||||
|
'src="/users/' + nickname + '/' + banner_file + '" /></a>\n' + \
|
||||||
|
'</header>\n'
|
||||||
|
|
||||||
access_keys_form += '<div class="container">\n'
|
access_keys_form += '<div class="container">\n'
|
||||||
|
|
||||||
access_keys_form += \
|
access_keys_form += \
|
||||||
|
|
@ -73,8 +91,6 @@ def html_access_keys(css_cache: {}, base_dir: str,
|
||||||
access_keys_form += ' <form method="POST" action="' + \
|
access_keys_form += ' <form method="POST" action="' + \
|
||||||
'/users/' + nickname + '/changeAccessKeys">\n'
|
'/users/' + nickname + '/changeAccessKeys">\n'
|
||||||
|
|
||||||
timeline_key = access_keys['menuTimeline']
|
|
||||||
submit_key = access_keys['submitButton']
|
|
||||||
access_keys_form += \
|
access_keys_form += \
|
||||||
' <center>\n' + \
|
' <center>\n' + \
|
||||||
' <button type="submit" class="button" ' + \
|
' <button type="submit" class="button" ' + \
|
||||||
|
|
|
||||||
|
|
@ -57,28 +57,42 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
if default_timeline == 'tlmedia':
|
if default_timeline == 'tlmedia':
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + '/tlmedia" tabindex="-1" ' + \
|
'<a href="' + users_path + '/tlmedia" tabindex="-1" ' + \
|
||||||
'accesskey="' + access_keys['menuMedia'] + '"' + \
|
'accesskey="' + access_keys['menuMedia'] + '"'
|
||||||
|
if box_name == 'tlmedia':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
'><button class="' + \
|
'><button class="' + \
|
||||||
mediaButton + '"><span>' + translate['Media'] + \
|
mediaButton + '"><span>' + translate['Media'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
elif default_timeline == 'tlblogs':
|
elif default_timeline == 'tlblogs':
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/tlblogs" tabindex="-1"><button class="' + \
|
'/tlblogs" tabindex="-1"'
|
||||||
|
if box_name == 'tlblogs':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
blogs_button + '"><span>' + translate['Blogs'] + \
|
blogs_button + '"><span>' + translate['Blogs'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
elif default_timeline == 'tlfeatures':
|
elif default_timeline == 'tlfeatures':
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/tlfeatures" tabindex="-1"><button class="' + \
|
'/tlfeatures" tabindex="-1"'
|
||||||
|
if box_name == 'tlfeatures':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
features_button + '"><span>' + translate['Features'] + \
|
features_button + '"><span>' + translate['Features'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
else:
|
else:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/inbox" tabindex="-1"><button class="' + \
|
'/inbox" tabindex="-1"><button class="' + \
|
||||||
inbox_button + '"><span>' + \
|
inbox_button + '"'
|
||||||
translate['Inbox'] + '</span></button></a>'
|
if box_name == 'inbox':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><span>' + translate['Inbox'] + '</span></button></a>'
|
||||||
|
|
||||||
# if this is a news instance and we are viewing the news timeline
|
# if this is a news instance and we are viewing the news timeline
|
||||||
features_header = False
|
features_header = False
|
||||||
|
|
@ -87,8 +101,11 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
|
|
||||||
if not features_header:
|
if not features_header:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + '/dm" tabindex="-1"'
|
||||||
'/dm" tabindex="-1"><button class="' + dm_button + \
|
if box_name == 'dm':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + dm_button + \
|
||||||
'"><span>' + html_highlight_label(translate['DM'], new_dm) + \
|
'"><span>' + html_highlight_label(translate['DM'], new_dm) + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
@ -96,8 +113,11 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
acct_dir(base_dir, nickname, domain) + '/tlreplies.index'
|
acct_dir(base_dir, nickname, domain) + '/tlreplies.index'
|
||||||
if os.path.isfile(replies_index_filename):
|
if os.path.isfile(replies_index_filename):
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + '/tlreplies" tabindex="-1">' + \
|
'<a href="' + users_path + '/tlreplies" tabindex="-1"'
|
||||||
'<button class="' + replies_button + '"><span>' + \
|
if box_name == 'tlreplies':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + replies_button + '"><span>' + \
|
||||||
html_highlight_label(translate['Replies'], new_reply) + \
|
html_highlight_label(translate['Replies'], new_reply) + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
@ -106,15 +126,22 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
if not minimal and not features_header:
|
if not minimal and not features_header:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + '/tlmedia" tabindex="-1" ' + \
|
'<a href="' + users_path + '/tlmedia" tabindex="-1" ' + \
|
||||||
'accesskey="' + access_keys['menuMedia'] + '">' + \
|
'accesskey="' + access_keys['menuMedia'] + '"'
|
||||||
'<button class="' + \
|
if box_name == 'tlmedia':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
mediaButton + '"><span>' + translate['Media'] + \
|
mediaButton + '"><span>' + translate['Media'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
else:
|
else:
|
||||||
if not minimal:
|
if not minimal:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/inbox" tabindex="-1"><button class="' + \
|
'/inbox" tabindex="-1"'
|
||||||
|
if box_name == 'inbox':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
inbox_button + '"><span>' + translate['Inbox'] + \
|
inbox_button + '"><span>' + translate['Inbox'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
@ -128,14 +155,22 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
title_str = translate['Article']
|
title_str = translate['Article']
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/tlblogs" tabindex="-1"><button class="' + \
|
'/tlblogs" tabindex="-1"'
|
||||||
|
if box_name == 'tlblogs':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
blogs_button + '"><span>' + title_str + \
|
blogs_button + '"><span>' + title_str + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
else:
|
else:
|
||||||
if not minimal:
|
if not minimal:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/inbox" tabindex="-1"><button class="' + \
|
'/inbox" tabindex="-1"'
|
||||||
|
if box_name == 'inbox':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
inbox_button + '"><span>' + translate['Inbox'] + \
|
inbox_button + '"><span>' + translate['Inbox'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
@ -145,7 +180,11 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
if not features_header:
|
if not features_header:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + \
|
||||||
'/inbox" tabindex="-1"><button class="' + \
|
'/inbox" tabindex="-1"'
|
||||||
|
if box_name == 'inbox':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
inbox_button + '"><span>' + translate['Inbox'] + \
|
inbox_button + '"><span>' + translate['Inbox'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
@ -205,7 +244,11 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
if not features_header:
|
if not features_header:
|
||||||
# button for the outbox
|
# button for the outbox
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + '/outbox"><button class="' + \
|
'<a href="' + users_path + '/outbox"'
|
||||||
|
if box_name == 'outbox':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="' + \
|
||||||
sent_button + '" tabindex="-1"><span>' + translate['Sent'] + \
|
sent_button + '" tabindex="-1"><span>' + translate['Sent'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
@ -278,8 +321,11 @@ def header_buttons_timeline(default_timeline: str,
|
||||||
|
|
||||||
if features_header:
|
if features_header:
|
||||||
tl_str += \
|
tl_str += \
|
||||||
'<a href="' + users_path + '/inbox" tabindex="-1">' + \
|
'<a href="' + users_path + '/inbox" tabindex="-1"'
|
||||||
'<button class="button">' + \
|
if box_name == 'inbox':
|
||||||
|
tl_str += ' aria-current="location"'
|
||||||
|
tl_str += \
|
||||||
|
'><button class="button">' + \
|
||||||
'<span>' + translate['User'] + '</span></button></a>'
|
'<span>' + translate['User'] + '</span></button></a>'
|
||||||
|
|
||||||
# the newswire button to show right column links
|
# the newswire button to show right column links
|
||||||
|
|
|
||||||
|
|
@ -1698,7 +1698,8 @@ def individual_post_as_html(signing_priv_key_pem: str,
|
||||||
nickname, domain, domain_full,
|
nickname, domain, domain_full,
|
||||||
post_json_object, person_cache,
|
post_json_object, person_cache,
|
||||||
translate, post_json_object['actor'],
|
translate, post_json_object['actor'],
|
||||||
theme_name)
|
theme_name, system_language,
|
||||||
|
box_name)
|
||||||
with open(announce_filename + '.tts', 'w+') as ttsfile:
|
with open(announce_filename + '.tts', 'w+') as ttsfile:
|
||||||
ttsfile.write('\n')
|
ttsfile.write('\n')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -419,13 +419,21 @@ def _page_number_buttons(users_path: str, box_name: str,
|
||||||
for page in range(min_page_number, max_page_number):
|
for page in range(min_page_number, max_page_number):
|
||||||
if num_str:
|
if num_str:
|
||||||
num_str += ' ⸻ '
|
num_str += ' ⸻ '
|
||||||
|
aria_page_str = ''
|
||||||
page_str = str(page)
|
page_str = str(page)
|
||||||
if page == page_number:
|
if page == page_number:
|
||||||
page_str = '<mark>' + str(page) + '</mark>'
|
page_str = '<mark>' + str(page) + '</mark>'
|
||||||
|
aria_page_str = ' aria-current="true"'
|
||||||
num_str += \
|
num_str += \
|
||||||
'<a href="' + users_path + '/' + box_name + '?page=' + \
|
'<a href="' + users_path + '/' + box_name + '?page=' + \
|
||||||
str(page) + '" class="pageslist">' + page_str + '</a>'
|
str(page) + '" class="pageslist" ' + \
|
||||||
return '<center>' + num_str + '</center>'
|
'aria-label="Current Page, Page ' + str(page) + \
|
||||||
|
'"' + aria_page_str + '>' + page_str + '</a>'
|
||||||
|
return '<center>\n' + \
|
||||||
|
' <nav role="navigation" aria-label="Pagination Navigation">\n' + \
|
||||||
|
' ' + num_str + '\n' + \
|
||||||
|
' </nav>\n' + \
|
||||||
|
'</center>\n'
|
||||||
|
|
||||||
|
|
||||||
def html_timeline(css_cache: {}, default_timeline: str,
|
def html_timeline(css_cache: {}, default_timeline: str,
|
||||||
|
|
@ -656,8 +664,11 @@ def html_timeline(css_cache: {}, default_timeline: str,
|
||||||
moderation_button_str = ''
|
moderation_button_str = ''
|
||||||
if moderator and not minimal:
|
if moderator and not minimal:
|
||||||
moderation_button_str = \
|
moderation_button_str = \
|
||||||
'<a href="' + users_path + \
|
'<a href="' + users_path + '/moderation"'
|
||||||
'/moderation"><button class="' + \
|
if box_name == 'moderation':
|
||||||
|
moderation_button_str += ' aria-current="location"'
|
||||||
|
moderation_button_str += \
|
||||||
|
'><button class="' + \
|
||||||
moderation_button + '"><span>' + \
|
moderation_button + '"><span>' + \
|
||||||
html_highlight_label(translate['Mod'], new_report) + \
|
html_highlight_label(translate['Mod'], new_report) + \
|
||||||
' </span></button></a>'
|
' </span></button></a>'
|
||||||
|
|
@ -669,19 +680,30 @@ def html_timeline(css_cache: {}, default_timeline: str,
|
||||||
events_button_str = ''
|
events_button_str = ''
|
||||||
if not minimal:
|
if not minimal:
|
||||||
shares_button_str = \
|
shares_button_str = \
|
||||||
'<a href="' + users_path + '/tlshares"><button class="' + \
|
'<a href="' + users_path + '/tlshares"'
|
||||||
shares_button + '"><span>' + \
|
if box_name == 'tlshares':
|
||||||
|
shares_button_str += ' aria-current="location"'
|
||||||
|
shares_button_str += \
|
||||||
|
'><button class="' + shares_button + '"><span>' + \
|
||||||
html_highlight_label(translate['Shares'], new_share) + \
|
html_highlight_label(translate['Shares'], new_share) + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
wanted_button_str = \
|
wanted_button_str = \
|
||||||
'<a href="' + users_path + '/tlwanted"><button class="' + \
|
'<a href="' + users_path + '/tlwanted"><button class="' + \
|
||||||
wanted_button + '"><span>' + \
|
wanted_button + '"'
|
||||||
|
if box_name == 'tlwanted':
|
||||||
|
wanted_button_str += ' aria-current="location"'
|
||||||
|
wanted_button_str += \
|
||||||
|
'><span>' + \
|
||||||
html_highlight_label(translate['Wanted'], new_wanted) + \
|
html_highlight_label(translate['Wanted'], new_wanted) + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
bookmarks_button_str = \
|
bookmarks_button_str = \
|
||||||
'<a href="' + users_path + '/tlbookmarks"><button class="' + \
|
'<a href="' + users_path + '/tlbookmarks"'
|
||||||
|
if box_name == 'tlbookmarks':
|
||||||
|
bookmarks_button_str += ' aria-current="location"'
|
||||||
|
bookmarks_button_str += \
|
||||||
|
'><button class="' + \
|
||||||
bookmarks_button + '"><span>' + translate['Bookmarks'] + \
|
bookmarks_button + '"><span>' + translate['Bookmarks'] + \
|
||||||
'</span></button></a>'
|
'</span></button></a>'
|
||||||
|
|
||||||
|
|
|
||||||