Merge branch 'main' of gitlab.com:bashrc2/epicyon

merge-requests/30/head
Bob Mottram 2022-08-22 23:28:17 +01:00
commit d209c5c256
36 changed files with 923 additions and 275 deletions

View File

@ -403,6 +403,7 @@ from crawlers import blocked_user_agent
from crawlers import load_known_web_bots
from qrcode import save_domain_qrcode
from importFollowing import run_import_following_watchdog
from maps import kml_from_tagmaps_path
import os
@ -14243,6 +14244,7 @@ class PubServer(BaseHTTPRequestHandler):
'/statuses/' not in path and \
'/emoji/' not in path and \
'/tags/' not in path and \
'/tagmaps/' not in path and \
'/avatars/' not in path and \
'/favicons/' not in path and \
'/headers/' not in path and \
@ -17086,6 +17088,24 @@ class PubServer(BaseHTTPRequestHandler):
self.server.getreq_busy = False
return
# hashtag map kml
if self.path.startswith('/tagmaps/') or \
(authorized and '/tagmaps/' in self.path):
kml_str = kml_from_tagmaps_path(self.server.base_dir, self.path)
if kml_str:
msg = kml_str.encode('utf-8')
msglen = len(msg)
header_type = \
'application/vnd.google-earth.kml+xml; charset=utf-8'
self._set_headers(header_type, msglen,
None, calling_domain, True)
self._write(msg)
self.server.getreq_busy = False
return
self._404()
self.server.getreq_busy = False
return
fitness_performance(getreq_start_time, self.server.fitness,
'_GET', 'hashtag search done',
self.server.debug)

File diff suppressed because one or more lines are too long

View File

