From 55bec518c0059ae9dbc9a8101b0596e04de8f59c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 8 Jan 2021 22:38:24 +0000 Subject: [PATCH 01/65] DMs aren't visible to unathorized users, even if they know the postId --- daemon.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/daemon.py b/daemon.py index 528fe5fff..250426cdf 100644 --- a/daemon.py +++ b/daemon.py @@ -65,6 +65,7 @@ from person import removeAccount from person import canRemovePost from person import personSnooze from person import personUnsnooze +from posts import isDM from posts import isModerator from posts import mutePost from posts import unmutePost @@ -6996,6 +6997,10 @@ class PubServer(BaseHTTPRequestHandler): # more social graph info if not authorized: pjo = postJsonObject + if isDM(pjo): + self._404() + self.server.GETbusy = False + return True self._removePostInteractions(pjo) if self._requestHTTP(): recentPostsCache = \ @@ -7114,6 +7119,10 @@ class PubServer(BaseHTTPRequestHandler): if not authorized: pjo = postJsonObject self._removePostInteractions(pjo) + if isDM(pjo): + self._404() + self.server.GETbusy = False + return True if self._requestHTTP(): recentPostsCache = \ From 6352a931ce1d21fb0038a130a26b8bcf05efcd0e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 8 Jan 2021 23:28:14 +0000 Subject: [PATCH 02/65] Instead of checkoing for dms check for public status --- daemon.py | 6 +++--- posts.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/daemon.py b/daemon.py index 250426cdf..d6bed05da 100644 --- a/daemon.py +++ b/daemon.py @@ -65,7 +65,6 @@ from person import removeAccount from person import canRemovePost from person import personSnooze from person import personUnsnooze -from posts import isDM from posts import isModerator from posts import mutePost from posts import unmutePost @@ -178,6 +177,7 @@ from shares import addShare from shares import removeShare from shares import expireShares from categories import setHashtagCategory +from utils import isPublicPost from utils import getLockedAccount from utils import hasUsersPath from utils import getFullDomain @@ -6997,7 +6997,7 @@ class PubServer(BaseHTTPRequestHandler): # more social graph info if not authorized: pjo = postJsonObject - if isDM(pjo): + if not isPublicPost(pjo): self._404() self.server.GETbusy = False return True @@ -7119,7 +7119,7 @@ class PubServer(BaseHTTPRequestHandler): if not authorized: pjo = postJsonObject self._removePostInteractions(pjo) - if isDM(pjo): + if not isPublicPost(pjo): self._404() self.server.GETbusy = False return True diff --git a/posts.py b/posts.py index e3af38f53..133929a9b 100644 --- a/posts.py +++ b/posts.py @@ -30,6 +30,7 @@ from session import postJsonString from session import postImage from webfinger import webfingerHandle from httpsig import createSignedHeader +from utils import isPublicPost from utils import hasUsersPath from utils import validPostDate from utils import getFullDomain @@ -3091,7 +3092,7 @@ def _createBoxIndexed(recentPostsCache: {}, if not authorized: if p.get('object'): if isinstance(p['object'], dict): - if isDM(p): + if not isPublicPost(p): continue if p['object'].get('likes'): p['likes'] = {'items': []} From c79ca40cc538fb7d0204572a3c0534d0cb9e365f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 8 Jan 2021 23:29:12 +0000 Subject: [PATCH 03/65] Sequence --- daemon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.py b/daemon.py index d6bed05da..7dfc843c4 100644 --- a/daemon.py +++ b/daemon.py @@ -7118,11 +7118,11 @@ class PubServer(BaseHTTPRequestHandler): # graph info if not authorized: pjo = postJsonObject - self._removePostInteractions(pjo) if not isPublicPost(pjo): self._404() self.server.GETbusy = False return True + self._removePostInteractions(pjo) if self._requestHTTP(): recentPostsCache = \ From 7d22d2ec25c626ff45ed5c68bbcceb2e245bc4d3 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 10:23:05 +0000 Subject: [PATCH 04/65] Handle exception on date format --- utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils.py b/utils.py index 0187f86ef..3ae51d9fa 100644 --- a/utils.py +++ b/utils.py @@ -47,8 +47,12 @@ def validPostDate(published: str, maxAgeDays=7) -> bool: daysDiff = datetime.datetime.utcnow() - baselineTime nowDaysSinceEpoch = daysDiff.days - postTimeObject = \ - datetime.datetime.strptime(published, "%Y-%m-%dT%H:%M:%SZ") + try: + postTimeObject = \ + datetime.datetime.strptime(published, "%Y-%m-%dT%H:%M:%SZ") + except BaseException: + return False + daysDiff = postTimeObject - baselineTime postDaysSinceEpoch = daysDiff.days From 579aa7f63d51e28c1c9461191311d239a8e4416b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 15:08:26 +0000 Subject: [PATCH 05/65] Add migrations option to check for moved follows --- epicyon.py | 31 +++++++++ migrate.py | 195 +++++++++++++++++++++++++++++++++++++++++++---------- tests.py | 1 - 3 files changed, 192 insertions(+), 35 deletions(-) diff --git a/epicyon.py b/epicyon.py index c7af7bfd0..f485ea410 100644 --- a/epicyon.py +++ b/epicyon.py @@ -73,6 +73,7 @@ from shares import addShare from theme import setTheme from announce import sendAnnounceViaServer from socnet import instancesGraph +from migrate import migrateAccounts import argparse @@ -321,6 +322,9 @@ parser.add_argument("--i2p", type=str2bool, nargs='?', parser.add_argument("--tor", type=str2bool, nargs='?', const=True, default=False, help="Route via Tor") +parser.add_argument("--migrations", type=str2bool, nargs='?', + const=True, default=False, + help="Migrate moved accounts") parser.add_argument("--tests", type=str2bool, nargs='?', const=True, default=False, help="Run unit tests") @@ -1304,6 +1308,33 @@ if args.hyper: if args.i2p: httpPrefix = 'http' +if args.migrations: + cachedWebfingers = {} + if args.http or domain.endswith('.onion'): + httpPrefix = 'http' + port = 80 + proxyType = 'tor' + elif domain.endswith('.i2p'): + httpPrefix = 'http' + port = 80 + proxyType = 'i2p' + elif args.gnunet: + httpPrefix = 'gnunet' + port = 80 + proxyType = 'gnunet' + else: + httpPrefix = 'https' + port = 443 + session = createSession(proxyType) + ctr = migrateAccounts(baseDir, session, + httpPrefix, cachedWebfingers, + True) + if ctr == 0: + print('No followed accounts have moved') + else: + print(str(ctr) + ' followed accounts were migrated') + sys.exit() + if args.actor: originalActor = args.actor if '/@' in args.actor or \ diff --git a/migrate.py b/migrate.py index 7f52b40d7..aba48447a 100644 --- a/migrate.py +++ b/migrate.py @@ -7,48 +7,175 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import getNicknameFromActor +from utils import getDomainFromActor +from webfinger import webfingerHandle +from blocking import isBlocked +from session import getJson +from posts import getUserUrl +from follow import unfollowAccount -def _migrateFollows(followFilename: str, oldHandle: str, - newHandle: str) -> None: - """Changes a handle within following or followers list +def _moveFollowingHandlesForAccount(baseDir: str, nickname: str, domain: str, + session, + httpPrefix: str, cachedWebfingers: {}, + followFile: str, debug: bool) -> int: + """Goes through all follows for an account and updates any that have moved """ - if not os.path.isfile(followFilename): - return - if oldHandle not in open(followFilename).read(): - return - followData = None - with open(followFilename, 'r') as followFile: - followData = followFile.read() - if not followData: - return - newFollowData = followData.replace(oldHandle, newHandle) - if followData == newFollowData: - return - with open(followFilename, 'w+') as followFile: - followFile.write(newFollowData) + ctr = 0 + followingFilename = \ + baseDir + '/accounts/' + nickname + '@' + domain + '/' + followFile + if not os.path.isfile(followingFilename): + return ctr + with open(followingFilename, "r") as f: + followingHandles = f.readlines() + for followHandle in followingHandles: + followHandle = followHandle.strip("\n").strip("\r") + ctr += \ + _updateMovedHandle(baseDir, nickname, domain, + followHandle, session, + httpPrefix, cachedWebfingers, + followFile, debug) + return ctr -def migrateAccount(baseDir: str, oldHandle: str, newHandle: str) -> None: - """If a followed account changes then this modifies the - following and followers lists for each account accordingly +def _updateMovedHandle(baseDir: str, nickname: str, domain: str, + handle: str, session, + httpPrefix: str, cachedWebfingers: {}, + followFile: str, debug: bool) -> int: + """Check if an account has moved, and if so then alter following.txt + for each account. + Returns 1 if moved, 0 otherwise """ - if oldHandle.startswith('@'): - oldHandle = oldHandle[1:] - if '@' not in oldHandle: - return - if newHandle.startswith('@'): - newHandle = newHandle[1:] - if '@' not in newHandle: - return + ctr = 0 + if '@' not in handle: + return ctr + if len(handle) < 5: + return ctr + if handle.startswith('@'): + handle = handle[1:] + wfRequest = webfingerHandle(session, handle, + httpPrefix, cachedWebfingers, + None, __version__) + if not wfRequest: + print('updateMovedHandle unable to webfinger ' + handle) + return ctr + if not isinstance(wfRequest, dict): + print('updateMovedHandle webfinger for ' + handle + + ' did not return a dict. ' + str(wfRequest)) + return ctr + + personUrl = None + if wfRequest.get('errors'): + print('wfRequest error: ' + str(wfRequest['errors'])) + return ctr + + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/activity+json; profile="' + profileStr + '"' + } + if not personUrl: + personUrl = getUserUrl(wfRequest) + if not personUrl: + return ctr + + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/ld+json; profile="' + profileStr + '"' + } + personJson = \ + getJson(session, personUrl, asHeader, None, __version__, + httpPrefix, None) + if not personJson: + return ctr + if not personJson.get('movedTo'): + return ctr + movedToUrl = personJson['movedTo'] + if '://' not in movedToUrl: + return ctr + if '.' not in movedToUrl: + return ctr + movedToNickname = getNicknameFromActor(movedToUrl) + if not movedToNickname: + return ctr + movedToDomain, movedToPort = getDomainFromActor(movedToUrl) + if not movedToDomain: + return ctr + movedToDomainFull = movedToDomain + if movedToPort: + if movedToPort != 80 and movedToPort != 443: + movedToDomainFull = movedToDomain + ':' + str(movedToPort) + if isBlocked(baseDir, nickname, domain, + movedToNickname, movedToDomain): + # someone that you follow has moved to a blocked domain + # so just unfollow them + unfollowAccount(baseDir, nickname, domain, + movedToNickname, movedToDomainFull, + followFile, debug) + return ctr + followingFilename = \ + baseDir + '/accounts/' + nickname + '@' + domain + '/' + followFile + if not os.path.isfile(followingFilename): + return ctr + with open(followingFilename, "r") as f: + followingHandles = f.readlines() + movedToHandle = movedToNickname + '@' + movedToDomainFull + movedToHandleLower = movedToHandle.lower() + handleLower = handle.lower() + # does the new handle already exist in the following list? + alreadyFollowingHandle = False + for followHandle in followingHandles: + if followHandle.strip("\n").strip("\r").lower() == \ + movedToHandleLower: + alreadyFollowingHandle = True + if not alreadyFollowingHandle: + # replace the old handle with the new one + with open(followingFilename, 'w+') as f: + for followHandle in followingHandles: + if followHandle.strip("\n").strip("\r").lower() != \ + handleLower: + f.write(followHandle) + else: + f.write(movedToHandleLower + '\n') + ctr += 1 + print('Follow moved from ' + handleLower + + ' to ' + movedToHandleLower) + else: + # remove the old handle + with open(followingFilename, 'w+') as f: + for followHandle in followingHandles: + if followHandle.strip("\n").strip("\r").lower() != \ + handleLower: + f.write(followHandle) + else: + ctr += 1 + return ctr + + +def migrateAccounts(baseDir: str, session, + httpPrefix: str, cachedWebfingers: {}, + debug: bool) -> int: + """If followed accounts change then this modifies the + following lists for each account accordingly. + Returns the number of accounts migrated + """ # update followers and following lists for each account + ctr = 0 for subdir, dirs, files in os.walk(baseDir + '/accounts'): for handle in dirs: - if '@' in handle: - accountDir = baseDir + '/accounts/' + handle - followFilename = accountDir + '/following.txt' - _migrateFollows(followFilename, oldHandle, newHandle) - followFilename = accountDir + '/followers.txt' - _migrateFollows(followFilename, oldHandle, newHandle) + if '@' not in handle: + continue + if handle.startswith('inbox@'): + continue + if handle.startswith('news@'): + continue + nickname = handle.split('@')[0] + domain = handle.split('@')[1] + ctr += \ + _moveFollowingHandlesForAccount(baseDir, nickname, domain, + session, httpPrefix, + cachedWebfingers, + 'following.txt', debug) break + return ctr diff --git a/tests.py b/tests.py index e88c651b3..b9121b1ef 100644 --- a/tests.py +++ b/tests.py @@ -2799,7 +2799,6 @@ def testFunctions(): 'threadSendPost', 'sendToFollowers', 'expireCache', - 'migrateAccount', 'getMutualsOfPerson', 'runPostsQueue', 'runSharesExpire', From 118da84fa6eb6d153304dd77ecdb918363e729d7 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 17:41:41 +0000 Subject: [PATCH 06/65] Unfollow rather than changing following handle --- migrate.py | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/migrate.py b/migrate.py index aba48447a..98df45aee 100644 --- a/migrate.py +++ b/migrate.py @@ -120,36 +120,26 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str, return ctr with open(followingFilename, "r") as f: followingHandles = f.readlines() + movedToHandle = movedToNickname + '@' + movedToDomainFull - movedToHandleLower = movedToHandle.lower() handleLower = handle.lower() - # does the new handle already exist in the following list? - alreadyFollowingHandle = False - for followHandle in followingHandles: - if followHandle.strip("\n").strip("\r").lower() == \ - movedToHandleLower: - alreadyFollowingHandle = True - if not alreadyFollowingHandle: - # replace the old handle with the new one - with open(followingFilename, 'w+') as f: - for followHandle in followingHandles: - if followHandle.strip("\n").strip("\r").lower() != \ - handleLower: - f.write(followHandle) - else: - f.write(movedToHandleLower + '\n') - ctr += 1 - print('Follow moved from ' + handleLower + - ' to ' + movedToHandleLower) - else: - # remove the old handle - with open(followingFilename, 'w+') as f: - for followHandle in followingHandles: - if followHandle.strip("\n").strip("\r").lower() != \ - handleLower: - f.write(followHandle) - else: - ctr += 1 + + # unfollow the old handle + with open(followingFilename, 'w+') as f: + for followHandle in followingHandles: + if followHandle.strip("\n").strip("\r").lower() != \ + handleLower: + f.write(followHandle) + else: + handleNickname = handle.split('@')[0] + handleDomain = handle.split('@')[1] + unfollowAccount(baseDir, nickname, domain, + handleNickname, + handleDomain, + followFile, debug) + ctr += 1 + print('Unfollowed ' + handle + ' who has moved to ' + + movedToHandle) return ctr From e7d0668cd6361d22de2f1e0dfb94b95d0045ce37 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 18:12:36 +0000 Subject: [PATCH 07/65] Create a list of handles to be followed --- daemon.py | 14 ++++++++++++-- migrate.py | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/daemon.py b/daemon.py index 7dfc843c4..d7ebef85a 100644 --- a/daemon.py +++ b/daemon.py @@ -2565,6 +2565,17 @@ class PubServer(BaseHTTPRequestHandler): elif ('@' in searchStr or ('://' in searchStr and hasUsersPath(searchStr))): + if searchStr.endswith(':') or \ + searchStr.endswith(';') or \ + searchStr.endswith('.'): + if callingDomain.endswith('.onion') and onionDomain: + actorStr = 'http://' + onionDomain + usersPath + elif (callingDomain.endswith('.i2p') and i2pDomain): + actorStr = 'http://' + i2pDomain + usersPath + self._redirect_headers(actorStr + '/search', + cookie, callingDomain) + self.server.POSTbusy = False + return # profile search nickname = getNicknameFromActor(actorStr) if not self.server.session: @@ -2580,8 +2591,7 @@ class PubServer(BaseHTTPRequestHandler): profilePathStr = path.replace('/searchhandle', '') # are we already following the searched for handle? - if isFollowingActor(baseDir, nickname, domain, - searchStr): + if isFollowingActor(baseDir, nickname, domain, searchStr): if not hasUsersPath(searchStr): searchNickname = getNicknameFromActor(searchStr) searchDomain, searchPort = \ diff --git a/migrate.py b/migrate.py index 98df45aee..e7216f81d 100644 --- a/migrate.py +++ b/migrate.py @@ -124,6 +124,9 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str, movedToHandle = movedToNickname + '@' + movedToDomainFull handleLower = handle.lower() + refollowFilename = \ + baseDir + '/accounts/' + nickname + '@' + domain + '/refollow.txt' + # unfollow the old handle with open(followingFilename, 'w+') as f: for followHandle in followingHandles: @@ -140,6 +143,14 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str, ctr += 1 print('Unfollowed ' + handle + ' who has moved to ' + movedToHandle) + + # save the new handles to the refollow list + if os.path.isfile(refollowFilename): + with open(refollowFilename, 'a+') as f: + f.write(movedToHandle + '\n') + else: + with open(refollowFilename, 'w+') as f: + f.write(movedToHandle + '\n') return ctr From 6d0678db545b74ae8b43b38b4d4e9a899ce79d14 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 20:27:17 +0000 Subject: [PATCH 08/65] Also remove moved accounts from followers --- migrate.py | 97 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/migrate.py b/migrate.py index e7216f81d..cf8c5eb04 100644 --- a/migrate.py +++ b/migrate.py @@ -19,12 +19,12 @@ from follow import unfollowAccount def _moveFollowingHandlesForAccount(baseDir: str, nickname: str, domain: str, session, httpPrefix: str, cachedWebfingers: {}, - followFile: str, debug: bool) -> int: + debug: bool) -> int: """Goes through all follows for an account and updates any that have moved """ ctr = 0 followingFilename = \ - baseDir + '/accounts/' + nickname + '@' + domain + '/' + followFile + baseDir + '/accounts/' + nickname + '@' + domain + '/following.txt' if not os.path.isfile(followingFilename): return ctr with open(followingFilename, "r") as f: @@ -35,14 +35,14 @@ def _moveFollowingHandlesForAccount(baseDir: str, nickname: str, domain: str, _updateMovedHandle(baseDir, nickname, domain, followHandle, session, httpPrefix, cachedWebfingers, - followFile, debug) + debug) return ctr def _updateMovedHandle(baseDir: str, nickname: str, domain: str, handle: str, session, httpPrefix: str, cachedWebfingers: {}, - followFile: str, debug: bool) -> int: + debug: bool) -> int: """Check if an account has moved, and if so then alter following.txt for each account. Returns 1 if moved, 0 otherwise @@ -112,45 +112,65 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str, # so just unfollow them unfollowAccount(baseDir, nickname, domain, movedToNickname, movedToDomainFull, - followFile, debug) + 'following.txt', debug) return ctr + followingFilename = \ - baseDir + '/accounts/' + nickname + '@' + domain + '/' + followFile - if not os.path.isfile(followingFilename): - return ctr - with open(followingFilename, "r") as f: - followingHandles = f.readlines() + baseDir + '/accounts/' + nickname + '@' + domain + '/following.txt' + if os.path.isfile(followingFilename): + with open(followingFilename, "r") as f: + followingHandles = f.readlines() - movedToHandle = movedToNickname + '@' + movedToDomainFull - handleLower = handle.lower() + movedToHandle = movedToNickname + '@' + movedToDomainFull + handleLower = handle.lower() - refollowFilename = \ - baseDir + '/accounts/' + nickname + '@' + domain + '/refollow.txt' + refollowFilename = \ + baseDir + '/accounts/' + \ + nickname + '@' + domain + '/refollow.txt' - # unfollow the old handle - with open(followingFilename, 'w+') as f: - for followHandle in followingHandles: - if followHandle.strip("\n").strip("\r").lower() != \ - handleLower: - f.write(followHandle) - else: - handleNickname = handle.split('@')[0] - handleDomain = handle.split('@')[1] - unfollowAccount(baseDir, nickname, domain, - handleNickname, - handleDomain, - followFile, debug) - ctr += 1 - print('Unfollowed ' + handle + ' who has moved to ' + - movedToHandle) - - # save the new handles to the refollow list - if os.path.isfile(refollowFilename): - with open(refollowFilename, 'a+') as f: - f.write(movedToHandle + '\n') + # unfollow the old handle + with open(followingFilename, 'w+') as f: + for followHandle in followingHandles: + if followHandle.strip("\n").strip("\r").lower() != \ + handleLower: + f.write(followHandle) else: - with open(refollowFilename, 'w+') as f: - f.write(movedToHandle + '\n') + handleNickname = handle.split('@')[0] + handleDomain = handle.split('@')[1] + unfollowAccount(baseDir, nickname, domain, + handleNickname, + handleDomain, + 'following.txt', debug) + ctr += 1 + print('Unfollowed ' + handle + ' who has moved to ' + + movedToHandle) + + # save the new handles to the refollow list + if os.path.isfile(refollowFilename): + with open(refollowFilename, 'a+') as f: + f.write(movedToHandle + '\n') + else: + with open(refollowFilename, 'w+') as f: + f.write(movedToHandle + '\n') + + followersFilename = \ + baseDir + '/accounts/' + nickname + '@' + domain + '/followers.txt' + if os.path.isfile(followersFilename): + with open(followersFilename, "r") as f: + followerHandles = f.readlines() + + handleLower = handle.lower() + + # remove followers who have moved + with open(followersFilename, 'w+') as f: + for followerHandle in followerHandles: + if followerHandle.strip("\n").strip("\r").lower() != \ + handleLower: + f.write(followerHandle) + else: + ctr += 1 + print('Removed follower who has moved ' + handle) + return ctr @@ -176,7 +196,6 @@ def migrateAccounts(baseDir: str, session, ctr += \ _moveFollowingHandlesForAccount(baseDir, nickname, domain, session, httpPrefix, - cachedWebfingers, - 'following.txt', debug) + cachedWebfingers, debug) break return ctr From 207d9febe82884f22355905af444b613c8db9916 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 21:47:52 +0000 Subject: [PATCH 09/65] Exclude system accounts --- schedule.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schedule.py b/schedule.py index 6d781b375..181c67288 100644 --- a/schedule.py +++ b/schedule.py @@ -142,6 +142,10 @@ def runPostSchedule(baseDir: str, httpd, maxScheduledPosts: int): for account in dirs: if '@' not in account: continue + if account.startswith('inbox@'): + continue + if account.startswith('news@'): + continue # scheduled posts index for this account scheduleIndexFilename = \ baseDir + '/accounts/' + account + '/schedule.index' From 2d64dd2dc6fb9c1f389a49d11daad46af85b3893 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 22:58:34 +0000 Subject: [PATCH 10/65] Lookup webfinger --- webapp_post.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/webapp_post.py b/webapp_post.py index 136adfc7b..92d5ae08f 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1153,10 +1153,19 @@ def individualPostAsHtml(allowDownloads: bool, # get the display name if domainFull not in postActor: + # lookup the correct webfinger for the postActor + postActorNickname = getNicknameFromActor(postActor) + postActorDomain, postActorPort = getNicknameFromActor(postActor) + postActorDomainFull = getFullDomain(postActorDomain, postActorPort) + postActorHandle = postActorNickname + '@' + postActorDomainFull + postActorWf = cachedWebfingers + if cachedWebfingers.get(postActorHandle): + postActorWf = cachedWebfingers[postActorHandle] + (inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl2, displayName) = getPersonBox(baseDir, session, - cachedWebfingers, + postActorWf, personCache, projectVersion, httpPrefix, nickname, domain, 'outbox', From b56d0643e6092efd365875645a7e45b9ec5225cb Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 23:00:36 +0000 Subject: [PATCH 11/65] Domain --- webapp_post.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_post.py b/webapp_post.py index 92d5ae08f..45810a24d 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1155,7 +1155,7 @@ def individualPostAsHtml(allowDownloads: bool, if domainFull not in postActor: # lookup the correct webfinger for the postActor postActorNickname = getNicknameFromActor(postActor) - postActorDomain, postActorPort = getNicknameFromActor(postActor) + postActorDomain, postActorPort = getDomainFromActor(postActor) postActorDomainFull = getFullDomain(postActorDomain, postActorPort) postActorHandle = postActorNickname + '@' + postActorDomainFull postActorWf = cachedWebfingers From 5ca38be487e99c9f548cc7b580d4e34733a7cb7f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 23:12:01 +0000 Subject: [PATCH 12/65] Try again --- webapp_post.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webapp_post.py b/webapp_post.py index 45810a24d..aff95bba1 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1161,6 +1161,8 @@ def individualPostAsHtml(allowDownloads: bool, postActorWf = cachedWebfingers if cachedWebfingers.get(postActorHandle): postActorWf = cachedWebfingers[postActorHandle] + if postActorWf.get(postActorHandle): + postActorWf = postActorWf[postActorHandle] (inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, From 2690f2f87d10ea0f5490758ced65562d3028112f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 23:22:30 +0000 Subject: [PATCH 13/65] Debug --- webapp_post.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webapp_post.py b/webapp_post.py index aff95bba1..373383c20 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1161,8 +1161,7 @@ def individualPostAsHtml(allowDownloads: bool, postActorWf = cachedWebfingers if cachedWebfingers.get(postActorHandle): postActorWf = cachedWebfingers[postActorHandle] - if postActorWf.get(postActorHandle): - postActorWf = postActorWf[postActorHandle] + print('postActorWf: ' + postActorHandle + ' ' + str(postActorWf)) (inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, From f4f946819e48221cc1651276b78d28871fe1bc90 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 23:32:47 +0000 Subject: [PATCH 14/65] Single entry webfinger --- posts.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/posts.py b/posts.py index 133929a9b..a2f340e38 100644 --- a/posts.py +++ b/posts.py @@ -213,6 +213,9 @@ def getPersonBox(baseDir: str, session, wfRequest: {}, nickname: str, domain: str, boxName='inbox', sourceId=0) -> (str, str, str, str, str, str, str, str): + if len(wfRequest.items()) == 1: + wfRequest = wfRequest.items()[0] + print('wfRequest changed to ' + str(wfRequest)) profileStr = 'https://www.w3.org/ns/activitystreams' asHeader = { 'Accept': 'application/activity+json; profile="' + profileStr + '"' From fcacd440d4c2b6a556cf8de2f23d7b8b4f2ee390 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 23:34:30 +0000 Subject: [PATCH 15/65] Change position --- posts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/posts.py b/posts.py index a2f340e38..7fe686bfe 100644 --- a/posts.py +++ b/posts.py @@ -213,14 +213,14 @@ def getPersonBox(baseDir: str, session, wfRequest: {}, nickname: str, domain: str, boxName='inbox', sourceId=0) -> (str, str, str, str, str, str, str, str): - if len(wfRequest.items()) == 1: - wfRequest = wfRequest.items()[0] - print('wfRequest changed to ' + str(wfRequest)) profileStr = 'https://www.w3.org/ns/activitystreams' asHeader = { 'Accept': 'application/activity+json; profile="' + profileStr + '"' } if not wfRequest.get('errors'): + if len(wfRequest.items()) == 1: + wfRequest = wfRequest.items()[0] + print('wfRequest changed to ' + str(wfRequest)) personUrl = getUserUrl(wfRequest, sourceId) else: if nickname == 'dev': From 57e3a7b6e8bf0246d5dc309a31d92e917daf85f4 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sat, 9 Jan 2021 23:38:04 +0000 Subject: [PATCH 16/65] Enumerate --- posts.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/posts.py b/posts.py index 7fe686bfe..5d3759e11 100644 --- a/posts.py +++ b/posts.py @@ -219,8 +219,9 @@ def getPersonBox(baseDir: str, session, wfRequest: {}, } if not wfRequest.get('errors'): if len(wfRequest.items()) == 1: - wfRequest = wfRequest.items()[0] - print('wfRequest changed to ' + str(wfRequest)) + for wfkey, wf in wfRequest.items(): + wfRequest = wf + print('wfRequest changed to ' + str(wfRequest)) personUrl = getUserUrl(wfRequest, sourceId) else: if nickname == 'dev': From 56ba0f28d715a800dbb640aa0cfb9f7c58972ab0 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 00:04:17 +0000 Subject: [PATCH 17/65] Abandon --- posts.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/posts.py b/posts.py index 5d3759e11..988d43886 100644 --- a/posts.py +++ b/posts.py @@ -218,10 +218,10 @@ def getPersonBox(baseDir: str, session, wfRequest: {}, 'Accept': 'application/activity+json; profile="' + profileStr + '"' } if not wfRequest.get('errors'): - if len(wfRequest.items()) == 1: - for wfkey, wf in wfRequest.items(): - wfRequest = wf - print('wfRequest changed to ' + str(wfRequest)) + # if len(wfRequest.items()) == 1: + # for wfkey, wf in wfRequest.items(): + # wfRequest = wf + # print('wfRequest changed to ' + str(wfRequest)) personUrl = getUserUrl(wfRequest, sourceId) else: if nickname == 'dev': From e7252a643fb90c93fed1ff9eafde1861d7a9df38 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 09:51:30 +0000 Subject: [PATCH 18/65] Check for single webfinger --- posts.py | 4 ---- webapp_post.py | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/posts.py b/posts.py index 988d43886..133929a9b 100644 --- a/posts.py +++ b/posts.py @@ -218,10 +218,6 @@ def getPersonBox(baseDir: str, session, wfRequest: {}, 'Accept': 'application/activity+json; profile="' + profileStr + '"' } if not wfRequest.get('errors'): - # if len(wfRequest.items()) == 1: - # for wfkey, wf in wfRequest.items(): - # wfRequest = wf - # print('wfRequest changed to ' + str(wfRequest)) personUrl = getUserUrl(wfRequest, sourceId) else: if nickname == 'dev': diff --git a/webapp_post.py b/webapp_post.py index 373383c20..f00fd702a 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1163,6 +1163,15 @@ def individualPostAsHtml(allowDownloads: bool, postActorWf = cachedWebfingers[postActorHandle] print('postActorWf: ' + postActorHandle + ' ' + str(postActorWf)) + # check for situations where the webfinger contains a single key + # which is the handle, with the webfinger content as the item + if len(postActorWf.items()) == 1: + for wfkey, wf in postActorWf.items(): + print('Single webfinger key: ' + wfkey + ' ' + postActorHandle) + if wfkey == postActorHandle: + postActorWf = wf + print('wfRequest changed to ' + str(postActorWf)) + (inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl2, displayName) = getPersonBox(baseDir, session, From ccc814daf58e374fc9a7410ded47b54495afcc0d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 10:13:10 +0000 Subject: [PATCH 19/65] Debug --- posts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posts.py b/posts.py index 133929a9b..53d115d26 100644 --- a/posts.py +++ b/posts.py @@ -147,10 +147,10 @@ def _cleanHtml(rawHtml: str) -> str: def getUserUrl(wfRequest: {}, sourceId=0) -> str: """Gets the actor url from a webfinger request """ - # print('getUserUrl: ' + str(sourceId) + ' ' + str(wfRequest)) if not wfRequest.get('links'): if sourceId == 72367: - print('getUserUrl failed to get display name for webfinger ' + + print('getUserUrl ' + str(sourceId) + + ' failed to get display name for webfinger ' + str(wfRequest)) else: print('getUserUrl webfinger activity+json contains no links ' + From 596d36d33e136f4b75bcc1500ae9d3582b30c475 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 10:34:29 +0000 Subject: [PATCH 20/65] Lookup webfinger --- webapp_post.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/webapp_post.py b/webapp_post.py index f00fd702a..5707dc824 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -61,6 +61,7 @@ from webapp_utils import getBrokenLinkSubstitute from webapp_media import addEmbeddedElements from webapp_question import insertQuestion from devices import E2EEdecryptMessageFromDevice +from webfinger import webfingerHandle def _logPostTiming(enableTimingLog: bool, postStartTime, debugId: str) -> None: @@ -1158,10 +1159,10 @@ def individualPostAsHtml(allowDownloads: bool, postActorDomain, postActorPort = getDomainFromActor(postActor) postActorDomainFull = getFullDomain(postActorDomain, postActorPort) postActorHandle = postActorNickname + '@' + postActorDomainFull - postActorWf = cachedWebfingers - if cachedWebfingers.get(postActorHandle): - postActorWf = cachedWebfingers[postActorHandle] - print('postActorWf: ' + postActorHandle + ' ' + str(postActorWf)) + postActorWf = \ + webfingerHandle(session, postActorHandle, httpPrefix, + cachedWebfingers, + domain, __version__) # check for situations where the webfinger contains a single key # which is the handle, with the webfinger content as the item @@ -1172,14 +1173,19 @@ def individualPostAsHtml(allowDownloads: bool, postActorWf = wf print('wfRequest changed to ' + str(postActorWf)) - (inboxUrl, pubKeyId, pubKey, - fromPersonId, sharedInbox, - avatarUrl2, displayName) = getPersonBox(baseDir, session, - postActorWf, - personCache, - projectVersion, httpPrefix, - nickname, domain, 'outbox', - 72367) + avatarUrl2 = None + displayName = None + if postActorWf: + (inboxUrl, pubKeyId, pubKey, + fromPersonId, sharedInbox, + avatarUrl2, displayName) = getPersonBox(baseDir, session, + postActorWf, + personCache, + projectVersion, + httpPrefix, + nickname, domain, + 'outbox', 72367) + _logPostTiming(enableTimingLog, postStartTime, '6') if avatarUrl2: From f7c84beb2cc738ef54d4fcf97baff05a7101d308 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 10:41:36 +0000 Subject: [PATCH 21/65] Remove test code --- webapp_post.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/webapp_post.py b/webapp_post.py index 5707dc824..046f7edc9 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1164,15 +1164,6 @@ def individualPostAsHtml(allowDownloads: bool, cachedWebfingers, domain, __version__) - # check for situations where the webfinger contains a single key - # which is the handle, with the webfinger content as the item - if len(postActorWf.items()) == 1: - for wfkey, wf in postActorWf.items(): - print('Single webfinger key: ' + wfkey + ' ' + postActorHandle) - if wfkey == postActorHandle: - postActorWf = wf - print('wfRequest changed to ' + str(postActorWf)) - avatarUrl2 = None displayName = None if postActorWf: From c807dc075cafd7995b424ffe82aab09df239ff33 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 12:32:09 +0000 Subject: [PATCH 22/65] Tidying --- webapp_profile.py | 12 +++++++++++- webfinger.py | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/webapp_profile.py b/webapp_profile.py index bd75f4a1a..2c8a265c5 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -1530,10 +1530,20 @@ def _individualFollowAsHtml(translate: {}, if not avatarUrl: avatarUrl = followUrl + '/avatar.png' if domain not in followUrl: + # lookup the correct webfinger for the followUrl + followUrlNickname = getNicknameFromActor(followUrl) + followUrlDomain, followUrlPort = getDomainFromActor(followUrl) + followUrlDomainFull = getFullDomain(followUrlDomain, followUrlPort) + followUrlHandle = followUrlNickname + '@' + followUrlDomainFull + followUrlWf = \ + webfingerHandle(session, followUrlHandle, httpPrefix, + cachedWebfingers, + domain, __version__) + (inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl2, displayName) = getPersonBox(baseDir, session, - cachedWebfingers, + followUrlWf, personCache, projectVersion, httpPrefix, nickname, domain, 'outbox', 43036) diff --git a/webfinger.py b/webfinger.py index fe31f6909..6fe57a80d 100644 --- a/webfinger.py +++ b/webfinger.py @@ -352,4 +352,4 @@ def webfingerUpdate(baseDir: str, nickname: str, domain: str, if _webfingerUpdateFromProfile(wfJson, actorJson): if saveJson(wfJson, filename): - cachedWebfingers[handle] = wfJson + storeWebfingerInCache(handle, wfJson, cachedWebfingers) From 0ec3e1ea72e3a5db0e80a9a7e4c89c6e8b154e28 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 14:05:07 +0000 Subject: [PATCH 23/65] Check that linked data context exists for inbox items --- context.py | 4 ++-- daemon.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/context.py b/context.py index ba130e423..de97cb38b 100644 --- a/context.py +++ b/context.py @@ -25,12 +25,12 @@ def hasValidContext(postJsonObject: {}) -> bool: if not isinstance(url, str): continue if url not in validContexts: - print('Invalid @context: ' + url) + print('Unrecognized @context: ' + url) return False elif isinstance(postJsonObject['@context'], str): url = postJsonObject['@context'] if url not in validContexts: - print('Invalid @context: ' + url) + print('Unrecognized @context: ' + url) return False else: # not a list or string diff --git a/daemon.py b/daemon.py index d7ebef85a..95b2dc18b 100644 --- a/daemon.py +++ b/daemon.py @@ -248,6 +248,7 @@ from newsdaemon import runNewswireDaemon from filters import isFiltered from filters import addGlobalFilter from filters import removeGlobalFilter +from context import hasValidContext import os @@ -1040,6 +1041,14 @@ class PubServer(BaseHTTPRequestHandler): self.server.POSTbusy = False return 2 + # check that the incoming message has a fully recognized + # linked data context + if not hasValidContext(messageJson): + print('Message arriving at inbox queue has no valid context') + self._400() + self.server.POSTbusy = False + return 3 + # check for blocked domains so that they can be rejected early messageDomain = None if messageJson.get('actor'): @@ -1050,6 +1059,11 @@ class PubServer(BaseHTTPRequestHandler): self._400() self.server.POSTbusy = False return 3 + else: + print('Message arriving at inbox queue has no actor') + self._400() + self.server.POSTbusy = False + return 3 # if the inbox queue is full then return a busy code if len(self.server.inboxQueue) >= self.server.maxQueueLength: From 758747740e01a909ec9e6b8a2d84c6b6c3e9a88a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 14:14:40 +0000 Subject: [PATCH 24/65] Wildcard schemas --- context.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/context.py b/context.py index de97cb38b..4375df9fc 100644 --- a/context.py +++ b/context.py @@ -11,7 +11,7 @@ validContexts = ( "https://www.w3.org/ns/activitystreams", "https://w3id.org/identity/v1", "https://w3id.org/security/v1", - "https://raitisoja.com/apschema/v1.21" + "*/apschema/v1.21" ) @@ -25,13 +25,29 @@ def hasValidContext(postJsonObject: {}) -> bool: if not isinstance(url, str): continue if url not in validContexts: - print('Unrecognized @context: ' + url) - return False + wildcardFound = False + for c in validContexts: + if c.startswith('*'): + c = c.replace('*', '') + if url.endswith(c): + wildcardFound = True + break + if not wildcardFound: + print('Unrecognized @context: ' + url) + return False elif isinstance(postJsonObject['@context'], str): url = postJsonObject['@context'] if url not in validContexts: - print('Unrecognized @context: ' + url) - return False + wildcardFound = False + for c in validContexts: + if c.startswith('*'): + c = c.replace('*', '') + if url.endswith(c): + wildcardFound = True + break + if not wildcardFound: + print('Unrecognized @context: ' + url) + return False else: # not a list or string return False @@ -39,7 +55,7 @@ def hasValidContext(postJsonObject: {}) -> bool: def getApschemaV1_21() -> {}: - # https://raitisoja.com/apschema/v1.21 + # https://domain/apschema/v1.21 return { "@context": { "zot": "https://raitisoja.com/apschema#", From 60b0e3fdfb93ade29944e4ebf5744b00cdb7ea1f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 14:21:54 +0000 Subject: [PATCH 25/65] Two apschema versions --- context.py | 43 +++++++++++++++++++++++++++++++++++++++++++ pyjsonld.py | 10 +++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/context.py b/context.py index 4375df9fc..3043616f0 100644 --- a/context.py +++ b/context.py @@ -11,6 +11,7 @@ validContexts = ( "https://www.w3.org/ns/activitystreams", "https://w3id.org/identity/v1", "https://w3id.org/security/v1", + "*/apschema/v1.9" "*/apschema/v1.21" ) @@ -54,6 +55,48 @@ def hasValidContext(postJsonObject: {}) -> bool: return True +def getApschemaV1_9() -> {}: + # https://domain/apschema/v1.9 + return { + "@context": { + "zot": "https://hub.disroot.org/apschema#", + "id": "@id", + "type": "@type", + "commentPolicy": "as:commentPolicy", + "meData": "zot:meData", + "meDataType": "zot:meDataType", + "meEncoding": "zot:meEncoding", + "meAlgorithm": "zot:meAlgorithm", + "meCreator": "zot:meCreator", + "meSignatureValue": "zot:meSignatureValue", + "locationAddress": "zot:locationAddress", + "locationPrimary": "zot:locationPrimary", + "locationDeleted": "zot:locationDeleted", + "nomadicLocation": "zot:nomadicLocation", + "nomadicHubs": "zot:nomadicHubs", + "emojiReaction": "zot:emojiReaction", + "expires": "zot:expires", + "directMessage": "zot:directMessage", + "schema": "http://schema.org#", + "PropertyValue": "schema:PropertyValue", + "value": "schema:value", + "magicEnv": { + "@id": "zot:magicEnv", + "@type": "@id" + }, + "nomadicLocations": { + "@id": "zot:nomadicLocations", + "@type": "@id" + }, + "ostatus": "http://ostatus.org#", + "conversation": "ostatus:conversation", + "diaspora": "https://diasporafoundation.org/ns/", + "guid": "diaspora:guid", + "Hashtag": "as:Hashtag" + } + } + + def getApschemaV1_21() -> {}: # https://domain/apschema/v1.21 return { diff --git a/pyjsonld.py b/pyjsonld.py index 35ebdf7a3..345418823 100644 --- a/pyjsonld.py +++ b/pyjsonld.py @@ -37,6 +37,7 @@ import traceback from collections import deque, namedtuple from numbers import Integral, Real +from context import getApschemaV1_9 from context import getApschemaV1_21 from context import getV1Schema from context import getV1SecuritySchema @@ -397,7 +398,14 @@ def load_document(url): 'document': getActivitystreamsSchema() } return doc - elif url == 'https://raitisoja.com/apschema/v1.21': + elif url.endswith('/apschema/v1.9'): + doc = { + 'contextUrl': None, + 'documentUrl': url, + 'document': getApschemaV1_9() + } + return doc + elif url.endswith('/apschema/v1.21'): doc = { 'contextUrl': None, 'documentUrl': url, From eeb8fba1f0e0a903c01b96e43c3e5a075a3b7c2d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 14:49:40 +0000 Subject: [PATCH 26/65] Add litepub schema --- context.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- pyjsonld.py | 8 ++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/context.py b/context.py index 3043616f0..1b4495f73 100644 --- a/context.py +++ b/context.py @@ -11,8 +11,9 @@ validContexts = ( "https://www.w3.org/ns/activitystreams", "https://w3id.org/identity/v1", "https://w3id.org/security/v1", - "*/apschema/v1.9" - "*/apschema/v1.21" + "*/apschema/v1.9", + "*/apschema/v1.21", + "*/litepub-0.1.jsonld" ) @@ -128,6 +129,51 @@ def getApschemaV1_21() -> {}: } +def getLitepubV0_1() -> {}: + # https://domain/schemas/litepub-0.1.jsonld + return { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Emoji": "toot:Emoji", + "Hashtag": "as:Hashtag", + "PropertyValue": "schema:PropertyValue", + "atomUri": "ostatus:atomUri", + "conversation": { + "@id": "ostatus:conversation", + "@type": "@id" + }, + "discoverable": "toot:discoverable", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "capabilities": "litepub:capabilities", + "ostatus": "http://ostatus.org#", + "schema": "http://schema.org#", + "toot": "http://joinmastodon.org/ns#", + "value": "schema:value", + "sensitive": "as:sensitive", + "litepub": "http://litepub.social/ns#", + "invisible": "litepub:invisible", + "directMessage": "litepub:directMessage", + "listMessage": { + "@id": "litepub:listMessage", + "@type": "@id" + }, + "oauthRegistrationEndpoint": { + "@id": "litepub:oauthRegistrationEndpoint", + "@type": "@id" + }, + "EmojiReact": "litepub:EmojiReact", + "ChatMessage": "litepub:ChatMessage", + "alsoKnownAs": { + "@id": "as:alsoKnownAs", + "@type": "@id" + } + } + ] + } + + def getV1SecuritySchema() -> {}: # https://w3id.org/security/v1 return { diff --git a/pyjsonld.py b/pyjsonld.py index 345418823..0ccffe504 100644 --- a/pyjsonld.py +++ b/pyjsonld.py @@ -39,6 +39,7 @@ from numbers import Integral, Real from context import getApschemaV1_9 from context import getApschemaV1_21 +from context import getLitepubV0_1 from context import getV1Schema from context import getV1SecuritySchema from context import getActivitystreamsSchema @@ -412,6 +413,13 @@ def load_document(url): 'document': getApschemaV1_21() } return doc + elif url.endswith('/litepub-0.1.jsonld'): + doc = { + 'contextUrl': None, + 'documentUrl': url, + 'document': getLitepubV0_1() + } + return doc return None except JsonLdError as e: raise e From f78f519e033c734b07cc71b3951a9c9793af2e6b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 20:10:07 +0000 Subject: [PATCH 27/65] Update default categories --- defaultcategories/en.xml | 434 ++++++++++++++++++++------------------- 1 file changed, 226 insertions(+), 208 deletions(-) diff --git a/defaultcategories/en.xml b/defaultcategories/en.xml index 71ae3dba1..606a5da62 100644 --- a/defaultcategories/en.xml +++ b/defaultcategories/en.xml @@ -6,523 +6,541 @@ sport billiard darts swim motorsport snooker marathon hockey diving baseball Millwall sailing athletics skating skiing sport football - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT events - neverforget award OONIbday waybackwednesday notifications throwbackthursday adventskalender live Day deepthoughts screenshotsaturday thursdaythoughts humanrightsday followfriday afediversechristmas wednesdaymotivation showerthoughts anarchymonday 100DaysToOffload ff holiday christmas week concert festival screenshottuesday dontstarve onthisday livestream sunday screenshotsunday liverpool adayinthelife day ccc InternationalCheetahDay interestingtimes christmaslights meetup + neverforget award OONIbday waybackwednesday notifications throwbackthursday adventskalender live Day deepthoughts thingaday screenshotsaturday thursdaythoughts beethoven250thbirthday humanrightsday followfriday afediversechristmas wednesdaymotivation showerthoughts beethoven anarchymonday 100DaysToOffload ff holiday christmas week concert festival FridayFolklore screenshottuesday dontstarve onthisday livestream BowieDay sunday screenshotsunday liverpool adayinthelife day ccc InternationalCheetahDay interestingtimes christmaslights meetup - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT gafam - zuckerberg caringissharing ads apple antitrust SpringerEnteignen GoogleDown AppleSearch bankruptBezos youtube ffs facebook interoperability amazon boycottinstagram amazonring googleplus degooglisation siri Facebook LeiharbeitAbschaffen advertising adtech fuckgoogle microsoft dtm twitter caffeine skype chrome hildebrandt youtubedl degoogled youtubers google sharingiscaring gis dt dotcoms deleteyoutube Instagram fascistbook FuckGoogle degoogle fuschia ungoogled ring affordances googledown gafam inspiring fuckoffgoogle deletefacebook fuckoffgoogleandco office365 instagram MatrixEffect playstore bigtech + zuckerberg caringissharing ads apple antitrust SpringerEnteignen ABoringDystopia GoogleDown AppleSearch bankruptBezos youtube ffs facebook interoperability amazon boycottinstagram amazonring Gafam googleplus degooglisation siri Facebook LeiharbeitAbschaffen advertising monopolies adtech fuckgoogle plottertwitter microsoft dtm twitter caffeine skype chrome hildebrandt youtubedl degoogled youtubers google sharingiscaring gis walledgarden dt dotcoms deleteyoutube Instagram fascistbook FuckGoogle degoogle fuschia appleiie ungoogled ring stopgoogle affordances googledown gafam inspiring fuckoffgoogle deletefacebook fuckoffgoogleandco office365 instagram MatrixEffect playstore bigtech whatsapp deleteamazon - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT activitypub - followerpower FederatedSocialMedia Fediverse activitypub activertypub pleroma losttoot PeerTube gofed fediblock lazyfedi federation instances fedilab pixiv mastotips mastodev mastotip friendica hiveway misskey siskin followers fediart Pixelfed contentwarnings pixelfed fediverseplaysjackbox fedidb block FediMemories Feditip Fediseminar onlyfedi socialcg monal tusky peertubers imagedescription feditips fedizens Mastodon following epicyon peertubeadmin mastomagic dev fediadmin pixeldev fosstodon instanceblock mastodonmonday isolategab fedireads PeertubeMastodonHost Bookwyrm federated socialhome fedivers MastodonMondays fediverse imagedescriptions mastoadmin smithereen mastodon fedi fediplay peertube lab mobilizon gemifedi + followerpower FederatedSocialMedia Fediverse activitypub activertypub pleroma losttoot PeerTube gofed fediblock lazyfedi federation instances fedilab pixiv mastotips mastodev mastotip friendica hiveway misskey siskin followers fediart blocking Pixelfed contentwarnings pixelfed fediverseplaysjackbox mapeocolaborativo fedidb block FediMemories Feditip Fediseminar onlyfedi socialcg monal tusky peertubers imagedescription feditips fedizens Mastodon following epicyon development peertubeadmin collaboration mastomagic dev fediadmin pixeldev fosstodon instanceblock mastodonmonday isolategab fedireads PeertubeMastodonHost Bookwyrm federated socialhome greenfediverse microblocks fedivers MastodonMondays fediverse imagedescriptions mastoadmin smithereen blabber mastodon fedi fediplay peertube developer lab mobilizon gemifedi - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT programming - Easer cpp report programming css objects Python FrancisBacon2020 mixers webdev gui release ada schutzstreifen rustlang ocaml program request_reaction uptronics solidarity hypocritcal profiles typescript forums vscode publiccode FreeSoftware vieprivée early adventofcode scripting warn spyware git solid trevornoah zinccoop tailwindcss raku fedidev c sourcecode publiekecode misc framaforms WendyLPatrick grep django gmic sackthelot gitportal relevance_P1Y kingparrot Leiharbeit programmer haskell Tarifvertrag unicode frgmntscnr github digitalmarketsact openrc tuskydev threema algorithms lisp forge pleaseshare HirsuteHippo resnetting fourtwenty libraries drivers freecode javascript fragment cpm code elisp patterns html terminal rust sauerkraut request spiritbomb r dramasystem go esbuild documentary golang clojurescript ruby contractpatch computers racket python indiedev kabelfernsehen alternatives OpenSource Scheibenwischer + Easer cpp report programming css objects Python FrancisBacon2020 mixers webdev gui release ada schutzstreifen rustlang ocaml program request_reaction uptronics hypocritcal profiles typescript forums vscode publiccode computerscience vieprivée early adventofcode cgit scripting warn spyware git solid trevornoah zinccoop tailwindcss raku fedidev c sourcecode publiekecode misc framaforms WendyLPatrick grep django gmic sackthelot gitportal gitlab relevance_P1Y kingparrot Leiharbeit programmer haskell OpenSourceHardware Tarifvertrag unicode frgmntscnr github digitalmarketsact freecodecamp openrc tuskydev threema algorithms lisp digitaldefenders forge pleaseshare HirsuteHippo resnetting fourtwenty libraries drivers freecode javascript fragment cpm code elisp patterns eq html terminal rust sauerkraut request spiritbomb r dramasystem go esbuild documentary golang clojurescript ruby contractpatch computers racket bugreport python indiedev kabelfernsehen alternatives OpenSource Scheibenwischer - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT nature - hiking wat StormBella morning trees light birds nature frogs sunrise coldwater inaturalist forest morningcrew australianwildlife capybara natur amphibians + hiking wat StormBella morning trees lichen light birds nature frogs sunrise moutains coldwater inaturalist forest morningcrew australianwildlife capybara enlightenment natur deforestation morningwalk amphibians - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT writing - blog tootfic authors poem magazine smallstories blogging smallpoems blogs interactivestorytelling WriteFreely storytelling goodreads creativewriting journal poetry + blog tootfic authors poem magazine smallstories blogging smallpoems writing blogs noblogo microfiction interactivestorytelling westernjournal quote WriteFreely storytelling goodreads creativewriting journal poetry - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT hardware - plugandplay PersonalComputer cyberdeck PineCUBE keyboards screenless modem analogcomputing TrueDelta keyboard ArmWorkstation daretocare printmaker cybredeck laptop solarpunk recycling lenovo fairelectronics fuse ibm 3dprinting MechcanicalKeyboards openhardware raspberrypi barcode pinetime pinebookpro PinebookPro 3dprint arm paperComputer amd openpower devopa thinkpad print electronic + plugandplay purism opennic PersonalComputer cyberdeck PineCUBE keyboards screenless pinebook modem analogcomputing TrueDelta keyboard ArmWorkstation daretocare laptops printmaker cybredeck computing laptop solarpunk recycling lenovo fairelectronics fuse ibm 3dprinting MechcanicalKeyboards hardware retrohardware openhardware raspberrypi barcode pinetime pinebookpro PinebookPro 3dprint arm paperComputer amd openpower devopa thinkpad raspberrypi4 print electronic - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT places - lapaz luanda asunción nouakchott conakry kyiv moscow saipan gibraltar dublin catalunya dannibleibt avarua hargeisa delhi niamey chișinău colombo brasília phnompenh mbabane belgrade belmopan pyongyang hannover ulaanbaatar oranjestad gaborone seattle ndjamena raw singapore kingedwardpoint abidjan nuuk pretoria papeete malé zagreb gitega abudhabi flyingfishcove castries georgetown hagåtña borikua basseterre hamburg kinshasa suva valparaíso athens roseau baku charlotteamalie antananarivo domi pristina santiago sukhumi berlin uptronicsberlin funafuti libreville hanoi philipsburg tehran banjul prague andorralavella daw yerevan portauprince dakar paramaribo tifariti capetown tirana klima ankara ipswich managua lisbon bishkek amsterdam portonovo santodomingo bangkok bucharest kathmandu aden madrid sanjuan vienna kingston kabul damascus stockholm douglas willemstad thehague panamacity beirut amman newdelhi tórshavn nouméa oslo alofi gustavia paris video cockburntown ottawa stepanakert portofspain fsberlin honiara asmara florida nicosia helsinki taipei tegucigalpa tokyo tashkent larochelle MadeInEU sarajevo algiers nairobi muscat monaco riyadh lusaka wellington bissau juba mariehamn majuro buenosaires ngerulmud dhaka guatemalacity washington vatican kuwaitcity londonboaters bern mexicocity bratislava bridgetown delhipolice tunis manila stanley matautu copenhagen barcelona lomé budapest ouagadougou mogadishu freetown victoria brazzaville portmoresby ashgabat kampala elaaiún vilnius bloemfontein sucre london marseille pagopago bradesestate oakland vaduz addis nürnberg naypyidaw CassetteNavigation khartoum baghdad bandar moroni lehavre portvila kingstown ChrisCrawford reykjavík manama accra windhoek nukualofa ciutatvella tbilisi canberra quito maputo cetinje putrajaya ramallah bogotá dodoma harare havana warsaw münster valletta localberlin ljubljana bamako kualalumpur podgorica rabat cotonou plymouth seoul Portland dushanbe bangui aotearoa westisland tskhinvali palikir caracas jamestown rome munich ass freestuffberlin sãotomé jakarta daressalaam sansalvador apia essex yaren cairo jerusalem brussels kigali southtarawa beijing minsk montevideo vientiane maseru hamilton doha tripoli celtic portlouis lima adamstown deventer abuja lilongwe nassau lobamba heathrow nyc strawberry montreal dili riga assembly lesbos monrovia nursultan gab sanjosé marigot islamabad malabo tallinn sahara thimphu yaoundé praia bujumbura sofia skopje + lapaz luanda asunción nouakchott conakry kyiv moscow saipan gibraltar dublin KlimaGerechtigkeit catalunya dannibleibt avarua hargeisa delhi niamey chișinău colombo brasília phnompenh mbabane danni belgrade belmopan pyongyang hannover ulaanbaatar oranjestad gaborone seattle ndjamena raw singapore kingedwardpoint abidjan nuuk pretoria papeete malé zagreb gitega abudhabi flyingfishcove castries georgetown hagåtña cassette borikua basseterre hamburg kinshasa suva valparaíso athens roseau baku charlotteamalie antananarivo domi pristina videocalls santiago sukhumi berlin uptronicsberlin funafuti libreville stopchasseacourre puertorico hanoi philipsburg tehran banjul prague andorralavella daw yerevan portauprince dakar paramaribo tifariti capetown tirana klima ankara ipswich managua lisbon bishkek amsterdam portonovo santodomingo bangkok bucharest kathmandu aden madrid sanjuan vienna kingston kabul damascus stockholm douglas willemstad thehague panamacity RassismusTötet beirut amman newdelhi tórshavn nouméa oslo alofi gustavia paris video cockburntown ottawa classical stepanakert portofspain klimakrise fsberlin honiara asmara florida nicosia helsinki taipei tegucigalpa tokyo tashkent larochelle MadeInEU sarajevo algiers KlimaKrise nairobi muscat monaco riyadh lusaka wellington bissau juba mariehamn klimaatcrisis majuro buenosaires ngerulmud dhaka guatemalacity washington vatican kuwaitcity londonboaters bern mexicocity bratislava bridgetown delhipolice tunis manila stanley matautu copenhagen barcelona lomé budapest ouagadougou mogadishu freetown victoria brazzaville portmoresby ashgabat kampala elaaiún vilnius bloemfontein sucre london marseille pagopago bradesestate oakland vaduz addis nürnberg naypyidaw CassetteNavigation khartoum baghdad bandar moroni lehavre portvila kingstown ChrisCrawford reykjavík manama accra windhoek nukualofa ciutatvella tbilisi canberra quito maputo cetinje putrajaya ramallah bogotá dodoma harare havana warsaw münster valletta localberlin ljubljana bamako kualalumpur podgorica rabat cotonou plymouth seoul Portland dushanbe bangui aotearoa westisland tskhinvali palikir caracas jamestown rome munich ass freestuffberlin sãotomé jakarta daressalaam sansalvador apia essex yaren cairo jerusalem brussels kigali southtarawa beijing minsk montevideo vientiane maseru hamilton doha tripoli celtic portlouis lima adamstown deventer weimar abuja lilongwe nassau lobamba heathrow nyc strawberry montreal dili riga assembly lesbos monrovia nursultan gab sanjosé klimaatrechtvaardigheid marigot islamabad malabo tallinn sahara thimphu yaoundé praia bujumbura washingtondc sofia skopje - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT music - musicprodution punk ourbeats indiemusic streetpunk bandcamp musicians jamendo ipod skinheadmusic rap mp3 indie Music EnvoieStopHashtagAu81212 thecure vaporwave dubstep synthwave oi rave freemusic nowplaying hiphop experimentalmusic fedimusic soundcloud frankiegoestohollywood dj newwave dorkwave producing musicproduction funkwhale retrosynth NowPlaying libremusicproduction MusicAdvent coinkydink arianagrande synth music darkwave metal fediversemusic cyberpunkmusic BandcampFriday + musicprodution punk ourbeats indiemusic streetpunk bikepunks bandcamp musicians jamendo ipod skinheadmusic rap mp3 indie Music EnvoieStopHashtagAu81212 thecure vaporwave dubstep synthwave bootstrap oi rave freemusic nowplaying hiphop experimentalmusic spotify liberapay fedimusic musicbrainz soundcloud frankiegoestohollywood ccmusic typographie dj newwave dorkwave producing musicproduction lastfm funkwhale punkwear retrosynth NowPlaying libremusicproduction MusicAdvent coinkydink arianagrande synth music np darkwave mastomusic grapheneos metal fediversemusic cyberpunkmusic BandcampFriday - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT politics - TakeOurPowerBack cia community wageslavery immigration dissent liberation fascism techtuesday skyofmywindow freedomofspeech rojava humanrights leftists Socialism ukpol FreeKeithLamar copwatch capitalismkills petition BorisJohnson freedom abolitionnow anarchism DefundThePolice technews smalltech oilwars kommunismus bjp ThirdRunway hierarchy election sky_of_my_window generalstrike antipolitics digitalfreedom mayday hatespeech fascists lowtech a11y burntheprisons cyberlaw peerproduction corporations iww commons corporatewatch wageslave uspol frontex communism RemoveThePolice Immigration neoliberalism socialecology MutualAid capitalism technology prisons wealth conspiracytheories corporatecrime communist KeirStarmer anarchismus politics inclusivity brightgreen anarchisme DominicCummings nzpol Bookchin ClemencyNow brexit totalitarianism privatisation TyskySour Labour freethemall green BAME decolonizeyourmind privilege AbolishPrisonsAbolishPolice surfaceworldblows ecofascism SocietalChange facialrecognition corruption anarchy propaganda decolonization digitalrights feminism polizei neo xp 18Source radicaltech redandanarchistskinheads PritiPatel latestagecapitalism racist MexicanRevolution elections RussellMaroonShoatz white prisoners warrants policebrutality borisjohnson Anarchist press mutuality whitehouse freedomofexpression censorship decolonize emmet decenterwhiteness Biden ChineseAppBan cooperative modi law deathtoamerica manipulation firetotheprisons britpol Capitalism surveillancecapitalism leftist Revolution ukpolitics JeremyCorbyn blacklivesmatter FreeAlabamaMovement rentstrike dsa techno migration mutualaid multipleexposure AbolishPrison fascist socialcoop anarchistprisoners polizeiproblem uselection IDPol Slavetrade met ourstreets refugees acab freewestpapua tech + TakeOurPowerBack trump cia community wageslavery immigration dissent liberation fascism techtuesday skyofmywindow techthursday freedomofspeech fascisme rojava humanrights leftists Socialism ukpol FreeKeithLamar Antifascisme copwatch capitalismkills petition BorisJohnson freedom abolitionnow anarchism DefundThePolice technews polizeigewalt smalltech antifascists oilwars kommunismus bjp ThirdRunway hierarchy election republicans solidarity techwear sky_of_my_window generalstrike antipolitics digitalfreedom mayday hatespeech fascists lowtech a11y burntheprisons cyberlaw peerproduction corporations iww freeassange commons corporatewatch wageslave uspol frontex communism RemoveThePolice Immigration neoliberalism socialecology MutualAid capitalism technology prisons wealth conspiracytheories corporatecrime communist KeirStarmer taoteching anarchismus politics inclusivity HeroesResist brightgreen anarchisme DominicCummings nzpol Bookchin ClemencyNow brexit totalitarianism privatisation TyskySour Labour freethemall green BAME decolonizeyourmind privilege antikapitalisme AbolishPrisonsAbolishPolice surfaceworldblows ecofascism SocietalChange facialrecognition corruption anarchy Feminism propaganda endsars decolonization digitalrights feminism polizei neo xp 18Source censorshipBook radicaltech conspiracy redandanarchistskinheads radicaldemocracy PritiPatel latestagecapitalism racist MexicanRevolution elections RussellMaroonShoatz commonspub white prisoners warrants policebrutality borisjohnson Anarchist press mutuality whitehouse freedomofexpression censorship decolonize emmet decenterwhiteness Biden ChineseAppBan cooperative modi law deathtoamerica manipulation firetotheprisons britpol Capitalism surveillancecapitalism leftist Revolution ukpolitics JeremyCorbyn blacklivesmatter FreeAlabamaMovement rentstrike dsa techno migration mutualaid multipleexposure AbolishPrison anarchists fascist socialcoop anarchistprisoners polizeiproblem uselection IDPol Antifa Slavetrade met ourstreets freespeech refugees acab ecology SurveillanceCapitalism freewestpapua sunnytech tech - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT food - vitamind cake margarine dessert salsa caviar theexpanse cookery pietons food skillet liquor milk bolognese recipe foodporn yeast plate waffle biscuit glaze omelette filet pastry wine hamburger juice Amazfish sourdough nuts gras toast broth batter foodie ketchup seasoning mayo soup pan voc imateapot teamcapy mayonnaise vegan dish avocado spice bakery cooking yogurt spotify crumble cider butter cook pottery cobbler steak pizza soda fedikitchen aroma oil flour cream nutella pie cuisine tartar tea marinade mushroom entree bread salad beans fresh syrup fermentation mushrooms cookie curd soysauce pudding beer baking fish foodwaste wheat pot TeamFerment stew chocolate paste wok recipes olive burger candy kitchen coffee bagel taste meat noodle raclette caramel rice eggs grill poutine lard croissant pasta foods cheese oregano drink muffin foie sauce soy vore cocoa sandwich mousse chili vinegar + vitamind cake margarine zwartepiet dessert salsa caviar theexpanse BellaSpielt cookery pietons food skillet spiel liquor milk bolognese recipe foodporn yeast drinking plate waffle biscuit glaze omelette filet pastry wine hamburger juice Amazfish sourdough nuts gras toast broth batter foodie spiele ketchup divoc seasoning mayo soup pan voc imateapot teamcapy mayonnaise vegan dish avocado spice bakery cooking yogurt crumble cider butter mastokitchen cook pottery mastocook cobbler steak pizza soda fedikitchen aroma oil angelfish flour cream nutella pie cuisine tartar tea marinade mushroom entree lfi bread salad beans fresh syrup fermentation mushrooms cookie wordstoliveby curd soysauce pudding beer baking fish foodwaste wheat pot TeamFerment stew chocolate paste wok recipes olive burger candy kitchen coffee bagel taste SpieleWinter2020 meat noodle raclette caramel rice eggs grill poutine lard croissant pasta foods cheese oregano drink muffin foie sauce soy vore pandemie cocoa sandwich mousse chili vinegar - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT farming johndeere - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT countries - romania burma lithuania solomon chile Instanz fiji tajikistan benin paraguay eeuu senegal ukraine italy brunei nicaragua guyana Pflanzenbestimmung euphoria zambia iceland morocco netherlands swaziland bosnian solo suriname elsalvador russia samoa european czech belarus hayabusa2 kyrgyzstan uk abuse translation sanmarino catalonia panama japan buyused venezuela gambia freeNukem kuwait barbados papua greece switzerland uae nigeria usa angola honduras djibouti laos sierraleone cambodia ych vietnam neofeud seychelles marshall kazakhstan estonia tonga stlucia burundi bangladesh egypt mali congo us jordan speedrun grenada israel algeria ghana bosnia russian industrial eritrea bhutan hungary saudi slovenia tig bahamas australia kiribati togo koreanorth poland malawi capeverde run armenia american hautrauswasgeht bahrain mozambique beleuchtung southsudan syria micronesia maldives iran indigenous sweden ethiopia cuba liberia canada burkina somalia Chile scotland aur vaticancity easttimor austria turkey yemen Bolivia denmark trunk madagascar finland philippines ivorycoast haiti ecuador Portugal azerbaijan gasuk spain albania afghanistan europe mauritania dominica thailand belize westpapuauprising macedonia montenegro qatar mongolia costarica boatingeurope birdsofkenya latvia uzbekistan kabelaufklärung ireland iraq malaysia mexico mauritius oman chad nz georgia zimbabwe france serbia lesotho oddmuse tunisia argentina cameroon namibia sudan indonesia colombia tuvalu britainology beckychambers turkmenistan tanzania germany neuhier norway comoros auteursrecht guatemala Thailand kosovo andorra wales servus pakistan belgium china antigua life koreasouth newzealand einzelfall rwanda luxembourg libya italyisntreal nauru Anarchismus moldova palau taiwan kenya trinidad eu botswana CuriosidadesVariadas jamaica vanuatu cyprus aminus3 malta niger westpapua busse unitedstates myanmar saintvincent guinea nepal peru uganda uruguay india lebanon neurodiversity southafrica croatia europeanunion bolivia chinese dominican srilanka bulgaria slovakia speedrunning gabon psychedelicart stkitts liechtenstein brazil shutdowncanada + romania burma lithuania solomon chile Instanz fiji tajikistan benin paraguay eeuu senegal ukraine italy brunei nicaragua guyana Pflanzenbestimmung euphoria zambia iceland morocco netherlands swaziland bosnian solo suriname winningatlife elsalvador russia samoa european czech belarus hayabusa2 kyrgyzstan uk abuse translation sanmarino catalonia panama japan buyused venezuela gambia freeNukem kuwait barbados papua greece switzerland uae nigeria usa angola honduras djibouti laos sierraleone cambodia ych vietnam neofeud seychelles marshall kazakhstan estonia tonga stlucia burundi bangladesh egypt mali congo us jordan speedrun grenada israel psychic algeria ghana bosnia translations russian industrial eritrea bhutan ios hungary saudi slovenia tig czechosvlovakia bahamas australia kiribati togo koreanorth poland Überbevölkerung malawi capeverde run armenia american hautrauswasgeht bahrain mozambique beleuchtung southsudan syria micronesia maldives iran indigenous sweden ethiopia cuba liberia canada burkina somalia Chile scotland aur vaticancity easttimor austria turkey yemen Bolivia denmark trunk madagascar finland philippines ivorycoast haiti ecuador Portugal azerbaijan gasuk spain albania afghanistan europe mauritania dominica thailand belize westpapuauprising macedonia montenegro qatar mongolia costarica boatingeurope birdsofkenya latvia uzbekistan kabelaufklärung ireland iraq malaysia mexico mauritius oman chad nz georgia zimbabwe france serbia lesotho oddmuse tunisia argentina czechia cameroon namibia sudan indonesia colombia tuvalu britainology beckychambers turkmenistan tanzania germany neuhier norway comoros auteursrecht guatemala Thailand kosovo andorra wales servus pakistan belgium china antigua life koreasouth newzealand einzelfall rwanda luxembourg libya italyisntreal nauru Anarchismus moldova palau taiwan kenya trinidad eu botswana CuriosidadesVariadas jamaica vanuatu cyprus aminus3 malta polychromatic niger westpapua busse unitedstates myanmar saintvincent guinea nepal peru uganda uruguay india lebanon neurodiversity southafrica croatia europeanunion bolivia chinese dominican srilanka bulgaria slovakia speedrunning gabon psychedelicart stkitts liechtenstein brazil shutdowncanada - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT cycling bicycle cycling bike thingsonbikes Snowbike cyclist - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT phones - mobileapp pine fdroid plasmamobile android phones smartphone iOS14 linuxphones QWERTYphones BriarProject librem5 pinephone mobile fairphone ubuntutouch Android ubports osmand vodafone iphones postmarketos iOS microg mobileKüfA + mobileapp pine fdroid plasmamobile android linuxmobile phones smartphone iOS14 linuxphones mobilelinux QWERTYphones siskinim Smartphones plasma phosh BriarProject librem5 osm pinetab pinephone mobile pine64 fairphone ubuntutouch Android ubports osmand vodafone linuxonmobile iphones postmarketos iOS microg mobileKüfA - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + security + signalboost encrypt letsencrypt autoritäreretatismus omemo password cryptography solarwinds communityalgorithmictrust infosec gchq IHaveSomethingToHide IronySec cryptowars supplychainattacks UseAMaskUseTor cyberattack security tor e2e bruceschneier vpn openssh openssl e2ee ed25519 encryption ssh misshaialert crypto giftofencryption malware opsec keepass torsocks nsa protonvpn yubikey nitrokey openpgp castor9 gpgtools gpg fotopiastory cybersecurity CryptoWars signal noscript trust cryptocurrency cryptomator openvpn datasecurity encryptiost securitynow tracking cloudflare + + Sun, 10 Jan 2021 20:09:37 UT science math womeninstem supercollider nextgeneration dna archaeologist dawkins graphTheory psychology biology generation gene paleontology - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT pandemic - covid19 corona Coronavirus CoronaWarnApp facemasks vaccines vaccine pandemic contacttracing tier4 covid coronavirus masks virus Lockdown rna codid19 COVID19 YesWeWork ContactTracing COVID + covid19 corona psmeandmywholefamilycaughtcovidfromwork Coronavirus CoronaWarnApp facemasks vaccines vaccine pandemic contacttracing tier4 covid coronavirus masks virus Lockdown rna codid19 COVID19 YesWeWork ContactTracing COVID - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT software - app freedombox windows libre nginx Framasoft invidious drm publicdomain kubernetes fossmendations jami FuckOffZoom quicksy free docker freesoftware gimp foss matrix thefreethoughtproject nextcloud wechat openscad TabOrder ikiwiki Linux rocketchat outreachy lyft nitter discord opensource diaspora yunohost littlebigdetails cabal conferencing libreboot accessibility devops owncast emacs freiesoftware email chatapps floss plugins deltachat application uifail FOSS bittorrent vlc zoom tiling gpl FriendofGNOME usability obnam snap cryptpad software OwnStream zrythm mumble grsync telegram containers blockchain irssi mutt design gameoftrees backup rotonde GNU thunderbird sysadmin apps licensing screenreaders profanity ffmpeg lemmy OSM distributedledger win10 element nativeApp jitsi wordpress ux rsync libreoffice dino plugin OCUPACAOCARLOSMARIGHELLA whatsapp openoffice + app freedombox windows libre nginx Framasoft invidious drm publicdomain kubernetes fossmendations jami FuckOffZoom quicksy whiteboard free docker freesoftware gimp foss matrix thefreethoughtproject filesystems nextcloud wechat openscad TabOrder ikiwiki Linux FreeSoftware rocketchat outreachy lyft nitter discord opensource diaspora yunohost littlebigdetails cabal conferencing libreboot accessibility devops owncast emacs freiesoftware writefreely email chatapps HappyNewYear floss plugins deltachat application uifail FOSS bittorrent vlc zoom tiling gpl FriendofGNOME usability obnam snap cryptpad software OwnStream upstream slack zrythm gnu mumble grsync freecad telegram containers blockchain irssi mcclim mutt design gameoftrees backup rotonde freetube GNU thunderbird sysadmin parler apps chat licensing screenreaders LINMOBapps profanity Tankklappe ffmpeg fossandcrafts lemmy OSM agpl distributedledger ghostscript win10 element chatty nativeApp jitsi wordpress ux rsync libreoffice dino plugin OCUPACAOCARLOSMARIGHELLA openoffice - Tue, 29 Dec 2020 20:59:38 UT - - - security - encrypt omemo password cryptography solarwinds communityalgorithmictrust infosec gchq IHaveSomethingToHide IronySec cryptowars supplychainattacks UseAMaskUseTor cyberattack security tor e2e bruceschneier vpn openssh openssl e2ee ed25519 encryption ssh misshaialert crypto giftofencryption malware opsec keepass torsocks nsa protonvpn yubikey nitrokey openpgp castor9 gpgtools gpg fotopiastory cybersecurity CryptoWars signal noscript np trust cryptocurrency cryptomator openvpn datasecurity tracking cloudflare - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT gardening - sporespondence blockade inde independant deno cabbage bundeswehr onions bordeaux datenschleuder florespondence garden thyme DailyFlowers permaculture papuamerdeka flowers gardening de devilslettuce fahrräder golden + sporespondence blockade inde independant deno cabbage bundeswehr onions bordeaux datenschleuder florespondence garden thyme DailyFlowers acu permaculture papuamerdeka flowers gardening de devilslettuce fahrräder golden - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT conferences - debconf talk fossdem FreedomBoxSummit apconf2020 schmoocon summit confidenceTricks minidebconf rc3worldleaks emacsconf ox defcon flossevent conf rC3 rC3World conference flossconf apconf rC3one C3 config + debconf talk fossdem FreedomBoxSummit apconf2020 schmoocon summit confidenceTricks minidebconf rc3worldleaks emacsconf MCH2021 ox defcon flossevent conf rC3 rC3World conference flossconf apconf rC3one C3 config - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT cats - Cat dailycatpic dxp DailyCatVid katze CatsOfMastodon Leopard catbellies LapCats + Cat dailycatpic dxp DailyCatVid dx katze CatsOfMastodon Leopard catbellies LapCats - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT employment - InterviewQuestions mywork reproductivework bullshitjobs antiwork kreaturworks worklog hire hirefedi carework nowhiring work letthenetwork jobs + InterviewQuestions mywork reproductivework bullshitjobs antiwork kreaturworks worklog hire hirefedi carework nowhiring work letthenetwork jobs sexworker - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + radio + cbradio hamr whydopeopledoshitlikethis amateurradio radiohost oshw localization vantascape vantaradio ca radio healthcare listening hamradio FreeAllPoliticalPrisoners card10 radiobroadcasting 3dcad radioshow local noshame osh hackerpublicradio california listeningtonow radiobroadcast spazradio anonradio io + + Sun, 10 Jan 2021 20:09:37 UT + + + years + newyearsresolutions Year2020 year 1yrago newyear happynewyear 5yrsago newyearseve + + Sun, 10 Jan 2021 20:09:37 UT linux - osdev opensuse linuxisnotanos elementaryos cli kde Debian11 slackware mobian openwrt distros nixos nix DebianBullseye shareyourdesktop wireguard linuxaudio nixpkgs gtk debian trisquel gnome linuxposting showyourdesktop windowmanager desktop ubuntu xubuntu unix fedora centos gentoo usergroup systemd linuxgaming Debian distro destinationlinux qubesos i3wm haiku linuxisnotaplatform linux EMMS netbsd termux btrfs reproduciblebuilds artix gtk4 archlinux rhel debianinstaller linuxisajoke + osdev opensuse linuxisnotanos elementaryos cli kde Debian11 slackware mobian openwrt distros nixos nix DebianBullseye shareyourdesktop wireguard linuxaudio nixpkgs gtk debian trisquel gnome linuxposting showyourdesktop windowmanager desktop ubuntu gnulinux justlinuxthings xubuntu unix fedora centos gentoo usergroup systemd linuxgaming Debian distro destinationlinux gtk3 qubesos i3wm kubuntu haiku linuxisnotaplatform linux EMMS netbsd termux btrfs reproduciblebuilds artix gtk4 archlinuxarm archlinux rhel debianinstaller linuxisajoke - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT photos - nikon photography photo photogrpahy tokyocameraclub photos photoshop camera myphoto picture streetphotography + nikon 90mm photography photo photogrpahy tokyocameraclub photos photoshop camera cameras myphoto picture streetphotography - Tue, 29 Dec 2020 20:59:38 UT - - - crafts - topic_imadethis textile upholstery dust3d hackers hackerspaces sanding sundiy knitting hack biohacking wip jewelry diy upcycling woodworking origami makers quilting hacker quilt 3dmodel woodwork ceramics embroidery - - Tue, 29 Dec 2020 20:59:38 UT - - - pets - catpics catofmastodon mastodogs catbehaviour Coolcats dogsofmastodon gentrification cats kittens pet dog caturday catsofmastodon cute catstodon dogs mastocats cat catcontent - - Tue, 29 Dec 2020 20:59:38 UT - - - news - news Wikileaks newsletter rt bbc doubledownnews journalism SkyNews - - Tue, 29 Dec 2020 20:59:38 UT - - - games - minecraft tetris99 TerraNil runequest boardgames computergames gamedesign chess nintendoswitch mud indiegame game 0ad ttrpg gamedev guildwars2 TetrisGore gaming nintendo Gamesphere rpg tetris dosgaming DnD cyber2077 cyberpunk2077 FreeNukum neopets minetest guildwars dnd games - - Tue, 29 Dec 2020 20:59:38 UT - - - climate - energy renewables clouds renewableenergy amp climateemergency climate windenergy coal globalwarming climatechange weather climatecamp windpower science fossilfuels sky climatescience climatecrisis - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT internet - i2p spam firefox redecentralize wikipedia rtmp decentralization decentralize w3c torrent data sitejs internetarchaeology WordPress self contentmoderation distributed router dataretention selfhosting communityhosting icann discourse PeerToPeer dns openstandards nojs oauth hypercore CDNsAreEvil protonmail standards yourdataisyourdata internetfreedom gemini webui SmallWeb xmpp semanticweb socialnetwork content ntp socialnetworks proton icmp videocast jabber decentralized wiki ssb darknet cookies darkweb netcat Reddit server browser cloudy p2p social antisocial www ilovewikipedia web WebsiteStatus twitch 9front theserverroom socialmedia domain rss ipns mozilla voicemail mail i2pd ipfs internetradio browsers decentralizeit netscape openculture cyberspace offthegrid cloud internet decentralisation internetarchive js dark openweb onlineharms dot ftp internetshutdowns fixtheweb socialweb + immersiveweb dotcons i2p spam firefox redecentralize decentral wikipedia rtmp decentralization inclusiónsocial decentralize w3c torrent data sitejs publicserviceinternet internetarchaeology WordPress darkages self contentmoderation distributed router dataretention bigdata selfhosting communityhosting icann hosting discourse weblate PeerToPeer dns openstandards nojs oauth hypercore CDNsAreEvil protonmail standards yourdataisyourdata internetfreedom gemini webui SmallWeb distributedcoop xmpp semanticweb socialnetwork selfie content domains ntp socialnetworks Meme proton disco icmp videocast jabber webbrowsers decentralized wiki ssb darknet cookies darkweb netcat darktable Reddit server browser cloudy IPFS p2p social antisocial www ilovewikipedia web WebsiteStatus netshutdowns twitch 9front theserverroom socialmedia domain OpenStreetMap filesharing rss ipns mozilla voicemail mail i2pd ipfs internetradio browsers decentralizeit netscape openculture cyberspace messaging offthegrid cloud internet decentralisation serverMeddling internetarchive godot js dark openweb onlineharms dot thepiratebay ftp internetshutdowns fixtheweb socialweb mozillahubs - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + crafts + topic_imadethis hackerexchange textile upholstery hackgregator dust3d hackers hackerspaces sanding sundiy knitting hack biohacking wip jewelry diy upcycling woodworking origami makers quilting hacker quilt 3dmodel woodwork ceramics embroidery + + Sun, 10 Jan 2021 20:09:37 UT + + + pets + catpics catofmastodon reEducationCamp mastodogs catbehaviour Coolcats dogsofmastodon gentrification fostercats cats kittens pet dog caturday catsofmastodon cute catstodon dogs mastocats notpixiethecat londoninnercitykitties cat catcontent + + Sun, 10 Jan 2021 20:09:37 UT + + + art + paperart Linke water urban glassart artvsartist2020 abstract bsd earthship dccomics circuitsculpture watercolor memes autisticartist barrigòtic art open krita urbanart queerart deviantart adultcolouring collage jordanlynngribbleart openai harmreductionart openmoko wallpaper agriculture streetart coverart stickers fiberart MastoArt particl ParticlV3 culture opencl fiberarts polArt ink painting opencoop digitalart comic artwork openbsd mandala xkcd comics santa mastoart illustration artopencall gnuimagemanipulationprogram os wireart cartoon webcomic furryart DisabledArtist openstreetmap sticker artbreeder arttherapy TattoosOfTheFediverse artvsartist abstractart sculpture artist meme cultureshipnames concretepoetry artwithopensource opencallforartists commissionsopen peppertop visionaryart blackartist zines zine furry genart pixelart alisajart WaterDrinkers opencollective openrailwaymap JuliaHartleyBrewer artistsOfMastodon + + Sun, 10 Jan 2021 20:09:37 UT + + + news + news Wikileaks newsletter newsflash rt bbc doubledownnews journalism SkyNews + + Sun, 10 Jan 2021 20:09:37 UT + + + games + minecraft tetris99 TerraNil runequest boardgames computergames fucknintendo gameassets FediDesign gamedesign chess nintendoswitch mud indiegame game 0ad gameart opengameart sign ttrpg gamedev guildwars2 TetrisGore gaming gameing nintendo Gamesphere rpg tetris dosgaming DnD cyber2077 tarot cyberpunk2077 gamesforcats FreeNukum supermariomaker2 neopets minetest guildwars dnd games + + Sun, 10 Jan 2021 20:09:37 UT + + + legal + eek hfgkarlsruhe amro SpreekJeUitBekenKleur GameSphere OnlineHarmsBill laipower gdpr intros Anticritique learning energyflow rms digitalservicesact geekproblem dmca + + Sun, 10 Jan 2021 20:09:37 UT + + + climate + energy renewables clouds renewableenergy amp climateemergency climate windenergy coal sciencefiction skypack globalwarming climatechange weather climatecamp windpower pollution science fossilfuels sky climatescience climateaction climatecrisis + + Sun, 10 Jan 2021 20:09:37 UT retro - A500 atarist commodore teletext floppy 8bit atari trs80 floppydisk retrocomputing C64 plan9 80s microcomputing omm retrogaming z80 8bitdo retro commissions amiga bbcmicro microcomputer bbsing + A500 atarist commodore teletext floppy 8bit atari trs80 floppydisk retrocomputing C64 plan9 80s microcomputing omm retrogaming z80 8bitdo retro retropie commissions amiga bbcmicro microcomputer bbsing - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT indymedia - visionontv globleIMC indymediaback pga indymedia hs2IMC indymediaIMC network roadsIMC omn tv roadstonowhereIMC UKIMC 4opens openmedianetwork + visionontv tredtionalmedia globleIMC indymediaback pga indymedia hs2IMC indymediaIMC network roadsIMC omn tv roadstonowhereIMC UKIMC 4opens openmedianetwork - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT media - livestreaming mainstreaming stream streaming weAreAllCrazy maiabeyrouti submedia theatlantic traditionalmedia videos railroads taina ai realmedia media + livestreaming mainstreaming stream trad streaming weAreAllCrazy maiabeyrouti sustainability diymedia submedia theatlantic traditionalmedia videos wikimedia railroads taina ai realmedia media independentmedia - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT activism - protestor grassroot g20 riseup sflc DanniVive reuse fsfe softwarefreedom ann activist xr directaction eff openrightsgroup protest JeffreySDukes actiondirecte kroymann HS2 ngo MarcWittmann fsf StopHS2 grassroots BLM changeisinyourhands conservancy JefferySaunders Kolektiva XR freeolabini announcement isolateByoblu annieleonard + protestor grassroot FreeLibreOpen g20 bekannt riseup sflc DanniVive reuse fsfe softwarefreedom ann activist xr SustainableUserFreedom directaction eff change openrightsgroup protest JeffreySDukes actiondirecte kroymann HS2 ngo MarcWittmann fsf StopHS2 grassroots antireport ClimateJustice BLM changeisinyourhands conservancy JefferySaunders Kolektiva XR freeolabini announcement isolateByoblu annieleonard - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT questions askmastodon askfedi question askmasto askfediverse ask askfosstodon - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT birds - RainbowBeeEater bird + RainbowBeeEater pigeonlover bird - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT ethics digitalethics ethics ethicallicense ethical - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT disability ableism disabled - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT economics - bitcoin theWorkshop feministeconomics WealthConcentration valuesovereignty funding value shop crowdfund startups HenryGeorge crowdfunding limitstogrowth micropatronage monetize smallbusiness GitPay gdp limits + bitcoin theWorkshop feministeconomics WealthConcentration disabilitycrowdfund coops valuesovereignty funding platformcoop workercoops economics value shop crowdfund RIPpla startups HenryGeorge crowdfunding limitstogrowth micropatronage lgbtcrowdfund monetize smallbusiness pla GitPay gdp coop smallbusinesses infoshop limits - Tue, 29 Dec 2020 20:59:38 UT - - - art - Linke urban glassart artvsartist2020 watercolor autisticartist barrigòtic art open krita urbanart queerart deviantart adultcolouring collage harmreductionart wallpaper streetart coverart fiberart MastoArt culture polArt ink painting opencoop digitalart comic artwork openbsd mandala xkcd comics santa mastoart illustration artopencall gnuimagemanipulationprogram os wireart cartoon webcomic furryart sticker artbreeder arttherapy TattoosOfTheFediverse artvsartist sculpture artist meme cultureshipnames concretepoetry artwithopensource opencallforartists commissionsopen peppertop blackartist zines zine furry opencollective JuliaHartleyBrewer artistsOfMastodon - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT podcasts - podcasting IntergalacticWasabiHour podcast tilde til tilderadio podcasts tildeverse smallisbeautiful tilvids + podcasting IntergalacticWasabiHour podcast tilde til tilderadio tildes podcasts tildeverse smallisbeautiful fertilizers tilvids - Tue, 29 Dec 2020 20:59:38 UT - - - years - Year2020 year 1yrago 5yrsago - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT culture etiquette - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + funding + donate disabledcrowdfund fundraiser patreon + + Sun, 10 Jan 2021 20:09:37 UT identity boomer - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT political copservation linguisticProgramming - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT fashion brasil fashionistas fashionesta bras fashion socks patches - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT month - april july march october november august june december september may feburary january month + april july march chapril october november august june december september may feburary january month - Tue, 29 Dec 2020 20:59:38 UT - - - funding - disabledcrowdfund patreon - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT books - justhollythings earthsea ebooks book amreading bookwyrm bookreview theLibrary wayfarers books ebook epub cookbook + justhollythings earthsea ebooks book amreading failbook bookwyrm bookreview theLibrary wayfarers fakebook books bookreviews ebook epub cookbook - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT comedy laugh humour satire irony standup funny humor - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT techbros - einfachredeneben hackernews red reddit + einfachredeneben redhat hackernews red reddit - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT health - medical burnout cannabis medicine treatment EmotionalFirstAid maryjane autistic health meds marijuana + medical burnout cannabis medicine treatment EmotionalFirstAid maryjane autistic neurodivergent health meds marijuana mentalhealth - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + facts + funfact didyouknow lifehack + + Sun, 10 Jan 2021 20:09:37 UT + + + ai + machinelearning + + Sun, 10 Jan 2021 20:09:37 UT seasons spring autumn winter summer solstice wintersolstice - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT gender - transwomen transcrowdfund womensart female nonbinary trans transphobia women estradiol queer genderQuiz woman transrights + transwomen transcrowdfund womensart female nonbinary trans transpositivity transphobia women estradiol queer genderQuiz genderqueerpositivity woman transrights - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + philosophy + minimalism maximalist maximalism stoic postmodernism minimalist + + Sun, 10 Jan 2021 20:09:37 UT history history anarchisthistory - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT fiction - cyberpunk thehobbit fiction microfiction genrefiction + cyberpunk thehobbit fiction genrefiction - Tue, 29 Dec 2020 20:59:38 UT - - - legal - hfgkarlsruhe amro GameSphere OnlineHarmsBill laipower gdpr intros Anticritique learning energyflow digitalservicesact geekproblem dmca - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT introductions newhere firsttoot recommends Introduction Introductions introduction intro introductions - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT audio - audioproduction audiofeedback audio + audioproduction audi audiofeedback audio - Tue, 29 Dec 2020 20:59:38 UT - - - bots - bot - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT scifi - startrek starwars babylon5 + startrekdiscovery startrek starwars babylon5 - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + bots + bot humanrobotinteraction + + Sun, 10 Jan 2021 20:09:37 UT religion neopagan pagan catholic - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + help + mastohelp helpful help + + Sun, 10 Jan 2021 20:09:37 UT + + + obituaries + rip + + Sun, 10 Jan 2021 20:09:37 UT astronomy amateurastronomy astronomy space jupiter BackYardAstronomy moon saturn milkyway - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT photography landscapephotography - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + privacy + privacypolicy surveillancetech privacymatters surveillance dataprivacy privacy WhatsappPrivacy + + Sun, 10 Jan 2021 20:09:37 UT moderation fedblock - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT languages lojban gaelic - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT + + + environment + s climatechaos + + Sun, 10 Jan 2021 20:09:37 UT election voted vote - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT #music trance - Tue, 29 Dec 2020 20:59:38 UT - - - facts - didyouknow lifehack - - Tue, 29 Dec 2020 20:59:38 UT - - - radio - radiohost vantascape vantaradio ca radio healthcare listening hamradio FreeAllPoliticalPrisoners card10 radiobroadcasting 3dcad radioshow local california listeningtonow radiobroadcast spazradio anonradio io - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT licenses - copyright creative common creativecommons + copyright creative creativetoots common creativecommons - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT education education teach tutorial - Tue, 29 Dec 2020 20:59:38 UT - - - privacy - surveillancetech privacymatters surveillance dataprivacy privacy - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT microcontroller microcontroller arduino - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT people monbiot aldoushuxley relationships AskVanta - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT scotland glasgow highlands edinburgh loch - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT entertainment - watching Thundercat thisisthetypeofmemethatilikecauseitcontainsreptiles entertainment me meow un themandalorian + watching Thundercat thisisthetypeofmemethatilikecauseitcontainsreptiles entertainment me meow un nowwatching themandalorian - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT #software flatpak - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT microcontrollers esp8266 esp32 - Tue, 29 Dec 2020 20:59:38 UT - - - help - helpful help - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT war weapons - Tue, 29 Dec 2020 20:59:38 UT - - - philosophy - stoic postmodernism - - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT france Macronavirus - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT travel travel taxi - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT - environment - climatechaos + architecture + concrete - Tue, 29 Dec 2020 20:59:38 UT + Sun, 10 Jan 2021 20:09:37 UT From c4d4dc5d6366a80aea70233735508afe216afc4c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 21:38:28 +0000 Subject: [PATCH 28/65] Option to show followers of an actor --- epicyon.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ webapp_utils.py | 31 +++++++++++++ 2 files changed, 151 insertions(+) diff --git a/epicyon.py b/epicyon.py index f485ea410..5c17cf26a 100644 --- a/epicyon.py +++ b/epicyon.py @@ -75,6 +75,7 @@ from announce import sendAnnounceViaServer from socnet import instancesGraph from migrate import migrateAccounts import argparse +from webapp_utils import downloadFollowersCollection def str2bool(v) -> bool: @@ -157,6 +158,10 @@ parser.add_argument('--maxFollowers', default=2000, help='Maximum number of followers per account. ' + 'Zero for no limit.') +parser.add_argument('--followers', + dest='followers', type=str, + default='', + help='Show list of followers for the given actor') parser.add_argument('--postcache', dest='maxRecentPosts', type=int, default=512, help='The maximum number of recent posts to store in RAM') @@ -1464,6 +1469,121 @@ if args.actor: print('Failed to get ' + personUrl) sys.exit() +if args.followers: + originalActor = args.followers + if '/@' in args.followers or \ + '/users/' in args.followers or \ + args.followers.startswith('http') or \ + args.followers.startswith('dat'): + # format: https://domain/@nick + prefixes = getProtocolPrefixes() + for prefix in prefixes: + args.followers = args.followers.replace(prefix, '') + args.followers = args.followers.replace('/@', '/users/') + if not hasUsersPath(args.followers): + print('Expected actor format: ' + + 'https://domain/@nick or https://domain/users/nick') + sys.exit() + if '/users/' in args.followers: + nickname = args.followers.split('/users/')[1] + nickname = nickname.replace('\n', '').replace('\r', '') + domain = args.followers.split('/users/')[0] + elif '/profile/' in args.followers: + nickname = args.followers.split('/profile/')[1] + nickname = nickname.replace('\n', '').replace('\r', '') + domain = args.followers.split('/profile/')[0] + elif '/channel/' in args.followers: + nickname = args.followers.split('/channel/')[1] + nickname = nickname.replace('\n', '').replace('\r', '') + domain = args.followers.split('/channel/')[0] + elif '/accounts/' in args.followers: + nickname = args.followers.split('/accounts/')[1] + nickname = nickname.replace('\n', '').replace('\r', '') + domain = args.followers.split('/accounts/')[0] + else: + # format: @nick@domain + if '@' not in args.followers: + print('Syntax: --actor nickname@domain') + sys.exit() + if args.followers.startswith('@'): + args.followers = args.followers[1:] + if '@' not in args.followers: + print('Syntax: --actor nickname@domain') + sys.exit() + nickname = args.followers.split('@')[0] + domain = args.followers.split('@')[1] + domain = domain.replace('\n', '').replace('\r', '') + cachedWebfingers = {} + if args.http or domain.endswith('.onion'): + httpPrefix = 'http' + port = 80 + proxyType = 'tor' + elif domain.endswith('.i2p'): + httpPrefix = 'http' + port = 80 + proxyType = 'i2p' + elif args.gnunet: + httpPrefix = 'gnunet' + port = 80 + proxyType = 'gnunet' + else: + httpPrefix = 'https' + port = 443 + session = createSession(proxyType) + if nickname == 'inbox': + nickname = domain + + handle = nickname + '@' + domain + wfRequest = webfingerHandle(session, handle, + httpPrefix, cachedWebfingers, + None, __version__) + if not wfRequest: + print('Unable to webfinger ' + handle) + sys.exit() + if not isinstance(wfRequest, dict): + print('Webfinger for ' + handle + ' did not return a dict. ' + + str(wfRequest)) + sys.exit() + + personUrl = None + if wfRequest.get('errors'): + print('wfRequest error: ' + str(wfRequest['errors'])) + if hasUsersPath(args.followers): + personUrl = originalActor + else: + sys.exit() + + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/activity+json; profile="' + profileStr + '"' + } + if not personUrl: + personUrl = getUserUrl(wfRequest) + if nickname == domain: + personUrl = personUrl.replace('/users/', '/actor/') + personUrl = personUrl.replace('/accounts/', '/actor/') + personUrl = personUrl.replace('/channel/', '/actor/') + personUrl = personUrl.replace('/profile/', '/actor/') + if not personUrl: + # try single user instance + personUrl = httpPrefix + '://' + domain + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/ld+json; profile="' + profileStr + '"' + } + if '/channel/' in personUrl or '/accounts/' in personUrl: + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/ld+json; profile="' + profileStr + '"' + } + + followersList = \ + downloadFollowersCollection(session, httpPrefix, personUrl, 1, 3) + if followersList: + for actor in followersList: + print(actor) + sys.exit() + if args.addaccount: if '@' in args.addaccount: nickname = args.addaccount.split('@')[0] diff --git a/webapp_utils.py b/webapp_utils.py index 02e30a78f..d53e0ebd8 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -868,3 +868,34 @@ def getAvatarImageUrl(session, avatarUrl = postActor + '/avatar.png' return avatarUrl + + +def downloadFollowersCollection(session, httpPrefix, + actor: str, pageNumber=1, + noOfPages=1) -> []: + """Returns a list of followers for the given actor + by downloading the json for their followers collection + """ + prof = 'https://www.w3.org/ns/activitystreams' + if '/channel/' not in actor or '/accounts/' not in actor: + sessionHeaders = { + 'Accept': 'application/activity+json; profile="' + prof + '"' + } + else: + sessionHeaders = { + 'Accept': 'application/ld+json; profile="' + prof + '"' + } + result = [] + for pageCtr in range(noOfPages): + followersJson = \ + getJson(session, actor + '/followers?page=' + + str(pageNumber + pageCtr), + sessionHeaders, None, __version__, httpPrefix, None) + if followersJson: + if followersJson.get('orderedItems'): + result += followersJson['orderedItems'] + else: + break + else: + break + return result From de94fdc1f15155c35fff233f790655392f774874 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 21:57:53 +0000 Subject: [PATCH 29/65] Move function --- epicyon.py | 2 +- posts.py | 31 +++++++++++++++++++++++++++++++ webapp_utils.py | 31 ------------------------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/epicyon.py b/epicyon.py index 5c17cf26a..eae3b83c1 100644 --- a/epicyon.py +++ b/epicyon.py @@ -15,6 +15,7 @@ from person import deactivateAccount from skills import setSkillLevel from roles import setRole from webfinger import webfingerHandle +from posts import downloadFollowersCollection from posts import getPublicPostDomains from posts import getPublicPostDomainsBlocked from posts import sendBlockViaServer @@ -75,7 +76,6 @@ from announce import sendAnnounceViaServer from socnet import instancesGraph from migrate import migrateAccounts import argparse -from webapp_utils import downloadFollowersCollection def str2bool(v) -> bool: diff --git a/posts.py b/posts.py index 53d115d26..f9995bef3 100644 --- a/posts.py +++ b/posts.py @@ -3376,6 +3376,37 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, return postDomains +def downloadFollowersCollection(session, httpPrefix, + actor: str, pageNumber=1, + noOfPages=1) -> []: + """Returns a list of followers for the given actor + by downloading the json for their followers collection + """ + prof = 'https://www.w3.org/ns/activitystreams' + if '/channel/' not in actor or '/accounts/' not in actor: + sessionHeaders = { + 'Accept': 'application/activity+json; profile="' + prof + '"' + } + else: + sessionHeaders = { + 'Accept': 'application/ld+json; profile="' + prof + '"' + } + result = [] + for pageCtr in range(noOfPages): + followersJson = \ + getJson(session, actor + '/followers?page=' + + str(pageNumber + pageCtr), + sessionHeaders, None, __version__, httpPrefix, None) + if followersJson: + if followersJson.get('orderedItems'): + result += followersJson['orderedItems'] + else: + break + else: + break + return result + + def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, debug: bool, projectVersion: str) -> []: diff --git a/webapp_utils.py b/webapp_utils.py index d53e0ebd8..02e30a78f 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -868,34 +868,3 @@ def getAvatarImageUrl(session, avatarUrl = postActor + '/avatar.png' return avatarUrl - - -def downloadFollowersCollection(session, httpPrefix, - actor: str, pageNumber=1, - noOfPages=1) -> []: - """Returns a list of followers for the given actor - by downloading the json for their followers collection - """ - prof = 'https://www.w3.org/ns/activitystreams' - if '/channel/' not in actor or '/accounts/' not in actor: - sessionHeaders = { - 'Accept': 'application/activity+json; profile="' + prof + '"' - } - else: - sessionHeaders = { - 'Accept': 'application/ld+json; profile="' + prof + '"' - } - result = [] - for pageCtr in range(noOfPages): - followersJson = \ - getJson(session, actor + '/followers?page=' + - str(pageNumber + pageCtr), - sessionHeaders, None, __version__, httpPrefix, None) - if followersJson: - if followersJson.get('orderedItems'): - result += followersJson['orderedItems'] - else: - break - else: - break - return result From 926f387b93e96ccb7ebed2271572a4a826488916 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 23:06:38 +0000 Subject: [PATCH 30/65] Show blocked followers in account info --- posts.py | 6 +++--- translations/ar.json | 3 ++- translations/ca.json | 3 ++- translations/cy.json | 3 ++- translations/de.json | 3 ++- translations/en.json | 3 ++- translations/es.json | 3 ++- translations/fr.json | 3 ++- translations/ga.json | 3 ++- translations/hi.json | 3 ++- translations/it.json | 3 ++- translations/ja.json | 3 ++- translations/oc.json | 3 ++- translations/pt.json | 3 ++- translations/ru.json | 3 ++- translations/zh.json | 3 ++- webapp_moderation.py | 50 +++++++++++++++++++++++++++++++++++--------- 17 files changed, 73 insertions(+), 28 deletions(-) diff --git a/posts.py b/posts.py index f9995bef3..a2bbba8dc 100644 --- a/posts.py +++ b/posts.py @@ -3393,10 +3393,10 @@ def downloadFollowersCollection(session, httpPrefix, } result = [] for pageCtr in range(noOfPages): + url = actor + '/followers?page=' + str(pageNumber + pageCtr) followersJson = \ - getJson(session, actor + '/followers?page=' + - str(pageNumber + pageCtr), - sessionHeaders, None, __version__, httpPrefix, None) + getJson(session, url, sessionHeaders, None, __version__, + httpPrefix, None) if followersJson: if followersJson.get('orderedItems'): result += followersJson['orderedItems'] diff --git a/translations/ar.json b/translations/ar.json index 658be63fe..a7118b656 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -351,5 +351,6 @@ "Peertube Instances": "مثيلات Peertube", "Show video previews for the following Peertube sites.": "إظهار معاينات الفيديو لمواقع Peertube التالية.", "Follows you": "يتبعك", - "Verify all signatures": "تحقق من جميع التوقيعات" + "Verify all signatures": "تحقق من جميع التوقيعات", + "Blocked followers": "المتابعون المحظورون" } diff --git a/translations/ca.json b/translations/ca.json index 06ea47e6d..1644b9298 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -351,5 +351,6 @@ "Peertube Instances": "Instàncies de Peertube", "Show video previews for the following Peertube sites.": "Mostra les previsualitzacions de vídeo dels següents llocs de Peertube.", "Follows you": "Et segueix", - "Verify all signatures": "Verifiqueu totes les signatures" + "Verify all signatures": "Verifiqueu totes les signatures", + "Blocked followers": "Seguidors bloquejats" } diff --git a/translations/cy.json b/translations/cy.json index a610b167a..8f5ed3655 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -351,5 +351,6 @@ "Peertube Instances": "Camau Peertube", "Show video previews for the following Peertube sites.": "Dangos rhagolygon fideo ar gyfer y safleoedd Peertube canlynol.", "Follows you": "Yn eich dilyn chi", - "Verify all signatures": "Gwirio pob llofnod" + "Verify all signatures": "Gwirio pob llofnod", + "Blocked followers": "Dilynwyr wedi'u blocio" } diff --git a/translations/de.json b/translations/de.json index cdf9aaefa..617f3fe30 100644 --- a/translations/de.json +++ b/translations/de.json @@ -351,5 +351,6 @@ "Peertube Instances": "Peertube-Instanzen", "Show video previews for the following Peertube sites.": "Zeigen Sie eine Videovorschau für die folgenden Peertube-Websites an.", "Follows you": "Folgt dir", - "Verify all signatures": "Überprüfen Sie alle Signaturen" + "Verify all signatures": "Überprüfen Sie alle Signaturen", + "Blocked followers": "Blockierte Follower" } diff --git a/translations/en.json b/translations/en.json index 40537ba17..5c881a9f5 100644 --- a/translations/en.json +++ b/translations/en.json @@ -351,5 +351,6 @@ "Peertube Instances": "Peertube Instances", "Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites.", "Follows you": "Follows you", - "Verify all signatures": "Verify all signatures" + "Verify all signatures": "Verify all signatures", + "Blocked followers": "Blocked followers" } diff --git a/translations/es.json b/translations/es.json index f63b2d4ea..ae2226f2b 100644 --- a/translations/es.json +++ b/translations/es.json @@ -351,5 +351,6 @@ "Peertube Instances": "Instancias de Peertube", "Show video previews for the following Peertube sites.": "Muestre vistas previas de video para los siguientes sitios de Peertube.", "Follows you": "Te sigue", - "Verify all signatures": "Verificar todas las firmas" + "Verify all signatures": "Verificar todas las firmas", + "Blocked followers": "Seguidores bloqueadas" } diff --git a/translations/fr.json b/translations/fr.json index 1ae6dc989..ee0f201b1 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -351,5 +351,6 @@ "Peertube Instances": "Instances Peertube", "Show video previews for the following Peertube sites.": "Afficher des aperçus vidéo pour les sites Peertube suivants.", "Follows you": "Vous suit", - "Verify all signatures": "Vérifier toutes les signatures" + "Verify all signatures": "Vérifier toutes les signatures", + "Blocked followers": "Abonnés bloqués" } diff --git a/translations/ga.json b/translations/ga.json index ef2f77fef..5f4910914 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -351,5 +351,6 @@ "Peertube Instances": "Imeachtaí Peertube", "Show video previews for the following Peertube sites.": "Taispeáin réamhamharcanna físe do na suíomhanna Peertube seo a leanas.", "Follows you": "Leanann tú", - "Verify all signatures": "Fíoraigh gach síniú" + "Verify all signatures": "Fíoraigh gach síniú", + "Blocked followers": "Leanúna blocáilte" } diff --git a/translations/hi.json b/translations/hi.json index 232cb54c2..833936d41 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -351,5 +351,6 @@ "Peertube Instances": "Peertube उदाहरण", "Show video previews for the following Peertube sites.": "निम्नलिखित Peertube साइटों के लिए वीडियो पूर्वावलोकन दिखाएं।", "Follows you": "आपका पीछा करता है", - "Verify all signatures": "सभी हस्ताक्षर सत्यापित करें" + "Verify all signatures": "सभी हस्ताक्षर सत्यापित करें", + "Blocked followers": "अवरुद्ध अनुयायियों" } diff --git a/translations/it.json b/translations/it.json index 1ad7efef6..738506da0 100644 --- a/translations/it.json +++ b/translations/it.json @@ -351,5 +351,6 @@ "Peertube Instances": "Istanze di Peertube", "Show video previews for the following Peertube sites.": "Mostra le anteprime dei video per i seguenti siti Peertube.", "Follows you": "Ti segue", - "Verify all signatures": "Verifica tutte le firme" + "Verify all signatures": "Verifica tutte le firme", + "Blocked followers": "Follower bloccati" } diff --git a/translations/ja.json b/translations/ja.json index 7606a7aff..435ad87e2 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -351,5 +351,6 @@ "Peertube Instances": "Peertubeインスタンス", "Show video previews for the following Peertube sites.": "次のPeertubeサイトのビデオプレビューを表示します。", "Follows you": "あなたについていきます", - "Verify all signatures": "すべての署名を確認する" + "Verify all signatures": "すべての署名を確認する", + "Blocked followers": "ブロックされたフォロワー" } diff --git a/translations/oc.json b/translations/oc.json index 07b9569c6..7daebb706 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -347,5 +347,6 @@ "Peertube Instances": "Peertube Instances", "Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites.", "Follows you": "Follows you", - "Verify all signatures": "Verify all signatures" + "Verify all signatures": "Verify all signatures", + "Blocked followers": "Blocked followers" } diff --git a/translations/pt.json b/translations/pt.json index 183b73d09..c18849d25 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -351,5 +351,6 @@ "Peertube Instances": "Instâncias Peertube", "Show video previews for the following Peertube sites.": "Mostrar visualizações de vídeo para os seguintes sites Peertube.", "Follows you": "Segue você", - "Verify all signatures": "Verifique todas as assinaturas" + "Verify all signatures": "Verifique todas as assinaturas", + "Blocked followers": "Seguidores bloqueados" } diff --git a/translations/ru.json b/translations/ru.json index 147a699a8..2380e6191 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -351,5 +351,6 @@ "Peertube Instances": "Экземпляры Peertube", "Show video previews for the following Peertube sites.": "Показать превью видео для следующих сайтов Peertube.", "Follows you": "Следует за вами", - "Verify all signatures": "Проверить все подписи" + "Verify all signatures": "Проверить все подписи", + "Blocked followers": "Заблокированные подписчики" } diff --git a/translations/zh.json b/translations/zh.json index 23a46718d..c6d5af6c9 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -351,5 +351,6 @@ "Peertube Instances": "Peertube实例", "Show video previews for the following Peertube sites.": "显示以下Peertube网站的视频预览。", "Follows you": "跟着你", - "Verify all signatures": "验证所有签名" + "Verify all signatures": "验证所有签名", + "Blocked followers": "被封锁的追随者" } diff --git a/webapp_moderation.py b/webapp_moderation.py index c18e5163d..34b2c631b 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -7,10 +7,12 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import getFullDomain from utils import isEditor from utils import loadJson from utils import getNicknameFromActor from utils import getDomainFromActor +from posts import downloadFollowersCollection from posts import getPublicPostInfo from posts import isModerator from webapp_timeline import htmlTimeline @@ -19,6 +21,8 @@ from webapp_utils import getContentWarningButton from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from blocking import isBlockedDomain +from blocking import isBlocked +from session import createSession def htmlModeration(cssCache: {}, defaultTimeline: str, @@ -76,25 +80,42 @@ def htmlAccountInfo(cssCache: {}, translate: {}, searchDomain, searchPort = getDomainFromActor(searchHandle) searchHandle = searchNickname + '@' + searchDomain + searchActor = \ + httpPrefix + '://' + searchDomain + '/users/' + searchNickname infoForm += \ '

' + \ - translate['Account Information'] + ': ' + searchHandle + '


' + translate['Account Information'] + ': ' + searchHandle + '
\n' - infoForm += translate[msgStr1] + '


' + infoForm += translate[msgStr1] + '

\n' proxyType = 'tor' if not os.path.isfile('/usr/bin/tor'): proxyType = None if domain.endswith('.i2p'): proxyType = None - domainDict = getPublicPostInfo(None, + + session = createSession(proxyType) + + domainDict = getPublicPostInfo(session, baseDir, searchNickname, searchDomain, proxyType, searchPort, httpPrefix, debug, __version__) - infoForm += '
' + + # get a list of any blocked followers + followersList = \ + downloadFollowersCollection(session, httpPrefix, searchActor, 1, 5) + blockedFollowers = [] + for followerActor in followersList: + followerNickname = getNicknameFromActor(followerActor) + followerDomain, followerPort = getDomainFromActor(followerActor) + followerDomainFull = getFullDomain(followerDomain, followerPort) + if isBlocked(baseDir, nickname, domain, + followerNickname, followerDomainFull): + blockedFollowers.append(followerActor) + + infoForm += '
\n' usersPath = '/users/' + nickname + '/accountinfo' ctr = 1 for postDomain, blockedPostUrls in domainDict.items(): @@ -122,7 +143,7 @@ def htmlAccountInfo(cssCache: {}, translate: {}, '?handle=' + searchHandle + '">' infoForm += ' ' + \ - blockedPostsHtml + blockedPostsHtml + '\n' else: infoForm += \ '' + \ translate['Block'] + '' - infoForm += '' - infoForm += '
' + infoForm += '\n' + infoForm += '
\n' + + infoForm += '
\n' + + if blockedFollowers: + blockedFollowers.sort() + infoForm += '
\n' + infoForm += '

