first commit
This commit is contained in:
21
Changelog.md
Normal file
21
Changelog.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
### V1.0
|
||||||
|
- First Version
|
||||||
|
|
||||||
|
### V1.1
|
||||||
|
- Cleanup code
|
||||||
|
|
||||||
|
### V1.2
|
||||||
|
- Redone the changelog:
|
||||||
|
- better structure
|
||||||
|
- Added env.example
|
||||||
|
- Chnaged Readme.md:
|
||||||
|
- Added how to get a API key
|
||||||
|
|
||||||
|
### V2.0
|
||||||
|
- Make more comments
|
||||||
|
- clearer structure
|
||||||
|
- added functions.py
|
||||||
|
|
||||||
|
Planned Features:
|
||||||
|
To-Do:
|
||||||
|
- Add arguments when running the script
|
||||||
32
README.md
Normal file
32
README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Bookstack Backup
|
||||||
|
This Script works via the Bookstack API.
|
||||||
|
You can decide which file Type you want to download, you can decide from text, markdown, pdf and html.
|
||||||
|
## How it works
|
||||||
|
You should have an Python virtual Environment and the pip package *bookstack* installed.
|
||||||
|
If it's not installed, you can install it via:
|
||||||
|
```
|
||||||
|
python3 -m venv [Name of your venv Folder]
|
||||||
|
source [Your Venv Folder]/bin/activate
|
||||||
|
pip install bookstack
|
||||||
|
```
|
||||||
|
Now you can run the script:
|
||||||
|
```
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
## How to get an API key
|
||||||
|
##### Step 1:
|
||||||
|
- Log in with an administrator account
|
||||||
|
##### Step 2:
|
||||||
|
- Click on settings in the top bar
|
||||||
|
##### Step 3:
|
||||||
|
- Go to the user tab
|
||||||
|
##### Step 4:
|
||||||
|
- Click on the user you want to create an API Token for
|
||||||
|
##### Step 5:
|
||||||
|
- Scroll down to API-Token
|
||||||
|
##### Step 6:
|
||||||
|
- Click on "Create Token"
|
||||||
|
##### Step 7:
|
||||||
|
- Give the token a name and expiry date
|
||||||
|
##### Step 8:
|
||||||
|
- Save your "Token ID" and "Token Secret"
|
||||||
5
env.example
Normal file
5
env.example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
BASE_URL=https://example.com ## Your full bookstack FQDN
|
||||||
|
TOKEN_ID= ## Your API token ID
|
||||||
|
TOKEN_SECRET= ## Your API token secret
|
||||||
|
|
||||||
|
BACKUP_DIR="" ## Your Backup destination
|
||||||
32
functions/__init__.py
Normal file
32
functions/__init__.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from . import get_set_Book
|
||||||
|
from . import set_Variables
|
||||||
|
from . import backupType
|
||||||
|
from . import backupLogic
|
||||||
|
from . import get_confirmation
|
||||||
|
import bookstack
|
||||||
|
|
||||||
|
def main(version):
|
||||||
|
print(f"Functions module running version: {version}")
|
||||||
|
env = set_Variables.set_variables()
|
||||||
|
print(f"You are currently running on Version: {version}")
|
||||||
|
|
||||||
|
api = bookstack.BookStack(env['base_url'], token_id=env['token_id'], token_secret=env['token_secret'])
|
||||||
|
api.generate_api_methods()
|
||||||
|
|
||||||
|
try:
|
||||||
|
book_list = api.get_books_list()['data']
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error loading books: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
get_set_Book.get_Books(book_list)
|
||||||
|
book_to_backup = get_set_Book.set_Book(book_list)
|
||||||
|
backup_extension = backupType.get_backup_extension()
|
||||||
|
backup_extension_fileType = backupType.set_backup_extension_filetype(backup_extension)
|
||||||
|
book_to_backup = next(book for book in book_list if book['id'] == book_to_backup)
|
||||||
|
|
||||||
|
if get_confirmation.get_confirmation(backup_extension, book_to_backup):
|
||||||
|
backupLogic.backup_book(api, env, book_to_backup, backup_extension, backup_extension_fileType)
|
||||||
|
print("Backup completed.")
|
||||||
|
else:
|
||||||
|
return
|
||||||
31
functions/backupLogic.py
Normal file
31
functions/backupLogic.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import os
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
def backup_book(api, env, selected_book, backup_extension, backup_extension_fileType):
|
||||||
|
base_url = env['base_url']
|
||||||
|
backup_dir = env['backup_dir']
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Token {env['token_id']}:{env['token_secret']}"
|
||||||
|
}
|
||||||
|
|
||||||
|
pages_list = api.get_pages_list()['data']
|
||||||
|
chapter_list = api.get_chapters_list()['data']
|
||||||
|
|
||||||
|
print(f"Backup type: {backup_extension}")
|
||||||
|
|
||||||
|
for chapter in chapter_list:
|
||||||
|
for page in pages_list:
|
||||||
|
if page['book_id'] == selected_book['id']:
|
||||||
|
if chapter['id'] == page['chapter_id']:
|
||||||
|
folder = os.path.join(backup_dir, chapter['name'])
|
||||||
|
filename = os.path.join(folder, page['name'] + backup_extension_fileType)
|
||||||
|
print(f"Backing up: {filename}")
|
||||||
|
if not os.path.exists(folder):
|
||||||
|
os.makedirs(folder, exist_ok=True)
|
||||||
|
response = requests.get(
|
||||||
|
f'{base_url}/api/pages/{page["id"]}/export/{backup_extension}',
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
with open(filename, 'wb') as file:
|
||||||
|
file.write(response.content)
|
||||||
24
functions/backupType.py
Normal file
24
functions/backupType.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
def get_backup_extension():
|
||||||
|
backup_type = input("Enter backup type (md, pdf, html, text): ").strip().lower()
|
||||||
|
if backup_type in ["md", "markdown"]:
|
||||||
|
return "markdown"
|
||||||
|
elif backup_type == "pdf":
|
||||||
|
return "PDF"
|
||||||
|
elif backup_type == "html":
|
||||||
|
return "HTML"
|
||||||
|
elif backup_type in ["plain", "text", "txt", "plain_text"]:
|
||||||
|
return "Plaintext"
|
||||||
|
else:
|
||||||
|
raise ValueError("Unsupported backup type")
|
||||||
|
|
||||||
|
def set_backup_extension_filetype(backup_type):
|
||||||
|
if backup_type == "markdown":
|
||||||
|
return ".md"
|
||||||
|
elif backup_type == "PDF":
|
||||||
|
return ".pdf"
|
||||||
|
elif backup_type == "HTML":
|
||||||
|
return ".html"
|
||||||
|
elif backup_type == "Plaintext":
|
||||||
|
return ".txt"
|
||||||
|
else:
|
||||||
|
print("Error file type not found")
|
||||||
14
functions/get_confirmation.py
Normal file
14
functions/get_confirmation.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
def get_confirmation(backup_extension, selected_book):
|
||||||
|
print(f"Backup type: {backup_extension}")
|
||||||
|
while True:
|
||||||
|
confirm = input("Are these settings correct? (y/n): ").strip().lower()
|
||||||
|
if confirm == "y":
|
||||||
|
print(f"Starting backup for book: {selected_book['name']} with filetype {backup_extension}.")
|
||||||
|
print("Starting now.......")
|
||||||
|
return True
|
||||||
|
elif confirm == "n":
|
||||||
|
print("Stopping now.....")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("Please enter 'y' or 'n'.")
|
||||||
|
|
||||||
16
functions/get_set_Book.py
Normal file
16
functions/get_set_Book.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
def get_Books(book_list):
|
||||||
|
print("Available books:")
|
||||||
|
print("Book_ID: ", "Book_Name")
|
||||||
|
for book in book_list:
|
||||||
|
print(f"{book['id']}: {book['name']}")
|
||||||
|
|
||||||
|
def set_Book(book_list):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
book_to_backup = int(input("Enter the book ID to backup: "))
|
||||||
|
if any(book['id'] == book_to_backup for book in book_list):
|
||||||
|
return book_to_backup
|
||||||
|
else:
|
||||||
|
print("Invalid book ID, please try again.")
|
||||||
|
except ValueError:
|
||||||
|
print("Please enter a valid number.")
|
||||||
11
functions/set_Variables.py
Normal file
11
functions/set_Variables.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
def set_variables():
|
||||||
|
load_dotenv()
|
||||||
|
return {
|
||||||
|
"base_url": os.getenv('BASE_URL'),
|
||||||
|
"token_id": os.getenv('TOKEN_ID'),
|
||||||
|
"token_secret": os.getenv('TOKEN_SECRET'),
|
||||||
|
"backup_dir": os.getenv('BACKUP_DIR')
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user