@ -136,6 +136,10 @@ from content import load_dogwhistles
from content import valid_url_lengths
from content import remove_script
from threads import begin_thread
from maps import get_map_links_from_post_content
from maps import get_location_from_tags
from maps import add_tag_map_links
from maps import geocoords_from_map_link
def cache_svg_images(session, base_dir: str, http_prefix: str,
@ -327,6 +331,32 @@ def store_hash_tags(base_dir: str, nickname: str, domain: str,
print('Creating tags directory')
os.mkdir(tags_dir)
# obtain any map links and these can be associated with hashtags
# get geolocations from content
map_links = []
published = None
if post_json_object['object'].get('content'):
published = post_json_object['object']['published']
post_content = post_json_object['object']['content']
map_links += get_map_links_from_post_content(post_content)
# get geolocation from tags
location_str = \
get_location_from_tags(post_json_object['object']['tag'])
if location_str:
if '://' in location_str and '.' in location_str:
zoom, latitude, longitude = geocoords_from_map_link(location_str)
if latitude and longitude and zoom and \
location_str not in map_links:
map_links.append(location_str)
tag_maps_dir = base_dir + '/tagmaps'
if map_links:
# add tagmaps directory if it doesn't exist
if not os.path.isdir(tag_maps_dir):
print('Creating tagmaps directory')
os.mkdir(tag_maps_dir)
post_url = remove_id_ending(post_json_object['id'])
post_url = post_url.replace('/', '#')
hashtags_ctr = 0
for tag in post_json_object['object']['tag']:
if not tag.get('type'):
@ -341,12 +371,13 @@ def store_hash_tags(base_dir: str, nickname: str, domain: str,
if not valid_hash_tag(tag_name):
continue
tags_filename = tags_dir + '/' + tag_name + '.txt'
post_url = remove_id_ending(post_json_object['id'])
post_url = post_url.replace('/', '#')
days_diff = datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)
days_since_epoch = days_diff.days
tag_line = \
str(days_since_epoch) + ' ' + nickname + ' ' + post_url + '\n'
if map_links and published:
add_tag_map_links(tag_maps_dir, tag_name, map_links,
published, post_url)
hashtag_added = False
if not os.path.isfile(tags_filename):
try:
@ -366,8 +397,8 @@ def store_hash_tags(base_dir: str, nickname: str, domain: str,
content = tag_line + content
try:
with open(tags_filename, 'w+',
encoding='utf-8') as tags_file:
tags_file.write(content)
encoding='utf-8') as tags_file2:
tags_file2.write(content)
hashtag_added = True
except OSError as ex:
print('EX: Failed to write entry to tags file ' +

261
maps.py
View File

@ -9,12 +9,29 @@ __module_group__ = "Core"
import os
import datetime
from utils import is_float
from utils import acct_dir
from utils import load_json
from utils import save_json
def get_location_from_tags(tags: []) -> str:
"""Returns the location from the tags list
"""
for tag_item in tags:
if not tag_item.get('type'):
continue
if tag_item['type'] != 'Place':
continue
if not tag_item.get('name'):
continue
if not isinstance(tag_item['name'], str):
continue
return tag_item['name'].replace('\n', ' ')
return None
def _geocoords_from_osm_link(url: str, osm_domain: str) -> (int, float, float):
"""Returns geocoordinates from an OSM map link
"""
@ -103,7 +120,10 @@ def _geocoords_from_gmaps_link(url: str) -> (int, float, float):
return None, None, None
zoom = coords[2]
if not zoom.isdigit():
return None, None, None
if is_float(str(zoom)):
zoom = int(float(str(zoom)))
else:
return None, None, None
latitude = coords[0]
if not is_float(latitude):
return None, None, None
@ -360,3 +380,242 @@ def get_map_preferences_coords(base_dir: str,
maps_json['longitude'], \
maps_json['zoom']
return None, None, None
def get_map_links_from_post_content(content: str) -> []:
"""Returns a list of map links
"""
osm_domain = 'openstreetmap.org'
sections = content.split('://')
map_links = []
ctr = 0
for link_str in sections:
if ctr == 0:
ctr += 1
continue
url = link_str
if '"' in url:
url = url.split('"')[0]
if '<' in url:
url = url.split('<')[0]
if not url:
continue
zoom, latitude, longitude = geocoords_from_map_link(url, osm_domain)
if not latitude:
continue
if not longitude:
continue
if not zoom:
continue
if url not in map_links:
map_links.append(url)
ctr += 1
return map_links
def add_tag_map_links(tag_maps_dir: str, tag_name: str,
map_links: [], published: str, post_url: str) -> None:
"""Appends to a hashtag file containing map links
This is used to show a map for a particular hashtag
"""
tag_map_filename = tag_maps_dir + '/' + tag_name + '.txt'
post_url = post_url.replace('#', '/')
# read the existing map links
existing_map_links = []
if os.path.isfile(tag_map_filename):
try:
with open(tag_map_filename, 'r', encoding='utf-8') as fp_tag:
existing_map_links = fp_tag.read().split('\n')
except OSError:
print('EX: error reading tag map ' + tag_map_filename)
# combine map links with the existing list
secs_since_epoch = \
int((datetime.datetime.strptime(published, '%Y-%m-%dT%H:%M:%SZ') -
datetime.datetime(1970, 1, 1)).total_seconds())
links_changed = False
for link in map_links:
line = str(secs_since_epoch) + ' ' + link + ' ' + post_url
if line in existing_map_links:
continue
links_changed = True
existing_map_links = [line] + existing_map_links
if not links_changed:
return
# sort the list of map links
existing_map_links.sort(reverse=True)
map_links_str = ''
ctr = 0
for link in existing_map_links:
if not link:
continue
map_links_str += link + '\n'
ctr += 1
# don't allow the list to grow indefinitely
if ctr >= 2000:
break
# save the tag
try:
with open(tag_map_filename, 'w+', encoding='utf-8') as fp_tag:
fp_tag.write(map_links_str)
except OSError:
print('EX: error writing tag map ' + tag_map_filename)
def _hashtag_map_to_kml(base_dir: str, tag_name: str,
start_hours_since_epoch: int,
end_hours_since_epoch: int) -> str:
"""Returns the KML for a given hashtag between the given times
"""
place_ctr = 0
osm_domain = 'openstreetmap.org'
tag_map_filename = base_dir + '/tagmaps/' + tag_name + '.txt'
kml_str = '<?xml version="1.0" encoding="UTF-8"?>\n'
kml_str += '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
kml_str += '<Document>\n'
if os.path.isfile(tag_map_filename):
map_links = []
try:
with open(tag_map_filename, 'r', encoding='utf-8') as fp_tag:
map_links = fp_tag.read().split('\n')
except OSError:
print('EX: unable to read tag map links ' + tag_map_filename)
if map_links:
start_secs_since_epoch = int(start_hours_since_epoch * 60 * 60)
end_secs_since_epoch = int(end_hours_since_epoch * 60 * 60)
for link_line in map_links:
link_line = link_line.strip().split(' ')
if len(link_line) < 3:
continue
secs_since_epoch = int(link_line[0])
if secs_since_epoch < start_secs_since_epoch or \
secs_since_epoch > end_secs_since_epoch:
continue
map_link = link_line[1]
zoom, latitude, longitude = \
geocoords_from_map_link(map_link, osm_domain)
if not zoom:
continue
if not latitude:
continue
if not longitude:
continue
post_id = link_line[2]
place_ctr += 1
kml_str += '<Placemark id="' + str(place_ctr) + '">\n'
kml_str += ' <name>' + str(place_ctr) + '</name>\n'
kml_str += ' <description><![CDATA[\n'
kml_str += '<a href="' + post_id + '">' + \
post_id + '</a>\n]]>\n'
kml_str += ' </description>\n'
kml_str += ' <Point>\n'
kml_str += ' <coordinates>' + str(longitude) + ',' + \
str(latitude) + ',0</coordinates>\n'
kml_str += ' </Point>\n'
kml_str += '</Placemark>\n'
kml_str += '</Document>\n'
kml_str += '</kml>'
if place_ctr == 0:
return None
return kml_str
def _hashtag_map_kml_within_hours(base_dir: str, tag_name: str,
hours: int) -> str:
"""Returns kml for a hashtag containing maps for the last number of hours
"""
secs_since_epoch = \
int((datetime.datetime.utcnow() -
datetime.datetime(1970, 1, 1)).total_seconds())
end_hours_since_epoch = int(secs_since_epoch / (60 * 60))
start_hours_since_epoch = end_hours_since_epoch - hours
kml_str = \
_hashtag_map_to_kml(base_dir, tag_name,
start_hours_since_epoch,
end_hours_since_epoch)
return kml_str
def _get_tagmaps_time_periods() -> {}:
"""dict of time periods for map display
"""
return {
"Last hour": -1,
"Last 3 hours": -3,
"Last 6 hours": -6,
"Last 12 hours": -12,
"Last day": -24,
"Last 2 days": -48,
"Last week": -24 * 7,
"Last 2 weeks": -24 * 7 * 2,
"Last month": -24 * 7 * 4,
"Last 6 months": -24 * 7 * 4 * 6,
"Last year": -24 * 7 * 4 * 12
}
def kml_from_tagmaps_path(base_dir: str, path: str) -> str:
"""Returns kml for a given tagmaps path
/tagmaps/tagname-time_period
"""
if '/tagmaps/' not in path:
return None
time_period = _get_tagmaps_time_periods()
tag_name = path.split('/tagmaps/')[1]
if '-' in tag_name:
tag_name = tag_name.split('-')[0]
if not tag_name:
return None
for period_str, hours in time_period.items():
period_str2 = period_str.replace('Last ', '').lower()
endpoint_str = \
'/tagmaps/' + tag_name + '-' + period_str2.replace(' ', '_')
if path == endpoint_str:
return _hashtag_map_kml_within_hours(base_dir, tag_name,
abs(hours))
return None
def html_hashtag_maps(base_dir: str, tag_name: str,
translate: {}) -> str:
"""Returns html for maps associated with a hashtag
"""
tag_map_filename = base_dir + '/tagmaps/' + tag_name + '.txt'
if not os.path.isfile(tag_map_filename):
return ''
time_period = _get_tagmaps_time_periods()
html_str = ''
kml_str = None
for period_str, hours in time_period.items():
new_kml_str = \
_hashtag_map_kml_within_hours(base_dir, tag_name, abs(hours))
if not new_kml_str:
continue
if new_kml_str == kml_str:
continue
kml_str = new_kml_str
period_str2 = period_str.replace('Last ', '').lower()
endpoint_str = \
'/tagmaps/' + tag_name + '-' + period_str2.replace(' ', '_')
download_filename = \
(tag_name + '-' +
period_str.lower()).replace(' ', '_') + '.kml'
if html_str:
html_str += ' '
description = period_str
if translate.get(period_str):
description = translate[period_str]
html_str += '<a href="' + endpoint_str + \
'" download="' + download_filename + '">' + \
description + '</a>'
if html_str:
html_str = '<center>🌍 ' + html_str + '</center>\n'
return html_str

View File

@ -40,6 +40,7 @@ from media import replace_you_tube
from media import replace_twitter
from media import get_media_path
from media import create_media_dirs
from inbox import store_hash_tags
from inbox import inbox_update_index
from announce import outbox_announce
from announce import outbox_undo_announce
@ -408,6 +409,10 @@ def post_message_to_outbox(session, translate: {},
if message_json['type'] != 'Upgrade':
outbox_name = 'outbox'
store_hash_tags(base_dir, post_to_nickname, domain,
http_prefix, domain_full,
message_json, translate)
# if this is a blog post or an event then save to its own box
if message_json['type'] == 'Create':
if has_object_dict(message_json):

View File

@ -1208,7 +1208,7 @@ def _remove_tags_for_nickname(base_dir: str, nickname: str,
continue
try:
tag_filename = os.path.join(directory, filename)
except BaseException:
except OSError:
print('EX: _remove_tags_for_nickname unable to join ' +
str(directory) + ' ' + str(filename))
continue

View File

@ -942,7 +942,8 @@ def save_post_to_box(base_dir: str, http_prefix: str, post_id: str,
return filename
def _update_hashtags_index(base_dir: str, tag: {}, new_post_id: str) -> None:
def _update_hashtags_index(base_dir: str, tag: {}, new_post_id: str,
nickname: str) -> None:
"""Writes the post url for hashtags to a file
This allows posts for a hashtag to be quickly looked up
"""
@ -955,25 +956,37 @@ def _update_hashtags_index(base_dir: str, tag: {}, new_post_id: str) -> None:
os.mkdir(tags_dir)
tag_name = tag['name']
tags_filename = tags_dir + '/' + tag_name[1:] + '.txt'
tagline = new_post_id + '\n'
new_post_id = new_post_id.replace('/', '#')
if not os.path.isfile(tags_filename):
days_diff = datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)
days_since_epoch = days_diff.days
tag_line = \
str(days_since_epoch) + ' ' + nickname + ' ' + \
new_post_id + '\n'
# create a new tags index file
try:
with open(tags_filename, 'w+', encoding='utf-8') as tags_file:
tags_file.write(tagline)
tags_file.write(tag_line)
except OSError:
print('EX: _update_hashtags_index unable to write tags file ' +
tags_filename)
else:
# prepend to tags index file
if not text_in_file(tagline, tags_filename):
if not text_in_file(new_post_id, tags_filename):
days_diff = \
datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)
days_since_epoch = days_diff.days
tag_line = \
str(days_since_epoch) + ' ' + nickname + ' ' + \
new_post_id + '\n'
try:
with open(tags_filename, 'r+', encoding='utf-8') as tags_file:
content = tags_file.read()
if tagline not in content:
if tag_line not in content:
tags_file.seek(0, 0)
tags_file.write(tagline + content)
tags_file.write(tag_line + content)
except OSError as ex:
print('EX: Failed to write entry to tags file ' +
tags_filename + ' ' + str(ex))
@ -1530,7 +1543,7 @@ def _create_post_base(base_dir: str,
if not post_tag_exists(tag['type'], tag['name'], tags):
tags.append(tag)
if is_public:
_update_hashtags_index(base_dir, tag, new_post_id)
_update_hashtags_index(base_dir, tag, new_post_id, nickname)
# print('Content tags: ' + str(tags))
sensitive, summary = \

View File

@ -191,6 +191,8 @@ from blocking import add_cw_from_lists
from happening import dav_month_via_server
from happening import dav_day_via_server
from webapp_theme_designer import color_contrast
from maps import get_map_links_from_post_content
from maps import geocoords_from_map_link
TEST_SERVER_GROUP_RUNNING = False
@ -7492,6 +7494,51 @@ def _test_combine_lines():
assert result == expected
def _test_hashtag_maps():
print('hashtag_maps')
content = \
"<p>This is a test, with a couple of links and a " + \
"<a href=\"https://epicyon.libreserver.org/tags/Hashtag\" " + \
"class=\"mention hashtag\" rel=\"tag\" tabindex=\"10\">#" + \
"<span>Hashtag</span></a><br><br>" + \
"<a href=\"https://" + \
"www.openstreetmap.org/#map=19/52.90860/-3.59917\" " + \
"tabindex=\"10\" rel=\"nofollow noopener noreferrer\" " + \
"target=\"_blank\"><span class=\"invisible\">https://" + \
"</span><span class=\"ellipsis\">" + \
"www.openstreetmap.org/#map=19/52.90860/-</span><span " + \
"class=\"invisible\">3.59917</span></a><br><br>" + \
"<a href=\"https://" + \
"www.google.com/maps/@52.217291,-3.0811865,20.04z\" " + \
"tabindex=\"10\" rel=\"nofollow noopener noreferrer\" " + \
"target=\"_blank\"><span class=\"invisible\">" + \
"https://</span><span class=\"ellipsis\">" + \
"www.google.com/maps/@52.217291,-3.081186</span>" + \
"<span class=\"invisible\">5,20.04z</span></a><br><br>" + \
"<a href=\"https://" + \
"epicyon.libreserver.org/tags/AnotherHashtag\" " + \
"class=\"mention hashtag\" rel=\"tag\" tabindex=\"10\">#" + \
"<span>AnotherHashtag</span></a></p>"
map_links = get_map_links_from_post_content(content)
link = "www.google.com/maps/@52.217291,-3.0811865,20.04z"
assert link in map_links
zoom, latitude, longitude = geocoords_from_map_link(link)
assert zoom == 20
assert latitude
assert int(latitude * 1000) == 52217
assert longitude
assert int(longitude * 1000) == -3081
link = "www.openstreetmap.org/#map=19/52.90860/-3.59917"
assert link in map_links
zoom, latitude, longitude = geocoords_from_map_link(link)
assert zoom == 19
assert latitude
assert int(latitude * 1000) == 52908
assert longitude
assert int(longitude * 1000) == -3599
assert len(map_links) == 2
def run_all_tests():
base_dir = os.getcwd()
print('Running tests...')
@ -7509,6 +7556,7 @@ def run_all_tests():
_test_checkbox_names()
_test_thread_functions()
_test_functions()
_test_hashtag_maps()
_test_combine_lines()
_test_text_standardize()
_test_dogwhistles()

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "احتفظ بالرسائل الخاصّة أثناء انتهاء صلاحية النشر",
"Notifications": "إشعارات",
"ntfy URL": "ntfy URL",
"ntfy topic": "موضوع ntfy"
"ntfy topic": "موضوع ntfy",
"Last hour": "الساعة الأخيرة",
"Last 3 hours": "آخر 3 ساعات",
"Last 6 hours": "آخر 6 ساعات",
"Last 12 hours": "آخر 12 ساعة",
"Last day": "بالأمس",
"Last 2 days": "آخر يومين",
"Last week": "الأسبوع الماضي",
"Last 2 weeks": "آخر أسبوعين",
"Last month": "الشهر الماضي",
"Last 6 months": "آخر 6 أشهر",
"Last year": "العام الماضي"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "পোস্টের মেয়াদ শেষ হওয়ার সময় সরাসরি বার্তা রাখুন",
"Notifications": "বিজ্ঞপ্তি",
"ntfy URL": "ntfy ইউআরএল",
"ntfy topic": "ntfy বিষয়"
"ntfy topic": "ntfy বিষয়",
"Last hour": "শেষ ঘন্টা",
"Last 3 hours": "শেষ ৩ ঘন্টা",
"Last 6 hours": "শেষ ৬ ঘণ্টা",
"Last 12 hours": "শেষ 12 ঘন্টা",
"Last day": "শেষ দিন",
"Last 2 days": "গত ২ দিন",
"Last week": "গত সপ্তাহে",
"Last 2 weeks": "গত ২ সপ্তাহ",
"Last month": "গত মাসে",
"Last 6 months": "গত ৬ মাস",
"Last year": "গত বছর"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Conserveu els missatges directes durant la caducitat posterior",
"Notifications": "Notificacions",
"ntfy URL": "URL ntfy",
"ntfy topic": "tema ntfy"
"ntfy topic": "tema ntfy",
"Last hour": "Última hora",
"Last 3 hours": "Últimes 3 hores",
"Last 6 hours": "Últimes 6 hores",
"Last 12 hours": "Últimes 12 hores",
"Last day": "L'últim dia",
"Last 2 days": "2 darrers dies",
"Last week": "La setmana passada",
"Last 2 weeks": "Últimes 2 setmanes",
"Last month": "El mes passat",
"Last 6 months": "Últims 6 mesos",
"Last year": "L'any passat"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Cadwch Negeseuon Uniongyrchol pan ddaw'r post i ben",
"Notifications": "Hysbysiadau",
"ntfy URL": "ntfy URL",
"ntfy topic": "pwnc ntfy"
"ntfy topic": "pwnc ntfy",
"Last hour": "Awr olaf",
"Last 3 hours": "3 awr diwethaf",
"Last 6 hours": "6 awr diwethaf",
"Last 12 hours": "12 awr diwethaf",
"Last day": "Diwrnod olaf",
"Last 2 days": "2 ddiwrnod diwethaf",
"Last week": "Wythnos diwethaf",
"Last 2 weeks": "2 wythnos diwethaf",
"Last month": "Mis diwethaf",
"Last 6 months": "6 mis diwethaf",
"Last year": "Blwyddyn diwethaf"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Bewahren Sie Direktnachrichten während des Ablaufs auf",
"Notifications": "Benachrichtigungen",
"ntfy URL": "ntfy-URL",
"ntfy topic": "ntfy-Thema"
"ntfy topic": "ntfy-Thema",
"Last hour": "Letzte Stunde",
"Last 3 hours": "Die letzten 3 Stunden",
"Last 6 hours": "Die letzten 6 Stunden",
"Last 12 hours": "Die letzten 12 Stunden",
"Last day": "Letzter Tag",
"Last 2 days": "Die letzten 2 Tage",
"Last week": "Letzte Woche",
"Last 2 weeks": "Letzte 2 Wochen",
"Last month": "Im vergangenen Monat",
"Last 6 months": "Letzte 6 Monate",
"Last year": "Vergangenes Jahr"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Διατηρήστε τα άμεσα μηνύματα κατά τη λήξη της ανάρτησης",
"Notifications": "Ειδοποιήσεις",
"ntfy URL": "ntfy URL",
"ntfy topic": "ntfy θέμα"
"ntfy topic": "ntfy θέμα",
"Last hour": "Τελευταία ώρα",
"Last 3 hours": "Τελευταίες 3 ώρες",
"Last 6 hours": "Τελευταίες 6 ώρες",
"Last 12 hours": "Τελευταίες 12 ώρες",
"Last day": "Τελευταία μέρα",
"Last 2 days": "Τελευταίες 2 μέρες",
"Last week": "Την προηγούμενη εβδομάδα",
"Last 2 weeks": "Τελευταίες 2 εβδομάδες",
"Last month": "Τον προηγούμενο μήνα",
"Last 6 months": "Τελευταίοι 6 μήνες",
"Last year": "Πέρυσι"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Keep DMs during post expiry",
"Notifications": "Notifications",
"ntfy URL": "ntfy URL",
"ntfy topic": "ntfy topic"
"ntfy topic": "ntfy topic",
"Last hour": "Last hour",
"Last 3 hours": "Last 3 hours",
"Last 6 hours": "Last 6 hours",
"Last 12 hours": "Last 12 hours",
"Last day": "Last day",
"Last 2 days": "Last 2 days",
"Last week": "Last week",
"Last 2 weeks": "Last 2 weeks",
"Last month": "Last month",
"Last 6 months": "Last 6 months",
"Last year": "Last year"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Conservar los mensajes directos durante el vencimiento de la publicación",
"Notifications": "Notificaciones",
"ntfy URL": "URL ntfy",
"ntfy topic": "tema ntfy"
"ntfy topic": "tema ntfy",
"Last hour": "Ultima hora",
"Last 3 hours": "últimas 3 horas",
"Last 6 hours": "últimas 6 horas",
"Last 12 hours": "últimas 12 horas",
"Last day": "Último día",
"Last 2 days": "últimos 2 días",
"Last week": "La semana pasada",
"Last 2 weeks": "últimas 2 semanas",
"Last month": "El mes pasado",
"Last 6 months": "últimos 6 meses",
"Last year": "El año pasado"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Conserver les messages directs après l'expiration",
"Notifications": "Avis",
"ntfy URL": "URL ntfy",
"ntfy topic": "sujet ntfy"
"ntfy topic": "sujet ntfy",
"Last hour": "Dernière heure",
"Last 3 hours": "3 dernières heures",
"Last 6 hours": "6 dernières heures",
"Last 12 hours": "12 dernières heures",
"Last day": "Dernier jour",
"Last 2 days": "2 derniers jours",
"Last week": "La semaine dernière",
"Last 2 weeks": "2 dernières semaines",
"Last month": "Le mois dernier",
"Last 6 months": "6 derniers mois",
"Last year": "L'année dernière"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Coinnigh Teachtaireachtaí Díreacha nuair a rachaidh postáil in éag",
"Notifications": "Fógraí",
"ntfy URL": "ntfy URL",
"ntfy topic": "topaic ntfy"
"ntfy topic": "topaic ntfy",
"Last hour": "Uair dheireanach",
"Last 3 hours": "3 uair an chloig caite",
"Last 6 hours": "6 uair an chloig caite",
"Last 12 hours": "12 uair an chloig caite",
"Last day": "Lá deirneach",
"Last 2 days": "2 lá seo caite",
"Last week": "An tseachtain seo caite",
"Last 2 weeks": "2 sheachtain anuas",
"Last month": "An mhí seo caite",
"Last 6 months": "6 mhí anuas",
"Last year": "Anuraidh"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "समाप्ति के बाद सीधे संदेश रखें",
"Notifications": "सूचनाएं",
"ntfy URL": "एनटीएफई यूआरएल",
"ntfy topic": "एनटीएफई विषय"
"ntfy topic": "एनटीएफई विषय",
"Last hour": "अंतिम घंटा",
"Last 3 hours": "पिछले 3 घंटे",
"Last 6 hours": "पिछले 6 घंटे",
"Last 12 hours": "पिछले 12 घंटे",
"Last day": "आखरी दिन",
"Last 2 days": "पिछले 2 दिन",
"Last week": "पिछले सप्ताह",
"Last 2 weeks": "पिछले 2 सप्ताह",
"Last month": "पिछले महीने",
"Last 6 months": "पिछले 6 महीने",
"Last year": "पिछले साल"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Conserva i messaggi diretti durante la scadenza successiva",
"Notifications": "Notifiche",
"ntfy URL": "ntfy URL",
"ntfy topic": "argomento ntfy"
"ntfy topic": "argomento ntfy",
"Last hour": "Ultima ora",
"Last 3 hours": "Ultime 3 ore",
"Last 6 hours": "Ultime 6 ore",
"Last 12 hours": "Ultime 12 ore",
"Last day": "Ultimo giorno",
"Last 2 days": "Ultimi 2 giorni",
"Last week": "La settimana scorsa",
"Last 2 weeks": "Ultime 2 settimane",
"Last month": "Lo scorso mese",
"Last 6 months": "Ultimi 6 mesi",
"Last year": "L'anno scorso"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "投稿の有効期限が切れるまでダイレクト メッセージを保持する",
"Notifications": "通知",
"ntfy URL": "ntfy URL",
"ntfy topic": "ntfy トピック"
"ntfy topic": "ntfy トピック",
"Last hour": "最後の時間",
"Last 3 hours": "過去 3 時間",
"Last 6 hours": "過去 6 時間",
"Last 12 hours": "過去 12 時間",
"Last day": "最終日",
"Last 2 days": "過去 2 日間",
"Last week": "先週",
"Last 2 weeks": "過去 2 週間",
"Last month": "先月",
"Last 6 months": "過去 6 か月",
"Last year": "去年"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "만료 후 DM 보관",
"Notifications": "알림",
"ntfy URL": "ntfy URL",
"ntfy topic": "ntfy 주제"
"ntfy topic": "ntfy 주제",
"Last hour": "지난 시간",
"Last 3 hours": "지난 3시간",
"Last 6 hours": "지난 6시간",
"Last 12 hours": "지난 12시간",
"Last day": "마지막 날",
"Last 2 days": "지난 2일",
"Last week": "지난주",
"Last 2 weeks": "지난 2주",
"Last month": "지난 달",
"Last 6 months": "지난 6개월",
"Last year": "작년"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Di dema qedandina postê de Peyamên Rasterast biparêzin",
"Notifications": "Notifications",
"ntfy URL": "ntfy URL",
"ntfy topic": "mijara ntfy"
"ntfy topic": "mijara ntfy",
"Last hour": "Saeta dawî",
"Last 3 hours": "3 saetên dawî",
"Last 6 hours": "6 saetên dawî",
"Last 12 hours": "12 saetên dawî",
"Last day": "Roja dawî",
"Last 2 days": "2 rojên dawî",
"Last week": "Hefteya çûyî",
"Last 2 weeks": "2 hefteyên dawî",
"Last month": "meha borî",
"Last 6 months": "6 mehên dawî",
"Last year": "Sala borî"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Directe berichten bewaren tijdens de vervaldatum",
"Notifications": "Meldingen",
"ntfy URL": "ntfy-URL",
"ntfy topic": "ntfy onderwerp"
"ntfy topic": "ntfy onderwerp",
"Last hour": "Laatste uur",
"Last 3 hours": "Laatste 3 uur",
"Last 6 hours": "Laatste 6 uur",
"Last 12 hours": "Laatste 12 uur",
"Last day": "Laatste dag",
"Last 2 days": "Laatste 2 dagen",
"Last week": "Vorige week",
"Last 2 weeks": "Afgelopen 2 weken",
"Last month": "Vorige maand",
"Last 6 months": "Afgelopen 6 maanden",
"Last year": "Afgelopen jaar"
}

View File

@ -572,5 +572,16 @@
"Keep DMs during post expiry": "Keep DMs during post expiry",
"Notifications": "Notifications",
"ntfy URL": "ntfy URL",
"ntfy topic": "ntfy topic"
"ntfy topic": "ntfy topic",
"Last hour": "Last hour",
"Last 3 hours": "Last 3 hours",
"Last 6 hours": "Last 6 hours",
"Last 12 hours": "Last 12 hours",
"Last day": "Last day",
"Last 2 days": "Last 2 days",
"Last week": "Last week",
"Last 2 weeks": "Last 2 weeks",
"Last month": "Last month",
"Last 6 months": "Last 6 months",
"Last year": "Last year"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Zachowaj bezpośrednie wiadomości po wygaśnięciu",
"Notifications": "Powiadomienia",
"ntfy URL": "URL ntfy",
"ntfy topic": "temat ntfy"
"ntfy topic": "temat ntfy",
"Last hour": "Ostatnia godzina",
"Last 3 hours": "Ostatnie 3 godzin",
"Last 6 hours": "Ostatnie 6 godzin",
"Last 12 hours": "Ostatnie 12 godzin",
"Last day": "Ostatni dzień",
"Last 2 days": "Ostatnie 2 dni",
"Last week": "Zeszły tydzień",
"Last 2 weeks": "Ostatnie 2 tygodnie",
"Last month": "W zeszłym miesiącu",
"Last 6 months": "Ostatnie 6 miesięcy",
"Last year": "Ostatni rok"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Manter mensagens diretas durante a expiração da postagem",
"Notifications": "Notificações",
"ntfy URL": "URL ntfy",
"ntfy topic": "tópico ntfy"
"ntfy topic": "tópico ntfy",
"Last hour": "Última hora",
"Last 3 hours": "Últimas 3 horas",
"Last 6 hours": "Últimas 6 horas",
"Last 12 hours": "Últimas 12 horas",
"Last day": "Último dia",
"Last 2 days": "Últimos 2 dias",
"Last week": "Semana Anterior",
"Last 2 weeks": "Últimas 2 semanas",
"Last month": "Mês passado",
"Last 6 months": "Últimos 6 meses",
"Last year": "Ano passado"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Сохраняйте личные сообщения в течение срока действия после истечения срока действия",
"Notifications": "Уведомления",
"ntfy URL": "URL-адрес ntfy",
"ntfy topic": "ntfy тема"
"ntfy topic": "ntfy тема",
"Last hour": "Последний час",
"Last 3 hours": "Последние 3 часов",
"Last 6 hours": "Последние 6 часов",
"Last 12 hours": "Последние 12 часов",
"Last day": "Последний день",
"Last 2 days": "Последние 2 дня",
"Last week": "Прошлая неделя",
"Last 2 weeks": "Последние 2 недели",
"Last month": "Прошлый месяц",
"Last 6 months": "Последние 6 месяцев",
"Last year": "Прошедший год"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Weka Ujumbe wa Moja kwa Moja wakati wa kuisha kwa chapisho",
"Notifications": "Arifa",
"ntfy URL": "ntfy URL",
"ntfy topic": "mada ya ntfy"
"ntfy topic": "mada ya ntfy",
"Last hour": "Saa iliyopita",
"Last 3 hours": "Saa 3 zilizopita",
"Last 6 hours": "Saa 6 zilizopita",
"Last 12 hours": "Saa 12 zilizopita",
"Last day": "Siku ya mwisho",
"Last 2 days": "Siku 2 zilizopita",
"Last week": "Wiki iliyopita",
"Last 2 weeks": "Wiki 2 zilizopita",
"Last month": "Mwezi uliopita",
"Last 6 months": "Miezi 6 iliyopita",
"Last year": "Mwaka jana"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Direkt Mesajları sona erme süresi boyunca saklayın",
"Notifications": "Bildirimler",
"ntfy URL": "ntfy URL'si",
"ntfy topic": "ntfy konusu"
"ntfy topic": "ntfy konusu",
"Last hour": "Son saat",
"Last 3 hours": "son 3 saat",
"Last 6 hours": "son 6 saat",
"Last 12 hours": "son 12 saat",
"Last day": "Son gun",
"Last 2 days": "son 2 gün",
"Last week": "Geçen hafta",
"Last 2 weeks": "Son 2 hafta",
"Last month": "Geçen ay",
"Last 6 months": "Son 6 ay",
"Last year": "Geçen yıl"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "Зберігайте прямі повідомлення протягом терміну дії",
"Notifications": "Сповіщення",
"ntfy URL": "ntfy URL",
"ntfy topic": "Тема ntfy"
"ntfy topic": "Тема ntfy",
"Last hour": "Остання година",
"Last 3 hours": "Останні 3 години",
"Last 6 hours": "Останні 6 години",
"Last 12 hours": "Останні 12 години",
"Last day": "Останній день",
"Last 2 days": "Останні 2 дні",
"Last week": "Минулого тижня",
"Last 2 weeks": "Останні 2 тижні",
"Last month": "Минулого місяця",
"Last 6 months": "Останні 6 місяців",
"Last year": "Минулого року"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "האַלטן דירעקט אַרטיקלען בעשאַס פּאָסטן עקספּיירי",
"Notifications": "נאָוטאַפאַקיישאַנז",
"ntfy URL": "ntfy URL",
"ntfy topic": "ntfy טעמע"
"ntfy topic": "ntfy טעמע",
"Last hour": "לעצטע שעה",
"Last 3 hours": "לעצטע 3 שעה",
"Last 6 hours": "לעצטע 6 שעה",
"Last 12 hours": "לעצטע 12 שעה",
"Last day": "לעצטע טאג",
"Last 2 days": "לעצטע 2 טעג",
"Last week": "לעצטע וואָך",
"Last 2 weeks": "לעצטע 2 וואָכן",
"Last month": "לעצטע מאנאט",
"Last 6 months": "לעצטע 6 חדשים",
"Last year": "לעצטע יאר"
}

View File

@ -576,5 +576,16 @@
"Keep DMs during post expiry": "在帖子到期期间保留直接消息",
"Notifications": "通知",
"ntfy URL": "ntfy 网址",
"ntfy topic": "ntfy 主题"
"ntfy topic": "ntfy 主题",
"Last hour": "上一个小时",
"Last 3 hours": "过去 3 小时",
"Last 6 hours": "过去 6 小时",
"Last 12 hours": "过去 12 小时",
"Last day": "最后一天",
"Last 2 days": "过去 2 天",
"Last week": "上周",
"Last 2 weeks": "过去 2 周",
"Last month": "上个月",
"Last 6 months": "过去 6 个月",
"Last year": "去年"
}

View File

@ -1900,6 +1900,35 @@ def delete_cached_html(base_dir: str, nickname: str, domain: str,
str(cached_post_filename))
def _remove_post_id_from_tag_index(tag_index_filename: str,
post_id: str) -> None:
"""Remove post_id from the tag index file
"""
lines = None
with open(tag_index_filename, 'r', encoding='utf-8') as index_file:
lines = index_file.readlines()
if not lines:
return
newlines = ''
for file_line in lines:
if post_id in file_line:
# skip over the deleted post
continue
newlines += file_line
if not newlines.strip():
# if there are no lines then remove the hashtag file
try:
os.remove(tag_index_filename)
except OSError:
print('EX: _delete_hashtags_on_post ' +
'unable to delete tag index ' + str(tag_index_filename))
else:
# write the new hashtag index without the given post in it
with open(tag_index_filename, 'w+',
encoding='utf-8') as index_file:
index_file.write(newlines)
def _delete_hashtags_on_post(base_dir: str, post_json_object: {}) -> None:
"""Removes hashtags when a post is deleted
"""
@ -1926,33 +1955,13 @@ def _delete_hashtags_on_post(base_dir: str, post_json_object: {}) -> None:
if not tag.get('name'):
continue
# find the index file for this tag
tag_map_filename = base_dir + '/tagmaps/' + tag['name'][1:] + '.txt'
if os.path.isfile(tag_map_filename):
_remove_post_id_from_tag_index(tag_map_filename, post_id)
# find the index file for this tag
tag_index_filename = base_dir + '/tags/' + tag['name'][1:] + '.txt'
if not os.path.isfile(tag_index_filename):
continue
# remove post_id from the tag index file
lines = None
with open(tag_index_filename, 'r', encoding='utf-8') as index_file:
lines = index_file.readlines()
if not lines:
continue
newlines = ''
for file_line in lines:
if post_id in file_line:
# skip over the deleted post
continue
newlines += file_line
if not newlines.strip():
# if there are no lines then remove the hashtag file
try:
os.remove(tag_index_filename)
except OSError:
print('EX: _delete_hashtags_on_post ' +
'unable to delete tag index ' + str(tag_index_filename))
else:
# write the new hashtag index without the given post in it
with open(tag_index_filename, 'w+',
encoding='utf-8') as index_file:
index_file.write(newlines)
if os.path.isfile(tag_index_filename):
_remove_post_id_from_tag_index(tag_index_filename, post_id)
def _delete_conversation_post(base_dir: str, nickname: str, domain: str,

View File

@ -99,22 +99,7 @@ from maps import html_open_street_map
from maps import set_map_preferences_coords
from maps import set_map_preferences_url
from maps import geocoords_from_map_link
def _get_location_from_tags(tags: []) -> str:
"""Returns the location from the tags list
"""
for tag_item in tags:
if not tag_item.get('type'):
continue
if tag_item['type'] != 'Place':
continue
if not tag_item.get('name'):
continue
if not isinstance(tag_item['name'], str):
continue
return tag_item['name'].replace('\n', ' ')
return None
from maps import get_location_from_tags
def _html_post_metadata_open_graph(domain: str, post_json_object: {},
@ -2298,7 +2283,7 @@ def individual_post_as_html(signing_priv_key_pem: str,
# show embedded map if the location contains a map url
location_str = \
_get_location_from_tags(post_json_object['object']['tag'])
get_location_from_tags(post_json_object['object']['tag'])
if location_str:
if '://' in location_str and '.' in location_str:
bounding_box_degrees = 0.001

View File

@ -40,6 +40,7 @@ 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
from maps import html_hashtag_maps
def html_search_emoji(translate: {}, base_dir: str, search_str: str) -> str:
@ -824,6 +825,8 @@ def html_hashtag_search(nickname: str, domain: str, port: int,
hashtag_search_form += ' </form>\n'
hashtag_search_form += '</div>\n'
hashtag_search_form += html_hashtag_maps(base_dir, hashtag, translate)
if start_index > 0:
# previous page link
hashtag_search_form += \