├── Backend ├── Procfile ├── README.md ├── requirements.txt └── main.py └── README.md /Backend/Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn main:app 2 | -------------------------------------------------------------------------------- /Backend/README.md: -------------------------------------------------------------------------------- 1 | # How to use 2 | 3 | I have added the Procfile and requirements.txt I use which is needed when deploying to Heroku. Make sure to change these to match your needs 4 | 5 | You may find unnecessary requirements in the `requirements.txt` file, please remove any that are not needed. 6 | -------------------------------------------------------------------------------- /Backend/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2021.10.8 2 | charset-normalizer==2.0.12 3 | click==8.0.4 4 | discord-webhook==0.15.0 5 | Flask==2.0.3 6 | gunicorn==20.1.0 7 | idna==3.3 8 | itsdangerous==2.1.2 9 | Jinja2==3.1.1 10 | MarkupSafe==2.1.1 11 | requests==2.27.1 12 | urllib3==1.26.9 13 | Werkzeug==2.0.3 14 | sentry_sdk==1.5.12 15 | -------------------------------------------------------------------------------- /Backend/main.py: -------------------------------------------------------------------------------- 1 | from flask import ( 2 | Flask, 3 | request, 4 | send_file 5 | ) 6 | 7 | app = Flask(__name__, static_folder=".", 8 | static_url_path="", template_folder=".") 9 | 10 | @app.route("/version", methods=["GET"]) 11 | def checkVersion(): 12 | return "0.2.9.1" 13 | 14 | @app.route("/download", methods=["GET"]) 15 | def download(): 16 | return send_file('file.exe') 17 | 18 | if __name__ == "__main__": 19 | app.run(port=3333) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Auto Updater 2 | My solution to automatically download the newest build of your python app. Will work in other languages but sytnax will need to be changed. 3 | 4 | # Backend / API 5 | To fetch the newest build, you will need to setup a Flask server and host it. This can be done for free using [Heroku](https://www.heroku.com). Below is the simple code needed for it, you will also find this in the files above. 6 | ```python 7 | from flask import ( 8 | Flask, 9 | request, 10 | send_file 11 | ) 12 | app = Flask(__name__, static_folder=".", 13 | static_url_path="", template_folder=".") 14 | 15 | @app.route("/version", methods=["GET"]) 16 | def checkVersion(): 17 | return "0.2.9.1" 18 | 19 | @app.route("/download", methods=["GET"]) 20 | def download(): 21 | return send_file('file.exe') 22 | 23 | if __name__ == "__main__": 24 | app.run(port=3333) 25 | ``` 26 | 27 | Let's break down the code. 28 | 29 | ```python 30 | from flask import ( 31 | Flask, 32 | request, 33 | send_file 34 | ) 35 | ``` 36 | Here we are importing the Flask library as well as some components of it. The most important one is the `send_file` one as we need this to return a file from the API 37 | 38 | Next we need the application to check what version the newest application is. Here is the code for that: 39 | ```python 40 | @app.route("/version", methods=["GET"]) 41 | def checkVersion(): 42 | return "0.2.9.1" 43 | ``` 44 | By using the `/version` endpoint on our API, we will get a number returned to us. In this example, we are on version 0.2.9.1. Everytime a new file is uploaded to the API, we will update this number. 45 | 46 | Let's get to the most important part of the code, sending the file to the user. 47 | ```python 48 | @app.route("/download", methods=["GET"]) 49 | def download(): 50 | return send_file('file.exe') 51 | ``` 52 | If we call the `/download` endpoint, we will get a file returned to us. We need to rename the paramater in `return send_file()` to the name of the application in the folder. It will be easier to keep the file name the same the whole time. 53 | 54 | 55 | # Application Code 56 | We have now covered the basics of the API we need. Below I will detail what is needed in the code of your application. 57 | 58 | I will include the snippet below of the code required. You should call this first function alongside any other checks you do upon startup of the app, such as license authentication and any file checks. 59 | ```python 60 | def checkVersion(): 61 | print("Checking for updates...") 62 | r = requests.get("https://name.herokuapp.com/version") 63 | newestVersion = r.text 64 | if newestVersion == currentVersion: 65 | print("No updates found") 66 | else: 67 | downloadUpdate(newestVersion) 68 | ``` 69 | You may notice the `currentVersion` variable and that it hasn't been delcared yet. I hardcode that in the startup checks as a variable and change the value for every update I push. The logic behind the function is very simple, call the version endpoint and if it matches the hardcoded current version, proceed. If not, call the download function which is seen below. 70 | 71 | ```python 72 | def downloadUpdate(newestVersion): 73 | print("Update found, downloading...") 74 | url = "https://name.herokuapp.com/download" 75 | 76 | output_file = f"Application Name V{newestVersion}.exe" 77 | with urllib.request.urlopen(url) as response, open(output_file, 'wb') as out_file: 78 | shutil.copyfileobj(response, out_file) 79 | 80 | input("Check your folder for the latest version. Press any key to close this window...") 81 | sys.exit() 82 | ``` 83 | So here we are telling the user that we have found a new update, and that we are downloading it. The `output_file` variable we are declaring is what the file will be called. Due to some permission issues when trying to delete the file you have open, we need to create a new one. Change `Application Name` to whatever your software is called. The file will then be called `Name V0.2.9.1.exe`. We then make the request and put the file we get in the same directory as the current version. After that it is just a simple line saying we have downloaded the new file and where you can find it. Once the user presses a key acknowledging this, the window will close. 84 | 85 | # Conclusion 86 | I am no way saying this is the optimal solution, but this is what I use and it works well for my needs. Setting up a Heroku server is very easy and there are loads of videos online going through the setup process. 87 | 88 | If you have any improvements or questions about this, don't hesitate to reach out. 89 | 90 | Discord - PolarOrb5705#3951 91 | --------------------------------------------------------------------------------