r0nmlt Posted 3 hours ago Posted 3 hours ago (edited) I don't know if this exists elsewhere but trying to search for "backup" and only found loads of questions but no solutions. Krydos referenced a dead wiki in this post in 2019 https://helionet.org/index/topic/35348-backup-heliohost-account-to-a-cloud-storage/#findComment-157124 . So without a solution here is what I did: 1) Created a folder under my domain for backups. 2) Under plex backup manager, Remote Storage Settings; I set this up to save backups to this folder. 3) Again using plex, for a full backup, click on Account, backup my account and websites, and then Schedule Backup. I setup a daily full backup to save into the FTP(S). 4) In the backups folder I created under my domain, I put this python file: #!/usr/bin/python3.12 print('Content-type: text/html\r\n\r') import json import os import requests import sys session: requests.Session = requests.Session() #-------------------------------------------------------------------------- #CONSTANTS local_backup_files_folder = "." dropbox_app_key = "" dropbox_app_secret = "" dropbox_basic_token = "" dropbox_access_token = "" #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def getLocalBackupFiles(local_backup_files_folder) -> dict[str, int]: local_files = {} all_local_files = os.listdir(local_backup_files_folder) for f in all_local_files: if os.path.isfile(os.path.join(local_backup_files_folder, f)) and f.endswith('.tar'): local_files[f] = os.path.getsize(f) return local_files #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def generateHeaders(auth_method) -> dict[str, str]: if auth_method == 'basic': headers: dict[str, str] = { 'Authorization': 'Basic ' + dropbox_basic_token, 'Content-Type': 'application/json' } if auth_method == 'bearer': headers: dict[str, str] = { 'Authorization': 'Bearer ' + dropbox_access_token, 'Content-Type': 'application/json' } if auth_method == 'upload': headers: dict[str, str] = { 'Authorization': 'Bearer ' + dropbox_access_token, 'Content-Type': 'application/octet-stream' } return headers #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def checkDropboxConnection() -> bool: headers: dict[str, str] = generateHeaders("basic") url: str='https://api.dropboxapi.com/2/check/app' data = json.dumps({"query":"heliohost"}) res: requests.Response = session.post(url, data=data, headers=headers, timeout=10, allow_redirects=False) if res.status_code == 200: if res.json()['result'] == "heliohost": return True else: return False else: return False #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def listDropboxFolder() -> dict[str, int]: headers: dict[str, str] = generateHeaders("bearer") url: str='https://api.dropboxapi.com/2/files/list_folder' data = json.dumps({ "path": "" }) res: requests.Response = session.post(url, data=data, headers=headers, timeout=10, allow_redirects=False) if res.status_code == 200: if "entries" in res.text: number_of_dropbox_files = len(res.json()['entries']) if number_of_dropbox_files > 0: #print(str(number_of_dropbox_files) + ' files in Dropbox Folder') print("<br>") dropbox_tar_files = {} for f in res.json()['entries']: #print(f) print("<br>") if f['name'].endswith('.tar'): dropbox_tar_files[f['name']] = f['size'] else: print('No files in Dropbox Folder') print("<br>") dropbox_tar_files = [] return dropbox_tar_files else: sys.exit('File list has wrong data') else: sys.exit('Cannot get file list') #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def checkMissingFiles(local_files, dropbox_tar_files): for f in local_files: #print(f) print("<br>") if f in dropbox_tar_files: print(f + " is in dropbox") print("<br>") if local_files[f] == dropbox_tar_files[f]: print(f + " size matches") print("<br>") continue else: print(f + " size mitchmatch in dropbox") print("<br>") result = uploadMissingFiles(f) if result == True: print(f + " uploaded successfully") print("<br>") else: print(f + " is not in dropbox") print("<br>") result = uploadMissingFiles(f) if result == True: print(f + " uploaded successfully") print("<br>") #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def uploadMissingFiles(f) -> bool: headers: dict[str, str] = generateHeaders("upload") headers['Dropbox-API-Arg'] = '{"autorename":false,"mode":"add","mute":false,"path":"/' + f + '","strict_conflict":false}' url: str='https://content.dropboxapi.com/2/files/upload' data = open(f, "rb").read() res: requests.Response = session.post(url, data=data, headers=headers, timeout=10, allow_redirects=False) if res.status_code == 200: if res.json()['name'] == f: return True else: sys.exit('Error uploading') else: sys.exit('Error uploading') #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- def deleteUploadedFiles(local_files, dropbox_tar_files): for f in dropbox_tar_files: if f in local_files: print(f + " exists in dropbox") print("<br>") if local_files[f] == dropbox_tar_files[f]: print(f + " size matches") print("<br>") os.remove(f) else: print(f + " size doesn't match") print("<br>") sys.exit('Size mismatch after upload') else: print(f + " is not in dropbox") print("<br>") sys.exit('File not in dropbox after upload') #-------------------------------------------------------------------------- print("Starting") print("<br>") local_files= getLocalBackupFiles(local_backup_files_folder) if len(local_files) == 0: exit(0) print(local_files) print("<br>") check = checkDropboxConnection() if check: dropbox_tar_files = listDropboxFolder() else: sys.exit('Error connecting to DropBox') print(dropbox_tar_files) print("<br>") print("------------------------------------------") print("<br>") checkMissingFiles(local_files, dropbox_tar_files) dropbox_tar_files = listDropboxFolder() print("------------------------------------------") print("<br>") deleteUploadedFiles(local_files, dropbox_tar_files) print("------------------------------------------") print("<br>") local_files= getLocalBackupFiles(local_backup_files_folder) print(local_files) print("<br>") Replace the: dropbox_app_key = "" dropbox_app_secret = "" dropbox_basic_token = "" dropbox_access_token = "" with you own values. 5) Setup a cron job to fetch the python url and execute the script. If you're having issues running python in this folder I used the .htaccess file in the folder: Options +ExecCGI AddHandler cgi-script .py DirectoryIndex backup_export.py where backup_export.py is the name of the script above. Hope this is of use. If anyone improves on this and wants to share with the rest of us please go ahead. Edited 3 hours ago by r0nmlt Quote
MoneyBroz Posted 2 hours ago Posted 2 hours ago This is indeed very useful. The only question about this is, do you need a paid Dropbox account for this to work? Quote
r0nmlt Posted 2 hours ago Author Posted 2 hours ago Thanks. No. I have the free account and it works. You need to setup dropbox api to get the keys. plenty of guides around. One that comes to mind is how to setup rclone with dropbox. You would obviously use just the instructions how to setup the api and get the keys. if anyone needs help I can show how I did it. 1 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.