Package: pydispix
PyDisPixA simple wrapper aroundPython Discord Pixels.
Check it out onPyPI.ExamplesMain usageimportpydispix# Create a client with your token.client=pydispix.Client('my-auth-token')# Fetch a specific pixel.print(client.get_pixel(4,10))# Draw a pixel.client.put_pixel(50,10,'cyan')client.put_pixel(1,5,pydispix.Color.BLURPLE)client.put_pixel(100,4,'93FF00')client.put_pixel(44,0,0xFF0000)client.put_pixel(8,54,(255,255,255))CanvasWe can also work with the whole pixels canvas# Fetch the canvascanvas=client.get_canvas()# Show the canvas using matplotlib, this will include coordinatescanvas.show()# Save the canvas to a filecanvas.save('canvas.png')# And access pixels from it.print(canvas[4,10])Draw image from pngLoad an image:fromPILimportImageim=Image.open('pretty.png')ad=pydispix.AutoDrawer.load_image(client,(5,40),im,scale=0.1)ad.draw()Auto-draw will avoid colouring already correct pixels, for efficiency.You can also run this continually withguard=Truewhich makes sure that after your image
is drawn, this keeps running to check if it haven't been tampered with, and fixes all non-matching
pixels.ad.draw(guard=True,guard_delay=2)guard_delayis the delay between each full iteration of all pixels. We need to wait since
looping without any changes is almost instant in python, and we don't want to put cpu through that
stress for no reasonDraw multiple imagesYou can also draw multiple images one by onefromPILimportImagefrompydispiximportClient,AutoDrawerclient=Client("pixels_api_token")positions=[(52,14),(120,54)]images=[Image("img1.png"),Image("img2.png")]scales=[0.5,1]ad=AutoDrawer.load_images(client,positions,images,scales,one_by_one=True)ad.draw()This will proceed to start drawing the images in order they were passed. You could also
setone_by_onetoFalse, which would cause the images to instead be drawn by pixel
from each, i.e. 1st pixel from img1, 1st pixel from img2, 2nd from img1, 2nd from img2, ...Collaborate on image drawingYou can share the load of drawing a single image between multiple joined clients.
This will mean each client will only ever work on it's part of given image, both when guarding and drawing it.fromPILimportImagefrompydispiximportDistributedClient,DistributedAutoDrawer# First machinemulti_client=DistributedClient('pixels_api_key',total_tasks=2,controlled_tasks=[0])# Second machine#multi_client = MultiClient('pixels_api_key2', total_tasks=2 ,controlled_tasks=[1])image=Image.open('my_img.png')auto_drawer=DistributedAutoDrawer.load_image(multi_client,(2,10),image,scale=0.8)auto_drawer.draw(guard=True)total_tasksis the number of clients you will have in total, i.e. the number of workers
for shared tasks. It's how many groups will the shared pixels be split into.controlled_tasksare the groups controlled by thisMultiClientinstance. This is usually
only 1 task, but you can specify multiple tasks and split the code further.ChurchesChurches are groups of people collaborating on some image, or set of images on the canvas.
It's basically a big botnet of people. Most popular church is currently theChurch Of Rick. Churches provide it's members with
tasks to fill certain pixels, and the members finish those tasks and report it back to the church.
This is how you run a single task like this with Church of Rick:frompydispix.churchesimportRickChurchClientclient=RickChurchClient(pixels_api_token,rick_church_api_token)client.run_task(show_progress=True)Church of SQLite is also supported, and they don't require an API key, it is free for everyone:frompydispix.churchesimportSQLiteChurchClientclient=SQLiteChurchClient(pixels_api_token)client.run_task()Continually running church tasksIf you wish to keep running church tasks continually in a loop, make sure to useclient.run_tasks(),
avoidclient.run_task()since it doesn't handle any errors specific to the used church,client.run_tasks()will handle these errors cleanly and log the problems if some ocurred.Note:client.run_tasks()only handles known exceptions, there might still be some exceptions that a church
could raise which aren't handled. If you manage to find one make sure to file an issue about it.Example of safe continual script to keep running church tasks on your machine:importpickleimporttimefrompydispix.churchesimportRickChurchClientclient=RickChurchClient(pixels_api_token,rick_church_api_token)exception_amt=0whileTrue:try:client.run_tasks(show_progress=True)exceptExceptionasexc:print(f"Exception ocurred:{exc}(#{exception_amt})")withopen(f"exception{exception_amt}.pickle","wb")asf:pickle.dump(exc,f)exception_amt+=1time.sleep(5)There is still exception handling here, but it shouldn't capture any, it's only here since you'll
likely not be there to monitor the process all the time, so even in the rare case that something
were to occur, the program will keep running and the exception will stored with pickle.If you see that this happened (if you findexceptionX.picklefiles in your working directory),
load the pickled exception and examine what exactly happened. Upload the traceback with the issue.importpicklewithopen("exception0.pickle","rb")asf:exc=pickle.load(f)raiseexcImportant: do not upload the pickle file anywhere, it contains the request, which includes your
API keys, uploading the pickled file would inevitable lead to leaked API key.Other churchesYou can also implement your own church according to it's specific API requirements, if you're
interested in doing this, check thechurch.pyand how the specific churches
are implemented using it:churches.py.If you do end up implementing it, feel free to also open a pull request and add it, if the church
is popular enough, you have a good chance of it being added to officialpydispix.Progress barsEvery request that has rate limits can now display a progress bar while it's sleeping on cooldown:pixel=client.get_pixel(0,0,show_progress=True)canvas=client.get_canvas(show_progress=True)client.put_pixel(52,10,"FFFFFF",show_progress=True)https://user-images.githubusercontent.com/20902250/119607092-418e4200-bde3-11eb-9ac5-4e455ffd47c2.mp4LoggingTo see logs, you can set theDEBUGenvironment variable, which changes the loglevel fromlogging.INFOtologging.DEBUGYou can also do this manually by executing:importlogginglogger=logging.getLogger("pydispix")logger.setLevel(logging.DEBUG)