diff --git a/Dockerfile b/Dockerfile index 17ded0a72..fa0ad6338 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,8 +8,6 @@ RUN apt-get update && \ python3-dateutil \ python3-idna \ python3-requests \ - python3-numpy \ - python3-pil.imagetk \ python3-pip \ python3-setuptools \ python3-socks \ diff --git a/README.md b/README.md index 3782db6a4..0347ae1e2 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ On Arch/Parabola: ``` bash sudo pacman -S tor python-pip python-pysocks python-pycryptodome \ - imagemagick python-pillow python-requests \ - perl-image-exiftool python-numpy python-dateutil \ + imagemagick python-requests \ + perl-image-exiftool python-dateutil \ certbot flake8 bandit sudo pip3 install pyqrcode pypng ``` @@ -39,9 +39,9 @@ Or on Debian: ``` bash sudo apt install -y \ tor python3-socks imagemagick \ - python3-numpy python3-setuptools \ + python3-setuptools \ python3-crypto python3-pycryptodome \ - python3-dateutil python3-pil.imagetk \ + python3-dateutil \ python3-idna python3-requests \ python3-django-timezone-field \ libimage-exiftool-perl python3-flake8 \ diff --git a/README_commandline.md b/README_commandline.md index 4bce92a8c..a8bfc9c92 100644 --- a/README_commandline.md +++ b/README_commandline.md @@ -118,7 +118,6 @@ python3 epicyon.py --nickname [yournick] --domain [name] \ --sendto othernick@domain --message "bees!" \ --warning "bee-related content" --attach bees.png \ --imagedescription "bees on flowers" \ - --blurhash \ --password [c2s password] ``` diff --git a/README_goals.md b/README_goals.md index 97f8837fd..be3567585 100644 --- a/README_goals.md +++ b/README_goals.md @@ -15,7 +15,6 @@ * http signatures and basic auth * Compatible with http (onion addresses), https and dat * Minimal dependencies. - * Support image blurhashes * Data minimization principle. Configurable post expiry time * Likes and repeats only visible to authorized viewers * ReplyGuy mitigation - maxmimum replies per post or posts per day diff --git a/blurhash.py b/blurhash.py deleted file mode 100644 index de2eb50ea..000000000 --- a/blurhash.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -Copyright (c) 2019 Lorenz Diener - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -* The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. -* You and any organization you work for may not promote white supremacy, hate -speech and homo- or transphobia - this license is void if you do. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -https://github.com/halcy/blurhash-python - -Pure python blurhash decoder with no additional dependencies, for -both de- and encoding. - -Very close port of the original Swift implementation by Dag Ă…gren. -""" - -import math - - -# Alphabet for base 83 -alphabet = \ - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + \ - "abcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~" -alphabet_values = dict(zip(alphabet, range(len(alphabet)))) - - -def _base83_encode(value, length): - """ - Decodes an integer to a base83 string, as used in blurhash. - - Length is how long the resulting string should be. Will complain - if the specified length is too short. - """ - if int(value) // (83 ** (length)) != 0: - raise ValueError("Specified length is too short to " + - "encode given value.") - - result = "" - for i in range(1, length + 1): - digit = int(value) // (83 ** (length - i)) % 83 - result += alphabet[int(digit)] - return result - - -def _srgb_to_linear(value): - """ - srgb 0-255 integer to linear 0.0-1.0 floating point conversion. - """ - value = float(value) / 255.0 - if value <= 0.04045: - return value / 12.92 - return math.pow((value + 0.055) / 1.055, 2.4) - - -def _sign_pow(value, exp): - """ - Sign-preserving exponentiation. - """ - return math.copysign(math.pow(abs(value), exp), value) - - -def _linear_to_srgb(value): - """ - linear 0.0-1.0 floating point to srgb 0-255 integer conversion. - """ - value = max(0.0, min(1.0, value)) - if value <= 0.0031308: - return int(value * 12.92 * 255 + 0.5) - return int((1.055 * math.pow(value, 1 / 2.4) - 0.055) * 255 + 0.5) - - -def blurhash_encode(image, components_x=4, components_y=4, linear=False): - """ - Calculates the blurhash for an image using the given x and y - component counts. - - Image should be a 3-dimensional array, with the first dimension - being y, the second being x, and the third being the three rgb - components that are assumed to be 0-255 srgb integers - (incidentally, this is the format you will get from a PIL RGB image). - - You can also pass in already linear data - to do this, set linear - to True. This is useful if you want to encode a version of your - image resized to a smaller size (which you should ideally do in - linear colour). - """ - if components_x < 1 or components_x > 9 or \ - components_y < 1 or components_y > 9: - raise ValueError("x and y component counts must be " + - "between 1 and 9 inclusive.") - height = float(len(image)) - width = float(len(image[0])) - - # Convert to linear if neeeded - image_linear = [] - if linear is False: - for y in range(int(height)): - image_linear_line = [] - for x in range(int(width)): - image_linear_line.append([ - _srgb_to_linear(image[y][x][0]), - _srgb_to_linear(image[y][x][1]), - _srgb_to_linear(image[y][x][2]) - ]) - image_linear.append(image_linear_line) - else: - image_linear = image - - # Calculate components - components = [] - max_ac_component = 0.0 - for j in range(components_y): - for i in range(components_x): - norm_factor = 1.0 if (i == 0 and j == 0) else 2.0 - component = [0.0, 0.0, 0.0] - for y in range(int(height)): - for x in range(int(width)): - basis = \ - norm_factor * \ - math.cos(math.pi * float(i) * float(x) / width) * \ - math.cos(math.pi * float(j) * float(y) / height) - component[0] += basis * image_linear[y][x][0] - component[1] += basis * image_linear[y][x][1] - component[2] += basis * image_linear[y][x][2] - - component[0] /= (width * height) - component[1] /= (width * height) - component[2] /= (width * height) - components.append(component) - - if not (i == 0 and j == 0): - max_ac_component = \ - max(max_ac_component, abs(component[0]), - abs(component[1]), abs(component[2])) - - # Encode components - dc_value = (_linear_to_srgb(components[0][0]) << 16) + \ - (_linear_to_srgb(components[0][1]) << 8) + \ - _linear_to_srgb(components[0][2]) - - quant_max_ac_component = int(max(0, min(82, - math.floor(max_ac_component * - 166 - 0.5)))) - ac_component_norm_factor = float(quant_max_ac_component + 1) / 166.0 - - ac_values = [] - for r, g, b in components[1:]: - r2 = r / ac_component_norm_factor - g2 = g / ac_component_norm_factor - b2 = b / ac_component_norm_factor - r3 = math.floor(_sign_pow(r2, 0.5) * 9.0 + 9.5) - g3 = math.floor(_sign_pow(g2, 0.5) * 9.0 + 9.5) - b3 = math.floor(_sign_pow(b2, 0.5) * 9.0 + 9.5) - ac_values.append( - int(max(0.0, min(18.0, r3))) * 19 * 19 + - int(max(0.0, min(18.0, g3))) * 19 + - int(max(0.0, min(18.0, b3))) - ) - - # Build final blurhash - blurhash = "" - blurhashValue = (components_x - 1) + (components_y - 1) * 9 - blurhash += _base83_encode(blurhashValue, 1) - blurhash += _base83_encode(quant_max_ac_component, 1) - blurhash += _base83_encode(dc_value, 4) - for ac_value in ac_values: - blurhash += _base83_encode(ac_value, 2) - - return blurhash diff --git a/daemon.py b/daemon.py index 4eb105fbd..528fe5fff 100644 --- a/daemon.py +++ b/daemon.py @@ -1127,6 +1127,7 @@ class PubServer(BaseHTTPRequestHandler): if self.path.startswith('/icons/') or \ self.path.startswith('/avatars/') or \ self.path.startswith('/favicon.ico') or \ + self.path.startswith('/newswire_favicon.ico') or \ self.path.startswith('/categories.xml') or \ self.path.startswith('/newswire.xml'): return False @@ -4835,18 +4836,18 @@ class PubServer(BaseHTTPRequestHandler): 'show logout', 'send manifest') def _getFavicon(self, callingDomain: str, - baseDir: str, debug: bool) -> None: - """Return the favicon + baseDir: str, debug: bool, + favFilename: str) -> None: + """Return the site favicon or default newswire favicon """ favType = 'image/x-icon' - favFilename = 'favicon.ico' if self._hasAccept(callingDomain): if 'image/webp' in self.headers['Accept']: favType = 'image/webp' - favFilename = 'favicon.webp' + favFilename = favFilename.split('.')[0] + '.webp' if 'image/avif' in self.headers['Accept']: favType = 'image/avif' - favFilename = 'favicon.avif' + favFilename = favFilename.split('.')[0] + '.avif' if not self.server.themeName: self.themeName = getConfigParam(baseDir, 'theme') if not self.server.themeName: @@ -4855,6 +4856,12 @@ class PubServer(BaseHTTPRequestHandler): faviconFilename = \ baseDir + '/theme/' + self.server.themeName + \ '/icons/' + favFilename + if not favFilename.endswith('.ico'): + if not os.path.isfile(faviconFilename): + if favFilename.endswith('.webp'): + favFilename = favFilename.replace('.webp', '.ico') + elif favFilename.endswith('.avif'): + favFilename = favFilename.replace('.avif', '.ico') if not os.path.isfile(faviconFilename): # default favicon faviconFilename = \ @@ -9728,10 +9735,19 @@ class PubServer(BaseHTTPRequestHandler): GETstartTime, GETtimings) return + # default newswire favicon, for links to sites which + # have no favicon + if 'newswire_favicon.ico' in self.path: + self._getFavicon(callingDomain, self.server.baseDir, + self.server.debug, + 'newswire_favicon.ico') + return + # favicon image if 'favicon.ico' in self.path: self._getFavicon(callingDomain, self.server.baseDir, - self.server.debug) + self.server.debug, + 'favicon.ico') return # check authorization @@ -11961,7 +11977,6 @@ class PubServer(BaseHTTPRequestHandler): False, False, False, commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['replyTo'], fields['replyTo'], fields['subject'], fields['schedulePost'], fields['eventDate'], fields['eventTime'], @@ -12016,7 +12031,6 @@ class PubServer(BaseHTTPRequestHandler): False, False, False, commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['replyTo'], fields['replyTo'], fields['subject'], fields['schedulePost'], @@ -12096,8 +12110,7 @@ class PubServer(BaseHTTPRequestHandler): postJsonObject['object'], filename, attachmentMediaType, - imgDescription, - self.server.useBlurHash) + imgDescription) replaceYouTube(postJsonObject, self.server.YTReplacementDomain) @@ -12128,7 +12141,6 @@ class PubServer(BaseHTTPRequestHandler): False, False, False, commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['replyTo'], fields['replyTo'], fields['subject'], @@ -12161,7 +12173,6 @@ class PubServer(BaseHTTPRequestHandler): commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['replyTo'], fields['replyTo'], fields['subject'], @@ -12214,7 +12225,6 @@ class PubServer(BaseHTTPRequestHandler): False, False, commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['subject'], fields['schedulePost'], fields['eventDate'], @@ -12252,7 +12262,6 @@ class PubServer(BaseHTTPRequestHandler): commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['replyTo'], fields['replyTo'], fields['subject'], @@ -12291,7 +12300,6 @@ class PubServer(BaseHTTPRequestHandler): True, False, False, False, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, None, None, fields['subject'], True, fields['schedulePost'], @@ -12324,7 +12332,6 @@ class PubServer(BaseHTTPRequestHandler): True, False, False, True, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, self.server.debug, fields['subject']) if messageJson: if self._postToOutbox(messageJson, __version__, nickname): @@ -12355,7 +12362,6 @@ class PubServer(BaseHTTPRequestHandler): commentsEnabled, filename, attachmentMediaType, fields['imageDescription'], - self.server.useBlurHash, fields['subject'], int(fields['duration'])) if messageJson: @@ -13448,7 +13454,6 @@ def runDaemon(verifyAllSignatures: bool, domainMaxPostsPerDay=8640, accountMaxPostsPerDay=864, allowDeletion=False, debug=False, unitTest=False, instanceOnlySkillsSearch=False, sendThreads=[], - useBlurHash=False, manualFollowerApproval=True) -> None: if len(domain) == 0: domain = 'localhost' @@ -13504,7 +13509,6 @@ def runDaemon(verifyAllSignatures: bool, httpd.manualFollowerApproval = manualFollowerApproval httpd.onionDomain = onionDomain httpd.i2pDomain = i2pDomain - httpd.useBlurHash = useBlurHash httpd.mediaInstance = mediaInstance httpd.blogsInstance = blogsInstance httpd.newsInstance = newsInstance diff --git a/epicyon.py b/epicyon.py index da5d1cda5..c7af7bfd0 100644 --- a/epicyon.py +++ b/epicyon.py @@ -375,9 +375,6 @@ parser.add_argument('--attach', dest='attach', type=str, default=None, help='File to attach to a post') parser.add_argument('--imagedescription', dest='imageDescription', type=str, default=None, help='Description of an attached image') -parser.add_argument("--blurhash", type=str2bool, nargs='?', - const=True, default=False, - help="Create blurhash for an image") parser.add_argument('--warning', '--warn', '--cwsubject', '--subject', dest='subject', type=str, default=None, help='Subject of content warning') @@ -1002,7 +999,6 @@ if args.message: followersOnly = args.followersonly clientToServer = args.client attachedImageDescription = args.imageDescription - useBlurhash = args.blurhash sendThreads = [] postLog = [] personCache = {} @@ -1023,7 +1019,7 @@ if args.message: toNickname, toDomain, toPort, ccUrl, httpPrefix, sendMessage, followersOnly, args.commentsEnabled, attach, mediaType, - attachedImageDescription, useBlurhash, + attachedImageDescription, cachedWebfingers, personCache, isArticle, args.debug, replyTo, replyTo, subject) for i in range(10): @@ -1864,7 +1860,6 @@ if args.unfilterStr: sys.exit() if args.testdata: - useBlurhash = False nickname = 'testuser567' password = 'boringpassword' print('Generating some test data for user: ' + nickname) @@ -1942,8 +1937,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, testAttachImageFilename, - testMediaType, testImageDescription, - useBlurhash) + testMediaType, testImageDescription) createPublicPost(baseDir, nickname, domain, port, httpPrefix, "Zoiks!!!", testFollowersOnly, @@ -1951,8 +1945,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, testAttachImageFilename, - testMediaType, testImageDescription, - useBlurhash) + testMediaType, testImageDescription) createPublicPost(baseDir, nickname, domain, port, httpPrefix, "Hey scoob we need like a hundred more #milkshakes", testFollowersOnly, @@ -1960,8 +1953,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, testAttachImageFilename, - testMediaType, testImageDescription, - useBlurhash) + testMediaType, testImageDescription) createPublicPost(baseDir, nickname, domain, port, httpPrefix, "Getting kinda spooky around here", testFollowersOnly, @@ -1970,7 +1962,7 @@ if args.testdata: testCommentsEnabled, testAttachImageFilename, testMediaType, testImageDescription, - useBlurhash, 'someone') + 'someone') createPublicPost(baseDir, nickname, domain, port, httpPrefix, "And they would have gotten away with it too" + "if it wasn't for those pesky hackers", @@ -1979,8 +1971,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, 'img/logo.png', 'image/png', - 'Description of image', - useBlurhash) + 'Description of image') createPublicPost(baseDir, nickname, domain, port, httpPrefix, "man these centralized sites are like the worst!", testFollowersOnly, @@ -1988,8 +1979,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, testAttachImageFilename, - testMediaType, testImageDescription, - useBlurhash) + testMediaType, testImageDescription) createPublicPost(baseDir, nickname, domain, port, httpPrefix, "another mystery solved #test", testFollowersOnly, @@ -1997,8 +1987,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, testAttachImageFilename, - testMediaType, testImageDescription, - useBlurhash) + testMediaType, testImageDescription) createPublicPost(baseDir, nickname, domain, port, httpPrefix, "let's go bowling", testFollowersOnly, @@ -2006,8 +1995,7 @@ if args.testdata: testClientToServer, testCommentsEnabled, testAttachImageFilename, - testMediaType, testImageDescription, - useBlurhash) + testMediaType, testImageDescription) domainFull = domain + ':' + str(port) clearFollows(baseDir, nickname, domain) @@ -2179,4 +2167,4 @@ if __name__ == "__main__": args.accountMaxPostsPerDay, args.allowdeletion, debug, False, args.instanceOnlySkillsSearch, [], - args.blurhash, not args.noapproval) + not args.noapproval) diff --git a/gemini/EN/install.gmi b/gemini/EN/install.gmi index 06000e78b..49dfaec68 100644 --- a/gemini/EN/install.gmi +++ b/gemini/EN/install.gmi @@ -4,7 +4,7 @@ You will need python version 3.7 or later. On a Debian based system: - sudo apt install -y tor python3-socks imagemagick python3-numpy python3-setuptools python3-crypto python3-pycryptodome python3-dateutil python3-pil.imagetk python3-idna python3-requests python3-flake8 python3-django-timezone-field python3-pyqrcode python3-png python3-bandit libimage-exiftool-perl certbot nginx wget + sudo apt install -y tor python3-socks imagemagick python3-setuptools python3-crypto python3-pycryptodome python3-dateutil python3-idna python3-requests python3-flake8 python3-django-timezone-field python3-pyqrcode python3-png python3-bandit libimage-exiftool-perl certbot nginx wget The following instructions install Epicyon to the /opt directory. It's not essential that it be installed there, and it could be in any other preferred directory. diff --git a/media.py b/media.py index 763ce77d9..d37487ae2 100644 --- a/media.py +++ b/media.py @@ -6,9 +6,6 @@ __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" -from blurhash import blurhash_encode -from PIL import Image -import numpy import os import datetime from hashlib import sha1 @@ -56,11 +53,6 @@ def removeMetaData(imageFilename: str, outputFilename: str) -> None: os.system('/usr/bin/mogrify -strip ' + outputFilename) # nosec -def _getImageHash(imageFilename: str) -> str: - value = numpy.array(Image.open(imageFilename).convert("RGB")) - return blurhash_encode(value) - - def _isMedia(imageFilename: str) -> bool: permittedMedia = getMediaExtensions() for m in permittedMedia: @@ -136,12 +128,9 @@ def _updateEtag(mediaFilename: str) -> None: def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int, postJson: {}, imageFilename: str, - mediaType: str, description: str, - useBlurhash: bool) -> {}: + mediaType: str, description: str) -> {}: """Attaches media to a json object post The description can be None - Blurhash is optional, since low power systems may take a long - time to calculate it """ if not _isMedia(imageFilename): return postJson @@ -181,8 +170,6 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int, } if mediaType.startswith('image/'): attachmentJson['focialPoint'] = [0.0, 0.0] - if useBlurhash: - attachmentJson['blurhash'] = _getImageHash(imageFilename) postJson['attachment'] = [attachmentJson] if baseDir: diff --git a/newsdaemon.py b/newsdaemon.py index 737b4ac9c..4f74d95bf 100644 --- a/newsdaemon.py +++ b/newsdaemon.py @@ -542,7 +542,6 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str, rssDescription = removeHtmlTag(rssDescription, 'height') followersOnly = False - useBlurhash = False # NOTE: the id when the post is created will not be # consistent (it's based on the current time, not the # published time), so we change that later @@ -550,7 +549,7 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str, domain, port, httpPrefix, rssDescription, followersOnly, False, - None, None, None, useBlurhash, + None, None, None, rssTitle) if not blog: continue diff --git a/posts.py b/posts.py index df87b2221..e3af38f53 100644 --- a/posts.py +++ b/posts.py @@ -146,7 +146,7 @@ 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)) + # print('getUserUrl: ' + str(sourceId) + ' ' + str(wfRequest)) if not wfRequest.get('links'): if sourceId == 72367: print('getUserUrl failed to get display name for webfinger ' + @@ -195,7 +195,7 @@ def parseUserFeed(session, feedUrl: str, asHeader: {}, userFeed = \ parseUserFeed(session, nextUrl, asHeader, projectVersion, httpPrefix, - domain, depth+1) + domain, depth + 1) if userFeed: for item in userFeed: yield item @@ -803,7 +803,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, imageDescription: str, - useBlurhash: bool, isModerationReport: bool, + isModerationReport: bool, isArticle: bool, inReplyTo=None, inReplyToAtomUri=None, subject=None, schedulePost=False, @@ -1034,7 +1034,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int, newPost['object'] = \ attachMedia(baseDir, httpPrefix, domain, port, newPost['object'], attachImageFilename, - mediaType, imageDescription, useBlurhash) + mediaType, imageDescription) _appendEventFields(newPost['object'], eventUUID, eventStatus, anonymousParticipationEnabled, repliesModerationOption, @@ -1082,7 +1082,7 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int, newPost = \ attachMedia(baseDir, httpPrefix, domain, port, newPost, attachImageFilename, - mediaType, imageDescription, useBlurhash) + mediaType, imageDescription) _appendEventFields(newPost, eventUUID, eventStatus, anonymousParticipationEnabled, repliesModerationOption, @@ -1225,7 +1225,7 @@ def createPublicPost(baseDir: str, content: str, followersOnly: bool, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, inReplyTo=None, inReplyToAtomUri=None, subject=None, schedulePost=False, eventDate=None, eventTime=None, location=None) -> {}: @@ -1239,7 +1239,7 @@ def createPublicPost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, False, inReplyTo, inReplyToAtomUri, subject, schedulePost, eventDate, eventTime, location, None, None, None, None, None, @@ -1251,7 +1251,7 @@ def createBlogPost(baseDir: str, content: str, followersOnly: bool, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, inReplyTo=None, inReplyToAtomUri=None, subject=None, schedulePost=False, eventDate=None, eventTime=None, location=None) -> {}: @@ -1261,7 +1261,7 @@ def createBlogPost(baseDir: str, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, inReplyTo, inReplyToAtomUri, subject, schedulePost, eventDate, eventTime, location) @@ -1298,7 +1298,7 @@ def createNewsPost(baseDir: str, domain: str, port: int, httpPrefix: str, content: str, followersOnly: bool, saveToFile: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, subject: str) -> {}: clientToServer = False inReplyTo = None @@ -1313,7 +1313,7 @@ def createNewsPost(baseDir: str, content, followersOnly, saveToFile, clientToServer, False, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, inReplyTo, inReplyToAtomUri, subject, schedulePost, eventDate, eventTime, location) @@ -1327,7 +1327,7 @@ def createQuestionPost(baseDir: str, followersOnly: bool, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, subject: str, durationDays: int) -> {}: """Question post with multiple choice options """ @@ -1340,7 +1340,7 @@ def createQuestionPost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, False, None, None, subject, False, None, None, None, None, None, None, None, None, @@ -1371,7 +1371,7 @@ def createUnlistedPost(baseDir: str, content: str, followersOnly: bool, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, inReplyTo=None, inReplyToAtomUri=None, subject=None, schedulePost=False, eventDate=None, eventTime=None, location=None) -> {}: @@ -1385,7 +1385,7 @@ def createUnlistedPost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, False, inReplyTo, inReplyToAtomUri, subject, schedulePost, eventDate, eventTime, location, None, None, None, None, None, @@ -1399,7 +1399,7 @@ def createFollowersOnlyPost(baseDir: str, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, inReplyTo=None, inReplyToAtomUri=None, subject=None, schedulePost=False, eventDate=None, eventTime=None, @@ -1414,7 +1414,7 @@ def createFollowersOnlyPost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, False, inReplyTo, inReplyToAtomUri, subject, schedulePost, eventDate, eventTime, location, None, None, None, None, None, @@ -1428,7 +1428,7 @@ def createEventPost(baseDir: str, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, subject=None, schedulePost=False, eventDate=None, eventTime=None, location=None, category=None, joinMode=None, @@ -1461,7 +1461,7 @@ def createEventPost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, False, None, None, subject, schedulePost, eventDate, eventTime, location, eventUUID, category, joinMode, @@ -1513,7 +1513,7 @@ def createDirectMessagePost(baseDir: str, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, inReplyTo=None, inReplyToAtomUri=None, subject=None, debug=False, schedulePost=False, @@ -1536,7 +1536,7 @@ def createDirectMessagePost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, False, inReplyTo, inReplyToAtomUri, subject, schedulePost, eventDate, eventTime, location, None, None, None, None, None, @@ -1557,7 +1557,7 @@ def createReportPost(baseDir: str, content: str, followersOnly: bool, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, debug: bool, subject=None) -> {}: """Send a report to moderators """ @@ -1626,7 +1626,7 @@ def createReportPost(baseDir: str, httpPrefix, content, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, True, False, None, None, subject, False, None, None, None, None, None, None, None, None, @@ -1717,7 +1717,7 @@ def sendPost(projectVersion: str, saveToFile: bool, clientToServer: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, federationList: [], sendThreads: [], postLog: [], cachedWebfingers: {}, personCache: {}, isArticle: bool, @@ -1776,7 +1776,7 @@ def sendPost(projectVersion: str, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, isArticle, inReplyTo, inReplyToAtomUri, subject, False, None, None, None, None, None, @@ -1838,7 +1838,7 @@ def sendPostViaServer(projectVersion: str, httpPrefix: str, content: str, followersOnly: bool, commentsEnabled: bool, attachImageFilename: str, mediaType: str, - imageDescription: str, useBlurhash: bool, + imageDescription: str, cachedWebfingers: {}, personCache: {}, isArticle: bool, debug=False, inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int: @@ -1914,7 +1914,7 @@ def sendPostViaServer(projectVersion: str, followersOnly, saveToFile, clientToServer, commentsEnabled, attachImageFilename, mediaType, - imageDescription, useBlurhash, + imageDescription, False, isArticle, inReplyTo, inReplyToAtomUri, subject, False, None, None, None, None, None, @@ -3086,11 +3086,13 @@ def _createBoxIndexed(recentPostsCache: {}, # created by individualPostAsHtml p['hasReplies'] = hasReplies - # Don't show likes, replies or shares (announces) to + # Don't show likes, replies, DMs or shares (announces) to # unauthorized viewers if not authorized: if p.get('object'): if isinstance(p['object'], dict): + if isDM(p): + continue if p['object'].get('likes'): p['likes'] = {'items': []} if p['object'].get('replies'): diff --git a/tests.py b/tests.py index d29671e2a..e88c651b3 100644 --- a/tests.py +++ b/tests.py @@ -256,7 +256,6 @@ def createServerAlice(path: str, domain: str, port: int, httpPrefix = 'http' proxyType = None password = 'alicepass' - useBlurhash = True maxReplies = 64 domainMaxPostsPerDay = 1000 accountMaxPostsPerDay = 1000 @@ -289,8 +288,7 @@ def createServerAlice(path: str, domain: str, port: int, testCommentsEnabled, testAttachImageFilename, testMediaType, - testImageDescription, - useBlurhash) + testImageDescription) createPublicPost(path, nickname, domain, port, httpPrefix, "Curiouser and curiouser!", testFollowersOnly, @@ -299,8 +297,7 @@ def createServerAlice(path: str, domain: str, port: int, testCommentsEnabled, testAttachImageFilename, testMediaType, - testImageDescription, - useBlurhash) + testImageDescription) createPublicPost(path, nickname, domain, port, httpPrefix, "In the gardens of memory, in the palace " + "of dreams, that is where you and I shall meet", @@ -310,8 +307,7 @@ def createServerAlice(path: str, domain: str, port: int, testCommentsEnabled, testAttachImageFilename, testMediaType, - testImageDescription, - useBlurhash) + testImageDescription) global testServerAliceRunning testServerAliceRunning = True maxMentions = 10 @@ -338,7 +334,7 @@ def createServerAlice(path: str, domain: str, port: int, httpPrefix, federationList, maxMentions, maxEmoji, False, proxyType, maxReplies, domainMaxPostsPerDay, accountMaxPostsPerDay, - allowDeletion, True, True, False, sendThreads, False, + allowDeletion, True, True, False, sendThreads, False) @@ -356,7 +352,6 @@ def createServerBob(path: str, domain: str, port: int, proxyType = None clientToServer = False password = 'bobpass' - useBlurhash = False maxReplies = 64 domainMaxPostsPerDay = 1000 accountMaxPostsPerDay = 1000 @@ -388,8 +383,7 @@ def createServerBob(path: str, domain: str, port: int, testCommentsEnabled, testAttachImageFilename, testMediaType, - testImageDescription, - useBlurhash) + testImageDescription) createPublicPost(path, nickname, domain, port, httpPrefix, "One of the things I've realised is that " + "I am very simple", @@ -399,8 +393,7 @@ def createServerBob(path: str, domain: str, port: int, testCommentsEnabled, testAttachImageFilename, testMediaType, - testImageDescription, - useBlurhash) + testImageDescription) createPublicPost(path, nickname, domain, port, httpPrefix, "Quantum physics is a bit of a passion of mine", testFollowersOnly, @@ -409,8 +402,7 @@ def createServerBob(path: str, domain: str, port: int, testCommentsEnabled, testAttachImageFilename, testMediaType, - testImageDescription, - useBlurhash) + testImageDescription) global testServerBobRunning testServerBobRunning = True maxMentions = 10 @@ -437,7 +429,7 @@ def createServerBob(path: str, domain: str, port: int, httpPrefix, federationList, maxMentions, maxEmoji, False, proxyType, maxReplies, domainMaxPostsPerDay, accountMaxPostsPerDay, - allowDeletion, True, True, False, sendThreads, False, + allowDeletion, True, True, False, sendThreads, False) @@ -485,7 +477,7 @@ def createServerEve(path: str, domain: str, port: int, federationList: [], onionDomain, i2pDomain, None, port, port, httpPrefix, federationList, maxMentions, maxEmoji, False, proxyType, maxReplies, allowDeletion, True, True, False, - sendThreads, False, False) + sendThreads, False) def testPostMessageBetweenServers(): @@ -574,7 +566,6 @@ def testPostMessageBetweenServers(): attachedImageFilename = baseDir + '/img/logo.png' mediaType = getAttachmentMediaType(attachedImageFilename) attachedImageDescription = 'Logo' - useBlurhash = True isArticle = False # nothing in Alice's outbox outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox' @@ -590,7 +581,7 @@ def testPostMessageBetweenServers(): followersOnly, saveToFile, clientToServer, True, attachedImageFilename, mediaType, - attachedImageDescription, useBlurhash, federationList, + attachedImageDescription, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers, alicePersonCache, isArticle, inReplyTo, inReplyToAtomUri, subject) @@ -890,7 +881,6 @@ def testFollowBetweenServers(): alicePersonCache = {} aliceCachedWebfingers = {} alicePostLog = [] - useBlurhash = False isArticle = False sendResult = \ sendPost(__version__, @@ -898,7 +888,7 @@ def testFollowBetweenServers(): 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Alice message', followersOnly, saveToFile, clientToServer, True, - None, None, None, useBlurhash, federationList, + None, None, None, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers, alicePersonCache, isArticle, inReplyTo, inReplyToAtomUri, subject) @@ -1178,7 +1168,6 @@ def testCreatePerson(): port = 80 httpPrefix = 'https' clientToServer = False - useBlurhash = False baseDir = currDir + '/.tests_createperson' if os.path.isdir(baseDir): shutil.rmtree(baseDir) @@ -1197,7 +1186,7 @@ def testCreatePerson(): archivePostsForPerson(nickname, domain, baseDir, 'outbox', None, {}, 4) createPublicPost(baseDir, nickname, domain, port, httpPrefix, "G'day world!", False, True, clientToServer, - True, None, None, useBlurhash, None, None, + True, None, None, None, None, 'Not suitable for Vogons') os.chdir(currDir) @@ -1401,7 +1390,6 @@ def testClientToServer(): attachedImageFilename = baseDir+'/img/logo.png' mediaType = getAttachmentMediaType(attachedImageFilename) attachedImageDescription = 'Logo' - useBlurhash = False isArticle = False cachedWebfingers = {} personCache = {} @@ -1420,7 +1408,7 @@ def testClientToServer(): httpPrefix, 'Sent from my ActivityPub client', followersOnly, True, attachedImageFilename, mediaType, - attachedImageDescription, useBlurhash, + attachedImageDescription, cachedWebfingers, personCache, isArticle, True, None, None, None) print('sendResult: ' + str(sendResult)) @@ -3041,6 +3029,23 @@ def testLinksWithinPost() -> None: 'https://' + \ 'freedombone.net
' + content = "Some text
Other text
More text
" + \ + "Errno::EOHNOES (No such file or rodent @ " + \
+ "ik_right - /tmp/blah.png)
" + \ + "(" + \ + "wuh)
Oh yeah like for sure
" + \ + "Ground sloth tin opener
" + \ + "" + postJsonObject = \ + createPublicPost(baseDir, nickname, domain, port, httpPrefix, + content, + False, False, False, True, + None, None, False, None) + assert postJsonObject['object']['content'] == content + def runAllTests(): print('Running tests...') diff --git a/theme/blue/icons/newswire_favicon.ico b/theme/blue/icons/newswire_favicon.ico new file mode 100644 index 000000000..a368686dc Binary files /dev/null and b/theme/blue/icons/newswire_favicon.ico differ diff --git a/theme/debian/icons/newswire_favicon.ico b/theme/debian/icons/newswire_favicon.ico new file mode 100644 index 000000000..a368686dc Binary files /dev/null and b/theme/debian/icons/newswire_favicon.ico differ diff --git a/theme/default/icons/newswire_favicon.ico b/theme/default/icons/newswire_favicon.ico new file mode 100644 index 000000000..a368686dc Binary files /dev/null and b/theme/default/icons/newswire_favicon.ico differ diff --git a/theme/hacker/icons/newswire_favicon.ico b/theme/hacker/icons/newswire_favicon.ico new file mode 100644 index 000000000..501ffe048 Binary files /dev/null and b/theme/hacker/icons/newswire_favicon.ico differ diff --git a/theme/henge/icons/newswire_favicon.ico b/theme/henge/icons/newswire_favicon.ico new file mode 100644 index 000000000..279a9d6fb Binary files /dev/null and b/theme/henge/icons/newswire_favicon.ico differ diff --git a/theme/indymediaclassic/icons/favicon.ico b/theme/indymediaclassic/icons/favicon.ico index c7cb1bbbe..061668e43 100644 Binary files a/theme/indymediaclassic/icons/favicon.ico and b/theme/indymediaclassic/icons/favicon.ico differ diff --git a/theme/indymediaclassic/icons/newswire_favicon.ico b/theme/indymediaclassic/icons/newswire_favicon.ico new file mode 100644 index 000000000..7aa32157d Binary files /dev/null and b/theme/indymediaclassic/icons/newswire_favicon.ico differ diff --git a/theme/indymediamodern/icons/favicon.ico b/theme/indymediamodern/icons/favicon.ico index c7cb1bbbe..061668e43 100644 Binary files a/theme/indymediamodern/icons/favicon.ico and b/theme/indymediamodern/icons/favicon.ico differ diff --git a/theme/indymediamodern/icons/newswire_favicon.ico b/theme/indymediamodern/icons/newswire_favicon.ico new file mode 100644 index 000000000..7aa32157d Binary files /dev/null and b/theme/indymediamodern/icons/newswire_favicon.ico differ diff --git a/theme/lcd/icons/newswire_favicon.ico b/theme/lcd/icons/newswire_favicon.ico new file mode 100644 index 000000000..eeef176c9 Binary files /dev/null and b/theme/lcd/icons/newswire_favicon.ico differ diff --git a/theme/light/icons/newswire_favicon.ico b/theme/light/icons/newswire_favicon.ico new file mode 100644 index 000000000..a368686dc Binary files /dev/null and b/theme/light/icons/newswire_favicon.ico differ diff --git a/theme/night/icons/newswire_favicon.ico b/theme/night/icons/newswire_favicon.ico new file mode 100644 index 000000000..a368686dc Binary files /dev/null and b/theme/night/icons/newswire_favicon.ico differ diff --git a/theme/purple/icons/newswire_favicon.ico b/theme/purple/icons/newswire_favicon.ico new file mode 100644 index 000000000..79ac5b019 Binary files /dev/null and b/theme/purple/icons/newswire_favicon.ico differ diff --git a/theme/rc3/icons/newswire_favicon.ico b/theme/rc3/icons/newswire_favicon.ico new file mode 100644 index 000000000..628d4f4d0 Binary files /dev/null and b/theme/rc3/icons/newswire_favicon.ico differ diff --git a/theme/solidaric/icons/newswire_favicon.ico b/theme/solidaric/icons/newswire_favicon.ico new file mode 100644 index 000000000..302007a70 Binary files /dev/null and b/theme/solidaric/icons/newswire_favicon.ico differ diff --git a/theme/starlight/icons/favicon.ico b/theme/starlight/icons/favicon.ico index c7cb1bbbe..ec27eb443 100644 Binary files a/theme/starlight/icons/favicon.ico and b/theme/starlight/icons/favicon.ico differ diff --git a/theme/starlight/icons/newswire_favicon.ico b/theme/starlight/icons/newswire_favicon.ico new file mode 100644 index 000000000..1fe6acaa8 Binary files /dev/null and b/theme/starlight/icons/newswire_favicon.ico differ diff --git a/theme/zen/icons/newswire_favicon.ico b/theme/zen/icons/newswire_favicon.ico new file mode 100644 index 000000000..09a2d9963 Binary files /dev/null and b/theme/zen/icons/newswire_favicon.ico differ diff --git a/webapp_column_right.py b/webapp_column_right.py index d52717fec..300fa9934 100644 --- a/webapp_column_right.py +++ b/webapp_column_right.py @@ -190,17 +190,17 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str, def _getBrokenFavSubstitute() -> str: """Substitute link used if a favicon is not available """ - return " onerror=\"this.onerror=null; this.style='width:0%'; this.src=''\"" + return " onerror=\"this.onerror=null; this.src='/newswire_favicon.ico'\"" def _getNewswireFavicon(url: str) -> str: """Returns a favicon url from the given article link """ if '://' not in url: - return None + return '/newswire_favicon.ico' if url.startswith('http://'): if not (url.endswith('.onion') or url.endswith('.i2p')): - return None + return '/newswire_favicon.ico' domain = url.split('://')[1] if '/' not in domain: return url + '/favicon.ico' diff --git a/website/EN/index.html b/website/EN/index.html index 26f5138b6..39a8b3af8 100644 --- a/website/EN/index.html +++ b/website/EN/index.html @@ -1267,7 +1267,7 @@You will need python version 3.7 or later.
On a Debian based system:
sudo apt install -y tor python3-socks imagemagick python3-numpy python3-setuptools python3-crypto python3-pycryptodome python3-dateutil python3-pil.imagetk python3-idna python3-requests python3-flake8 python3-django-timezone-field python3-pyqrcode python3-png python3-bandit libimage-exiftool-perl certbot nginx wget
+sudo apt install -y tor python3-socks imagemagick python3-setuptools python3-crypto python3-pycryptodome python3-dateutil python3-idna python3-requests python3-flake8 python3-django-timezone-field python3-pyqrcode python3-png python3-bandit libimage-exiftool-perl certbot nginx wget