diff --git a/README.md b/README.md index bc68f3b1..2c0fe24b 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ Even if Eve has an account on Alice's instance this won't help her very much unl ## Install ``` bash -sudo pacman -S tor python-pip python-pysocks python-pycryptodome python-beautifulsoup4 imagemagick +sudo pacman -S tor python-pip python-pysocks python-pycryptodome python-beautifulsoup4 imagemagick python-pillow python-numpy sudo pip install commentjson ``` diff --git a/blurhash.py b/blurhash.py new file mode 100644 index 00000000..3ed47e73 --- /dev/null +++ b/blurhash.py @@ -0,0 +1,254 @@ +""" +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 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~" +alphabet_values = dict(zip(alphabet, range(len(alphabet)))) + +def base83_decode(base83_str): + """ + Decodes a base83 string, as used in blurhash, to an integer. + """ + value = 0 + for base83_char in base83_str: + value = value * 83 + alphabet_values[base83_char] + return value + +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_components(blurhash): + """ + Decodes and returns the number of x and y components in the given blurhash. + """ + if len(blurhash) < 6: + raise ValueError("BlurHash must be at least 6 characters long.") + + # Decode metadata + size_info = base83_decode(blurhash[0]) + size_y = int(size_info / 9) + 1 + size_x = (size_info % 9) + 1 + + return size_x, size_y + +def blurhash_decode(blurhash, width, height, punch = 1.0, linear = False): + """ + Decodes the given blurhash to an image of the specified size. + + Returns the resulting image a list of lists of 3-value sRGB 8 bit integer + lists. Set linear to True if you would prefer to get linear floating point + RGB back. + + The punch parameter can be used to de- or increase the contrast of the + resulting image. + + As per the original implementation it is suggested to only decode + to a relatively small size and then scale the result up, as it + basically looks the same anyways. + """ + if len(blurhash) < 6: + raise ValueError("BlurHash must be at least 6 characters long.") + + # Decode metadata + size_info = base83_decode(blurhash[0]) + size_y = int(size_info / 9) + 1 + size_x = (size_info % 9) + 1 + + quant_max_value = base83_decode(blurhash[1]) + real_max_value = (float(quant_max_value + 1) / 166.0) * punch + + # Make sure we at least have the right number of characters + if len(blurhash) != 4 + 2 * size_x * size_y: + raise ValueError("Invalid BlurHash length.") + + # Decode DC component + dc_value = base83_decode(blurhash[2:6]) + colours = [( + srgb_to_linear(dc_value >> 16), + srgb_to_linear((dc_value >> 8) & 255), + srgb_to_linear(dc_value & 255) + )] + + # Decode AC components + for component in range(1, size_x * size_y): + ac_value = base83_decode(blurhash[4+component*2:4+(component+1)*2]) + colours.append(( + sign_pow((float(int(ac_value / (19 * 19))) - 9.0) / 9.0, 2.0) * real_max_value, + sign_pow((float(int(ac_value / 19) % 19) - 9.0) / 9.0, 2.0) * real_max_value, + sign_pow((float(ac_value % 19) - 9.0) / 9.0, 2.0) * real_max_value + )) + + # Return image RGB values, as a list of lists of lists, + # consumable by something like numpy or PIL. + pixels = [] + for y in range(height): + pixel_row = [] + for x in range(width): + pixel = [0.0, 0.0, 0.0] + + for j in range(size_y): + for i in range(size_x): + basis = math.cos(math.pi * float(x) * float(i) / float(width)) * \ + math.cos(math.pi * float(y) * float(j) / float(height)) + colour = colours[i + j * size_x] + pixel[0] += colour[0] * basis + pixel[1] += colour[1] * basis + pixel[2] += colour[2] * basis + if linear == False: + pixel_row.append([ + linear_to_srgb(pixel[0]), + linear_to_srgb(pixel[1]), + linear_to_srgb(pixel[2]), + ]) + else: + pixel_row.append(pixel) + pixels.append(pixel_row) + return pixels + +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 == 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:]: + ac_values.append( + int(max(0.0, min(18.0, math.floor(sign_pow(r / ac_component_norm_factor, 0.5) * 9.0 + 9.5)))) * 19 * 19 + \ + int(max(0.0, min(18.0, math.floor(sign_pow(g / ac_component_norm_factor, 0.5) * 9.0 + 9.5)))) * 19 + \ + int(max(0.0, min(18.0, math.floor(sign_pow(b / ac_component_norm_factor, 0.5) * 9.0 + 9.5)))) + ) + + # Build final blurhash + blurhash = "" + blurhash += base83_encode((components_x - 1) + (components_y - 1) * 9, 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/epicyon.py b/epicyon.py index 89dd7d51..2842c399 100644 --- a/epicyon.py +++ b/epicyon.py @@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" + from person import createPerson from person import createSharedInbox from person import createCapabilitiesInbox @@ -442,6 +443,7 @@ if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain): createPerson(baseDir,nickname,domain,port,httpPrefix,True,adminPassword) if args.testdata: + useBlurhash=False nickname='testuser567' print('Generating some test data for user: '+nickname) createPerson(baseDir,nickname,domain,port,httpPrefix,True,'likewhateveryouwantscoob') @@ -449,15 +451,15 @@ if args.testdata: deleteAllPosts(baseDir,nickname,domain,'outbox') followPerson(baseDir,nickname,domain,'admin',domain,federationList,True) followerOfPerson(baseDir,nickname,domain,'admin',domain,federationList,True) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"like, this is totally just a test, man",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Zoiks!!!",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Hey scoob we need like a hundred more milkshakes",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Getting kinda spooky around here",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"And they would have gotten away with it too if it wasn't for those pesky hackers",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"man, these centralized sites are, like, the worst!",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"another mystery solved hey",False,True,False) - createPublicPost(baseDir,nickname,domain,port,httpPrefix,"let's go bowling",False,True,False) - + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"like, this is totally just a test, man",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Zoiks!!!",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Hey scoob we need like a hundred more milkshakes",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"Getting kinda spooky around here",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"And they would have gotten away with it too if it wasn't for those pesky hackers",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"man, these centralized sites are, like, the worst!",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"another mystery solved hey",False,True,False,None,None,useBlurhash) + createPublicPost(baseDir,nickname,domain,port,httpPrefix,"let's go bowling",False,True,False,None,None,useBlurhash) + runDaemon(baseDir,domain,port,httpPrefix,federationList, \ args.noreply,args.nolike,args.nopics, \ args.noannounce,args.cw,ocapAlways,useTor,debug) diff --git a/media.py b/media.py new file mode 100644 index 00000000..9ec15e45 --- /dev/null +++ b/media.py @@ -0,0 +1,92 @@ +__filename__ = "media.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "0.0.1" +__maintainer__ = "Bob Mottram" +__email__ = "bob@freedombone.net" +__status__ = "Production" + +from blurhash import blurhash_encode as blurencode +from PIL import Image +import numpy +import os +import json +import commentjson +import datetime +from auth import createPassword +from shutil import copyfile + +def getImageHash(imageFilename: str): + return blurencode(numpy.array(Image.open("img/logo.png").convert("RGB"))) + +def isImage(imageFilename: str) -> bool: + if imageFilename.endswith('.png') or \ + imageFilename.endswith('.jpg') or \ + imageFilename.endswith('.gif'): + return True + return False + +def createMediaPath(baseDir: str,weeksSinceEpoch: int) -> None: + if not os.path.isdir(baseDir+'/media'): + os.mkdir(baseDir+'/media') + if not os.path.isdir(baseDir+'/media/'+str(weeksSinceEpoch)): + os.mkdir(baseDir+'/media/'+str(weeksSinceEpoch)) + +def attachImage(baseDir: str,httpPrefix: str,domain: str,port: int, \ + postJson: {},imageFilename: str,description: str, \ + useBlurhash: bool) -> {}: + """Attaches an image 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 isImage(imageFilename): + return postJson + + mediaType='image/png' + fileExtension='png' + if imageFilename.endswith('.jpg'): + mediaType='image/jpeg' + fileExtension='jpg' + if imageFilename.endswith('.gif'): + mediaType='image/gif' + fileExtension='gif' + + if port!=80 and port!=443: + if ':' not in domain: + domain=domain+':'+str(port) + + currTime=datetime.datetime.utcnow() + weeksSinceEpoch=(currTime - datetime.datetime(1970,1,1)).days/7 + createMediaPath(baseDir,weeksSinceEpoch) + mediaPath='media/'+str(weeksSinceEpoch)+'/'+createPassword(32)+'.'+fileExtension + mediaFilename=baseDir+'/'+mediaPath + + attachmentJson={ + 'mediaType': mediaType, + 'name': description, + 'type': 'Document', + 'url': httpPrefix+'://'+domain+'/'+mediaPath + } + if useBlurhash: + attachmentJson['blurhash']=getImageHash(imageFilename) + postJson['attachment']=[attachmentJson] + + copyfile(imageFilename,mediaFilename) + + return postJson + +def removeAttachment(baseDir: str,httpPrefix: str,domain: str,postJson: {}): + if not postJson.get('attachment'): + return + if not postJson['attachment'][0].get('url'): + return + if port!=80 and port!=443: + if ':' not in domain: + domain=domain+':'+str(port) + attachmentUrl=postJson['attachment'][0]['url'] + if not attachmentUrl: + return + mediaFilename=baseDir+'/'+attachmentUrl.replace(httpPrefix+'://'+domain+'/','') + if os.path.isfile(mediaFilename): + os.remove(mediaFilename) + postJson['attachment']=[] diff --git a/posts.py b/posts.py index d2919386..b62aa5a4 100644 --- a/posts.py +++ b/posts.py @@ -34,6 +34,7 @@ from utils import getNicknameFromActor from utils import getDomainFromActor from capabilities import getOcapFilename from capabilities import capabilitiesUpdate +from media import attachImage try: from BeautifulSoup import BeautifulSoup except ImportError: @@ -321,7 +322,8 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ toUrl: str, ccUrl: str, httpPrefix: str, content: str, \ - followersOnly: bool, saveToFile: bool, clientToServer: bool, \ + followersOnly: bool, saveToFile: bool, clientToServer: bool, + attachImageFilename: str,imageDescription: str,useBlurhash: bool, \ inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}: """Creates a message """ @@ -396,6 +398,11 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ } } } + if attachImageFilename: + newPost['object']= \ + attachImage(baseDir,httpPrefix,domain,port, \ + postJson['object'],attachImageFilename, \ + imageDescription,useBlurhash) else: newPost = { 'id': newPostId, @@ -417,8 +424,21 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ }, 'attachment': [], 'tag': [], - 'replies': {} + 'replies': { + 'id': 'https://'+domain+'/users/'+nickname+'/statuses/'+statusNumber+'/replies', + 'type': 'Collection', + 'first': { + 'type': 'CollectionPage', + 'partOf': 'https://'+domain+'/users/'+nickname+'/statuses/'+statusNumber+'/replies', + 'items': [] + } + } } + if attachImageFilename: + newPost= \ + attachImage(baseDir,httpPrefix,domain,port, \ + postJson,attachImageFilename, \ + imageDescription,useBlurhash) if ccUrl: if len(ccUrl)>0: newPost['cc']=ccUrl @@ -490,6 +510,7 @@ def createPublicPost(baseDir: str, nickname: str, domain: str, port: int,httpPrefix: str, \ content: str, followersOnly: bool, saveToFile: bool, clientToServer: bool,\ + attachImageFilename: str,imageDescription: str,useBlurhash: bool, \ inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}: """Public post to the outbox """ @@ -498,6 +519,7 @@ def createPublicPost(baseDir: str, httpPrefix+'://'+domain+'/users/'+nickname+'/followers', \ httpPrefix, content, followersOnly, saveToFile, \ clientToServer, \ + attachImageFilename,imageDescription,useBlurhash, \ inReplyTo, inReplyToAtomUri, subject) def threadSendPost(session,postJsonObject: {},federationList: [],\ @@ -536,6 +558,7 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \ toNickname: str, toDomain: str, toPort: int, cc: str, \ httpPrefix: str, content: str, followersOnly: bool, \ saveToFile: bool, clientToServer: bool, \ + attachImageFilename: str,imageDescription: str,useBlurhash: bool, \ federationList: [],\ sendThreads: [], postLog: [], cachedWebfingers: {},personCache: {}, \ debug=False,inReplyTo=None,inReplyToAtomUri=None,subject=None) -> int: @@ -585,6 +608,7 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \ createPostBase(baseDir,nickname,domain,port, \ toPersonId,cc,httpPrefix,content, \ followersOnly,saveToFile,clientToServer, \ + attachImageFilename,imageDescription,useBlurhash, \ inReplyTo,inReplyToAtomUri,subject) # get the senders private key diff --git a/tests.py b/tests.py index 01ad3274..a8d18120 100644 --- a/tests.py +++ b/tests.py @@ -131,6 +131,7 @@ def createServerAlice(path: str,domain: str,port: int,federationList: [],hasFoll nopics=False noannounce=False cw=False + useBlurhash=True privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,httpPrefix,True,password) deleteAllPosts(path,nickname,domain,'inbox') deleteAllPosts(path,nickname,domain,'outbox') @@ -138,9 +139,9 @@ def createServerAlice(path: str,domain: str,port: int,federationList: [],hasFoll followPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList,True) followerOfPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList,True) if hasPosts: - createPublicPost(path,nickname, domain, port,httpPrefix, "No wise fish would go anywhere without a porpoise", False, True, clientToServer) - createPublicPost(path,nickname, domain, port,httpPrefix, "Curiouser and curiouser!", False, True, clientToServer) - createPublicPost(path,nickname, domain, port,httpPrefix, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True, clientToServer) + createPublicPost(path,nickname, domain, port,httpPrefix, "No wise fish would go anywhere without a porpoise", False, True, clientToServer,None,None,useBlurhash) + createPublicPost(path,nickname, domain, port,httpPrefix, "Curiouser and curiouser!", False, True, clientToServer,None,None,useBlurhash) + createPublicPost(path,nickname, domain, port,httpPrefix, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True, clientToServer,None,None,useBlurhash) global testServerAliceRunning testServerAliceRunning = True print('Server running: Alice') @@ -162,6 +163,7 @@ def createServerBob(path: str,domain: str,port: int,federationList: [],hasFollow nopics=False noannounce=False cw=False + useBlurhash=False privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,httpPrefix,True,password) deleteAllPosts(path,nickname,domain,'inbox') deleteAllPosts(path,nickname,domain,'outbox') @@ -169,9 +171,9 @@ def createServerBob(path: str,domain: str,port: int,federationList: [],hasFollow followPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList,True) followerOfPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList,True) if hasPosts: - createPublicPost(path,nickname, domain, port,httpPrefix, "It's your life, live it your way.", False, True, clientToServer) - createPublicPost(path,nickname, domain, port,httpPrefix, "One of the things I've realised is that I am very simple", False, True, clientToServer) - createPublicPost(path,nickname, domain, port,httpPrefix, "Quantum physics is a bit of a passion of mine", False, True, clientToServer) + createPublicPost(path,nickname, domain, port,httpPrefix, "It's your life, live it your way.", False, True, clientToServer,None,None,useBlurhash) + createPublicPost(path,nickname, domain, port,httpPrefix, "One of the things I've realised is that I am very simple", False, True, clientToServer,None,None,useBlurhash) + createPublicPost(path,nickname, domain, port,httpPrefix, "Quantum physics is a bit of a passion of mine", False, True, clientToServer,None,None,useBlurhash) global testServerBobRunning testServerBobRunning = True print('Server running: Bob') @@ -257,12 +259,12 @@ def testPostMessageBetweenServers(): ccUrl=None alicePersonCache={} aliceCachedWebfingers={} - + useBlurhash=False # nothing in Alice's outbox outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox' assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==0 - sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject) + sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer,None,None,useBlurhash, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject) print('sendResult: '+str(sendResult)) queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue' @@ -469,7 +471,8 @@ def testFollowBetweenServers(): eveCachedWebfingers={} eveSendThreads=[] evePostLog=[] - sendResult = sendPost(sessionEve,eveDir,'eve', eveDomain, evePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Eve message', followersOnly, saveToFile, clientToServer, federationList, eveSendThreads, evePostLog, eveCachedWebfingers,evePersonCache,inReplyTo, inReplyToAtomUri, subject) + useBlurhash=False + sendResult = sendPost(sessionEve,eveDir,'eve', eveDomain, evePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Eve message', followersOnly, saveToFile, clientToServer,None,None,useBlurhash, federationList, eveSendThreads, evePostLog, eveCachedWebfingers,evePersonCache,inReplyTo, inReplyToAtomUri, subject) print('sendResult: '+str(sendResult)) queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue' @@ -495,7 +498,8 @@ def testFollowBetweenServers(): aliceCachedWebfingers={} aliceSendThreads=[] alicePostLog=[] - sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Alice message', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject) + useBlurhash=False + sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Alice message', followersOnly, saveToFile, clientToServer,None,None,useBlurhash, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject) print('sendResult: '+str(sendResult)) queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue' @@ -783,6 +787,7 @@ def testCreatePerson(): port=80 httpPrefix='https' clientToServer=False + useBlurhash=False baseDir=currDir+'/.tests_createperson' if os.path.isdir(baseDir): shutil.rmtree(baseDir) @@ -797,7 +802,7 @@ def testCreatePerson(): setBio(baseDir,nickname,domain,'Randomly roaming in your backyard') archivePosts(nickname,domain,baseDir,'inbox',4) archivePosts(nickname,domain,baseDir,'outbox',4) - createPublicPost(baseDir,nickname, domain, port,httpPrefix, "G'day world!", False, True, clientToServer, None, None, 'Not suitable for Vogons') + createPublicPost(baseDir,nickname, domain, port,httpPrefix, "G'day world!", False, True, clientToServer,None,None,useBlurhash, None, None, 'Not suitable for Vogons') os.chdir(currDir) shutil.rmtree(baseDir)