From 94dce81f3feec64fb82229b4f34a1cbb7bfa79d2 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 22:38:42 -0400 Subject: [PATCH 01/14] Fix proxy and Tor again --- main.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index 275d0774..16d40c7c 100755 --- a/main.py +++ b/main.py @@ -109,7 +109,11 @@ def set_pixel_and_check_ratelimit( } response = requests.request( - "POST", url, headers=headers, data=payload, proxies=proxy.get_random_proxy() + "POST", + url, + headers=headers, + data=payload, + proxies=proxy.get_random_proxy(self), ) logger.debug("Thread #{} : Received response: {}", thread_index, response.text) @@ -260,7 +264,7 @@ def get_board(self, access_token_in): requests.get( msg["data"]["name"], stream=True, - proxies=proxy.get_random_proxy(), + proxies=proxy.get_random_proxy(self), ).content ) ), @@ -465,12 +469,17 @@ def task(self, index, name, worker): while True: try: client = requests.Session() + client.proxies = proxy.get_random_proxy(self) client.headers.update( { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36" } ) - r = client.get("https://www.reddit.com/login") + + r = client.get( + "https://www.reddit.com/login", + proxies=proxy.get_random_proxy(self), + ) login_get_soup = BeautifulSoup(r.content, "html.parser") csrf_token = login_get_soup.find( "input", {"name": "csrf_token"} @@ -485,7 +494,7 @@ def task(self, index, name, worker): r = client.post( "https://www.reddit.com/login", data=data, - proxies=proxy.get_random_proxy(), + proxies=proxy.get_random_proxy(self), ) break except Exception: @@ -502,7 +511,9 @@ def task(self, index, name, worker): else: logger.success("Authorization successful!") logger.info("Obtaining access token...") - r = client.get("https://new.reddit.com/") + r = client.get( + "https://new.reddit.com/", proxies=proxy.get_random_proxy(self) + ) data_str = ( BeautifulSoup(r.content, features="html.parser") .find("script", {"id": "data"}) From eb4bc72732f4c1aa738af9a3a51a0a43a8aace08 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 22:39:09 -0400 Subject: [PATCH 02/14] Fix proxy --- src/proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proxy.py b/src/proxy.py index 5a8f9e1a..66d47dc4 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -112,7 +112,7 @@ def get_random_proxy(self): return random_proxy return random_proxy else: - tor_reconnect() + tor_reconnect(self) self.logger.debug("Using Tor. Selecting first proxy: {}.", str(self.proxies[0])) return self.proxies[0] From 2616c4753aa989e6e543d4bd5a659b12d51a7801 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 22:56:53 -0400 Subject: [PATCH 03/14] Remove self. from some things --- src/proxy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/proxy.py b/src/proxy.py index 66d47dc4..d0564c54 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -8,14 +8,14 @@ def Init(self): self.proxies = ( - self.GetProxies(self.json_data["proxies"]) + get_proxies(self.json_data["proxies"]) if "proxies" in self.json_data and self.json_data["proxies"] is not None else None ) if self.proxies is None and os.path.exists( os.path.join(os.getcwd(), "proxies.txt") ): - self.proxies = self.get_proxies_text() + self.proxies = get_proxies_text() self.compactlogging = ( self.json_data["compact_logging"] if "compact_logging" in self.json_data From eb7820e06aef622d5802d936fc707aada0c15ffb Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:30:09 -0400 Subject: [PATCH 04/14] Personal Proxy Update --- src/proxy.py | 260 ++++++++++++++++++++++++++------------------------- 1 file changed, 132 insertions(+), 128 deletions(-) diff --git a/src/proxy.py b/src/proxy.py index d0564c54..8caea152 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -1,128 +1,132 @@ -import os -import random -import subprocess -import time -from stem import Signal, InvalidArguments, SocketError, ProtocolError -from stem.control import Controller - - -def Init(self): - self.proxies = ( - get_proxies(self.json_data["proxies"]) - if "proxies" in self.json_data and self.json_data["proxies"] is not None - else None - ) - if self.proxies is None and os.path.exists( - os.path.join(os.getcwd(), "proxies.txt") - ): - self.proxies = get_proxies_text() - self.compactlogging = ( - self.json_data["compact_logging"] - if "compact_logging" in self.json_data - and self.json_data["compact_logging"] is not None - else True - ) - self.using_tor = ( - self.json_data["using_tor"] - if "using_tor" in self.json_data and self.json_data["using_tor"] is not None - else False - ) - self.tor_password = ( - self.json_data["tor_password"] - if "tor_password" in self.json_data - and self.json_data["tor_password"] is not None - else "Passwort" # this is intentional, as I don't really want to mess around with the torrc again - ) - self.tor_delay = ( - self.json_data["tor_delay"] - if "tor_delay" in self.json_data and self.json_data["tor_delay"] is not None - else 10 - ) - self.use_builtin_tor = ( - self.json_data["use_builtin_tor"] - if "use_builtin_tor" in self.json_data - and self.json_data["use_builtin_tor"] is not None - else True - ) - self.tor_port = ( - self.json_data["tor_port"] - if "tor_port" in self.json_data and self.json_data["tor_port"] is not None - else 1881 - ) - self.tor_control_port = ( - self.json_data["tor_control_port"] - if "tor_port" in self.json_data - and self.json_data["tor_control_port"] is not None - else 9051 - ) - - # tor connection - if self.using_tor: - self.proxies = get_proxies(self, ["127.0.0.1:" + str(self.tor_port)]) - if self.use_builtin_tor: - subprocess.Popen( - '"' - + os.path.join(os.getcwd(), "./tor/Tor/tor.exe") - + '"' - + " --defaults-torrc " - + '"' - + os.path.join(os.getcwd(), "./Tor/Tor/torrc") - + '"' - + " --HTTPTunnelPort " - + str(self.tor_port), - shell=True, - ) - try: - self.tor_controller = Controller.from_port(port=self.tor_control_port) - self.tor_controller.authenticate(self.tor_password) - self.logger.info("successfully connected to tor!") - except (ValueError, SocketError): - self.logger.error("connection to tor failed, disabling tor") - self.using_tor = False - - -def get_proxies_text(self): - path_proxies = os.path.join(os.getcwd(), "proxies.txt") - f = open(path_proxies) - file = f.read() - f.close() - proxies_list = file.splitlines() - self.proxies = [] - for i in proxies_list: - self.proxies.append({"https": i, "http": i}) - self.logger.debug("loaded proxies {} from file {}", i, path_proxies) - - -def get_proxies(self, proxies): - proxies_list = [] - for i in proxies: - proxies_list.append({"https": i, "http": i}) - - self.logger.debug("Loaded proxies: {}", str(proxies_list)) - return proxies_list - return proxies_list - - -def get_random_proxy(self): - if not self.using_tor: - random_proxy = None - if self.proxies is not None: - random_proxy = self.proxies[random.randint(0, len(self.proxies) - 1)] - self.logger.debug("Using proxy: {}", str(random_proxy)) - return random_proxy - return random_proxy - else: - tor_reconnect(self) - self.logger.debug("Using Tor. Selecting first proxy: {}.", str(self.proxies[0])) - return self.proxies[0] - - -def tor_reconnect(self): - if self.using_tor: - try: - self.tor_controller.signal(Signal.NEWNYM) - self.logger.info("New Tor connection processing") - time.sleep(self.tor_delay) - except (InvalidArguments, ProtocolError): - self.logger.error("couldn't establish new tor connection, disabling tor") - self.using_tor = False +import os +import random +import subprocess +import time +from stem import Signal, InvalidArguments, SocketError, ProtocolError +from stem.control import Controller + + +def Init(self): + self.proxies = ( + get_proxies(self.json_data["proxies"]) + if "proxies" in self.json_data and self.json_data["proxies"] is not None + else None + ) + if self.proxies is None and os.path.exists( + os.path.join(os.getcwd(), "proxies.txt") + ): + self.proxies = get_proxies_text() + self.compactlogging = ( + self.json_data["compact_logging"] + if "compact_logging" in self.json_data + and self.json_data["compact_logging"] is not None + else True + ) + self.using_tor = ( + self.json_data["using_tor"] + if "using_tor" in self.json_data and self.json_data["using_tor"] is not None + else False + ) + self.tor_password = ( + self.json_data["tor_password"] + if "tor_password" in self.json_data + and self.json_data["tor_password"] is not None + else "Passwort" # this is intentional, as I don't really want to mess around with the torrc again + ) + self.tor_delay = ( + self.json_data["tor_delay"] + if "tor_delay" in self.json_data and self.json_data["tor_delay"] is not None + else 10 + ) + self.use_builtin_tor = ( + self.json_data["use_builtin_tor"] + if "use_builtin_tor" in self.json_data + and self.json_data["use_builtin_tor"] is not None + else True + ) + self.tor_port = ( + self.json_data["tor_port"] + if "tor_port" in self.json_data and self.json_data["tor_port"] is not None + else 1881 + ) + self.tor_control_port = ( + self.json_data["tor_control_port"] + if "tor_port" in self.json_data + and self.json_data["tor_control_port"] is not None + else 9051 + ) + + # tor connection + if self.using_tor: + self.proxies = get_proxies(self, ["127.0.0.1:" + str(self.tor_port)]) + if self.use_builtin_tor: + subprocess.Popen( + '"' + + os.path.join(os.getcwd(), "./tor/Tor/tor.exe") + + '"' + + " --defaults-torrc " + + '"' + + os.path.join(os.getcwd(), "./Tor/Tor/torrc") + + '"' + + " --HTTPTunnelPort " + + str(self.tor_port), + shell=True, + ) + try: + self.tor_controller = Controller.from_port(port=self.tor_control_port) + self.tor_controller.authenticate(self.tor_password) + self.logger.info("successfully connected to tor!") + except (ValueError, SocketError): + self.logger.error("connection to tor failed, disabling tor") + self.using_tor = False + + +def get_proxies_text(self): + path_proxies = os.path.join(os.getcwd(), "proxies.txt") + f = open(path_proxies) + file = f.read() + f.close() + proxies_list = file.splitlines() + self.proxies = [] + for i in proxies_list: + self.proxies.append({"https": i, "http": i}) + self.logger.debug("loaded proxies {} from file {}", i, path_proxies) + + +def get_proxies(self, proxies): + proxies_list = [] + for i in proxies: + proxies_list.append({"https": i, "http": i}) + + self.logger.debug("Loaded proxies: {}", str(proxies_list)) + return proxies_list + return proxies_list + +def get_random_proxy(self, name): + if not self.using_tor: + random_proxy = None + if name is not None: + if self.json_data["workers"][name]["personal_proxy"] is not None: + proxy = self.json_data["workers"][name]["personal_proxy"] + return {"https": proxy, "http": proxy} + if self.proxies is not None: + random_proxy = self.proxies[random.randint(0, len(self.proxies) - 1)] + self.logger.debug("Using proxy: {}", str(random_proxy)) + return random_proxy + + return random_proxy + else: + tor_reconnect(self) + self.logger.debug("Using Tor. Selecting first proxy: {}.", str(self.proxies[0])) + return self.proxies[0] + + +def tor_reconnect(self): + if self.using_tor: + try: + self.tor_controller.signal(Signal.NEWNYM) + self.logger.info("New Tor connection processing") + time.sleep(self.tor_delay) + except (InvalidArguments, ProtocolError): + self.logger.error("couldn't establish new tor connection, disabling tor") + self.using_tor = False From bd771ce06c7ce6cbbbeb530a4d1bc0df1104c14b Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:30:35 -0400 Subject: [PATCH 05/14] Personal Proxy Update --- src/proxy.py | 264 +++++++++++++++++++++++++-------------------------- 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/src/proxy.py b/src/proxy.py index 8caea152..bdfa7dbd 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -1,132 +1,132 @@ -import os -import random -import subprocess -import time -from stem import Signal, InvalidArguments, SocketError, ProtocolError -from stem.control import Controller - - -def Init(self): - self.proxies = ( - get_proxies(self.json_data["proxies"]) - if "proxies" in self.json_data and self.json_data["proxies"] is not None - else None - ) - if self.proxies is None and os.path.exists( - os.path.join(os.getcwd(), "proxies.txt") - ): - self.proxies = get_proxies_text() - self.compactlogging = ( - self.json_data["compact_logging"] - if "compact_logging" in self.json_data - and self.json_data["compact_logging"] is not None - else True - ) - self.using_tor = ( - self.json_data["using_tor"] - if "using_tor" in self.json_data and self.json_data["using_tor"] is not None - else False - ) - self.tor_password = ( - self.json_data["tor_password"] - if "tor_password" in self.json_data - and self.json_data["tor_password"] is not None - else "Passwort" # this is intentional, as I don't really want to mess around with the torrc again - ) - self.tor_delay = ( - self.json_data["tor_delay"] - if "tor_delay" in self.json_data and self.json_data["tor_delay"] is not None - else 10 - ) - self.use_builtin_tor = ( - self.json_data["use_builtin_tor"] - if "use_builtin_tor" in self.json_data - and self.json_data["use_builtin_tor"] is not None - else True - ) - self.tor_port = ( - self.json_data["tor_port"] - if "tor_port" in self.json_data and self.json_data["tor_port"] is not None - else 1881 - ) - self.tor_control_port = ( - self.json_data["tor_control_port"] - if "tor_port" in self.json_data - and self.json_data["tor_control_port"] is not None - else 9051 - ) - - # tor connection - if self.using_tor: - self.proxies = get_proxies(self, ["127.0.0.1:" + str(self.tor_port)]) - if self.use_builtin_tor: - subprocess.Popen( - '"' - + os.path.join(os.getcwd(), "./tor/Tor/tor.exe") - + '"' - + " --defaults-torrc " - + '"' - + os.path.join(os.getcwd(), "./Tor/Tor/torrc") - + '"' - + " --HTTPTunnelPort " - + str(self.tor_port), - shell=True, - ) - try: - self.tor_controller = Controller.from_port(port=self.tor_control_port) - self.tor_controller.authenticate(self.tor_password) - self.logger.info("successfully connected to tor!") - except (ValueError, SocketError): - self.logger.error("connection to tor failed, disabling tor") - self.using_tor = False - - -def get_proxies_text(self): - path_proxies = os.path.join(os.getcwd(), "proxies.txt") - f = open(path_proxies) - file = f.read() - f.close() - proxies_list = file.splitlines() - self.proxies = [] - for i in proxies_list: - self.proxies.append({"https": i, "http": i}) - self.logger.debug("loaded proxies {} from file {}", i, path_proxies) - - -def get_proxies(self, proxies): - proxies_list = [] - for i in proxies: - proxies_list.append({"https": i, "http": i}) - - self.logger.debug("Loaded proxies: {}", str(proxies_list)) - return proxies_list - return proxies_list - -def get_random_proxy(self, name): - if not self.using_tor: - random_proxy = None - if name is not None: - if self.json_data["workers"][name]["personal_proxy"] is not None: - proxy = self.json_data["workers"][name]["personal_proxy"] - return {"https": proxy, "http": proxy} - if self.proxies is not None: - random_proxy = self.proxies[random.randint(0, len(self.proxies) - 1)] - self.logger.debug("Using proxy: {}", str(random_proxy)) - return random_proxy - - return random_proxy - else: - tor_reconnect(self) - self.logger.debug("Using Tor. Selecting first proxy: {}.", str(self.proxies[0])) - return self.proxies[0] - - -def tor_reconnect(self): - if self.using_tor: - try: - self.tor_controller.signal(Signal.NEWNYM) - self.logger.info("New Tor connection processing") - time.sleep(self.tor_delay) - except (InvalidArguments, ProtocolError): - self.logger.error("couldn't establish new tor connection, disabling tor") - self.using_tor = False +import os +import random +import subprocess +import time +from stem import Signal, InvalidArguments, SocketError, ProtocolError +from stem.control import Controller + + +def Init(self): + self.proxies = ( + get_proxies(self.json_data["proxies"]) + if "proxies" in self.json_data and self.json_data["proxies"] is not None + else None + ) + if self.proxies is None and os.path.exists( + os.path.join(os.getcwd(), "proxies.txt") + ): + self.proxies = get_proxies_text() + self.compactlogging = ( + self.json_data["compact_logging"] + if "compact_logging" in self.json_data + and self.json_data["compact_logging"] is not None + else True + ) + self.using_tor = ( + self.json_data["using_tor"] + if "using_tor" in self.json_data and self.json_data["using_tor"] is not None + else False + ) + self.tor_password = ( + self.json_data["tor_password"] + if "tor_password" in self.json_data + and self.json_data["tor_password"] is not None + else "Passwort" # this is intentional, as I don't really want to mess around with the torrc again + ) + self.tor_delay = ( + self.json_data["tor_delay"] + if "tor_delay" in self.json_data and self.json_data["tor_delay"] is not None + else 10 + ) + self.use_builtin_tor = ( + self.json_data["use_builtin_tor"] + if "use_builtin_tor" in self.json_data + and self.json_data["use_builtin_tor"] is not None + else True + ) + self.tor_port = ( + self.json_data["tor_port"] + if "tor_port" in self.json_data and self.json_data["tor_port"] is not None + else 1881 + ) + self.tor_control_port = ( + self.json_data["tor_control_port"] + if "tor_port" in self.json_data + and self.json_data["tor_control_port"] is not None + else 9051 + ) + + # tor connection + if self.using_tor: + self.proxies = get_proxies(self, ["127.0.0.1:" + str(self.tor_port)]) + if self.use_builtin_tor: + subprocess.Popen( + '"' + + os.path.join(os.getcwd(), "./tor/Tor/tor.exe") + + '"' + + " --defaults-torrc " + + '"' + + os.path.join(os.getcwd(), "./Tor/Tor/torrc") + + '"' + + " --HTTPTunnelPort " + + str(self.tor_port), + shell=True, + ) + try: + self.tor_controller = Controller.from_port(port=self.tor_control_port) + self.tor_controller.authenticate(self.tor_password) + self.logger.info("successfully connected to tor!") + except (ValueError, SocketError): + self.logger.error("connection to tor failed, disabling tor") + self.using_tor = False + + +def get_proxies_text(self): + path_proxies = os.path.join(os.getcwd(), "proxies.txt") + f = open(path_proxies) + file = f.read() + f.close() + proxies_list = file.splitlines() + self.proxies = [] + for i in proxies_list: + self.proxies.append({"https": i, "http": i}) + self.logger.debug("loaded proxies {} from file {}", i, path_proxies) + + +def get_proxies(self, proxies): + proxies_list = [] + for i in proxies: + proxies_list.append({"https": i, "http": i}) + + self.logger.debug("Loaded proxies: {}", str(proxies_list)) + return proxies_list + return proxies_list + +def get_random_proxy(self, name): + if not self.using_tor: + random_proxy = None + if name is not None: + if self.json_data["workers"][name]["personal_proxy"] is not None: + proxy = self.json_data["workers"][name]["personal_proxy"] + return {"https": proxy, "http": proxy} + if self.proxies is not None: + random_proxy = self.proxies[random.randint(0, len(self.proxies) - 1)] + self.logger.debug("Using proxy: {}", str(random_proxy)) + return random_proxy + + return random_proxy + else: + tor_reconnect(self) + self.logger.debug("Using Tor. Selecting first proxy: {}.", str(self.proxies[0])) + return self.proxies[0] + + +def tor_reconnect(self): + if self.using_tor: + try: + self.tor_controller.signal(Signal.NEWNYM) + self.logger.info("New Tor connection processing") + time.sleep(self.tor_delay) + except (InvalidArguments, ProtocolError): + self.logger.error("couldn't establish new tor connection, disabling tor") + self.using_tor = False From f819b182dd9ef5d17bdcd4f7f34038bffede4558 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:31:21 -0400 Subject: [PATCH 06/14] Personal Proxy Update --- README.md | 440 +++++++++++++++++++++++++++--------------------------- main.py | 16 +- 2 files changed, 231 insertions(+), 225 deletions(-) diff --git a/README.md b/README.md index 844b9602..86a164e3 100644 --- a/README.md +++ b/README.md @@ -1,218 +1,222 @@ -# Reddit Place Script 2022 - -[![Code style: black](./black_badge.svg)](https://github.com/psf/black) -[![forthebadge](https://forthebadge.com/images/badges/made-with-python.svg)](https://forthebadge.com) -[![forthebadge](https://forthebadge.com/images/badges/60-percent-of-the-time-works-every-time.svg)](https://forthebadge.com) - -## About - -This is a script to draw an image onto r/place (). - -## Features - -- Support for multiple accounts. -- Determines the cooldown time remaining for each account. -- Detects existing matching pixels on the r/place map and skips them. -- Automatically converts colors to the r/place color palette. -- Easy(ish) to read output with colors. -- SOCKS proxy support. -- No client id and secret needed. -- Proxies from "proxies.txt" file. -- Tor support. - -## Requirements - -- [Latest Version of Python 3](https://www.python.org/downloads/) - -## MacOSX - -If you want to use tor on MacOSX. you'll need to provide your own tor binary and start it manually. deactivate the "use_builtin tor" -option in the config and make sure you configure your tor to use the specified ports and password. - -*Please note that socks proxy connection to tor doesn't work for the time being, so the config value is for an httpTunnel port* - -## Get Started - -Move the file 'config_example.json' to config.json - -Edit the values to replace with actual credentials and values - -Note: Please use https://jsonlint.com/ to check that your JSON file is correctly formatted - -```json -{ - //Where the image's path is - "image_path": "image.png", - // [x,y] where you want the top left pixel of the local image to be drawn on canvas - "image_start_coords": [741, 610], - // delay between starting threads (can be 0) - "thread_delay": 2, - // array of accounts to use - "workers": { - // username of account 1 - "worker1username": { - // password of account 1 - "password": "password", - // which pixel of the image to draw first - "start_coords": [0, 0] - }, - // username of account 2 - "worker1username": { - // password of account 2 - "password": "password", - // which pixel of the image to draw first - "start_coords": [0, 0] - } - // etc... add as many accounts as you want (but reddit may detect you the more you add) - } -} -``` - -### Notes - -- Use `.png` if you wish to make use of transparency or non rectangular images -- If you use 2 factor authentication (2FA) in your account, then change `password` to `password:XXXXXX` where `XXXXXX` is your 2FA code. - -## Run the Script - -### Windows - -```shell -start.bat or startverbose.bat -``` - -### Unix-like (Linux, MacOS etc.) - -```shell -chmod +x start.sh startverbose.sh -./start.sh or ./startverbose.sh -``` - -**You can get more logs (`DEBUG`) by running the script with `-d` flag:** - -`python3 main.py -d` or `python3 main.py --debug` - -## Multiple Workers -Just create multiple child arrays to "workers" in the .json file: - -```json -{ - "image_path": "image.png", - "image_start_coords": [741, 610], - "thread_delay": 2, - - "workers": { - "worker1username": { - "password": "password", - "start_coords": [0, 0] - }, - "worker2username": { - "password": "password", - "start_coords": [0, 50] - } - } -} -``` - -In this case, the first worker will start drawing from (0, 0) and the second worker will start drawing from (0, 50) from the input image.jpg file. - -This is useful if you want different threads drawing different parts of the image with different accounts. - -## Other Settings - -If any JSON decoders errors are found, the `config.json` needs to be fixed. Make sure to add the below 2 lines in the file. - -```json -{ - "thread_delay": 2, - "unverified_place_frequency": false, - "proxies": ["1.1.1.1:8080", "2.2.2.2:1234"], - "compact_logging": true -} -``` - -- thread_delay - Adds a delay between starting a new thread. Can be used to avoid ratelimiting. -- unverified_place_frequency - Sets the pixel place frequency to the unverified account limit. -- proxies - Sets proxies to use for sending requests to reddit. The proxy used is randomly selected for each request. Can be used to avoid ratelimiting. -- compact_logging - Disables timer text until next pixel. -- Transparency can be achieved by using the RGB value (69, 42, 0) in any part of your image. -- If you'd like, you can enable Verbose Mode by adding `--verbose` to "python main.py". This will output a lot more information, and not neccessarily in the right order, but it is useful for development and debugging. -- You can also setup proxies by creating a "proxies" and have a new line for each proxies. - -# Tor -Tor can be used as an alternative to normal proxies. Note that currently, you cannot use normal proxies and tor at the same time. - -```json -"using_tor": false, -"tor_port": 1881, -"tor_control_port": 9051, -"tor_password": "Passwort", -"tor_delay": 5, -"use_builtin_tor": true -``` - -The config values are as follows: -- Deactivates or activates tor. -- Sets the httptunnel port that should be used. -- Sets the tor control port. -- Sets the password (leave it as "Passwort" if you want to use the default binaries. -- The delay that tor should receive to process a new connection. -- Whether the included tor binary should be used. It is preconfigured. If you want to use your own binary, make sure you configure it properly. - -Note that when using the included binaries, only the tunnel port is explicitly set while starting tor. - -

If you want to use your own binaries, follow these steps:

- -- Get tor standalone for your platform [here](https://www.torproject.org/download/tor/). For Windows just use the expert bundle. For MacOS you'll have to compile the binaries yourself or get them from somewhere else, which is both out of the scope of this guide. -- In your tor folder, create a file named ``torrc``. Copy [this](https://github.com/torproject/tor/blob/main/src/config/torrc.sample.in) into it. -- Search for ``ControlPort`` in your torrc file and uncomment it. Change the port number to your desired control port. -- Decide on the password you want to use. Run ``tor --hash-password PASSWORD`` from a terminal in the folder with your tor executable, with "PASSWORD" being your desired password. Copy the resulting hash. -- Search for ``HashedControlPassword`` and uncomment it. Paste the hash value you copied after it. -- Decide on a port for your httptunnel. The default for this script is 1881. -- Fill in your password, your httptunnel port and your control port in this script's ``config.json`` and enable tor with ``using_tor = true``. -- To start tor, run ``tor --defaults-torrc PATHTOTORRC --HttpTunnelPort TUNNELPORT``, with PATHTOTORRC being your path to the torrc file you created and TUNNELPORT being your httptunnel port. -- Now run the script and (hopefully) everything should work. - -License for the included tor binary: - -> Tor is distributed under the "3-clause BSD" license, a commonly used -software license that means Tor is both free software and open source: -Copyright (c) 2001-2004, Roger Dingledine -Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson -Copyright (c) 2007-2019, The Tor Project, Inc. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: ->- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. ->- Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. ->- Neither the names of the copyright owners nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. -> ->THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -## Docker - -A dockerfile is provided. Instructions on installing docker are outside the scope of this guide. - -To build: After editing the `config.json` file, run `docker build . -t place-bot`. and wait for the image to build. - -You can now run it with `docker run place-bot` - -## Contributing - -See the [Contributing Guide](docs/CONTRIBUTING.md). +# Reddit Place Script 2022 + +[![Code style: black](./black_badge.svg)](https://github.com/psf/black) +[![forthebadge](https://forthebadge.com/images/badges/made-with-python.svg)](https://forthebadge.com) +[![forthebadge](https://forthebadge.com/images/badges/60-percent-of-the-time-works-every-time.svg)](https://forthebadge.com) + +## About + +This is a script to draw an image onto r/place (). + +## Features + +- Support for multiple accounts. +- Determines the cooldown time remaining for each account. +- Detects existing matching pixels on the r/place map and skips them. +- Automatically converts colors to the r/place color palette. +- Easy(ish) to read output with colors. +- SOCKS proxy support. +- No client id and secret needed. +- Proxies from "proxies.txt" file. +- Tor support. + +## Requirements + +- [Latest Version of Python 3](https://www.python.org/downloads/) + +## MacOSX + +If you want to use tor on MacOSX. you'll need to provide your own tor binary and start it manually. deactivate the "use_builtin tor" +option in the config and make sure you configure your tor to use the specified ports and password. + +*Please note that socks proxy connection to tor doesn't work for the time being, so the config value is for an httpTunnel port* + +## Get Started + +Move the file 'config_example.json' to config.json + +Edit the values to replace with actual credentials and values + +Note: Please use https://jsonlint.com/ to check that your JSON file is correctly formatted + +```json +{ + //Where the image's path is + "image_path": "image.png", + // [x,y] where you want the top left pixel of the local image to be drawn on canvas + "image_start_coords": [741, 610], + // delay between starting threads (can be 0) + "thread_delay": 2, + // array of accounts to use + "workers": { + // username of account 1 + "worker1username": { + // password of account 1 + "password": "password", + // which pixel of the image to draw first + "start_coords": [0, 0] + }, + // username of account 2 + "worker1username": { + // password of account 2 + "password": "password", + // which pixel of the image to draw first + "start_coords": [0, 0], + // A proxy for this worker only + "personal_proxy": "1.2.3.4:4321" + } + // etc... add as many accounts as you want (but reddit may detect you the more you add) + } +} +``` + +### Notes + +- Use `.png` if you wish to make use of transparency or non rectangular images +- If you use 2 factor authentication (2FA) in your account, then change `password` to `password:XXXXXX` where `XXXXXX` is your 2FA code. +- If you do use a personal proxy (A proxy for that worker only), you need put some proxies for random selection else things that are not worker related will be set to have no proxy at all + +## Run the Script + +### Windows + +```shell +start.bat or startverbose.bat +``` + +### Unix-like (Linux, MacOS etc.) + +```shell +chmod +x start.sh startverbose.sh +./start.sh or ./startverbose.sh +``` + +**You can get more logs (`DEBUG`) by running the script with `-d` flag:** + +`python3 main.py -d` or `python3 main.py --debug` + +## Multiple Workers +Just create multiple child arrays to "workers" in the .json file: + +```json +{ + "image_path": "image.png", + "image_start_coords": [741, 610], + "thread_delay": 2, + + "workers": { + "worker1username": { + "password": "password", + "start_coords": [0, 0], + "personal_proxy": "1.2.3.4:4321" + }, + "worker2username": { + "password": "password", + "start_coords": [0, 50] + } + } +} +``` + +In this case, the first worker will start drawing from (0, 0) and the second worker will start drawing from (0, 50) from the input image.jpg file. + +This is useful if you want different threads drawing different parts of the image with different accounts. + +## Other Settings + +If any JSON decoders errors are found, the `config.json` needs to be fixed. Make sure to add the below 2 lines in the file. + +```json +{ + "thread_delay": 2, + "unverified_place_frequency": false, + "proxies": ["1.1.1.1:8080", "2.2.2.2:1234"], + "compact_logging": true, +} +``` + +- thread_delay - Adds a delay between starting a new thread. Can be used to avoid ratelimiting. +- unverified_place_frequency - Sets the pixel place frequency to the unverified account limit. +- proxies - Sets proxies to use for sending requests to reddit. The proxy used is randomly selected for each request. Can be used to avoid ratelimiting. +- compact_logging - Disables timer text until next pixel. +- Transparency can be achieved by using the RGB value (69, 42, 0) in any part of your image. +- If you'd like, you can enable Verbose Mode by adding `--verbose` to "python main.py". This will output a lot more information, and not neccessarily in the right order, but it is useful for development and debugging. +- You can also setup proxies by creating a "proxies" and have a new line for each proxies. + +# Tor +Tor can be used as an alternative to normal proxies. Note that currently, you cannot use normal proxies and tor at the same time. + +```json +"using_tor": false, +"tor_port": 1881, +"tor_control_port": 9051, +"tor_password": "Passwort", +"tor_delay": 5, +"use_builtin_tor": true +``` + +The config values are as follows: +- Deactivates or activates tor. +- Sets the httptunnel port that should be used. +- Sets the tor control port. +- Sets the password (leave it as "Passwort" if you want to use the default binaries. +- The delay that tor should receive to process a new connection. +- Whether the included tor binary should be used. It is preconfigured. If you want to use your own binary, make sure you configure it properly. + +Note that when using the included binaries, only the tunnel port is explicitly set while starting tor. + +

If you want to use your own binaries, follow these steps:

+ +- Get tor standalone for your platform [here](https://www.torproject.org/download/tor/). For Windows just use the expert bundle. For MacOS you'll have to compile the binaries yourself or get them from somewhere else, which is both out of the scope of this guide. +- In your tor folder, create a file named ``torrc``. Copy [this](https://github.com/torproject/tor/blob/main/src/config/torrc.sample.in) into it. +- Search for ``ControlPort`` in your torrc file and uncomment it. Change the port number to your desired control port. +- Decide on the password you want to use. Run ``tor --hash-password PASSWORD`` from a terminal in the folder with your tor executable, with "PASSWORD" being your desired password. Copy the resulting hash. +- Search for ``HashedControlPassword`` and uncomment it. Paste the hash value you copied after it. +- Decide on a port for your httptunnel. The default for this script is 1881. +- Fill in your password, your httptunnel port and your control port in this script's ``config.json`` and enable tor with ``using_tor = true``. +- To start tor, run ``tor --defaults-torrc PATHTOTORRC --HttpTunnelPort TUNNELPORT``, with PATHTOTORRC being your path to the torrc file you created and TUNNELPORT being your httptunnel port. +- Now run the script and (hopefully) everything should work. + +License for the included tor binary: + +> Tor is distributed under the "3-clause BSD" license, a commonly used +software license that means Tor is both free software and open source: +Copyright (c) 2001-2004, Roger Dingledine +Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson +Copyright (c) 2007-2019, The Tor Project, Inc. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +>- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +>- Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. +>- Neither the names of the copyright owners nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. +> +>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Docker + +A dockerfile is provided. Instructions on installing docker are outside the scope of this guide. + +To build: After editing the `config.json` file, run `docker build . -t place-bot`. and wait for the image to build. + +You can now run it with `docker run place-bot` + +## Contributing + +See the [Contributing Guide](docs/CONTRIBUTING.md). diff --git a/main.py b/main.py index 16d40c7c..dacfc77d 100755 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ import math +from unicodedata import name import requests import json @@ -24,6 +25,7 @@ class PlaceClient: def __init__(self, config_path): self.logger = logger # Data + self.json_data = utils.get_json_data(self, config_path) self.pixel_x_start: int = self.json_data["image_start_coords"][0] self.pixel_y_start: int = self.json_data["image_start_coords"][1] @@ -113,7 +115,7 @@ def set_pixel_and_check_ratelimit( url, headers=headers, data=payload, - proxies=proxy.get_random_proxy(self), + proxies=proxy.get_random_proxy(self, None), ) logger.debug("Thread #{} : Received response: {}", thread_index, response.text) @@ -264,7 +266,7 @@ def get_board(self, access_token_in): requests.get( msg["data"]["name"], stream=True, - proxies=proxy.get_random_proxy(self), + proxies=proxy.get_random_proxy(self, None), ).content ) ), @@ -386,7 +388,7 @@ def get_unset_pixel(self, x, y, index): def task(self, index, name, worker): # Whether image should keep drawing itself repeat_forever = True - + proxy.check_and_set_personal_proxy() while True: # last_time_placed_pixel = math.floor(time.time()) @@ -469,7 +471,7 @@ def task(self, index, name, worker): while True: try: client = requests.Session() - client.proxies = proxy.get_random_proxy(self) + client.proxies = proxy.get_random_proxy(self, name) client.headers.update( { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36" @@ -478,7 +480,7 @@ def task(self, index, name, worker): r = client.get( "https://www.reddit.com/login", - proxies=proxy.get_random_proxy(self), + proxies=proxy.get_random_proxy(self, name), ) login_get_soup = BeautifulSoup(r.content, "html.parser") csrf_token = login_get_soup.find( @@ -494,7 +496,7 @@ def task(self, index, name, worker): r = client.post( "https://www.reddit.com/login", data=data, - proxies=proxy.get_random_proxy(self), + proxies=proxy.get_random_proxy(self, name), ) break except Exception: @@ -512,7 +514,7 @@ def task(self, index, name, worker): logger.success("Authorization successful!") logger.info("Obtaining access token...") r = client.get( - "https://new.reddit.com/", proxies=proxy.get_random_proxy(self) + "https://new.reddit.com/", proxies=proxy.get_random_proxy(self, name) ) data_str = ( BeautifulSoup(r.content, features="html.parser") From df7162a42d4c35f062f621509b7e914bb99e7a88 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:36:22 -0400 Subject: [PATCH 07/14] Personal Proxy Update --- main.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index dacfc77d..1c656451 100755 --- a/main.py +++ b/main.py @@ -1,5 +1,4 @@ import math -from unicodedata import name import requests import json @@ -24,8 +23,8 @@ class PlaceClient: def __init__(self, config_path): self.logger = logger + # Data - self.json_data = utils.get_json_data(self, config_path) self.pixel_x_start: int = self.json_data["image_start_coords"][0] self.pixel_y_start: int = self.json_data["image_start_coords"][1] @@ -388,7 +387,6 @@ def get_unset_pixel(self, x, y, index): def task(self, index, name, worker): # Whether image should keep drawing itself repeat_forever = True - proxy.check_and_set_personal_proxy() while True: # last_time_placed_pixel = math.floor(time.time()) @@ -514,7 +512,8 @@ def task(self, index, name, worker): logger.success("Authorization successful!") logger.info("Obtaining access token...") r = client.get( - "https://new.reddit.com/", proxies=proxy.get_random_proxy(self, name) + "https://new.reddit.com/", + proxies=proxy.get_random_proxy(self, name), ) data_str = ( BeautifulSoup(r.content, features="html.parser") From 91c27cbe4fb7f75b24b16bd0b211be0c23a2b734 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:36:36 -0400 Subject: [PATCH 08/14] Personal Proxy Update --- src/proxy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/proxy.py b/src/proxy.py index bdfa7dbd..b636f7f0 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -102,6 +102,7 @@ def get_proxies(self, proxies): return proxies_list return proxies_list + def get_random_proxy(self, name): if not self.using_tor: random_proxy = None @@ -113,7 +114,7 @@ def get_random_proxy(self, name): random_proxy = self.proxies[random.randint(0, len(self.proxies) - 1)] self.logger.debug("Using proxy: {}", str(random_proxy)) return random_proxy - + return random_proxy else: tor_reconnect(self) From 8f6ed3242e21e759eb72f0adf1b75162bae3117f Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:43:39 -0400 Subject: [PATCH 09/14] Update main.py --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 8baa7b84..1c656451 100755 --- a/main.py +++ b/main.py @@ -494,7 +494,7 @@ def task(self, index, name, worker): r = client.post( "https://www.reddit.com/login", data=data, - proxies=proxy.get_random_proxy(self, name) + proxies=proxy.get_random_proxy(self, name), ) break except Exception: From 639e4458be7af528450167e9ea85b7da6ddafff7 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:44:05 -0400 Subject: [PATCH 10/14] Line ending fix From f017e6956f4a0d3d493eaddcf66ea1b3b5a387b5 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Mon, 4 Apr 2022 00:16:47 -0400 Subject: [PATCH 11/14] Fix missing self --- src/proxy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/proxy.py b/src/proxy.py index b636f7f0..fe2d05f0 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -8,14 +8,14 @@ def Init(self): self.proxies = ( - get_proxies(self.json_data["proxies"]) + get_proxies(self, self.json_data["proxies"]) if "proxies" in self.json_data and self.json_data["proxies"] is not None else None ) if self.proxies is None and os.path.exists( os.path.join(os.getcwd(), "proxies.txt") ): - self.proxies = get_proxies_text() + self.proxies = get_proxies_text(self) self.compactlogging = ( self.json_data["compact_logging"] if "compact_logging" in self.json_data From 23aa8d2de5e1c41f46d204aa586513daab5c0777 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Mon, 4 Apr 2022 14:07:59 -0400 Subject: [PATCH 12/14] name = None --- main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 1c656451..e236a766 100755 --- a/main.py +++ b/main.py @@ -114,7 +114,7 @@ def set_pixel_and_check_ratelimit( url, headers=headers, data=payload, - proxies=proxy.get_random_proxy(self, None), + proxies=proxy.get_random_proxy(self, name=None), ) logger.debug("Thread #{} : Received response: {}", thread_index, response.text) @@ -265,7 +265,7 @@ def get_board(self, access_token_in): requests.get( msg["data"]["name"], stream=True, - proxies=proxy.get_random_proxy(self, None), + proxies=proxy.get_random_proxy(self, name=None), ).content ) ), From d1a886ee6d8bb16f1c6d002ad29787d5404e8070 Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Mon, 4 Apr 2022 14:09:58 -0400 Subject: [PATCH 13/14] Update proxy.py --- src/proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proxy.py b/src/proxy.py index fe2d05f0..cdc29ce7 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -102,7 +102,7 @@ def get_proxies(self, proxies): return proxies_list return proxies_list - +#name is the username of the worker and is used for personal proxies def get_random_proxy(self, name): if not self.using_tor: random_proxy = None From b9eaf95c6bfa42765ab0da8f237391461a23ddec Mon Sep 17 00:00:00 2001 From: Risewill23 <69612616+Risewill23@users.noreply.github.com> Date: Mon, 4 Apr 2022 16:12:22 -0400 Subject: [PATCH 14/14] Update proxy.py --- src/proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proxy.py b/src/proxy.py index c0a9f2f0..37fada32 100644 --- a/src/proxy.py +++ b/src/proxy.py @@ -111,7 +111,7 @@ def get_proxies(self, proxies): return proxies_list #name is the username of the worker and is used for personal proxies -def get_random_proxy(self, name): +def get_random_proxy(self, name=None): if not self.using_tor: random_proxy = None if name is not None: