updating scripts
This commit is contained in:
18
bash-scripts/master-perms.sh
Executable file
18
bash-scripts/master-perms.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script will update the permissions of the /home/zaine/master-folder directory and all its contents to ensure that the nextcloud user has the necessary permissions to access and modify files within that directory.
|
||||||
|
|
||||||
|
# The two commands to run are:
|
||||||
|
# sudo chown -R zaine:www-data /home/zaine/master-folder
|
||||||
|
# sudo chmod -R 2775 /home/zaine/master-folder
|
||||||
|
|
||||||
|
# Update ownership to zaine:www-data
|
||||||
|
sudo chown -R zaine:www-data /home/zaine/master-folder
|
||||||
|
|
||||||
|
# Update permissions to 2775
|
||||||
|
sudo chmod -R 2775 /home/zaine/master-folder
|
||||||
|
|
||||||
|
echo "Permissions updated for /home/zaine/master-folder and its contents."
|
||||||
|
|
||||||
|
# cron job to run this script every hour
|
||||||
|
# 0 * * * * /path/to/this/script.sh
|
||||||
0
bash-scripts/system-clean.sh~
Normal file → Executable file
0
bash-scripts/system-clean.sh~
Normal file → Executable file
@@ -1,132 +1,88 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
from decimal import Decimal, InvalidOperation
|
import re
|
||||||
from pathlib import Path
|
from decimal import Decimal
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import sys
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
RAW_DIR = Path("/home/zaine/master-folder/attachments/bank-statements/nationwide/raw")
|
RAW_DIR = Path("/home/zaine/master-folder/attachments/bank-statements/nationwide/raw")
|
||||||
CLEANED_DIR = Path("/home/zaine/master-folder/attachments/bank-statements/nationwide/cleaned")
|
CLEANED_DIR = Path("/home/zaine/master-folder/attachments/bank-statements/nationwide/cleaned")
|
||||||
|
|
||||||
|
# Only keep digits, dot, minus for money
|
||||||
|
MONEY_REGEX = re.compile(r"[^\d\.-]")
|
||||||
|
|
||||||
def clean_money(value: str) -> Decimal | None:
|
def clean_money(value: str):
|
||||||
if not value:
|
if not value:
|
||||||
return None
|
return None
|
||||||
|
# Remove all non-numeric characters
|
||||||
value = (
|
value = MONEY_REGEX.sub("", value)
|
||||||
value.replace("£", "")
|
|
||||||
.replace(",", "")
|
|
||||||
.strip()
|
|
||||||
)
|
|
||||||
|
|
||||||
if not value:
|
if not value:
|
||||||
return None
|
return None
|
||||||
|
return Decimal(value)
|
||||||
|
|
||||||
try:
|
def parse_date(value: str):
|
||||||
return Decimal(value)
|
# Input format: 27 Feb 2026
|
||||||
except InvalidOperation:
|
return datetime.strptime(value.strip(), "%d %b %Y").strftime("%m/%d/%Y")
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def parse_date(value: str) -> str | None:
|
|
||||||
"""
|
|
||||||
Convert '01 Dec 2025' → '12/01/2025'
|
|
||||||
"""
|
|
||||||
value = value.strip()
|
|
||||||
if not value:
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
|
||||||
dt = datetime.strptime(value, "%d %b %Y")
|
|
||||||
return dt.strftime("%m/%d/%Y")
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def convert(in_path: Path, out_path: Path):
|
def convert(in_path: Path, out_path: Path):
|
||||||
with open(in_path, newline="", encoding="latin-1") as f_in, \
|
rows_written = 0
|
||||||
open(out_path, "w", newline="", encoding="utf-8") as f_out:
|
|
||||||
|
|
||||||
reader = csv.reader(f_in)
|
# Read raw bytes and decode aggressively
|
||||||
|
with open(in_path, "rb") as f:
|
||||||
|
lines = f.read().decode("utf-8", errors="ignore").splitlines()
|
||||||
|
|
||||||
# Skip metadata lines until header
|
with open(out_path, "w", newline="", encoding="utf-8") as f_out:
|
||||||
for row in reader:
|
writer = csv.writer(f_out, lineterminator="\r\n")
|
||||||
if row and row[0] == "Date":
|
writer.writerow(["Date", "Payee", "Description", "Amount"])
|
||||||
header = row
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise RuntimeError("Could not find Nationwide CSV header row")
|
|
||||||
|
|
||||||
dict_reader = csv.DictReader(f_in, fieldnames=header)
|
for row in csv.reader(lines):
|
||||||
|
if not row:
|
||||||
fieldnames = ["Date", "Payee", "Description", "Amount"]
|
continue
|
||||||
writer = csv.DictWriter(f_out, fieldnames=fieldnames)
|
first = row[0].strip()
|
||||||
writer.writeheader()
|
if first.startswith("Account") or first == "Date":
|
||||||
|
continue
|
||||||
for row in dict_reader:
|
if len(row) < 5:
|
||||||
raw_date = row.get("Date") or ""
|
|
||||||
date = parse_date(raw_date)
|
|
||||||
if not date:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
desc = (row.get("Description") or "").strip()
|
try:
|
||||||
payee = desc
|
date = parse_date(row[0])
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
paid_out = clean_money(row.get("Paid out", ""))
|
desc = row[2].strip()
|
||||||
paid_in = clean_money(row.get("Paid in", ""))
|
paid_out = clean_money(row[3])
|
||||||
|
paid_in = clean_money(row[4])
|
||||||
|
|
||||||
if paid_out is not None:
|
if paid_out is not None:
|
||||||
amount = -paid_out
|
amount = f"{-paid_out:.2f}"
|
||||||
elif paid_in is not None:
|
elif paid_in is not None:
|
||||||
amount = paid_in
|
amount = f"{paid_in:.2f}"
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
writer.writerow({
|
writer.writerow([date, desc, desc, amount])
|
||||||
"Date": date,
|
rows_written += 1
|
||||||
"Payee": payee,
|
|
||||||
"Description": desc,
|
|
||||||
"Amount": f"{amount:.2f}",
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
def select_file(files: list[Path]) -> Path:
|
|
||||||
print("\nSelect a Nationwide CSV to clean:\n")
|
|
||||||
for i, f in enumerate(files, start=1):
|
|
||||||
print(f"[{i}] {f.name}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
choice = int(input("\nEnter number: ").strip())
|
|
||||||
return files[choice - 1]
|
|
||||||
except (ValueError, IndexError):
|
|
||||||
print("Invalid selection.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
return rows_written
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if not RAW_DIR.exists():
|
|
||||||
print(f"Raw directory does not exist: {RAW_DIR}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
CLEANED_DIR.mkdir(parents=True, exist_ok=True)
|
CLEANED_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
csv_files = sorted(RAW_DIR.glob("*.csv"))
|
files = sorted(RAW_DIR.glob("*.csv"))
|
||||||
|
if not files:
|
||||||
|
print("No CSV files found.")
|
||||||
|
return
|
||||||
|
|
||||||
if not csv_files:
|
print("\nSelect a Nationwide CSV to clean:\n")
|
||||||
print("No CSV files found in raw directory.")
|
for i, f in enumerate(files, 1):
|
||||||
sys.exit(0)
|
print(f" [{i}] {f.name}")
|
||||||
|
|
||||||
in_path = select_file(csv_files)
|
choice = int(input("\nEnter number: "))
|
||||||
|
in_path = files[choice - 1]
|
||||||
out_name = f"{in_path.stem}-cleaned.csv"
|
out_path = CLEANED_DIR / f"{in_path.stem}-cleaned.csv"
|
||||||
out_path = CLEANED_DIR / out_name
|
|
||||||
|
|
||||||
convert(in_path, out_path)
|
|
||||||
|
|
||||||
print(f"\n✔ Written cleaned file to:\n{out_path}\n")
|
|
||||||
|
|
||||||
|
n = convert(in_path, out_path)
|
||||||
|
print(f"\n✔ {n} rows written to:\n {out_path}\n")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
2
cookbook_org_sync.py
Normal file → Executable file
2
cookbook_org_sync.py
Normal file → Executable file
@@ -38,7 +38,7 @@ NEXTCLOUD_PASSWORD = os.environ.get("NEXTCLOUD_PASS", "Shakkal123!") # or hard
|
|||||||
RECIPES_ENDPOINT = "/apps/cookbook/api/v1/recipes"
|
RECIPES_ENDPOINT = "/apps/cookbook/api/v1/recipes"
|
||||||
|
|
||||||
OUTPUT_ORG = Path(
|
OUTPUT_ORG = Path(
|
||||||
"/home/zaine/master-folder/org_files/org_roam/"
|
"/home/zaine/master-folder/org_files/org_roam/Misc/"
|
||||||
"20260307233451-recipes_cookbook.org"
|
"20260307233451-recipes_cookbook.org"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
0
cookbook_org_sync.py~
Normal file → Executable file
0
cookbook_org_sync.py~
Normal file → Executable file
@@ -28,7 +28,7 @@ APP_DB = Path("/home/zaine/master-folder/projects/calibre/data/app.db")
|
|||||||
|
|
||||||
CALIBRE_LIBRARY_ROOT = Path("/home/zaine/master-folder/projects/calibre/library")
|
CALIBRE_LIBRARY_ROOT = Path("/home/zaine/master-folder/projects/calibre/library")
|
||||||
|
|
||||||
OUTPUT_ORG = Path("/home/zaine/master-folder/org_files/org_roam/20250724230557-books_org_agenda.org")
|
OUTPUT_ORG = Path("/home/zaine/master-folder/org_files/org_roam/Books/20250724230557-books_org_agenda.org")
|
||||||
|
|
||||||
UNSORTED_SHELF = "Unsorted"
|
UNSORTED_SHELF = "Unsorted"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user