Jump to content

Recommended Posts

Posted (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 by r0nmlt
Posted

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.

 

  • Like 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...