' + translate['Blocked followers'] + '

\n' + for actor in blockedFollowers: + infoForm += '' + actor + '
\n' + infoForm += '
\n' - infoForm += '
' infoForm += htmlFooter() return infoForm From 300c192fd5372369780f134ae423d2fa390dd19a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 23:11:32 +0000 Subject: [PATCH 31/65] Extra vertical space --- webapp_moderation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_moderation.py b/webapp_moderation.py index 34b2c631b..2dfed40c5 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -161,7 +161,7 @@ def htmlAccountInfo(cssCache: {}, translate: {}, infoForm += '
\n' infoForm += '

' + translate['Blocked followers'] + '

\n' for actor in blockedFollowers: - infoForm += '' + actor + '
\n' + infoForm += '' + actor + '

\n' infoForm += '
\n' infoForm += htmlFooter() From 31359313de895659632e13841319137b8ede0a17 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 23:16:10 +0000 Subject: [PATCH 32/65] Show handle rather than actor --- webapp_moderation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/webapp_moderation.py b/webapp_moderation.py index 2dfed40c5..12c72f8f2 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -161,7 +161,11 @@ def htmlAccountInfo(cssCache: {}, translate: {}, infoForm += '
\n' infoForm += '

' + translate['Blocked followers'] + '

\n' for actor in blockedFollowers: - infoForm += '' + actor + '

\n' + followerNickname = getNicknameFromActor(actor) + followerDomain, followerPort = getDomainFromActor(actor) + followerDomainFull = getFullDomain(followerDomain, followerPort) + infoForm += '' + \ + followerNickname + '@' + followerDomainFull + '

\n' infoForm += '
\n' infoForm += htmlFooter() From bf22aeb7b4a6070679096f3c63c4bc1865c8eb5a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 23:17:29 +0000 Subject: [PATCH 33/65] Sequence --- webapp_moderation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_moderation.py b/webapp_moderation.py index 12c72f8f2..5c7e6853a 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -158,8 +158,8 @@ def htmlAccountInfo(cssCache: {}, translate: {}, if blockedFollowers: blockedFollowers.sort() - infoForm += '
\n' infoForm += '

' + translate['Blocked followers'] + '

\n' + infoForm += '
\n' for actor in blockedFollowers: followerNickname = getNicknameFromActor(actor) followerDomain, followerPort = getDomainFromActor(actor) From 19b5ab8b99999d77adba9fb5805335b51da6daf5 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 23:19:06 +0000 Subject: [PATCH 34/65] Sequence --- webapp_moderation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_moderation.py b/webapp_moderation.py index 5c7e6853a..12c72f8f2 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -158,8 +158,8 @@ def htmlAccountInfo(cssCache: {}, translate: {}, if blockedFollowers: blockedFollowers.sort() - infoForm += '

