epicyon/webapp_search.py

1025 lines
42 KiB
Python
Raw Normal View History

2020-11-09 19:41:01 +00:00
__filename__ = "webapp_search.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2022-02-03 13:58:20 +00:00
__version__ = "1.3.0"
2020-11-09 19:41:01 +00:00
__maintainer__ = "Bob Mottram"
2021-09-10 16:14:50 +00:00
__email__ = "bob@libreserver.org"
2020-11-09 19:41:01 +00:00
__status__ = "Production"
2021-06-15 15:08:12 +00:00
__module_group__ = "Web Interface"
2020-11-09 19:41:01 +00:00
import os
from shutil import copyfile
import urllib.parse
from datetime import datetime
2021-12-26 11:29:40 +00:00
from utils import get_base_content_from_post
2021-12-26 18:46:43 +00:00
from utils import is_account_dir
2021-12-26 14:08:58 +00:00
from utils import get_config_param
2021-12-26 12:45:03 +00:00
from utils import get_full_domain
2021-12-26 13:27:57 +00:00
from utils import is_editor
2021-12-26 15:13:34 +00:00
from utils import load_json
2021-12-27 22:19:18 +00:00
from utils import get_nickname_from_actor
2021-12-26 20:36:08 +00:00
from utils import locate_post
2021-12-28 14:41:10 +00:00
from utils import is_public_post
2021-12-27 15:52:08 +00:00
from utils import first_paragraph_from_string
2021-12-28 13:07:02 +00:00
from utils import search_box_posts
2021-12-26 18:32:02 +00:00
from utils import get_alt_path
2021-12-26 12:02:29 +00:00
from utils import acct_dir
2021-12-26 10:19:59 +00:00
from utils import local_actor_url
2021-12-28 20:32:11 +00:00
from skills import no_of_actor_skills
from skills import get_skills_from_list
2021-12-29 21:55:09 +00:00
from categories import get_hashtag_category
from feeds import rss2tag_header
from feeds import rss2tag_footer
from webapp_utils import set_custom_background
from webapp_utils import html_keyboard_navigation
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import get_search_banner_file
from webapp_utils import html_post_separator
from webapp_utils import html_search_result_share
from webapp_post import individual_post_as_html
from webapp_hashtagswarm import html_hash_tag_swarm
def html_search_emoji(css_cache: {}, translate: {},
base_dir: str, http_prefix: str,
2022-01-04 13:19:00 +00:00
search_str: str) -> str:
2020-11-09 19:41:01 +00:00
"""Search results for emoji
"""
# emoji.json is generated so that it can be customized and the changes
# will be retained even if default_emoji.json is subsequently updated
2021-12-25 16:17:53 +00:00
if not os.path.isfile(base_dir + '/emoji/emoji.json'):
copyfile(base_dir + '/emoji/default_emoji.json',
base_dir + '/emoji/emoji.json')
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
search_str = search_str.lower().replace(':', '').strip('\n').strip('\r')
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-profile.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/epicyon.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon.css'
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
emoji_lookup_filename = base_dir + '/emoji/emoji.json'
2022-01-01 20:36:56 +00:00
custom_emoji_lookup_filename = base_dir + '/emojicustom/emoji.json'
# create header
2022-01-04 13:19:00 +00:00
instance_title = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceTitle')
2022-01-04 13:19:00 +00:00
emoji_form = \
html_header_with_external_style(css_filename, instance_title, None)
emoji_form += '<center><h1>' + \
translate['Emoji Search'] + \
'</h1></center>'
2020-11-09 19:41:01 +00:00
# does the lookup file exist?
2022-01-04 13:19:00 +00:00
if not os.path.isfile(emoji_lookup_filename):
emoji_form += '<center><h5>' + \
2021-11-01 23:42:37 +00:00
translate['No results'] + '</h5></center>'
2022-01-04 13:19:00 +00:00
emoji_form += html_footer()
return emoji_form
2022-01-04 13:19:00 +00:00
emoji_json = load_json(emoji_lookup_filename)
if emoji_json:
2022-01-01 20:36:56 +00:00
if os.path.isfile(custom_emoji_lookup_filename):
custom_emoji_json = load_json(custom_emoji_lookup_filename)
if custom_emoji_json:
2022-01-04 13:19:00 +00:00
emoji_json = dict(emoji_json, **custom_emoji_json)
2021-11-01 23:46:31 +00:00
results = {}
2022-01-04 13:19:00 +00:00
for emoji_name, filename in emoji_json.items():
if search_str in emoji_name:
results[emoji_name] = filename + '.png'
for emoji_name, filename in emoji_json.items():
if emoji_name in search_str:
results[emoji_name] = filename + '.png'
2021-11-01 23:46:31 +00:00
if not results:
2022-01-04 13:19:00 +00:00
emoji_form += '<center><h5>' + \
2021-11-01 23:46:31 +00:00
translate['No results'] + '</h5></center>'
2022-01-04 13:19:00 +00:00
heading_shown = False
emoji_form += '<center>'
msg_str1 = translate['Copy the text then paste it into your post']
2022-03-28 08:47:53 +00:00
msg_str2 = ':<img loading="lazy" decoding="async" ' + \
'class="searchEmoji" src="/emoji/'
2022-01-04 13:19:00 +00:00
for emoji_name, filename in results.items():
2021-12-25 16:17:53 +00:00
if not os.path.isfile(base_dir + '/emoji/' + filename):
if not os.path.isfile(base_dir + '/emojicustom/' + filename):
2021-11-01 23:17:14 +00:00
continue
2022-01-04 13:19:00 +00:00
if not heading_shown:
emoji_form += \
'<center><h5>' + msg_str1 + '</h5></center>'
heading_shown = True
emoji_form += \
'<h3>:' + emoji_name + msg_str2 + filename + '"/></h3>'
emoji_form += '</center>'
2022-01-04 13:19:00 +00:00
emoji_form += html_footer()
return emoji_form
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
def _match_shared_item(search_str_lower_list: [],
shared_item: {}) -> bool:
"""Returns true if the shared item matches search criteria
"""
2022-01-04 13:19:00 +00:00
for search_substr in search_str_lower_list:
search_substr = search_substr.strip()
if shared_item.get('location'):
if search_substr in shared_item['location'].lower():
2021-07-27 19:23:55 +00:00
return True
2022-01-04 13:19:00 +00:00
if search_substr in shared_item['summary'].lower():
return True
2022-01-04 13:19:00 +00:00
if search_substr in shared_item['displayName'].lower():
return True
2022-01-04 13:19:00 +00:00
if search_substr in shared_item['category'].lower():
return True
return False
2021-12-29 21:55:09 +00:00
def _html_search_result_share_page(actor: str, domain_full: str,
2022-01-04 13:19:00 +00:00
calling_domain: str, page_number: int,
search_str_lower: str, translate: {},
2021-12-29 21:55:09 +00:00
previous: bool) -> str:
2021-07-27 09:57:52 +00:00
"""Returns the html for the previous button on shared items search results
"""
2022-01-04 13:19:00 +00:00
post_actor = get_alt_path(actor, domain_full, calling_domain)
2021-07-27 09:57:52 +00:00
# previous page link, needs to be a POST
2021-07-27 10:05:57 +00:00
if previous:
2022-01-04 13:19:00 +00:00
page_number -= 1
title_str = translate['Page up']
image_url = 'pageup.png'
2021-07-27 10:05:57 +00:00
else:
2022-01-04 13:19:00 +00:00
page_number += 1
title_str = translate['Page down']
image_url = 'pagedown.png'
shared_items_form = \
'<form method="POST" action="' + post_actor + '/searchhandle?page=' + \
str(page_number) + '">\n'
shared_items_form += \
2021-07-27 09:57:52 +00:00
' <input type="hidden" ' + 'name="actor" value="' + actor + '">\n'
2022-01-04 13:19:00 +00:00
shared_items_form += \
2021-07-27 09:57:52 +00:00
' <input type="hidden" ' + 'name="searchtext" value="' + \
2022-01-04 13:19:00 +00:00
search_str_lower + '"><br>\n'
shared_items_form += \
2021-07-27 09:57:52 +00:00
' <center>\n' + ' <a href="' + actor + \
'" type="submit" name="submitSearch">\n'
2022-01-04 13:19:00 +00:00
shared_items_form += \
2022-03-28 08:47:53 +00:00
' <img loading="lazy" decoding="async" ' + \
'class="pageicon" src="/icons' + \
2022-01-04 13:19:00 +00:00
'/' + image_url + '" title="' + title_str + \
'" alt="' + title_str + '"/></a>\n'
shared_items_form += ' </center>\n'
shared_items_form += '</form>\n'
return shared_items_form
2021-07-27 09:57:52 +00:00
2022-01-04 13:19:00 +00:00
def _html_shares_result(base_dir: str, shares_json: {}, page_number: int,
results_per_page: int,
search_str_lower_list: [], curr_page: int, ctr: int,
2021-12-29 21:55:09 +00:00
calling_domain: str, http_prefix: str,
2022-01-04 13:19:00 +00:00
domain_full: str, contact_nickname: str, actor: str,
results_exist: bool, search_str_lower: str,
translate: {},
shares_file_type: str) -> (bool, int, int, str):
"""Result for shared items search
"""
2022-01-04 13:19:00 +00:00
shared_items_form = ''
if curr_page > page_number:
return results_exist, curr_page, ctr, shared_items_form
2022-01-04 13:19:00 +00:00
for name, shared_item in shares_json.items():
if _match_shared_item(search_str_lower_list, shared_item):
if curr_page == page_number:
# show individual search result
2022-01-04 13:19:00 +00:00
shared_items_form += \
html_search_result_share(base_dir, shared_item, translate,
2021-12-29 21:55:09 +00:00
http_prefix, domain_full,
2022-01-04 13:19:00 +00:00
contact_nickname,
name, actor, shares_file_type,
shared_item['category'])
if not results_exist and curr_page > 1:
# show the previous page button
2022-01-04 13:19:00 +00:00
shared_items_form += \
2021-12-29 21:55:09 +00:00
_html_search_result_share_page(actor, domain_full,
calling_domain,
2022-01-04 13:19:00 +00:00
page_number,
search_str_lower,
2021-12-29 21:55:09 +00:00
translate, True)
2022-01-04 13:19:00 +00:00
results_exist = True
ctr += 1
2022-01-04 13:19:00 +00:00
if ctr >= results_per_page:
curr_page += 1
if curr_page > page_number:
# show the next page button
2022-01-04 13:19:00 +00:00
shared_items_form += \
2021-12-29 21:55:09 +00:00
_html_search_result_share_page(actor, domain_full,
calling_domain,
2022-01-04 13:19:00 +00:00
page_number,
search_str_lower,
2021-12-29 21:55:09 +00:00
translate, False)
2022-01-04 13:19:00 +00:00
return results_exist, curr_page, ctr, shared_items_form
ctr = 0
2022-01-04 13:19:00 +00:00
return results_exist, curr_page, ctr, shared_items_form
2021-12-29 21:55:09 +00:00
def html_search_shared_items(css_cache: {}, translate: {},
2022-01-04 13:19:00 +00:00
base_dir: str, search_str: str,
page_number: int,
results_per_page: int,
2021-12-29 21:55:09 +00:00
http_prefix: str,
domain_full: str, actor: str,
calling_domain: str,
shared_items_federated_domains: [],
2022-01-04 13:19:00 +00:00
shares_file_type: str) -> str:
2020-11-09 19:41:01 +00:00
"""Search results for shared items
"""
2022-01-04 13:19:00 +00:00
curr_page = 1
2020-11-09 19:41:01 +00:00
ctr = 0
2022-01-04 13:19:00 +00:00
shared_items_form = ''
search_str_lower = urllib.parse.unquote(search_str)
search_str_lower = search_str_lower.lower().strip('\n').strip('\r')
search_str_lower_list = search_str_lower.split('+')
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-profile.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/epicyon.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon.css'
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
instance_title = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceTitle')
2022-01-04 13:19:00 +00:00
shared_items_form = \
html_header_with_external_style(css_filename, instance_title, None)
if shares_file_type == 'shares':
title_str = translate['Shared Items Search']
else:
2022-01-04 13:19:00 +00:00
title_str = translate['Wanted Items Search']
shared_items_form += \
2020-12-07 12:06:30 +00:00
'<center><h1>' + \
2022-01-04 13:19:00 +00:00
'<a href="' + actor + '/search">' + title_str + '</a></h1></center>'
results_exist = False
for _, dirs, files in os.walk(base_dir + '/accounts'):
for handle in dirs:
2021-12-26 18:46:43 +00:00
if not is_account_dir(handle):
continue
2022-01-04 13:19:00 +00:00
contact_nickname = handle.split('@')[0]
shares_filename = base_dir + '/accounts/' + handle + \
'/' + shares_file_type + '.json'
if not os.path.isfile(shares_filename):
continue
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
shares_json = load_json(shares_filename)
if not shares_json:
continue
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
(results_exist, curr_page, ctr,
result_str) = _html_shares_result(base_dir, shares_json,
page_number,
results_per_page,
search_str_lower_list,
curr_page, ctr,
calling_domain, http_prefix,
domain_full,
contact_nickname,
actor, results_exist,
search_str_lower, translate,
shares_file_type)
shared_items_form += result_str
if curr_page > page_number:
break
2020-12-13 22:13:45 +00:00
break
# search federated shared items
2022-01-04 13:19:00 +00:00
if shares_file_type == 'shares':
catalogs_dir = base_dir + '/cache/catalogs'
else:
2022-01-04 13:19:00 +00:00
catalogs_dir = base_dir + '/cache/wantedItems'
if curr_page <= page_number and os.path.isdir(catalogs_dir):
for _, dirs, files in os.walk(catalogs_dir):
for fname in files:
if '#' in fname:
continue
2022-01-04 13:19:00 +00:00
if not fname.endswith('.' + shares_file_type + '.json'):
continue
2022-01-04 13:19:00 +00:00
federated_domain = fname.split('.')[0]
if federated_domain not in shared_items_federated_domains:
continue
2022-01-04 13:19:00 +00:00
shares_filename = catalogs_dir + '/' + fname
shares_json = load_json(shares_filename)
if not shares_json:
continue
2022-01-04 13:19:00 +00:00
(results_exist, curr_page, ctr,
result_str) = _html_shares_result(base_dir, shares_json,
page_number,
results_per_page,
search_str_lower_list,
curr_page, ctr,
calling_domain, http_prefix,
domain_full,
contact_nickname,
actor, results_exist,
search_str_lower, translate,
shares_file_type)
shared_items_form += result_str
if curr_page > page_number:
break
break
2022-01-04 13:19:00 +00:00
if not results_exist:
shared_items_form += \
'<center><h5>' + translate['No results'] + '</h5></center>\n'
2022-01-04 13:19:00 +00:00
shared_items_form += html_footer()
return shared_items_form
2020-11-09 19:41:01 +00:00
2021-12-29 21:55:09 +00:00
def html_search_emoji_text_entry(css_cache: {}, translate: {},
base_dir: str, path: str) -> str:
2020-11-09 19:41:01 +00:00
"""Search for an emoji by name
"""
# emoji.json is generated so that it can be customized and the changes
# will be retained even if default_emoji.json is subsequently updated
2021-12-25 16:17:53 +00:00
if not os.path.isfile(base_dir + '/emoji/emoji.json'):
copyfile(base_dir + '/emoji/default_emoji.json',
base_dir + '/emoji/emoji.json')
2020-11-09 19:41:01 +00:00
actor = path.replace('/search', '')
2021-12-29 21:55:09 +00:00
set_custom_background(base_dir, 'search-background', 'follow-background')
2020-11-09 19:41:01 +00:00
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-follow.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/follow.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/follow.css'
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
instance_title = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceTitle')
2022-01-04 13:19:00 +00:00
emoji_str = \
html_header_with_external_style(css_filename, instance_title, None)
emoji_str += '<div class="follow">\n'
emoji_str += ' <div class="followAvatar">\n'
emoji_str += ' <center>\n'
emoji_str += \
2020-11-09 19:41:01 +00:00
' <p class="followText">' + \
translate['Enter an emoji name to search for'] + '</p>\n'
2022-01-04 13:19:00 +00:00
emoji_str += ' <form role="search" method="POST" action="' + \
2020-11-09 19:41:01 +00:00
actor + '/searchhandleemoji">\n'
2022-01-04 13:19:00 +00:00
emoji_str += ' <input type="hidden" name="actor" value="' + \
2020-11-09 19:41:01 +00:00
actor + '">\n'
2022-01-04 13:19:00 +00:00
emoji_str += ' <input type="text" name="searchtext" autofocus><br>\n'
emoji_str += \
2020-11-09 19:41:01 +00:00
' <button type="submit" class="button" name="submitSearch">' + \
translate['Submit'] + '</button>\n'
2022-01-04 13:19:00 +00:00
emoji_str += ' </form>\n'
emoji_str += ' </center>\n'
emoji_str += ' </div>\n'
emoji_str += '</div>\n'
emoji_str += html_footer()
return emoji_str
2020-11-09 19:41:01 +00:00
2021-12-29 21:55:09 +00:00
def html_search(css_cache: {}, translate: {},
base_dir: str, path: str, domain: str,
2021-12-31 23:50:29 +00:00
default_timeline: str, theme: str,
2021-12-31 21:18:12 +00:00
text_mode_banner: str, access_keys: {}) -> str:
2020-11-09 19:41:01 +00:00
"""Search called from the timeline icon
"""
actor = path.replace('/search', '')
2022-01-04 13:19:00 +00:00
search_nickname = get_nickname_from_actor(actor)
if not search_nickname:
return ''
2020-11-09 19:41:01 +00:00
2021-12-29 21:55:09 +00:00
set_custom_background(base_dir, 'search-background', 'follow-background')
2020-11-09 19:41:01 +00:00
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-search.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/search.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/search.css'
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
instance_title = get_config_param(base_dir, 'instanceTitle')
follow_str = \
html_header_with_external_style(css_filename, instance_title, None)
2020-11-09 19:41:01 +00:00
# show a banner above the search box
2022-01-04 13:19:00 +00:00
search_banner_file, search_banner_filename = \
get_search_banner_file(base_dir, search_nickname, domain, theme)
text_mode_banner_str = html_keyboard_navigation(text_mode_banner, {}, {})
if text_mode_banner_str is None:
text_mode_banner_str = ''
if os.path.isfile(search_banner_filename):
timeline_key = access_keys['menuTimeline']
users_path = '/users/' + search_nickname
follow_str += \
'<header>\n' + text_mode_banner_str + \
'<a href="' + users_path + '/' + default_timeline + '" title="' + \
2020-11-09 19:41:01 +00:00
translate['Switch to timeline view'] + '" alt="' + \
2021-04-23 09:15:53 +00:00
translate['Switch to timeline view'] + '" ' + \
2022-01-04 13:19:00 +00:00
'accesskey="' + timeline_key + '">\n'
2022-03-28 08:47:53 +00:00
follow_str += '<img loading="lazy" decoding="async" ' + \
'class="timeline-banner" src="' + \
2022-01-04 13:19:00 +00:00
users_path + '/' + search_banner_file + '" alt="" /></a>\n' + \
2020-12-27 16:57:15 +00:00
'</header>\n'
2020-11-09 19:41:01 +00:00
# show the search box
2022-01-04 13:19:00 +00:00
follow_str += '<div class="follow">\n'
follow_str += ' <div class="followAvatar">\n'
follow_str += ' <center>\n'
follow_str += \
2021-08-10 09:10:25 +00:00
' <p class="followText">' + translate['Search screen text'] + '</p>\n'
2022-01-04 13:19:00 +00:00
follow_str += ' <form role="search" method="POST" ' + \
2020-11-09 19:41:01 +00:00
'accept-charset="UTF-8" action="' + actor + '/searchhandle">\n'
2022-01-04 13:19:00 +00:00
follow_str += \
2020-11-09 19:41:01 +00:00
' <input type="hidden" name="actor" value="' + actor + '">\n'
2022-01-04 13:19:00 +00:00
follow_str += ' <input type="text" name="searchtext" autofocus><br>\n'
submit_key = access_keys['submitButton']
follow_str += ' <button type="submit" class="button" ' + \
'name="submitSearch" accesskey="' + submit_key + '">' + \
2021-04-23 09:15:53 +00:00
translate['Submit'] + '</button>\n'
2022-01-04 13:19:00 +00:00
follow_str += ' </form>\n'
2021-10-20 13:33:34 +00:00
2022-01-04 13:19:00 +00:00
cached_hashtag_swarm_filename = \
acct_dir(base_dir, search_nickname, domain) + '/.hashtagSwarm'
swarm_str = ''
if os.path.isfile(cached_hashtag_swarm_filename):
2021-10-20 13:33:34 +00:00
try:
2022-01-04 13:19:00 +00:00
with open(cached_hashtag_swarm_filename, 'r') as fp_swarm:
swarm_str = fp_swarm.read()
2021-11-25 22:22:54 +00:00
except OSError:
2021-12-29 21:55:09 +00:00
print('EX: html_search unable to read cached hashtag swarm ' +
2022-01-04 13:19:00 +00:00
cached_hashtag_swarm_filename)
if not swarm_str:
swarm_str = html_hash_tag_swarm(base_dir, actor, translate)
if swarm_str:
2021-10-20 14:20:27 +00:00
try:
2022-01-04 13:19:00 +00:00
with open(cached_hashtag_swarm_filename, 'w+') as fp_hash:
fp_hash.write(swarm_str)
2021-11-25 22:22:54 +00:00
except OSError:
2021-12-29 21:55:09 +00:00
print('EX: html_search unable to save cached hashtag swarm ' +
2022-01-04 13:19:00 +00:00
cached_hashtag_swarm_filename)
2021-10-20 13:33:34 +00:00
2022-01-04 13:19:00 +00:00
follow_str += ' <p class="hashtagswarm">' + swarm_str + '</p>\n'
follow_str += ' </center>\n'
follow_str += ' </div>\n'
follow_str += '</div>\n'
follow_str += html_footer()
return follow_str
2020-11-09 19:41:01 +00:00
2021-12-29 21:55:09 +00:00
def html_skills_search(actor: str,
css_cache: {}, translate: {}, base_dir: str,
http_prefix: str,
2022-01-04 13:19:00 +00:00
skillsearch: str, instance_only: bool,
posts_per_page: int) -> str:
2020-11-19 14:02:16 +00:00
"""Show a page containing search results for a skill
2020-11-09 19:41:01 +00:00
"""
2020-11-19 14:02:16 +00:00
if skillsearch.startswith('*'):
skillsearch = skillsearch[1:].strip()
2020-11-09 19:41:01 +00:00
2020-11-19 14:02:16 +00:00
skillsearch = skillsearch.lower().strip('\n').strip('\r')
results = []
# search instance accounts
2022-01-04 13:19:00 +00:00
for subdir, _, files in os.walk(base_dir + '/accounts/'):
for fname in files:
if not fname.endswith('.json'):
2020-11-09 19:41:01 +00:00
continue
2022-01-04 13:19:00 +00:00
if not is_account_dir(fname):
2021-04-21 16:09:56 +00:00
continue
2022-01-04 13:19:00 +00:00
actor_filename = os.path.join(subdir, fname)
actor_json = load_json(actor_filename)
2021-12-26 10:29:52 +00:00
if actor_json:
if actor_json.get('id') and \
2021-12-28 20:32:11 +00:00
no_of_actor_skills(actor_json) > 0 and \
2021-12-26 10:29:52 +00:00
actor_json.get('name') and \
actor_json.get('icon'):
actor = actor_json['id']
2022-01-04 13:19:00 +00:00
actor_skills_list = actor_json['hasOccupation']['skills']
skills = get_skills_from_list(actor_skills_list)
for skill_name, skill_level in skills.items():
skill_name = skill_name.lower()
if not (skill_name in skillsearch or
skillsearch in skill_name):
2020-11-19 14:02:16 +00:00
continue
2022-01-04 13:19:00 +00:00
skill_level_str = str(skill_level)
if skill_level < 100:
skill_level_str = '0' + skill_level_str
if skill_level < 10:
skill_level_str = '0' + skill_level_str
index_str = \
skill_level_str + ';' + actor + ';' + \
2021-12-26 10:29:52 +00:00
actor_json['name'] + \
';' + actor_json['icon']['url']
2022-01-04 13:19:00 +00:00
if index_str not in results:
results.append(index_str)
2020-12-13 22:13:45 +00:00
break
2022-01-04 13:19:00 +00:00
if not instance_only:
2020-11-19 14:02:16 +00:00
# search actor cache
2022-01-04 13:19:00 +00:00
for subdir, _, files in os.walk(base_dir + '/cache/actors/'):
for fname in files:
if not fname.endswith('.json'):
2020-11-19 14:02:16 +00:00
continue
2022-01-04 13:19:00 +00:00
if not is_account_dir(fname):
2021-04-21 16:09:56 +00:00
continue
2022-01-04 13:19:00 +00:00
actor_filename = os.path.join(subdir, fname)
cached_actor_json = load_json(actor_filename)
if cached_actor_json:
if cached_actor_json.get('actor'):
actor_json = cached_actor_json['actor']
2021-12-26 10:29:52 +00:00
if actor_json.get('id') and \
2021-12-28 20:32:11 +00:00
no_of_actor_skills(actor_json) > 0 and \
2021-12-26 10:29:52 +00:00
actor_json.get('name') and \
actor_json.get('icon'):
actor = actor_json['id']
2022-01-04 13:19:00 +00:00
actor_skills_list = \
2021-12-26 10:29:52 +00:00
actor_json['hasOccupation']['skills']
2022-01-04 13:19:00 +00:00
skills = get_skills_from_list(actor_skills_list)
for skill_name, skill_level in skills.items():
skill_name = skill_name.lower()
if not (skill_name in skillsearch or
skillsearch in skill_name):
2020-11-19 14:02:16 +00:00
continue
2022-01-04 13:19:00 +00:00
skill_level_str = str(skill_level)
if skill_level < 100:
skill_level_str = '0' + skill_level_str
if skill_level < 10:
skill_level_str = '0' + skill_level_str
index_str = \
skill_level_str + ';' + actor + ';' + \
2021-12-26 10:29:52 +00:00
actor_json['name'] + \
';' + actor_json['icon']['url']
2022-01-04 13:19:00 +00:00
if index_str not in results:
results.append(index_str)
2020-12-13 22:13:45 +00:00
break
2020-11-19 14:02:16 +00:00
results.sort(reverse=True)
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-profile.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/epicyon.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon.css'
2020-11-19 14:02:16 +00:00
2022-01-04 13:19:00 +00:00
instance_title = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceTitle')
2022-01-04 13:19:00 +00:00
skill_search_form = \
html_header_with_external_style(css_filename, instance_title, None)
skill_search_form += \
2020-12-07 12:28:13 +00:00
'<center><h1><a href = "' + actor + '/search">' + \
2020-12-07 12:25:32 +00:00
translate['Skills search'] + ': ' + \
skillsearch + \
'</a></h1></center>'
2020-11-19 14:02:16 +00:00
if len(results) == 0:
2022-01-04 13:19:00 +00:00
skill_search_form += \
2020-11-19 14:02:16 +00:00
'<center><h5>' + translate['No results'] + \
'</h5></center>'
else:
2022-01-04 13:19:00 +00:00
skill_search_form += '<center>'
2020-11-19 14:02:16 +00:00
ctr = 0
2022-01-04 13:19:00 +00:00
for skill_match in results:
skill_match_fields = skill_match.split(';')
if len(skill_match_fields) != 4:
2020-11-09 19:41:01 +00:00
continue
2022-01-04 13:19:00 +00:00
actor = skill_match_fields[1]
actor_name = skill_match_fields[2]
avatar_url = skill_match_fields[3]
skill_search_form += \
2020-11-19 14:02:16 +00:00
'<div class="search-result""><a href="' + \
actor + '/skills">'
2022-01-04 13:19:00 +00:00
skill_search_form += \
2022-03-28 08:47:53 +00:00
'<img loading="lazy" decoding="async" src="' + avatar_url + \
2022-01-04 13:19:00 +00:00
'" alt="" /><span class="search-result-text">' + actor_name + \
2020-11-19 14:02:16 +00:00
'</span></a></div>'
ctr += 1
2022-01-04 13:19:00 +00:00
if ctr >= posts_per_page:
2020-11-19 14:02:16 +00:00
break
2022-01-04 13:19:00 +00:00
skill_search_form += '</center>'
skill_search_form += html_footer()
return skill_search_form
2020-11-09 19:41:01 +00:00
2020-11-19 14:02:16 +00:00
2021-12-29 21:55:09 +00:00
def html_history_search(css_cache: {}, translate: {}, base_dir: str,
http_prefix: str,
nickname: str, domain: str,
historysearch: str,
2022-01-04 13:19:00 +00:00
posts_per_page: int, page_number: int,
2021-12-29 21:55:09 +00:00
project_version: str,
recent_posts_cache: {},
max_recent_posts: int,
session,
cached_webfingers,
person_cache: {},
port: int,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
peertube_instances: [],
allow_local_network_access: bool,
theme_name: str, boxName: str,
system_language: str,
max_like_count: int,
signing_priv_key_pem: str,
cw_lists: {},
2022-02-25 19:12:40 +00:00
lists_enabled: str,
2022-03-24 13:14:41 +00:00
timezone: str, bold_reading: bool) -> str:
2020-11-19 14:02:16 +00:00
"""Show a page containing search results for your post history
"""
if historysearch.startswith("'"):
2020-11-19 14:02:16 +00:00
historysearch = historysearch[1:].strip()
historysearch = historysearch.lower().strip('\n').strip('\r')
2022-01-04 13:19:00 +00:00
box_filenames = \
2021-12-28 13:07:02 +00:00
search_box_posts(base_dir, nickname, domain,
2022-01-04 13:19:00 +00:00
historysearch, posts_per_page, boxName)
2020-11-19 14:02:16 +00:00
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-profile.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/epicyon.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon.css'
2020-11-19 14:02:16 +00:00
2022-01-04 13:19:00 +00:00
instance_title = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceTitle')
2022-01-04 13:19:00 +00:00
history_search_form = \
html_header_with_external_style(css_filename, instance_title, None)
2020-11-19 14:02:16 +00:00
# add the page title
2021-12-26 12:45:03 +00:00
domain_full = get_full_domain(domain, port)
2021-12-26 10:19:59 +00:00
actor = local_actor_url(http_prefix, nickname, domain_full)
2022-01-04 13:19:00 +00:00
history_search_title = '🔍 ' + translate['Your Posts']
2021-05-03 22:33:12 +00:00
if boxName == 'bookmarks':
2022-01-04 13:19:00 +00:00
history_search_title = '🔍 ' + translate['Bookmarks']
2021-05-03 22:31:06 +00:00
2022-01-04 13:19:00 +00:00
history_search_form += \
2020-12-07 12:16:30 +00:00
'<center><h1><a href="' + actor + '/search">' + \
2022-01-04 13:19:00 +00:00
history_search_title + '</a></h1></center>'
2020-11-19 14:02:16 +00:00
2022-01-04 13:19:00 +00:00
if len(box_filenames) == 0:
history_search_form += \
2020-11-19 14:02:16 +00:00
'<center><h5>' + translate['No results'] + \
'</h5></center>'
2022-01-04 13:19:00 +00:00
return history_search_form
2020-11-19 14:02:16 +00:00
2022-01-04 13:19:00 +00:00
separator_str = html_post_separator(base_dir, None)
2020-11-19 14:02:16 +00:00
# ensure that the page number is in bounds
2022-01-04 13:19:00 +00:00
if not page_number:
page_number = 1
elif page_number < 1:
page_number = 1
2020-11-19 14:02:16 +00:00
# get the start end end within the index file
2022-01-04 13:19:00 +00:00
start_index = int((page_number - 1) * posts_per_page)
end_index = start_index + posts_per_page
no_of_box_filenames = len(box_filenames)
if end_index >= no_of_box_filenames and no_of_box_filenames > 0:
end_index = no_of_box_filenames - 1
index = start_index
while index <= end_index:
post_filename = box_filenames[index]
2021-12-26 23:41:34 +00:00
if not post_filename:
2020-11-19 14:02:16 +00:00
index += 1
continue
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-25 22:09:19 +00:00
if not post_json_object:
2020-11-19 14:02:16 +00:00
index += 1
continue
2022-01-04 13:19:00 +00:00
show_individual_post_icons = True
2021-12-25 21:29:53 +00:00
allow_deletion = False
2022-01-04 13:19:00 +00:00
post_str = \
2021-12-29 21:55:09 +00:00
individual_post_as_html(signing_priv_key_pem,
True, recent_posts_cache,
max_recent_posts,
translate, None,
base_dir, session, cached_webfingers,
person_cache,
nickname, domain, port,
post_json_object,
None, True, allow_deletion,
http_prefix, project_version,
'search',
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
allow_local_network_access,
theme_name, system_language,
max_like_count,
2022-01-04 13:19:00 +00:00
show_individual_post_icons,
show_individual_post_icons,
2021-12-29 21:55:09 +00:00
False, False, False, False,
2022-02-25 19:12:40 +00:00
cw_lists, lists_enabled,
2022-03-24 13:14:41 +00:00
timezone, False, bold_reading)
2022-01-04 13:19:00 +00:00
if post_str:
history_search_form += separator_str + post_str
2020-11-19 14:02:16 +00:00
index += 1
2022-01-04 13:19:00 +00:00
history_search_form += html_footer()
return history_search_form
2020-11-09 19:41:01 +00:00
2021-12-29 21:55:09 +00:00
def html_hashtag_search(css_cache: {},
nickname: str, domain: str, port: int,
recent_posts_cache: {}, max_recent_posts: int,
translate: {},
2022-01-04 13:19:00 +00:00
base_dir: str, hashtag: str, page_number: int,
posts_per_page: int,
2021-12-29 21:55:09 +00:00
session, cached_webfingers: {}, person_cache: {},
http_prefix: str, project_version: str,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
peertube_instances: [],
allow_local_network_access: bool,
theme_name: str, system_language: str,
max_like_count: int,
signing_priv_key_pem: str,
2022-02-25 19:12:40 +00:00
cw_lists: {}, lists_enabled: str,
2022-03-24 13:14:41 +00:00
timezone: str, bold_reading: bool) -> str:
2020-11-09 19:41:01 +00:00
"""Show a page containing search results for a hashtag
2021-07-21 13:43:04 +00:00
or after selecting a hashtag from the swarm
2020-11-09 19:41:01 +00:00
"""
if hashtag.startswith('#'):
hashtag = hashtag[1:]
hashtag = urllib.parse.unquote(hashtag)
2022-01-04 13:19:00 +00:00
hashtag_index_file = base_dir + '/tags/' + hashtag + '.txt'
if not os.path.isfile(hashtag_index_file):
2020-11-09 19:41:01 +00:00
if hashtag != hashtag.lower():
hashtag = hashtag.lower()
2022-01-04 13:19:00 +00:00
hashtag_index_file = base_dir + '/tags/' + hashtag + '.txt'
if not os.path.isfile(hashtag_index_file):
print('WARN: hashtag file not found ' + hashtag_index_file)
2020-11-09 19:41:01 +00:00
return None
2022-01-04 13:19:00 +00:00
separator_str = html_post_separator(base_dir, None)
2020-11-09 19:41:01 +00:00
# check that the directory for the nickname exists
if nickname:
2022-01-04 13:19:00 +00:00
account_dir = acct_dir(base_dir, nickname, domain)
if not os.path.isdir(account_dir):
2020-11-09 19:41:01 +00:00
nickname = None
# read the index
2022-01-04 13:19:00 +00:00
with open(hashtag_index_file, 'r') as fp_hash:
lines = fp_hash.readlines()
2020-11-09 19:41:01 +00:00
# read the css
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon-profile.css'
2021-12-25 16:17:53 +00:00
if os.path.isfile(base_dir + '/epicyon.css'):
2021-12-31 21:18:12 +00:00
css_filename = base_dir + '/epicyon.css'
2020-11-09 19:41:01 +00:00
# ensure that the page number is in bounds
2022-01-04 13:19:00 +00:00
if not page_number:
page_number = 1
elif page_number < 1:
page_number = 1
2020-11-09 19:41:01 +00:00
# get the start end end within the index file
2022-01-04 13:19:00 +00:00
start_index = int((page_number - 1) * posts_per_page)
end_index = start_index + posts_per_page
no_of_lines = len(lines)
if end_index >= no_of_lines and no_of_lines > 0:
end_index = no_of_lines - 1
2020-11-09 19:41:01 +00:00
# add the page title
2022-01-04 13:19:00 +00:00
instance_title = \
2021-12-26 14:08:58 +00:00
get_config_param(base_dir, 'instanceTitle')
2022-01-04 13:19:00 +00:00
hashtag_search_form = \
html_header_with_external_style(css_filename, instance_title, None)
2020-11-09 19:41:01 +00:00
if nickname:
2022-01-04 13:19:00 +00:00
hashtag_search_form += '<center>\n' + \
2020-11-09 19:41:01 +00:00
'<h1><a href="/users/' + nickname + '/search">#' + \
2020-12-01 22:21:33 +00:00
hashtag + '</a></h1>\n'
2020-11-09 19:41:01 +00:00
else:
2022-01-04 13:19:00 +00:00
hashtag_search_form += '<center>\n' + \
2020-12-01 22:21:33 +00:00
'<h1>#' + hashtag + '</h1>\n'
# RSS link for hashtag feed
2022-01-04 13:19:00 +00:00
hashtag_search_form += '<a href="/tags/rss2/' + hashtag + '">'
hashtag_search_form += \
2020-12-01 22:21:33 +00:00
'<img style="width:3%;min-width:50px" ' + \
2022-03-28 08:47:53 +00:00
'loading="lazy" decoding="async" ' + \
'alt="RSS 2.0" title="RSS 2.0" src="/' + \
2020-12-09 13:08:26 +00:00
'icons/logorss.png" /></a></center>\n'
2020-11-09 19:41:01 +00:00
2020-12-01 21:44:27 +00:00
# edit the category for this hashtag
2021-12-26 13:27:57 +00:00
if is_editor(base_dir, nickname):
2021-12-29 21:55:09 +00:00
category = get_hashtag_category(base_dir, hashtag)
2022-01-04 13:19:00 +00:00
hashtag_search_form += '<div class="hashtagCategoryContainer">\n'
hashtag_search_form += ' <form enctype="multipart/form-data" ' + \
2020-12-02 11:55:40 +00:00
'method="POST" accept-charset="UTF-8" action="' + \
2020-12-02 11:12:56 +00:00
'/users/' + nickname + '/tags/' + hashtag + \
'/sethashtagcategory">\n'
2022-01-04 13:19:00 +00:00
hashtag_search_form += ' <center>\n'
hashtag_search_form += translate['Category']
hashtag_search_form += \
2020-12-01 22:56:26 +00:00
' <input type="text" style="width: 20ch" ' + \
2020-12-01 22:54:09 +00:00
'name="hashtagCategory" value="' + category + '">\n'
2022-01-04 13:19:00 +00:00
hashtag_search_form += \
2020-12-01 21:44:27 +00:00
' <button type="submit" class="button" name="submitYes">' + \
translate['Submit'] + '</button>\n'
2022-01-04 13:19:00 +00:00
hashtag_search_form += ' </center>\n'
hashtag_search_form += ' </form>\n'
hashtag_search_form += '</div>\n'
2022-01-04 13:19:00 +00:00
if start_index > 0:
2020-11-09 19:41:01 +00:00
# previous page link
2022-01-04 13:19:00 +00:00
hashtag_search_form += \
2020-11-09 19:41:01 +00:00
' <center>\n' + \
2021-10-20 16:08:20 +00:00
' <a href="/users/' + nickname + \
'/tags/' + hashtag + '?page=' + \
2022-01-04 13:19:00 +00:00
str(page_number - 1) + \
2022-03-28 08:47:53 +00:00
'"><img loading="lazy" decoding="async" ' + \
'class="pageicon" src="/' + \
2020-12-09 13:08:26 +00:00
'icons/pageup.png" title="' + \
2020-11-09 19:41:01 +00:00
translate['Page up'] + \
'" alt="' + translate['Page up'] + \
'"></a>\n </center>\n'
2022-01-04 13:19:00 +00:00
index = start_index
while index <= end_index:
2021-12-26 19:47:06 +00:00
post_id = lines[index].strip('\n').strip('\r')
if ' ' not in post_id:
2021-12-27 22:19:18 +00:00
nickname = get_nickname_from_actor(post_id)
2020-11-09 19:41:01 +00:00
if not nickname:
index += 1
continue
else:
2022-01-04 13:19:00 +00:00
post_fields = post_id.split(' ')
if len(post_fields) != 3:
2020-11-09 19:41:01 +00:00
index += 1
continue
2022-01-04 13:19:00 +00:00
nickname = post_fields[1]
post_id = post_fields[2]
2021-12-26 23:41:34 +00:00
post_filename = locate_post(base_dir, nickname, domain, post_id)
if not post_filename:
2020-11-09 19:41:01 +00:00
index += 1
continue
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-25 22:09:19 +00:00
if not post_json_object:
2020-11-30 10:44:37 +00:00
index += 1
continue
2021-12-28 14:41:10 +00:00
if not is_public_post(post_json_object):
2020-11-30 10:44:37 +00:00
index += 1
continue
2022-01-04 13:19:00 +00:00
show_individual_post_icons = False
2020-11-30 10:44:37 +00:00
if nickname:
2022-01-04 13:19:00 +00:00
show_individual_post_icons = True
2021-12-25 21:29:53 +00:00
allow_deletion = False
2022-01-04 13:19:00 +00:00
show_repeats = show_individual_post_icons
show_icons = show_individual_post_icons
manually_approves_followers = False
show_public_only = False
store_to_sache = False
allow_downloads = True
avatar_url = None
show_avatar_options = True
post_str = \
2021-12-29 21:55:09 +00:00
individual_post_as_html(signing_priv_key_pem,
2022-01-04 13:19:00 +00:00
allow_downloads, recent_posts_cache,
2021-12-29 21:55:09 +00:00
max_recent_posts,
translate, None,
base_dir, session, cached_webfingers,
person_cache,
nickname, domain, port,
post_json_object,
2022-01-04 13:19:00 +00:00
avatar_url, show_avatar_options,
2021-12-29 21:55:09 +00:00
allow_deletion,
http_prefix, project_version,
'search',
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
allow_local_network_access,
theme_name, system_language,
max_like_count,
2022-01-04 13:19:00 +00:00
show_repeats, show_icons,
manually_approves_followers,
show_public_only,
store_to_sache, False, cw_lists,
2022-03-24 13:14:41 +00:00
lists_enabled, timezone, False,
bold_reading)
2022-01-04 13:19:00 +00:00
if post_str:
hashtag_search_form += separator_str + post_str
2020-11-09 19:41:01 +00:00
index += 1
2022-01-04 13:19:00 +00:00
if end_index < no_of_lines - 1:
2020-11-09 19:41:01 +00:00
# next page link
2022-01-04 13:19:00 +00:00
hashtag_search_form += \
2020-11-09 19:41:01 +00:00
' <center>\n' + \
2021-10-20 16:08:20 +00:00
' <a href="/users/' + nickname + '/tags/' + hashtag + \
2022-01-04 13:19:00 +00:00
'?page=' + str(page_number + 1) + \
2022-03-28 08:47:53 +00:00
'"><img loading="lazy" decoding="async" ' + \
'class="pageicon" src="/icons' + \
2020-11-09 19:41:01 +00:00
'/pagedown.png" title="' + translate['Page down'] + \
'" alt="' + translate['Page down'] + '"></a>' + \
' </center>'
2022-01-04 13:19:00 +00:00
hashtag_search_form += html_footer()
return hashtag_search_form
2020-11-09 19:41:01 +00:00
2021-12-29 21:55:09 +00:00
def rss_hashtag_search(nickname: str, domain: str, port: int,
recent_posts_cache: {}, max_recent_posts: int,
translate: {},
base_dir: str, hashtag: str,
2022-01-04 13:19:00 +00:00
posts_per_page: int,
2021-12-29 21:55:09 +00:00
session, cached_webfingers: {}, person_cache: {},
http_prefix: str, project_version: str,
yt_replace_domain: str,
twitter_replacement_domain: str,
system_language: str) -> str:
2020-11-09 19:41:01 +00:00
"""Show an rss feed for a hashtag
"""
if hashtag.startswith('#'):
hashtag = hashtag[1:]
hashtag = urllib.parse.unquote(hashtag)
2022-01-04 13:19:00 +00:00
hashtag_index_file = base_dir + '/tags/' + hashtag + '.txt'
if not os.path.isfile(hashtag_index_file):
2020-11-09 19:41:01 +00:00
if hashtag != hashtag.lower():
hashtag = hashtag.lower()
2022-01-04 13:19:00 +00:00
hashtag_index_file = base_dir + '/tags/' + hashtag + '.txt'
if not os.path.isfile(hashtag_index_file):
print('WARN: hashtag file not found ' + hashtag_index_file)
2020-11-09 19:41:01 +00:00
return None
# check that the directory for the nickname exists
if nickname:
2022-01-04 13:19:00 +00:00
account_dir = acct_dir(base_dir, nickname, domain)
if not os.path.isdir(account_dir):
2020-11-09 19:41:01 +00:00
nickname = None
# read the index
lines = []
2022-01-04 13:19:00 +00:00
with open(hashtag_index_file, 'r') as fp_hash:
lines = fp_hash.readlines()
2020-11-09 19:41:01 +00:00
if not lines:
return None
2021-12-26 12:45:03 +00:00
domain_full = get_full_domain(domain, port)
2020-11-09 19:41:01 +00:00
2022-01-04 13:19:00 +00:00
max_feed_length = 10
2022-01-08 10:58:54 +00:00
hashtag_feed = rss2tag_header(hashtag, http_prefix, domain_full)
for index, _ in enumerate(lines):
2021-12-26 19:47:06 +00:00
post_id = lines[index].strip('\n').strip('\r')
if ' ' not in post_id:
2021-12-27 22:19:18 +00:00
nickname = get_nickname_from_actor(post_id)
2020-11-09 19:41:01 +00:00
if not nickname:
index += 1
2022-01-04 13:19:00 +00:00
if index >= max_feed_length:
2020-11-09 19:41:01 +00:00
break
continue
else:
2022-01-04 13:19:00 +00:00
post_fields = post_id.split(' ')
if len(post_fields) != 3:
2020-11-09 19:41:01 +00:00
index += 1
2022-01-04 13:19:00 +00:00
if index >= max_feed_length:
2020-11-09 19:41:01 +00:00
break
continue
2022-01-04 13:19:00 +00:00
nickname = post_fields[1]
post_id = post_fields[2]
2021-12-26 23:41:34 +00:00
post_filename = locate_post(base_dir, nickname, domain, post_id)
if not post_filename:
2020-11-09 19:41:01 +00:00
index += 1
2022-01-04 13:19:00 +00:00
if index >= max_feed_length:
2020-11-09 19:41:01 +00:00
break
continue
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-25 22:09:19 +00:00
if post_json_object:
2021-12-28 14:41:10 +00:00
if not is_public_post(post_json_object):
2020-11-09 19:41:01 +00:00
index += 1
2022-01-04 13:19:00 +00:00
if index >= max_feed_length:
2020-11-09 19:41:01 +00:00
break
continue
# add to feed
2021-12-25 22:09:19 +00:00
if post_json_object['object'].get('content') and \
post_json_object['object'].get('attributedTo') and \
post_json_object['object'].get('published'):
published = post_json_object['object']['published']
2022-01-04 13:19:00 +00:00
pub_date = datetime.strptime(published, "%Y-%m-%dT%H:%M:%SZ")
rss_date_str = pub_date.strftime("%a, %d %b %Y %H:%M:%S UT")
hashtag_feed += ' <item>'
hashtag_feed += \
2020-11-09 19:41:01 +00:00
' <author>' + \
2021-12-25 22:09:19 +00:00
post_json_object['object']['attributedTo'] + \
2020-11-09 19:41:01 +00:00
'</author>'
2021-12-25 22:09:19 +00:00
if post_json_object['object'].get('summary'):
2022-01-04 13:19:00 +00:00
hashtag_feed += \
2020-11-09 19:41:01 +00:00
' <title>' + \
2021-12-25 22:09:19 +00:00
post_json_object['object']['summary'] + \
2020-11-09 19:41:01 +00:00
'</title>'
description = \
2021-12-26 11:29:40 +00:00
get_base_content_from_post(post_json_object,
system_language)
2021-12-27 15:52:08 +00:00
description = first_paragraph_from_string(description)
2022-01-04 13:19:00 +00:00
hashtag_feed += \
2020-11-09 19:41:01 +00:00
' <description>' + description + '</description>'
2022-01-04 13:19:00 +00:00
hashtag_feed += \
' <pubDate>' + rss_date_str + '</pubDate>'
2021-12-25 22:09:19 +00:00
if post_json_object['object'].get('attachment'):
for attach in post_json_object['object']['attachment']:
2020-11-09 19:41:01 +00:00
if not attach.get('url'):
continue
2022-01-04 13:19:00 +00:00
hashtag_feed += \
2020-11-09 19:41:01 +00:00
' <link>' + attach['url'] + '</link>'
2022-01-04 13:19:00 +00:00
hashtag_feed += ' </item>'
2020-11-09 19:41:01 +00:00
index += 1
2022-01-04 13:19:00 +00:00
if index >= max_feed_length:
2020-11-09 19:41:01 +00:00
break
2022-01-04 13:19:00 +00:00
return hashtag_feed + rss2tag_footer()