File: //proc/self/root/mnt/onedrive/openclaw/organize_onedrive.py
#!/usr/bin/env python3
"""
OneDrive Datei-Organisierer
===========================
Kopiert alle Dateien aus /mnt/onedrive in eine strukturierte Ordnerhierarchie.
Ausführen wenn:
1. Alle Dateien lokal verfügbar sind (OneDrive "Immer auf diesem Gerät behalten")
ODER
2. Direkt mit rclone (empfohlen für Cloud-Only Dateien)
Verwendung:
python3 organize_onedrive.py --rclone # Nutzt rclone copy direkt
python3 organize_onedrive.py --local # Kopiert vom lokalen Mount
"""
import os
import shutil
import subprocess
import re
import argparse
from collections import defaultdict
SOURCE = "/mnt/onedrive"
DEST = "/mnt/onedrive_write/Organisiert"
# GPuG-Themen nach Lehrplan+ Bayern
GPUG_TOPICS = {
"Weimarer_Republik": ["weimarer", "weimar", "novemberrevolution", "ruhraufstand",
"vertrag von versailles", "völkerbund", "reparation",
"weltwirtschaftskrise", "krisenjahre", "wrv", "goldene 20er"],
"Nationalsozialismus_2Weltkrieg": ["nationalsozialismus", "ns-", "hitler", "nazi",
"mussolini", "faschismus", "zweiter weltkrieg",
"2. weltkrieg", "stauffenberg", "widerstand"],
"Internationale_Beziehungen": ["internationale beziehungen", "nato", "friedensordnung",
"nachkriegskonferenz", "europäische einigung"],
"Wahlen_Parteien_Demokratie": ["parteien", "wahl", "wahlen", "csu", "spd", "fdp",
"grüne", "ödp", "freie wähler", "demokratie"],
"Politische_Theorie_Grundlagen": ["hobbes", "locke", "rousseau", "montesquieu",
"utopia", "vertragstheorie", "vertragslehre"],
"Menschenrechte_Grundrechte": ["menschenrecht", "grundrecht", "freiheitsrecht"]
}
# Deutsch-Themen
DEUTSCH_TOPICS = {
"Fokus_Epik": ["charakterisierung", "inhaltsangabe", "epik", "roman", "kurzgeschichte",
"erzähl", "22 bahnen", "perfect storm", "horváth", "wiener wald"],
"Fokus_Drama": ["drama", "dramat", "theater", "brecht", "arturo ui", "faust",
"terror von schirach", "physiker", "dürrenmatt", "klassisches drama"],
"Fokus_Sachtext": ["sachtext", "kommentar", "erörterung", "argument", "synthese",
"diskussion", "polemisch", "digitales lesen", "erörter"],
"Lyrik": ["lyrik", "gedicht", "poesie", "metrik", "verse", "reim", "liebeslyrik"],
"Grundwissen_Sprache": ["grundwissen", "grammatik", "konjunktiv", "indirekte rede",
"kommasetzung", "stilmittel", "rhetorisch", "textsorten"],
"Literaturgeschichte": ["epoche", "literaturgeschichte", "barock", "aufklärung",
"klassik", "romantik", "realismus", "expressionismus"]
}
def detect_file_type(name, path):
name_lower = name.lower()
if any(x in name_lower for x in ["klausur", "test", "prüfung", "abitur", "vorabitur"]):
return "Klausuren"
if any(x in path.lower() for x in ["abgabe", "portfolio", "feedback"]):
return "Schülerarbeiten"
if any(x in name_lower for x in ["quartalsplan", "jahresplan", "lernplan"]):
return "Organisatorisches"
if any(x in name_lower for x in ["feedbackbogen", "bewertungsbogen", "korrekturbogen"]):
return "Bewertungshilfen"
if name_lower.endswith((".mp4", ".mov")):
return "Lernvideos"
if name_lower.endswith((".jpg", ".jpeg", ".png")):
return "Bilder"
return "Material"
def categorize_file(filepath):
path_lower = filepath.lower()
name = os.path.basename(filepath)
name_lower = name.lower()
file_type = detect_file_type(name, filepath)
fach = "Sonstiges"
jahrgang = "Allgemein"
thema = "Sonstige_Dokumente"
# Vorklasse erkennen
if "/vorklasse" in path_lower:
jahrgang = "Vorklasse"
if "/gpug" in path_lower or "/gepug" in path_lower:
fach = "GPuG"
else:
fach = "Deutsch"
# Klassenordner erkennen
if not jahrgang or jahrgang == "Allgemein":
if re.search(r"/11[gwsv12]", path_lower) or "/11/" in path_lower:
jahrgang = "11_Klasse"
elif "12" in path_lower:
jahrgang = "12_Klasse"
# GPuG-Themen
for topic, keywords in GPUG_TOPICS.items():
if any(kw in path_lower or kw in name_lower for kw in keywords):
if fach != "Deutsch":
fach = "GPuG"
thema = topic
break
# Deutsch-Themen
if fach == "Sonstiges":
for topic, keywords in DEUTSCH_TOPICS.items():
if any(kw in path_lower or kw in name_lower for kw in keywords):
fach = "Deutsch"
thema = topic
break
# Sonstiges
if fach == "Sonstiges":
if "exkursion" in path_lower:
thema = "Exkursionen"
elif "projekt" in path_lower:
thema = "Projekte"
elif "/deutschbücher" in path_lower:
fach = "Deutsch"
thema = "Lehrbücher"
return fach, jahrgang, thema, file_type
def main(use_rclone=False):
print("OneDrive Datei-Organisierer")
print("=" * 50)
# Alle Dateien sammeln
print("Sammle Dateien...")
file_map = defaultdict(list)
for root, dirs, files in os.walk(SOURCE):
for f in files:
src_path = os.path.join(root, f)
rel_path = os.path.relpath(src_path, SOURCE)
if rel_path.startswith("Organisiert"):
continue
fach, jahrgang, thema, file_type = categorize_file(src_path)
if fach == "Sonstiges":
dest = f"{fach}/{thema}"
elif file_type and file_type not in ["Material", "Bilder"]:
dest = f"{fach}/{jahrgang}/{thema}/{file_type}"
else:
dest = f"{fach}/{jahrgang}/{thema}"
file_map[dest].append((src_path, rel_path, f))
total = sum(len(v) for v in file_map.values())
print(f"{total} Dateien in {len(file_map)} Zielordnern")
# Ordner erstellen
print("Erstelle Ordnerstruktur...")
for folder in file_map.keys():
os.makedirs(f"{DEST}/{folder}", exist_ok=True)
# Dateien kopieren
print(f"Kopiere Dateien {'(mit rclone)' if use_rclone else '(lokal)'}...")
copied = 0
errors = 0
for dest_folder, files in file_map.items():
for src_path, rel_path, filename in files:
dest_path = f"{DEST}/{dest_folder}/{filename}"
# Namenskonflikt lösen
if os.path.exists(dest_path):
base, ext = os.path.splitext(filename)
dest_path = f"{DEST}/{dest_folder}/{base}_{hash(rel_path) % 10000}{ext}"
try:
if use_rclone:
result = subprocess.run(
["rclone", "copy", f"onedrive:{rel_path}", f"{DEST}/{dest_folder}"],
capture_output=True, timeout=120
)
if result.returncode == 0:
copied += 1
else:
errors += 1
else:
shutil.copy2(src_path, dest_path)
copied += 1
if copied % 100 == 0:
print(f" {copied}/{total} kopiert...")
except Exception as e:
errors += 1
print(f"\n{'=' * 50}")
print(f"FERTIG: {copied} kopiert, {errors} Fehler")
print(f"Ziel: {DEST}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Organisiert OneDrive-Dateien")
parser.add_argument("--rclone", action="store_true", help="Nutze rclone statt lokalem Mount")
parser.add_argument("--local", action="store_true", help="Kopiere vom lokalen Mount")
args = parser.parse_args()
main(use_rclone=args.rclone)