' + translate['Blocked followers'] + '

\n' infoForm += '
\n' + infoForm += '

' + translate['Blocked followers'] + '

\n' for actor in blockedFollowers: followerNickname = getNicknameFromActor(actor) followerDomain, followerPort = getDomainFromActor(actor) From a19a318f9fe00d422816a13ae28752fa78b6407b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Sun, 10 Jan 2021 23:29:03 +0000 Subject: [PATCH 35/65] Deduplicate --- posts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/posts.py b/posts.py index a2bbba8dc..10fa3e316 100644 --- a/posts.py +++ b/posts.py @@ -3399,7 +3399,9 @@ def downloadFollowersCollection(session, httpPrefix, httpPrefix, None) if followersJson: if followersJson.get('orderedItems'): - result += followersJson['orderedItems'] + for followerActor in followersJson['orderedItems']: + if followerActor not in result: + result.append(followerActor) else: break else: From 80587cf83b4857a99fc3ff2c201fa591aadbca23 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 10:08:05 +0000 Subject: [PATCH 36/65] Also show blocked following on account info --- epicyon.py | 5 +++-- posts.py | 13 +++++++------ translations/ar.json | 5 ++++- translations/ca.json | 5 ++++- translations/cy.json | 5 ++++- translations/de.json | 5 ++++- translations/en.json | 5 ++++- translations/es.json | 5 ++++- translations/fr.json | 5 ++++- translations/ga.json | 5 ++++- translations/hi.json | 5 ++++- translations/it.json | 5 ++++- translations/ja.json | 5 ++++- translations/oc.json | 5 ++++- translations/pt.json | 5 ++++- translations/ru.json | 5 ++++- translations/zh.json | 5 ++++- webapp_moderation.py | 40 ++++++++++++++++++++++++++++++++++++++-- 18 files changed, 108 insertions(+), 25 deletions(-) diff --git a/epicyon.py b/epicyon.py index eae3b83c1..47c85c493 100644 --- a/epicyon.py +++ b/epicyon.py @@ -15,7 +15,7 @@ from person import deactivateAccount from skills import setSkillLevel from roles import setRole from webfinger import webfingerHandle -from posts import downloadFollowersCollection +from posts import downloadFollowCollection from posts import getPublicPostDomains from posts import getPublicPostDomainsBlocked from posts import sendBlockViaServer @@ -1578,7 +1578,8 @@ if args.followers: } followersList = \ - downloadFollowersCollection(session, httpPrefix, personUrl, 1, 3) + downloadFollowCollection('followers', session, + httpPrefix, personUrl, 1, 3) if followersList: for actor in followersList: print(actor) diff --git a/posts.py b/posts.py index 10fa3e316..c775ce784 100644 --- a/posts.py +++ b/posts.py @@ -3376,11 +3376,12 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, return postDomains -def downloadFollowersCollection(session, httpPrefix, - actor: str, pageNumber=1, - noOfPages=1) -> []: - """Returns a list of followers for the given actor - by downloading the json for their followers collection +def downloadFollowCollection(followType: str, + session, httpPrefix, + actor: str, pageNumber=1, + noOfPages=1) -> []: + """Returns a list of following/followers for the given actor + by downloading the json for their following/followers collection """ prof = 'https://www.w3.org/ns/activitystreams' if '/channel/' not in actor or '/accounts/' not in actor: @@ -3393,7 +3394,7 @@ def downloadFollowersCollection(session, httpPrefix, } result = [] for pageCtr in range(noOfPages): - url = actor + '/followers?page=' + str(pageNumber + pageCtr) + url = actor + '/' + followType + '?page=' + str(pageNumber + pageCtr) followersJson = \ getJson(session, url, sessionHeaders, None, __version__, httpPrefix, None) diff --git a/translations/ar.json b/translations/ar.json index a7118b656..910b893ff 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "إظهار معاينات الفيديو لمواقع Peertube التالية.", "Follows you": "يتبعك", "Verify all signatures": "تحقق من جميع التوقيعات", - "Blocked followers": "المتابعون المحظورون" + "Blocked followers": "المتابعون المحظورون", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/ca.json b/translations/ca.json index 1644b9298..223325d3a 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Mostra les previsualitzacions de vídeo dels següents llocs de Peertube.", "Follows you": "Et segueix", "Verify all signatures": "Verifiqueu totes les signatures", - "Blocked followers": "Seguidors bloquejats" + "Blocked followers": "Seguidors bloquejats", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/cy.json b/translations/cy.json index 8f5ed3655..8a286a9a8 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Dangos rhagolygon fideo ar gyfer y safleoedd Peertube canlynol.", "Follows you": "Yn eich dilyn chi", "Verify all signatures": "Gwirio pob llofnod", - "Blocked followers": "Dilynwyr wedi'u blocio" + "Blocked followers": "Dilynwyr wedi'u blocio", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/de.json b/translations/de.json index 617f3fe30..4c3043758 100644 --- a/translations/de.json +++ b/translations/de.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Zeigen Sie eine Videovorschau für die folgenden Peertube-Websites an.", "Follows you": "Folgt dir", "Verify all signatures": "Überprüfen Sie alle Signaturen", - "Blocked followers": "Blockierte Follower" + "Blocked followers": "Blockierte Follower", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/en.json b/translations/en.json index 5c881a9f5..07c7fd653 100644 --- a/translations/en.json +++ b/translations/en.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites.", "Follows you": "Follows you", "Verify all signatures": "Verify all signatures", - "Blocked followers": "Blocked followers" + "Blocked followers": "Blocked followers", + "Blocked following": "Blocked following", + "Receives posts from the following accounts": "Receives posts from the following accounts", + "Sends out posts to the following accounts": "Sends out posts to the following accounts" } diff --git a/translations/es.json b/translations/es.json index ae2226f2b..104c3dad4 100644 --- a/translations/es.json +++ b/translations/es.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Muestre vistas previas de video para los siguientes sitios de Peertube.", "Follows you": "Te sigue", "Verify all signatures": "Verificar todas las firmas", - "Blocked followers": "Seguidores bloqueadas" + "Blocked followers": "Seguidores bloqueadas", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/fr.json b/translations/fr.json index ee0f201b1..46de63b12 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Afficher des aperçus vidéo pour les sites Peertube suivants.", "Follows you": "Vous suit", "Verify all signatures": "Vérifier toutes les signatures", - "Blocked followers": "Abonnés bloqués" + "Blocked followers": "Abonnés bloqués", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/ga.json b/translations/ga.json index 5f4910914..916f045f1 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Taispeáin réamhamharcanna físe do na suíomhanna Peertube seo a leanas.", "Follows you": "Leanann tú", "Verify all signatures": "Fíoraigh gach síniú", - "Blocked followers": "Leanúna blocáilte" + "Blocked followers": "Leanúna blocáilte", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/hi.json b/translations/hi.json index 833936d41..4d423fea3 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "निम्नलिखित Peertube साइटों के लिए वीडियो पूर्वावलोकन दिखाएं।", "Follows you": "आपका पीछा करता है", "Verify all signatures": "सभी हस्ताक्षर सत्यापित करें", - "Blocked followers": "अवरुद्ध अनुयायियों" + "Blocked followers": "अवरुद्ध अनुयायियों", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/it.json b/translations/it.json index 738506da0..2b5c6cd0f 100644 --- a/translations/it.json +++ b/translations/it.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Mostra le anteprime dei video per i seguenti siti Peertube.", "Follows you": "Ti segue", "Verify all signatures": "Verifica tutte le firme", - "Blocked followers": "Follower bloccati" + "Blocked followers": "Follower bloccati", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/ja.json b/translations/ja.json index 435ad87e2..ecefa5da1 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "次のPeertubeサイトのビデオプレビューを表示します。", "Follows you": "あなたについていきます", "Verify all signatures": "すべての署名を確認する", - "Blocked followers": "ブロックされたフォロワー" + "Blocked followers": "ブロックされたフォロワー", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/oc.json b/translations/oc.json index 7daebb706..87b99583a 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -348,5 +348,8 @@ "Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites.", "Follows you": "Follows you", "Verify all signatures": "Verify all signatures", - "Blocked followers": "Blocked followers" + "Blocked followers": "Blocked followers", + "Blocked following": "Blocked following", + "Receives posts from the following accounts": "Receives posts from the following accounts", + "Sends out posts to the following accounts": "Sends out posts to the following accounts" } diff --git a/translations/pt.json b/translations/pt.json index c18849d25..9e1506482 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Mostrar visualizações de vídeo para os seguintes sites Peertube.", "Follows you": "Segue você", "Verify all signatures": "Verifique todas as assinaturas", - "Blocked followers": "Seguidores bloqueados" + "Blocked followers": "Seguidores bloqueados", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/ru.json b/translations/ru.json index 2380e6191..ded92510f 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "Показать превью видео для следующих сайтов Peertube.", "Follows you": "Следует за вами", "Verify all signatures": "Проверить все подписи", - "Blocked followers": "Заблокированные подписчики" + "Blocked followers": "Заблокированные подписчики", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/translations/zh.json b/translations/zh.json index c6d5af6c9..4dbfb6dcc 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -352,5 +352,8 @@ "Show video previews for the following Peertube sites.": "显示以下Peertube网站的视频预览。", "Follows you": "跟着你", "Verify all signatures": "验证所有签名", - "Blocked followers": "被封锁的追随者" + "Blocked followers": "被封锁的追随者", + "Blocked following": "", + "Receives posts from the following accounts": "", + "Sends out posts to the following accounts": "" } diff --git a/webapp_moderation.py b/webapp_moderation.py index 12c72f8f2..f3d17db09 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -12,7 +12,7 @@ from utils import isEditor from utils import loadJson from utils import getNicknameFromActor from utils import getDomainFromActor -from posts import downloadFollowersCollection +from posts import downloadFollowCollection from posts import getPublicPostInfo from posts import isModerator from webapp_timeline import htmlTimeline @@ -105,7 +105,8 @@ def htmlAccountInfo(cssCache: {}, translate: {}, # get a list of any blocked followers followersList = \ - downloadFollowersCollection(session, httpPrefix, searchActor, 1, 5) + downloadFollowCollection('followers', session, + httpPrefix, searchActor, 1, 5) blockedFollowers = [] for followerActor in followersList: followerNickname = getNicknameFromActor(followerActor) @@ -115,6 +116,19 @@ def htmlAccountInfo(cssCache: {}, translate: {}, followerNickname, followerDomainFull): blockedFollowers.append(followerActor) + # get a list of any blocked following + followingList = \ + downloadFollowCollection('following', session, + httpPrefix, searchActor, 1, 5) + blockedFollowing = [] + for followingActor in followingList: + followingNickname = getNicknameFromActor(followingActor) + followingDomain, followingPort = getDomainFromActor(followingActor) + followingDomainFull = getFullDomain(followingDomain, followingPort) + if isBlocked(baseDir, nickname, domain, + followingNickname, followingDomainFull): + blockedFollowing.append(followingActor) + infoForm += '
\n' usersPath = '/users/' + nickname + '/accountinfo' ctr = 1 @@ -156,10 +170,32 @@ def htmlAccountInfo(cssCache: {}, translate: {}, infoForm += '
\n' + if blockedFollowing: + blockedFollowing.sort() + infoForm += '
\n' + infoForm += '

' + translate['Blocked following'] + '

\n' + infoForm += \ + '

' + \ + translate['Receives posts from the following accounts'] + \ + '

\n' + for actor in blockedFollowing: + followingNickname = getNicknameFromActor(actor) + followingDomain, followingPort = getDomainFromActor(actor) + followingDomainFull = \ + getFullDomain(followingDomain, followingPort) + infoForm += '' + \ + followingNickname + '@' + followingDomainFull + \ + '

\n' + infoForm += '
\n' + if blockedFollowers: blockedFollowers.sort() infoForm += '
\n' infoForm += '

' + translate['Blocked followers'] + '

\n' + infoForm += \ + '

' + \ + translate['Sends out posts to the following accounts'] + \ + '

\n' for actor in blockedFollowers: followerNickname = getNicknameFromActor(actor) followerDomain, followerPort = getDomainFromActor(actor) From 914160ef05bb1059b1ee2b23f55b357364e1a348 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 10:38:10 +0000 Subject: [PATCH 37/65] Translations --- translations/ar.json | 6 +++--- translations/ca.json | 6 +++--- translations/cy.json | 6 +++--- translations/de.json | 6 +++--- translations/es.json | 6 +++--- translations/fr.json | 6 +++--- translations/ga.json | 6 +++--- translations/hi.json | 6 +++--- translations/it.json | 6 +++--- translations/ja.json | 6 +++--- translations/pt.json | 6 +++--- translations/ru.json | 6 +++--- translations/zh.json | 6 +++--- 13 files changed, 39 insertions(+), 39 deletions(-) diff --git a/translations/ar.json b/translations/ar.json index 910b893ff..44a842f4a 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -353,7 +353,7 @@ "Follows you": "يتبعك", "Verify all signatures": "تحقق من جميع التوقيعات", "Blocked followers": "المتابعون المحظورون", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "المتابعة المحظورة", + "Receives posts from the following accounts": "يتلقى المشاركات من الحسابات التالية", + "Sends out posts to the following accounts": "يرسل المنشورات إلى الحسابات التالية" } diff --git a/translations/ca.json b/translations/ca.json index 223325d3a..75a6722bc 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -353,7 +353,7 @@ "Follows you": "Et segueix", "Verify all signatures": "Verifiqueu totes les signatures", "Blocked followers": "Seguidors bloquejats", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Seguiment bloquejat", + "Receives posts from the following accounts": "Rep publicacions dels comptes següents", + "Sends out posts to the following accounts": "Envia publicacions als comptes següents" } diff --git a/translations/cy.json b/translations/cy.json index 8a286a9a8..613ca52e0 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -353,7 +353,7 @@ "Follows you": "Yn eich dilyn chi", "Verify all signatures": "Gwirio pob llofnod", "Blocked followers": "Dilynwyr wedi'u blocio", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Wedi'i rwystro yn dilyn", + "Receives posts from the following accounts": "Yn derbyn swyddi o'r cyfrifon canlynol", + "Sends out posts to the following accounts": "Yn anfon postiadau i'r cyfrifon canlynol" } diff --git a/translations/de.json b/translations/de.json index 4c3043758..f6c2522f1 100644 --- a/translations/de.json +++ b/translations/de.json @@ -353,7 +353,7 @@ "Follows you": "Folgt dir", "Verify all signatures": "Überprüfen Sie alle Signaturen", "Blocked followers": "Blockierte Follower", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Folgendes blockiert", + "Receives posts from the following accounts": "Erhält Beiträge von folgenden Konten", + "Sends out posts to the following accounts": "Sendet Beiträge an die folgenden Konten" } diff --git a/translations/es.json b/translations/es.json index 104c3dad4..4813e7d3a 100644 --- a/translations/es.json +++ b/translations/es.json @@ -353,7 +353,7 @@ "Follows you": "Te sigue", "Verify all signatures": "Verificar todas las firmas", "Blocked followers": "Seguidores bloqueadas", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Seguimiento bloqueado", + "Receives posts from the following accounts": "Recibe publicaciones de las siguientes cuentas", + "Sends out posts to the following accounts": "Envía publicaciones a las siguientes cuentas" } diff --git a/translations/fr.json b/translations/fr.json index 46de63b12..3c254476f 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -353,7 +353,7 @@ "Follows you": "Vous suit", "Verify all signatures": "Vérifier toutes les signatures", "Blocked followers": "Abonnés bloqués", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Bloqué suite", + "Receives posts from the following accounts": "Reçoit les publications des comptes suivants", + "Sends out posts to the following accounts": "Envoie des messages aux comptes suivants" } diff --git a/translations/ga.json b/translations/ga.json index 916f045f1..62a5bb55b 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -353,7 +353,7 @@ "Follows you": "Leanann tú", "Verify all signatures": "Fíoraigh gach síniú", "Blocked followers": "Leanúna blocáilte", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Blocáilte ina dhiaidh", + "Receives posts from the following accounts": "Faigheann sé poist ó na cuntais seo a leanas", + "Sends out posts to the following accounts": "Seoltar poist chuig na cuntais seo a leanas" } diff --git a/translations/hi.json b/translations/hi.json index 4d423fea3..9620d1b74 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -353,7 +353,7 @@ "Follows you": "आपका पीछा करता है", "Verify all signatures": "सभी हस्ताक्षर सत्यापित करें", "Blocked followers": "अवरुद्ध अनुयायियों", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "बाद में ब्लॉक किया गया", + "Receives posts from the following accounts": "निम्नलिखित खातों से पोस्ट प्राप्त करता है", + "Sends out posts to the following accounts": "निम्नलिखित खातों में पोस्ट भेजता है" } diff --git a/translations/it.json b/translations/it.json index 2b5c6cd0f..505a0e872 100644 --- a/translations/it.json +++ b/translations/it.json @@ -353,7 +353,7 @@ "Follows you": "Ti segue", "Verify all signatures": "Verifica tutte le firme", "Blocked followers": "Follower bloccati", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Seguito bloccato", + "Receives posts from the following accounts": "Riceve post dai seguenti account", + "Sends out posts to the following accounts": "Invia messaggi ai seguenti account" } diff --git a/translations/ja.json b/translations/ja.json index ecefa5da1..effc4d09b 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -353,7 +353,7 @@ "Follows you": "あなたについていきます", "Verify all signatures": "すべての署名を確認する", "Blocked followers": "ブロックされたフォロワー", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "次のブロック", + "Receives posts from the following accounts": "以下のアカウントから投稿を受け取ります", + "Sends out posts to the following accounts": "以下のアカウントに投稿を送信します" } diff --git a/translations/pt.json b/translations/pt.json index 9e1506482..0356f26b5 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -353,7 +353,7 @@ "Follows you": "Segue você", "Verify all signatures": "Verifique todas as assinaturas", "Blocked followers": "Seguidores bloqueados", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Seguindo bloqueado", + "Receives posts from the following accounts": "Recebe postagens das seguintes contas", + "Sends out posts to the following accounts": "Envia postagens para as seguintes contas" } diff --git a/translations/ru.json b/translations/ru.json index ded92510f..a5e5a3ffd 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -353,7 +353,7 @@ "Follows you": "Следует за вами", "Verify all signatures": "Проверить все подписи", "Blocked followers": "Заблокированные подписчики", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "Заблокировано подписок", + "Receives posts from the following accounts": "Получает сообщения от следующих аккаунтов", + "Sends out posts to the following accounts": "Отправляет сообщения на следующие аккаунты" } diff --git a/translations/zh.json b/translations/zh.json index 4dbfb6dcc..608650a2e 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -353,7 +353,7 @@ "Follows you": "跟着你", "Verify all signatures": "验证所有签名", "Blocked followers": "被封锁的追随者", - "Blocked following": "", - "Receives posts from the following accounts": "", - "Sends out posts to the following accounts": "" + "Blocked following": "被阻止", + "Receives posts from the following accounts": "从以下帐户接收帖子", + "Sends out posts to the following accounts": "将帖子发送到以下帐户" } From 345145927a8a15ad819779e5c76e57483f75d3e0 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 13:14:22 +0000 Subject: [PATCH 38/65] Calculate word frequencies for account info --- epicyon.py | 8 +++++-- posts.py | 52 +++++++++++++++++++++++++++++++++++--------- socnet.py | 4 +++- webapp_moderation.py | 3 ++- 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/epicyon.py b/epicyon.py index 47c85c493..3aaca074c 100644 --- a/epicyon.py +++ b/epicyon.py @@ -564,12 +564,14 @@ if args.postDomains: args.port = 80 elif args.gnunet: proxyType = 'gnunet' + wordFrequency = {} domainList = [] domainList = getPublicPostDomains(None, baseDir, nickname, domain, proxyType, args.port, httpPrefix, debug, - __version__, domainList) + __version__, + wordFrequency, domainList) for postDomain in domainList: print(postDomain) sys.exit() @@ -602,12 +604,14 @@ if args.postDomainsBlocked: args.port = 80 elif args.gnunet: proxyType = 'gnunet' + wordFrequency = {} domainList = [] domainList = getPublicPostDomainsBlocked(None, baseDir, nickname, domain, proxyType, args.port, httpPrefix, debug, - __version__, domainList) + __version__, + wordFrequency, domainList) for postDomain in domainList: print(postDomain) sys.exit() diff --git a/posts.py b/posts.py index c775ce784..2fd02523c 100644 --- a/posts.py +++ b/posts.py @@ -469,6 +469,27 @@ def _getPosts(session, outboxUrl: str, maxPosts: int, return personPosts +def _updateWordFrequency(content: str, wordFrequency: {}) -> None: + """Creates a dictionary containing words and the number of times + that they appear + """ + plainText = removeHtml(content) + plainText = plainText.replace('.', ' ') + plainText = plainText.replace(';', ' ') + wordsList = plainText.split(' ') + for word in wordsList: + wordLen = len(word) + if wordLen < 3: + continue + if wordLen < 4: + if word.upper() != word: + continue + if wordFrequency.get(word): + wordFrequency[word] += 1 + else: + wordFrequency[word] = 1 + + def getPostDomains(session, outboxUrl: str, maxPosts: int, maxMentions: int, maxEmoji: int, maxAttachments: int, @@ -476,7 +497,9 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int, personCache: {}, debug: bool, projectVersion: str, httpPrefix: str, - domain: str, domainList=[]) -> []: + domain: str, + wordFrequency: {}, + domainList=[]) -> []: """Returns a list of domains referenced within public posts """ if not outboxUrl: @@ -503,6 +526,9 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int, continue if not isinstance(item['object'], dict): continue + if item['object'].get('content'): + _updateWordFrequency(item['object']['content'], + wordFrequency) if item['object'].get('inReplyTo'): if isinstance(item['object']['inReplyTo'], str): postDomain, postPort = \ @@ -3334,7 +3360,7 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str, def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, debug: bool, projectVersion: str, - domainList=[]) -> []: + wordFrequency: {}, domainList=[]) -> []: """ Returns a list of domains referenced within public posts """ if not session: @@ -3371,7 +3397,8 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, getPostDomains(session, personUrl, 64, maxMentions, maxEmoji, maxAttachments, federationList, personCache, debug, - projectVersion, httpPrefix, domain, domainList) + projectVersion, httpPrefix, domain, + wordFrequency, domainList) postDomains.sort() return postDomains @@ -3412,7 +3439,8 @@ def downloadFollowCollection(followType: str, def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, - debug: bool, projectVersion: str) -> []: + debug: bool, projectVersion: str, + wordFrequency: {}) -> []: """ Returns a dict of domains referenced within public posts """ if not session: @@ -3450,7 +3478,8 @@ def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str, getPostDomains(session, personUrl, maxPosts, maxMentions, maxEmoji, maxAttachments, federationList, personCache, debug, - projectVersion, httpPrefix, domain, []) + projectVersion, httpPrefix, domain, + wordFrequency, []) postDomains.sort() domainsInfo = {} for d in postDomains: @@ -3476,7 +3505,7 @@ def getPublicPostDomainsBlocked(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, debug: bool, projectVersion: str, - domainList=[]) -> []: + wordFrequency: {}, domainList=[]) -> []: """ Returns a list of domains referenced within public posts which are globally blocked on this instance """ @@ -3484,7 +3513,7 @@ def getPublicPostDomainsBlocked(session, baseDir: str, getPublicPostDomains(session, baseDir, nickname, domain, proxyType, port, httpPrefix, debug, projectVersion, - domainList) + wordFrequency, domainList) if not postDomains: return [] @@ -3532,9 +3561,10 @@ def checkDomains(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, debug: bool, projectVersion: str, - maxBlockedDomains: int, singleCheck: bool): + maxBlockedDomains: int, singleCheck: bool) -> None: """Checks follower accounts for references to globally blocked domains """ + wordFrequency = {} nonMutuals = _getNonMutualsOfPerson(baseDir, nickname, domain) if not nonMutuals: print('No non-mutual followers were found') @@ -3558,7 +3588,8 @@ def checkDomains(session, baseDir: str, nonMutualNickname, nonMutualDomain, proxyType, port, httpPrefix, - debug, projectVersion, []) + debug, projectVersion, + wordFrequency, []) if blockedDomains: if len(blockedDomains) > maxBlockedDomains: followerWarningStr += handle + '\n' @@ -3577,7 +3608,8 @@ def checkDomains(session, baseDir: str, nonMutualNickname, nonMutualDomain, proxyType, port, httpPrefix, - debug, projectVersion, []) + debug, projectVersion, + wordFrequency, []) if blockedDomains: print(handle) for d in blockedDomains: diff --git a/socnet.py b/socnet.py index 36b5c7cb4..555512231 100644 --- a/socnet.py +++ b/socnet.py @@ -67,11 +67,13 @@ def instancesGraph(baseDir: str, handles: str, projectVersion, httpPrefix, nickname, domain, 'outbox', 27261) + wordFrequency = {} postDomains = \ getPostDomains(session, personUrl, 64, maxMentions, maxEmoji, maxAttachments, federationList, personCache, debug, - projectVersion, httpPrefix, domain, []) + projectVersion, httpPrefix, domain, + wordFrequency, []) postDomains.sort() for fedDomain in postDomains: dotLineStr = ' "' + domain + '" -> "' + fedDomain + '";\n' diff --git a/webapp_moderation.py b/webapp_moderation.py index f3d17db09..a73fef526 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -97,11 +97,12 @@ def htmlAccountInfo(cssCache: {}, translate: {}, session = createSession(proxyType) + wordFrequency = {} domainDict = getPublicPostInfo(session, baseDir, searchNickname, searchDomain, proxyType, searchPort, httpPrefix, debug, - __version__) + __version__, wordFrequency) # get a list of any blocked followers followersList = \ From 7f1281e9e9ad2e53a8da9bf22ce1525333902d64 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 13:42:47 +0000 Subject: [PATCH 39/65] Show word frequencies on account info --- translations/ar.json | 3 ++- translations/ca.json | 3 ++- translations/cy.json | 3 ++- translations/de.json | 3 ++- translations/en.json | 3 ++- translations/es.json | 3 ++- translations/fr.json | 3 ++- translations/ga.json | 3 ++- translations/hi.json | 3 ++- translations/it.json | 3 ++- translations/ja.json | 3 ++- translations/oc.json | 3 ++- translations/pt.json | 3 ++- translations/ru.json | 3 ++- translations/zh.json | 3 ++- webapp_moderation.py | 26 ++++++++++++++++++++++++++ 16 files changed, 56 insertions(+), 15 deletions(-) diff --git a/translations/ar.json b/translations/ar.json index 44a842f4a..62adc6c37 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -355,5 +355,6 @@ "Blocked followers": "المتابعون المحظورون", "Blocked following": "المتابعة المحظورة", "Receives posts from the following accounts": "يتلقى المشاركات من الحسابات التالية", - "Sends out posts to the following accounts": "يرسل المنشورات إلى الحسابات التالية" + "Sends out posts to the following accounts": "يرسل المنشورات إلى الحسابات التالية", + "Word frequencies": "ترددات الكلمات" } diff --git a/translations/ca.json b/translations/ca.json index 75a6722bc..4cf76febd 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -355,5 +355,6 @@ "Blocked followers": "Seguidors bloquejats", "Blocked following": "Seguiment bloquejat", "Receives posts from the following accounts": "Rep publicacions dels comptes següents", - "Sends out posts to the following accounts": "Envia publicacions als comptes següents" + "Sends out posts to the following accounts": "Envia publicacions als comptes següents", + "Word frequencies": "Freqüències de paraules" } diff --git a/translations/cy.json b/translations/cy.json index 613ca52e0..c7635cb77 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -355,5 +355,6 @@ "Blocked followers": "Dilynwyr wedi'u blocio", "Blocked following": "Wedi'i rwystro yn dilyn", "Receives posts from the following accounts": "Yn derbyn swyddi o'r cyfrifon canlynol", - "Sends out posts to the following accounts": "Yn anfon postiadau i'r cyfrifon canlynol" + "Sends out posts to the following accounts": "Yn anfon postiadau i'r cyfrifon canlynol", + "Word frequencies": "Amleddau geiriau" } diff --git a/translations/de.json b/translations/de.json index f6c2522f1..6ce203988 100644 --- a/translations/de.json +++ b/translations/de.json @@ -355,5 +355,6 @@ "Blocked followers": "Blockierte Follower", "Blocked following": "Folgendes blockiert", "Receives posts from the following accounts": "Erhält Beiträge von folgenden Konten", - "Sends out posts to the following accounts": "Sendet Beiträge an die folgenden Konten" + "Sends out posts to the following accounts": "Sendet Beiträge an die folgenden Konten", + "Word frequencies": "Worthäufigkeiten" } diff --git a/translations/en.json b/translations/en.json index 07c7fd653..c82e9d747 100644 --- a/translations/en.json +++ b/translations/en.json @@ -355,5 +355,6 @@ "Blocked followers": "Blocked followers", "Blocked following": "Blocked following", "Receives posts from the following accounts": "Receives posts from the following accounts", - "Sends out posts to the following accounts": "Sends out posts to the following accounts" + "Sends out posts to the following accounts": "Sends out posts to the following accounts", + "Word frequencies": "Word frequencies" } diff --git a/translations/es.json b/translations/es.json index 4813e7d3a..e7ce8e0cc 100644 --- a/translations/es.json +++ b/translations/es.json @@ -355,5 +355,6 @@ "Blocked followers": "Seguidores bloqueadas", "Blocked following": "Seguimiento bloqueado", "Receives posts from the following accounts": "Recibe publicaciones de las siguientes cuentas", - "Sends out posts to the following accounts": "Envía publicaciones a las siguientes cuentas" + "Sends out posts to the following accounts": "Envía publicaciones a las siguientes cuentas", + "Word frequencies": "Frecuencias de palabras" } diff --git a/translations/fr.json b/translations/fr.json index 3c254476f..d869cd71e 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -355,5 +355,6 @@ "Blocked followers": "Abonnés bloqués", "Blocked following": "Bloqué suite", "Receives posts from the following accounts": "Reçoit les publications des comptes suivants", - "Sends out posts to the following accounts": "Envoie des messages aux comptes suivants" + "Sends out posts to the following accounts": "Envoie des messages aux comptes suivants", + "Word frequencies": "Fréquences des mots" } diff --git a/translations/ga.json b/translations/ga.json index 62a5bb55b..e606e9543 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -355,5 +355,6 @@ "Blocked followers": "Leanúna blocáilte", "Blocked following": "Blocáilte ina dhiaidh", "Receives posts from the following accounts": "Faigheann sé poist ó na cuntais seo a leanas", - "Sends out posts to the following accounts": "Seoltar poist chuig na cuntais seo a leanas" + "Sends out posts to the following accounts": "Seoltar poist chuig na cuntais seo a leanas", + "Word frequencies": "Minicíochtaí focal" } diff --git a/translations/hi.json b/translations/hi.json index 9620d1b74..e86071c70 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -355,5 +355,6 @@ "Blocked followers": "अवरुद्ध अनुयायियों", "Blocked following": "बाद में ब्लॉक किया गया", "Receives posts from the following accounts": "निम्नलिखित खातों से पोस्ट प्राप्त करता है", - "Sends out posts to the following accounts": "निम्नलिखित खातों में पोस्ट भेजता है" + "Sends out posts to the following accounts": "निम्नलिखित खातों में पोस्ट भेजता है", + "Word frequencies": "शब्द आवृत्तियों" } diff --git a/translations/it.json b/translations/it.json index 505a0e872..de57e36bf 100644 --- a/translations/it.json +++ b/translations/it.json @@ -355,5 +355,6 @@ "Blocked followers": "Follower bloccati", "Blocked following": "Seguito bloccato", "Receives posts from the following accounts": "Riceve post dai seguenti account", - "Sends out posts to the following accounts": "Invia messaggi ai seguenti account" + "Sends out posts to the following accounts": "Invia messaggi ai seguenti account", + "Word frequencies": "Frequenze di parole" } diff --git a/translations/ja.json b/translations/ja.json index effc4d09b..5a886997d 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -355,5 +355,6 @@ "Blocked followers": "ブロックされたフォロワー", "Blocked following": "次のブロック", "Receives posts from the following accounts": "以下のアカウントから投稿を受け取ります", - "Sends out posts to the following accounts": "以下のアカウントに投稿を送信します" + "Sends out posts to the following accounts": "以下のアカウントに投稿を送信します", + "Word frequencies": "単語の頻度" } diff --git a/translations/oc.json b/translations/oc.json index 87b99583a..66fc70b42 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -351,5 +351,6 @@ "Blocked followers": "Blocked followers", "Blocked following": "Blocked following", "Receives posts from the following accounts": "Receives posts from the following accounts", - "Sends out posts to the following accounts": "Sends out posts to the following accounts" + "Sends out posts to the following accounts": "Sends out posts to the following accounts", + "Word frequencies": "Word frequencies" } diff --git a/translations/pt.json b/translations/pt.json index 0356f26b5..0b4e85327 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -355,5 +355,6 @@ "Blocked followers": "Seguidores bloqueados", "Blocked following": "Seguindo bloqueado", "Receives posts from the following accounts": "Recebe postagens das seguintes contas", - "Sends out posts to the following accounts": "Envia postagens para as seguintes contas" + "Sends out posts to the following accounts": "Envia postagens para as seguintes contas", + "Word frequencies": "Frequências de palavras" } diff --git a/translations/ru.json b/translations/ru.json index a5e5a3ffd..5147951f0 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -355,5 +355,6 @@ "Blocked followers": "Заблокированные подписчики", "Blocked following": "Заблокировано подписок", "Receives posts from the following accounts": "Получает сообщения от следующих аккаунтов", - "Sends out posts to the following accounts": "Отправляет сообщения на следующие аккаунты" + "Sends out posts to the following accounts": "Отправляет сообщения на следующие аккаунты", + "Word frequencies": "Частоты слов" } diff --git a/translations/zh.json b/translations/zh.json index 608650a2e..2bfb4b236 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -355,5 +355,6 @@ "Blocked followers": "被封锁的追随者", "Blocked following": "被阻止", "Receives posts from the following accounts": "从以下帐户接收帖子", - "Sends out posts to the following accounts": "将帖子发送到以下帐户" + "Sends out posts to the following accounts": "将帖子发送到以下帐户", + "Word frequencies": "词频" } diff --git a/webapp_moderation.py b/webapp_moderation.py index a73fef526..fe2e1d869 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -205,6 +205,32 @@ def htmlAccountInfo(cssCache: {}, translate: {}, followerNickname + '@' + followerDomainFull + '

\n' infoForm += '
\n' + if wordFrequency: + maxCount = 1 + for word, count in wordFrequency.items(): + if count > maxCount: + maxCount = count + minimumWordCount = int(maxCount / 2) + if minimumWordCount >= 3: + infoForm += '
\n' + infoForm += '

' + translate['Word frequencies'] + '

\n' + wordSwarm = '' + ctr = 0 + for word, count in wordFrequency.items(): + if count >= minimumWordCount: + if ctr > 0: + wordSwarm += ' ' + if count < maxCount - int(maxCount / 4): + wordSwarm += word + else: + if count != maxCount: + wordSwarm += '' + word + '' + else: + wordSwarm += '' + word + '' + ctr += 1 + infoForm += wordSwarm + infoForm += '
\n' + infoForm += htmlFooter() return infoForm From aac3eb816c9de1b197948a47b086a9e6d7103ada Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 13:57:08 +0000 Subject: [PATCH 40/65] Remove common words --- posts.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/posts.py b/posts.py index 2fd02523c..f219e04bc 100644 --- a/posts.py +++ b/posts.py @@ -477,6 +477,10 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: plainText = plainText.replace('.', ' ') plainText = plainText.replace(';', ' ') wordsList = plainText.split(' ') + commonWords = ( + 'that', 'some', 'about', 'then', 'they', 'were', + 'also', 'from', 'with', 'this', 'have', 'more' + ) for word in wordsList: wordLen = len(word) if wordLen < 3: @@ -484,6 +488,12 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: if wordLen < 4: if word.upper() != word: continue + if '&' in word or \ + '"' in word or \ + '@' in word: + continue + if word in commonWords: + continue if wordFrequency.get(word): wordFrequency[word] += 1 else: From 7d8719161fdd8af36cc23bbf282cb5df4356620f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 14:01:26 +0000 Subject: [PATCH 41/65] More common words --- posts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/posts.py b/posts.py index f219e04bc..c51f78d78 100644 --- a/posts.py +++ b/posts.py @@ -479,7 +479,9 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: wordsList = plainText.split(' ') commonWords = ( 'that', 'some', 'about', 'then', 'they', 'were', - 'also', 'from', 'with', 'this', 'have', 'more' + 'also', 'from', 'with', 'this', 'have', 'more', + 'need', 'here', 'would', 'these', 'into', 'very', + 'well', 'when', 'what', 'your' ) for word in wordsList: wordLen = len(word) From 1934a269f15d096d155674171ad4e667f6bcc6bc Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 14:05:16 +0000 Subject: [PATCH 42/65] More common words --- posts.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/posts.py b/posts.py index c51f78d78..99d7c83fd 100644 --- a/posts.py +++ b/posts.py @@ -481,7 +481,8 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: 'that', 'some', 'about', 'then', 'they', 'were', 'also', 'from', 'with', 'this', 'have', 'more', 'need', 'here', 'would', 'these', 'into', 'very', - 'well', 'when', 'what', 'your' + 'well', 'when', 'what', 'your', 'there', 'which', + 'even', 'there', 'such', 'just', 'those', 'only' ) for word in wordsList: wordLen = len(word) From 2d31488d49801b17d6d73d48dcf8f3b1f9d61274 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 14:13:17 +0000 Subject: [PATCH 43/65] Remove colon endings and question marks --- posts.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/posts.py b/posts.py index 99d7c83fd..62069d607 100644 --- a/posts.py +++ b/posts.py @@ -476,13 +476,15 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: plainText = removeHtml(content) plainText = plainText.replace('.', ' ') plainText = plainText.replace(';', ' ') + plainText = plainText.replace('?', ' ') wordsList = plainText.split(' ') commonWords = ( 'that', 'some', 'about', 'then', 'they', 'were', 'also', 'from', 'with', 'this', 'have', 'more', 'need', 'here', 'would', 'these', 'into', 'very', 'well', 'when', 'what', 'your', 'there', 'which', - 'even', 'there', 'such', 'just', 'those', 'only' + 'even', 'there', 'such', 'just', 'those', 'only', + 'will', 'much' ) for word in wordsList: wordLen = len(word) @@ -493,8 +495,11 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: continue if '&' in word or \ '"' in word or \ - '@' in word: + '@' in word or \ + '://' in word: continue + if word.endswith(':'): + word = word.replace(':', '') if word in commonWords: continue if wordFrequency.get(word): From e6be377a10fca893f4f2eccf374a57eeafa56d64 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 14:16:19 +0000 Subject: [PATCH 44/65] Compare lower case --- posts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posts.py b/posts.py index 62069d607..93f197ca3 100644 --- a/posts.py +++ b/posts.py @@ -484,7 +484,7 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: 'need', 'here', 'would', 'these', 'into', 'very', 'well', 'when', 'what', 'your', 'there', 'which', 'even', 'there', 'such', 'just', 'those', 'only', - 'will', 'much' + 'will', 'much', 'than' ) for word in wordsList: wordLen = len(word) @@ -500,7 +500,7 @@ def _updateWordFrequency(content: str, wordFrequency: {}) -> None: continue if word.endswith(':'): word = word.replace(':', '') - if word in commonWords: + if word.lower() in commonWords: continue if wordFrequency.get(word): wordFrequency[word] += 1 From 99b92c31c7933136d1a6730852da64f239674bb7 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 17:08:42 +0000 Subject: [PATCH 45/65] Banner title alignment --- theme/indymediamodern/banner.png | Bin 6041 -> 6091 bytes theme/indymediamodern/search_banner.png | Bin 6041 -> 6078 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/indymediamodern/banner.png b/theme/indymediamodern/banner.png index d6f5e8a0aefcd4f3d8e505b96f40b855f9b036c0..a4e63123ac02aa2db8deed4f38db3bc985e9464a 100644 GIT binary patch delta 5327 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 Jl^XU>{tt;-g#-Wq diff --git a/theme/indymediamodern/search_banner.png b/theme/indymediamodern/search_banner.png index e8b0ef87177b8ed4bcaa521aae438f5c355ccdcc..37e3e37079a1cd4bb3a177f518ac6dc5486dc3fe 100644 GIT binary patch delta 5312 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 delta 5260 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 Date: Mon, 11 Jan 2021 17:14:56 +0000 Subject: [PATCH 46/65] Post separator style --- theme/indymediamodern/icons/separator.png | Bin 1271 -> 1274 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/indymediamodern/icons/separator.png b/theme/indymediamodern/icons/separator.png index f3b5f079929dc06bd296951393a50e561200f4bd..c7da64a05f4400e3a06a40bc0c213453b597de66 100644 GIT binary patch delta 1227 zcmV;+1T_2i3Hk|;BmvlwB_DrlmLn$&h5xgPSpt#}63d}@oRb}7`E$XP+n(+u^GIwP@iM#ek1hQU|igwi`#H(k!p8^_@aw35sZ=ZL!F}@1)Ci2}2 zKdK-3Yw@`r3;99Id{fI`Pmq2s{+9S=f>)GSGx4dmtB69t2U%hOHEsD*1VNgJ9p{0CVKAH zy_a4Gg@K!5q@g1Z8$QaY6S+2Jrl~Ven?B2|Pilwir}7Kb=uqQLYT4P78b*WJ?Sj^I zqKg@baUu}6MF0uSi&=C^i5I!WEEdM0P)3lt*o01t7!ZG^L9COW>^{i-6t|%MQ{4E! z$c2UO{~#BD?lZS9sP*+f*EX@oDO{RH!RZ@gIP%Er`cJF;r|oY!LVP8B2P4MB%p9MV zFaQ7nhG|1XP)S2WAaHVTW@&6?004NLeUUv#!%!53Pg|v;Eh2UhamY{w!GfrWqgJ5^ z6+*4hs)K*YOaGurLz3d+D7Y3J{8_9zxH#+T;3^1$KOk;yPKqv4;(bY>MT{37@8i6C z4)5Iu`0Hh+njPbSs#!)V5f?JqRU!BaA9~P-Fh(V2>T{x)glB!-Q#aLJjAwcG{aIlp zXEMMi5YIB*u!uK^r#CH~^FDEe6(xoEoOsNj3le`na$R=$jdQ_aKhKO9>C`-NgjguF zvE0V2XsEe3JSuIyt^Pc>Lp`5m|%yn8rNMI355FtQD6(y8mAx67K ziis4R$36Umj$b5~Os*0bITlcX3d!+<|H1Fsn)%5IHz^bcI$v!2V;BhT0*#t&e;?a+ z;{<;QJOfu+%U`JjGoPf_T3Yl7=-mb`u3MVC2VCv|15dhSNRAYs<~)WKceT&$-=60DegHewa*^UG-PQmA00v@9M??T6 z06+kb{r?Dh00009a7bBm000XU000XU0RTUmoEQKA00(qQO+^Rg0SgfhCq_}bnjnS(;+?~ki30k=()XTrZ zu5T0WHRyP?2fs$xuRwR;E1;~ER~G#_N!a72Ba7 zLDui^Y)A%`y24AChmgcw`#Dl?vnH$TtIT#gg zvN)wxXtGI>E)JHBM*y=V{K$p&x@E7|$gy%KxH2IaVag9n_}So}lrU#o644fvw^qoD zm*7Zaky|yq0EFhnO}D^zx$wuQjfJfWg1TjPd|-{o8RAfS+gpFKISc$0?RhFFSib^5 zBCM@Q21g)K%p^*gaBr{?K}QFmip*IOA0R-g+>s>o>xJycaRscKeJ4_dTl$ti2j+48#Ns);32%Vy?Qth#t|_3Y;E#cSar zxC6E1V#P}-wQ_%`Sg0aag@1+R;6sjd=#dXQ{3u6l*gh>aZMj+VR$A@crQ@3Dxm)*M zdL0x7Zi3+lhcjekWh zEOh^aTmZU{+&-b!*Z*AG#LiQ=G>wAOH^y-6Bd_Z}t@6LNe-#M%mGB*2r^MA;J!QTC z00D$)LqkwWLqi~Na&Km7Y-Iodc$|HaJxIeq9K~N#rJ@xPJBT<$s7@9|MI5yXMW_&J zg;pI*F8zOkCJjl7i=*ILaPVWX>fqw6tAnc`2!4P#IXWr2NQwVT3oT+iIPS;0dyl(! zfKV+m&1xG5G~G56v8b3zuZn?JbRmFVjA2M-mN6$uad?ied-(Wz7vWjn=l&esYQ|!K zPb8jYhG`RT5KnK~2Iqa^5X;Ld@j3CRNf#u3Du$r-;LRA0s5Z|*_2($PgBTdf%h}|rZmuZ3v{m4 zdu#0D^Z`gxSMeL*;1C$eQTDpWyE|HY`}a(vzaNQea Date: Mon, 11 Jan 2021 17:18:31 +0000 Subject: [PATCH 47/65] Post separator color --- theme/indymediamodern/icons/separator.png | Bin 1274 -> 1275 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/indymediamodern/icons/separator.png b/theme/indymediamodern/icons/separator.png index c7da64a05f4400e3a06a40bc0c213453b597de66..592bf171ed976c39d129c25e39da410208eab803 100644 GIT binary patch delta 769 zcmV+c1OEK_3Hu3#g{G0Da4HP!39LVr7sJC$>b?avwoH zB!fy_;U&yNNaF7Ok%6q6q+(n>3GtfQo_oN+a=$ACd3(KkjPX^VH<9mI_)-1HUyIN6 zc*qZ0=9^mn`T^gz&3|K!4RCsF@j`1{8H`W+!Usle%%s86>LM7vSauBM3 zm6D=uZ1^anPSo0znWoM>ZTc*;KB*n5pV}`_qeG21spV%+YOn^gI|QxcL>Ds<<3u2C zivS9m7qjS;5-)O#SuBi?LK#WwViP(oVnCP%u|!UKvil(SQ{003PjTb_A{Q3A|ASlr zy3gFcpw`#_T-(GRU*Xa;3cfygRrY{8Ms$BV{#GEF$PoXO;X5@!#hkeY9#gXg1I7U` z5*cAfpL75K01`<=K~xyiV|@Sq{eOm0FysLM!GZ(MAdf5>00000NkvXXu0mjf?1Op( delta 768 zcmV+b1ONQ{3Hk|;Mt>tG42A!*idh1Z5E9Fwc$||RWchQ!l-r)}B=bmd3NQ$vx}U&d z{QcJq-|$e3F(ft5C1>{w=up7^d|D%3qPtK`D^jH z9t-(F%Y0MIUr&&JE&i7HWn+0p#P1UqKV$kN@|@l09FMQ7DMQhGGAf2!owWvr7bKUx zETb4+Mc;NQD1RPnY=F~aix*0xLJTT1P@+ziCXL-TY6vOuV5BfJH-K7WF2;r1CYDyA z$tFd*I9N6w0nC!{GZxzWmc3si$IhK#$^>VGCI48$zfJy133Ik35p6+vYlXOY363xp zxmCjoKxiIrx&^+=!5?1|3#kf%x@C5JV2#(q#ijI-TYs`S3+xo_<5WZkGx)aX#-O={WMlNv^Y+3kYXb)t(Ih;bqi zw?zO6&5K!dN{JV_#Vi)ap-@JUy4ZwHix?25K}4*Rp6ouz{S>#L{!`rezsQA!?*AYc zfbKK5FR1nPKi4*~$0=NzM#1SDV>t52>-tZt{HN`2IYN9Td Date: Mon, 11 Jan 2021 17:21:55 +0000 Subject: [PATCH 48/65] Post separator color --- theme/indymediamodern/icons/separator.png | Bin 1275 -> 1275 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/indymediamodern/icons/separator.png b/theme/indymediamodern/icons/separator.png index 592bf171ed976c39d129c25e39da410208eab803..080feb1cec15797ab03b1b08b2a9d218781b8942 100644 GIT binary patch delta 739 zcmV<90v!GO3Hu37sVJuQuADL#yF;u3Res~KCZH#6w`k0 z%lOREyFJ{4$QTKFIScCXudwUKf_o3T-tEE94EqUm2R;F1?Yy$+uSvqr4?Cq3sEo%T z7q{0`uk#A+IPO%=Ew)2HgRI}-)sPG-b%mEO45mL#-G3w%{d$rRuaRL4dq5|0 zzbgcJd%e4l@l~KVk?&FXQT@nYi_i6V$PZfPn_B*Qg7jpSbv$(^|psyj@Khisn;MG2H5`HE_Hjx$I>b&2THmwp&5-SYrd69$UQ78WmztnSl~@sx)cr zzEML;i3g*EnSZ$f$g;T@7jBzaT8$=~6zSq%)_4RkOTy1wXzyG0evKSEcY-Suf)SSd zV+;Q_`715V*_K4K1?8<3^5P{p(pcoy6J7v9^KjEG@ZApn_)=IXRS?uIv*QJ8ydEJg zrH|T@%~{~5=pSDN1?wjOB*NZ`WKjHxVkS|_gmZ(92!A>{099nplK27vQss^$If-Nr z#?EVRtTEcYtekn7aW(;jO2+r(AXEV>B}M&Ma@0^&(WI(bO+9GQnkA>KIcLl3kgFz^ zOf8$4Te0fm$(FU=3z>2wKO9E@mLci9p;I0TeVZX3;4nUgQ?DSa=;|j3jlj37r-(AWVZ; zCq3DHkozfaLH(z=@qdvE3*G-gE&$zUZeLLA>n4A$ZDNnFaA_I^U*8zRQAb|ae_G`~ z?SCr}@+;vx{LjS3UPh=#vjqdj0WcLK=nBvQ0000INkl7sbdSsd+9rM_j3-!W9#bkE`sSV%q(_ zjL$QAw}*QY88g8sXF)yw6?XktaPL9ayFK`M!hQnXflokLJFhJIYm%_@!%pc0D&sN9 z#qBlK>%2lcjysiei|x?QAnSK{H6(*dUEw9nLrCK8{gHvJn}4KYTs;Z#n%SOvz`%09 zD+GCay?c!DRiHPK?^*a!{m5U7&-Hl74_fA%TK@V0>DS_KiC;FBXGZ+~;F4!fpG2Os z`<&zPb~R-vnomW=aI3S{!103QvX^Bv!>yRxZUxO_jSX;mZ1F;CRER-k21?Ya(xkD+ zMhz(@9*h!Z=6?oI%jRNSxNTx-HJWTvq>BSq;}Jw)=4URn_bq$BMvk33!IcTY2uuF4 zg@1eaD=o~~mPE7#<*gO+;w3oJSmag@F94x=xak)7ZU=vSDJ+yK2q-lPG1vxxq#R9e*8wDl%tDe1QO|az~P!L^20s z=e0N17;Rrx&b-Vxn*c&3<9l)ts(_V}qJAtnYN)DcQq`=c9<*r9l2g{4v*mTjRTE35 zmd(tqSatE_>eZ)&GZ5oMAa08Q3Yr(Q=#&yKa*J6kjE_PYN$O$~IxS*Am(nF zAeqPz|CHf7H9^Ikxdt9nvjqdj0WcC7VMm{I0000INkl Date: Mon, 11 Jan 2021 17:40:31 +0000 Subject: [PATCH 49/65] Post separator style --- epicyon-profile.css | 3 ++- theme/indymediamodern/theme.json | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/epicyon-profile.css b/epicyon-profile.css index bef667da1..810e46442 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -136,6 +136,7 @@ --publish-button-bottom-offset: 10px; --banner-height: 15vh; --banner-height-mobile: 10vh; + --post-separator-background: transparent; --post-separator-margin-top: 0; --post-separator-margin-bottom: 0; --post-separator-width: 95%; @@ -186,7 +187,7 @@ body, html { } .postSeparatorImage img { - background-color: transparent; + background-color: var(--post-separator-background); padding-top: var(--post-separator-margin-top); padding-bottom: var(--post-separator-margin-bottom); width: var(--post-separator-width); diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json index 48a92eeed..910e66191 100644 --- a/theme/indymediamodern/theme.json +++ b/theme/indymediamodern/theme.json @@ -34,12 +34,13 @@ "font-size-newswire": "12px", "font-size-newswire-mobile": "30px", "font-size-dropdown-header": "30px", + "post-separator-background": "#efefef", "post-separator-margin-top": "1%", "post-separator-margin-bottom": "1%", - "post-separator-width": "96%", + "post-separator-width": "100%", "separator-width-left": "98%", "separator-width-right": "99%", - "post-separator-height": "1px", + "post-separator-height": "0px", "column-left-top-margin": "10px", "column-left-border-width": "0px", "column-right-border-width": "0px", From d284dda4216166d94554799e7f18e175b0ffba5d Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 18:01:38 +0000 Subject: [PATCH 50/65] Edit icon on the right --- epicyon-profile.css | 1 + 1 file changed, 1 insertion(+) diff --git a/epicyon-profile.css b/epicyon-profile.css index 810e46442..135030495 100644 --- a/epicyon-profile.css +++ b/epicyon-profile.css @@ -1125,6 +1125,7 @@ div.container { filter: brightness(var(--icon-brightness-change)); } .col-right img.rightColEdit { + float: right; background: transparent; width: var(--column-right-icon-size); } From 50b27f544f16c6331c874a2c8ab736b0ca5ef078 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 18:12:42 +0000 Subject: [PATCH 51/65] Vertical alignment of time --- theme/indymediamodern/theme.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json index 910e66191..aab14209e 100644 --- a/theme/indymediamodern/theme.json +++ b/theme/indymediamodern/theme.json @@ -17,7 +17,7 @@ "hashtag-size2": "30px", "font-size-calendar-header": "2rem", "font-size-calendar-cell": "2rem", - "time-vertical-align": "10px", + "time-vertical-align": "1.1%", "publish-button-vertical-offset": "15px", "vertical-between-posts": "0", "vertical-between-posts-header": "0 0", From 1f7d9633b23c52acc818bb0a4bf718ef35c0e7fd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 18:41:24 +0000 Subject: [PATCH 52/65] Title alignment --- theme/indymediamodern/banner.png | Bin 6091 -> 6099 bytes theme/indymediamodern/search_banner.png | Bin 6078 -> 6086 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/theme/indymediamodern/banner.png b/theme/indymediamodern/banner.png index a4e63123ac02aa2db8deed4f38db3bc985e9464a..59fa1c9861becba2988b6f841d8881348d3e4468 100644 GIT binary patch delta 4624 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 yNvZVczd7Y;{2v68f<9^B1VaZH0Pc9HG?LK( delta 4643 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 From bcfba505531ba70ba07a93868410be769b9660ce Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 11 Jan 2021 19:46:21 +0000 Subject: [PATCH 53/65] Set html page title --- blog.py | 17 +++++++++++++---- webapp_about.py | 4 +++- webapp_calendar.py | 13 ++++++++++--- webapp_column_left.py | 8 ++++++-- webapp_column_right.py | 17 +++++++++++++---- webapp_confirm.py | 21 ++++++++++++++++----- webapp_create_post.py | 5 ++++- webapp_frontscreen.py | 5 ++++- webapp_hashtagswarm.py | 5 ++++- webapp_login.py | 4 +++- webapp_moderation.py | 9 +++++++-- webapp_person_options.py | 4 +++- webapp_post.py | 11 +++++++++-- webapp_profile.py | 13 ++++++++++--- webapp_search.py | 29 ++++++++++++++++++++++------- webapp_suspended.py | 5 ++++- webapp_timeline.py | 5 ++++- webapp_tos.py | 4 +++- webapp_utils.py | 15 +++++++++++---- 19 files changed, 149 insertions(+), 45 deletions(-) diff --git a/blog.py b/blog.py index bd6df769f..0f61bcf9d 100644 --- a/blog.py +++ b/blog.py @@ -14,6 +14,7 @@ from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from webapp_utils import getPostAttachmentsAsHtml from webapp_media import addEmbeddedElements +from utils import getConfigParam from utils import getFullDomain from utils import getMediaFormats from utils import getNicknameFromActor @@ -386,7 +387,9 @@ def htmlBlogPost(authorized: bool, cssFilename = baseDir + '/epicyon-blog.css' if os.path.isfile(baseDir + '/blog.css'): cssFilename = baseDir + '/blog.css' - blogStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + blogStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) _htmlBlogRemoveCwButton(blogStr, translate) blogStr += _htmlBlogPostContent(authorized, baseDir, @@ -433,7 +436,9 @@ def htmlBlogPage(authorized: bool, session, cssFilename = baseDir + '/epicyon-profile.css' if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - blogStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + blogStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) _htmlBlogRemoveCwButton(blogStr, translate) blogsIndex = baseDir + '/accounts/' + \ @@ -653,7 +658,9 @@ def htmlBlogView(authorized: bool, cssFilename = baseDir + '/epicyon-profile.css' if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - blogStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + blogStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) if _noOfBlogAccounts(baseDir) <= 1: nickname = _singleBlogAccountNickname(baseDir) @@ -755,7 +762,9 @@ def htmlEditBlog(mediaInstance: bool, translate: {}, dateAndLocation += '' dateAndLocation += '

' - editBlogForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + editBlogForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) editBlogForm += \ '
' if onionDomain: aboutForm += \ diff --git a/webapp_calendar.py b/webapp_calendar.py index e3a2dc495..d919e6535 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -10,6 +10,7 @@ import os from datetime import datetime from datetime import date from shutil import copyfile +from utils import getConfigParam from utils import getNicknameFromActor from utils import getDomainFromActor from utils import locatePost @@ -52,7 +53,9 @@ def htmlCalendarDeleteConfirm(cssCache: {}, translate: {}, baseDir: str, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - deletePostStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + deletePostStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) deletePostStr += \ '

' + postTime + ' ' + str(year) + '/' + \ str(monthNumber) + \ @@ -109,7 +112,9 @@ def _htmlCalendarDay(cssCache: {}, translate: {}, if '/users/' in actor: calActor = '/users/' + actor.split('/users/')[1] - calendarStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + calendarStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) calendarStr += '
\n' calendarStr += '
\n' calendarStr += \ @@ -290,7 +295,9 @@ def htmlCalendar(cssCache: {}, translate: {}, if '/users/' in actor: calActor = '/users/' + actor.split('/users/')[1] - calendarStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + calendarStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) calendarStr += '
\n' calendarStr += '
\n' calendarStr += \ diff --git a/webapp_column_left.py b/webapp_column_left.py index 3157d9857..f9d608757 100644 --- a/webapp_column_left.py +++ b/webapp_column_left.py @@ -260,7 +260,9 @@ def htmlLinksMobile(cssCache: {}, baseDir: str, if ':' in domain: domain = domain.split(':')[0] - htmlStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) htmlStr += \ @@ -321,7 +323,9 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str, bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) - editLinksForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + editLinksForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) # top banner editLinksForm += \ diff --git a/webapp_column_right.py b/webapp_column_right.py index 300fa9934..cf0fb10e8 100644 --- a/webapp_column_right.py +++ b/webapp_column_right.py @@ -15,6 +15,7 @@ from utils import loadJson from utils import votesOnNewswireItem from utils import getNicknameFromActor from utils import isEditor +from utils import getConfigParam from posts import isModerator from webapp_utils import getRightImageFile from webapp_utils import htmlHeaderWithExternalStyle @@ -342,7 +343,9 @@ def htmlCitations(baseDir: str, nickname: str, domain: str, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - htmlStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) # top banner bannerFile, bannerFilename = \ @@ -452,7 +455,9 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str, showPublishButton = editor - htmlStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) @@ -515,7 +520,9 @@ def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str, bannerFile, bannerFilename = \ getBannerFile(baseDir, nickname, domain, theme) - editNewswireForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + editNewswireForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) # top banner editNewswireForm += \ @@ -631,7 +638,9 @@ def htmlEditNewsPost(cssCache: {}, translate: {}, baseDir: str, path: str, if os.path.isfile(baseDir + '/links.css'): cssFilename = baseDir + '/links.css' - editNewsPostForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + editNewsPostForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) editNewsPostForm += \ '\n' diff --git a/webapp_confirm.py b/webapp_confirm.py index bf6b564c5..c6bbc00b7 100644 --- a/webapp_confirm.py +++ b/webapp_confirm.py @@ -13,6 +13,7 @@ from utils import getNicknameFromActor from utils import getDomainFromActor from utils import locatePost from utils import loadJson +from utils import getConfigParam from webapp_utils import getAltPath from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter @@ -57,7 +58,9 @@ def htmlConfirmDelete(cssCache: {}, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - deletePostStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + deletePostStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) deletePostStr += \ individualPostAsHtml(True, recentPostsCache, maxRecentPosts, translate, pageNumber, @@ -130,7 +133,9 @@ def htmlConfirmRemoveSharedItem(cssCache: {}, translate: {}, baseDir: str, if os.path.isfile(baseDir + '/follow.css'): cssFilename = baseDir + '/follow.css' - sharesStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + sharesStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) sharesStr += '
\n' + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') profileStr = \ - htmlHeaderWithExternalStyle(cssFilename) + \ + htmlHeaderWithExternalStyle(cssFilename, instanceTitle) + \ profileStr + profileFooterStr + htmlFooter() return profileStr diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py index 47369045f..68c7ec220 100644 --- a/webapp_hashtagswarm.py +++ b/webapp_hashtagswarm.py @@ -10,6 +10,7 @@ import os from shutil import copyfile from datetime import datetime from utils import getNicknameFromActor +from utils import getConfigParam from categories import getHashtagCategories from categories import getHashtagCategory from webapp_utils import getSearchBannerFile @@ -246,7 +247,9 @@ def htmlSearchHashtagCategory(cssCache: {}, translate: {}, if os.path.isfile(baseDir + '/search.css'): cssFilename = baseDir + '/search.css' - htmlStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) # show a banner above the search box searchBannerFile, searchBannerFilename = \ diff --git a/webapp_login.py b/webapp_login.py index 423d7fb24..44699b2a6 100644 --- a/webapp_login.py +++ b/webapp_login.py @@ -129,7 +129,9 @@ def htmlLogin(cssCache: {}, translate: {}, if not autocomplete: autocompleteStr = 'autocomplete="off" value=""' - loginForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + loginForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) loginForm += '
\n' loginForm += '\n' loginForm += '
\n' diff --git a/webapp_moderation.py b/webapp_moderation.py index fe2e1d869..79c888178 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -12,6 +12,7 @@ from utils import isEditor from utils import loadJson from utils import getNicknameFromActor from utils import getDomainFromActor +from utils import getConfigParam from posts import downloadFollowCollection from posts import getPublicPostInfo from posts import isModerator @@ -74,7 +75,9 @@ def htmlAccountInfo(cssCache: {}, translate: {}, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - infoForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + infoForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) searchNickname = getNicknameFromActor(searchHandle) searchDomain, searchPort = getDomainFromActor(searchHandle) @@ -248,7 +251,9 @@ def htmlModerationInfo(cssCache: {}, translate: {}, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - infoForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + infoForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) infoForm += \ '

' + \ diff --git a/webapp_person_options.py b/webapp_person_options.py index 30d623e0e..921f12c5c 100644 --- a/webapp_person_options.py +++ b/webapp_person_options.py @@ -109,7 +109,9 @@ def htmlPersonOptions(defaultTimeline: str, '">\n' - optionsStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + optionsStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) optionsStr += '

\n' optionsStr += '
\n' optionsStr += '
\n' diff --git a/webapp_post.py b/webapp_post.py index 046f7edc9..ff1bfea8d 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -22,6 +22,7 @@ from posts import getPersonBox from posts import isDM from posts import downloadAnnounce from posts import populateRepliesJson +from utils import getConfigParam from utils import getFullDomain from utils import isEditor from utils import locatePost @@ -1705,7 +1706,10 @@ def htmlIndividualPost(cssCache: {}, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - return htmlHeaderWithExternalStyle(cssFilename) + postStr + htmlFooter() + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + return htmlHeaderWithExternalStyle(cssFilename, instanceTitle) + \ + postStr + htmlFooter() def htmlPostReplies(cssCache: {}, @@ -1740,4 +1744,7 @@ def htmlPostReplies(cssCache: {}, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' - return htmlHeaderWithExternalStyle(cssFilename) + repliesStr + htmlFooter() + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + return htmlHeaderWithExternalStyle(cssFilename, instanceTitle) + \ + repliesStr + htmlFooter() diff --git a/webapp_profile.py b/webapp_profile.py index 2c8a265c5..b11319267 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -288,7 +288,10 @@ def htmlProfileAfterSearch(cssCache: {}, if i >= 20: break - return htmlHeaderWithExternalStyle(cssFilename) + profileStr + htmlFooter() + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + return htmlHeaderWithExternalStyle(cssFilename, instanceTitle) + \ + profileStr + htmlFooter() def _getProfileHeader(baseDir: str, nickname: str, domain: str, @@ -680,8 +683,10 @@ def htmlProfile(rssIconAtTop: bool, nickname, domainFull, extraJson) + licenseStr + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') profileStr = \ - htmlHeaderWithExternalStyle(cssFilename) + \ + htmlHeaderWithExternalStyle(cssFilename, instanceTitle) + \ profileStr + htmlFooter() return profileStr @@ -1196,7 +1201,9 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, 'style="height:200px">' + peertubeInstancesStr + \ '\n' - editProfileForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + editProfileForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) # top banner editProfileForm += \ diff --git a/webapp_search.py b/webapp_search.py index 126722058..c833a9419 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -10,6 +10,7 @@ import os from shutil import copyfile import urllib.parse from datetime import datetime +from utils import getConfigParam from utils import getFullDomain from utils import isEditor from utils import loadJson @@ -50,7 +51,9 @@ def htmlSearchEmoji(cssCache: {}, translate: {}, emojiLookupFilename = baseDir + '/emoji/emoji.json' # create header - emojiForm = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + emojiForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) emojiForm += '

' + \ translate['Emoji Search'] + \ '

' @@ -110,8 +113,10 @@ def htmlSearchSharedItems(cssCache: {}, translate: {}, if os.path.isfile(baseDir + '/epicyon.css'): cssFilename = baseDir + '/epicyon.css' + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') sharedItemsForm = \ - htmlHeaderWithExternalStyle(cssFilename) + htmlHeaderWithExternalStyle(cssFilename, instanceTitle) sharedItemsForm += \ '

' + \ '' + \ @@ -285,7 +290,9 @@ def htmlSearchEmojiTextEntry(cssCache: {}, translate: {}, if os.path.isfile(baseDir + '/follow.css'): cssFilename = baseDir + '/follow.css' - emojiStr = htmlHeaderWithExternalStyle(cssFilename) + instanceTitle = \ + getConfigParam(baseDir, 'instanceTitle') + emojiStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle) emojiStr += '