Version 1 = here:
The requirements for the script are the same as in version 1. read beforehand if necessary.
Due to an idea from another user => here version 2 with extended output.
The new version now shows the amount of plots that would fit.
Also the ones that already exist.
Also new is an overview table:
See 2nd table on the right.
But this is just for now. Surely there is still some more information possible. E.g. with maximum c30 plots = how many EB would result. Or percentage added value, etc etc.
But I didn’t want to make the table too long. Anyone can add to it themselves.
The number of possible plots is available. You only need to multiply them with “ziel_plot_groesse_gib”.
Have fun with it
P.s. As before: Without guarantee
import os
import time
from pathlib import Path
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from datetime import timedelta
import locale
import datetime
# Konfiguration
testlauf = 0 # 1 für Testmodus, 0 für echten Löschvorgang
wait_time_minutes = 30 # Wartezeit in Minuten zwischen den Durchläufen
min_free_space_gb = 44 # Mindestmenge an freiem Speicherplatz in GB
to_delete_patterns = ["plot-k32-c07", "plot-k32-c05", "plot-k32-202"] # Muster für zu löschende Dateien
not_to_delete_pattern = "plot-k32-c30" # Muster für nicht zu löschende Dateien
plot_name_short = "c30" ## Nur fĂĽr die Textliche Ausgabe ohne Berechnung
ziel_plot_groesse_gib = 43.3 # Zielgröße für Plots in GiB
min_plotting_time_in_min = "2:10" # Die Laufzeit fĂĽr den schnellsten Plotvorgang in Minuten
max_plotting_time_in_min = "2:30" # Die Laufzeit fĂĽr den langsamsten Plotvorgang in Minuten
directories = [
"/mnt/01", "/mnt/02", "/mnt/03", "/mnt/04", "/mnt/05", "/mnt/06", "/mnt/07", "/mnt/08",
"/mnt/09", "/mnt/10", "/mnt/11", "/mnt/12", "/mnt/13", "/mnt/14", "/mnt/15", "/mnt/16",
"/mnt/17", "/mnt/18", "/mnt/19", "/mnt/20", "/mnt/21", "/mnt/22", "/mnt/23", "/mnt/24",
"/mnt/25", "/mnt/26", "/mnt/27", "/mnt/28", "/mnt/29", "/mnt/30", "/mnt/31", "/mnt/32",
"/mnt/97", "/mnt/98", "/mnt/99", "/mnt/100"
]
# Setze das Locale, um Tausender-Trennzeichen entsprechend zu formatieren
locale.setlocale(locale.LC_ALL, '')
def format_number(number):
"""Formatiert die Zahl mit Tausender-Trennzeichen und rundet sie ab."""
return f"{number:n}"
def calculate_rest_time(total_plots, min_time, max_time):
"""Berechnet die geschätzte Restlaufzeit in Minuten basierend auf der Anzahl der verbleibenden Plots und Plot-Zeiten in Minuten."""
min_time_minutes = convert_time_to_minutes(min_time)
max_time_minutes = convert_time_to_minutes(max_time)
# Berechnung der Restlaufzeit direkt in Minuten
total_min_rest_time_minutes = total_plots * min_time_minutes
total_max_rest_time_minutes = total_plots * max_time_minutes
return total_min_rest_time_minutes, total_max_rest_time_minutes
def convert_time_to_minutes(time_str):
"""Konvertiert eine Zeit im Format 'MM:SS' direkt in Minuten."""
minutes, seconds = map(int, time_str.split(":"))
return minutes + seconds / 60
def format_time(minutes):
"""Formatiert Minuten in Tage, Stunden und Minuten."""
days, remainder = divmod(minutes, 1440)
hours, minutes = divmod(remainder, 60)
return f"{int(days)}d {int(hours)}h {int(minutes)}m"
def gb_to_gib(size_gb):
"""Umrechnung von GB in GiB."""
return size_gb / 1.07374
def get_free_space_gb(folder):
"""Gibt den freien Speicherplatz des Verzeichnisses in Gigabyte zurĂĽck."""
st = os.statvfs(folder)
free_space_bytes = st.f_bavail * st.f_frsize
free_space_gb = free_space_bytes / 1024 / 1024 / 1024
return free_space_gb
def get_total_space_gb(folder):
"""Gibt die Gesamtkapazität des Verzeichnisses in Gigabyte zurück."""
st = os.statvfs(folder)
total_space_bytes = st.f_blocks * st.f_frsize
total_space_gb = total_space_bytes / 1024 / 1024 / 1024
return total_space_gb
def can_delete_any_file(directory):
"""Überprüft, ob eine löschbare Datei im Verzeichnis vorhanden ist."""
for root, dirs, files in os.walk(directory):
for file in files:
if any(file.startswith(pattern) for pattern in to_delete_patterns) and not file.startswith(not_to_delete_pattern):
return True
return False
def count_c30_plots(directory):
"""Zählt die Anzahl der c30 Plots im Verzeichnis."""
count = 0
for root, dirs, files in os.walk(directory):
for file in files:
if file.startswith(not_to_delete_pattern):
count += 1
return count
def delete_file(directory, console):
"""Löscht eine Datei aus dem Verzeichnis basierend auf den gegebenen Kriterien."""
deleted = False
for root, dirs, files in os.walk(directory):
for file in files:
if any(file.startswith(pattern) for pattern in to_delete_patterns) and not file.startswith(not_to_delete_pattern):
file_path = Path(root) / file
current_time = datetime.datetime.now().strftime("%d.%m.%Y %H:%M")
if testlauf == 1:
console.print(f"[white]{current_time}[/white] [TESTMODUS] Würde Datei löschen: {file_path}", style="yellow")
else:
os.remove(file_path)
console.print(f"[white]{current_time}[/white] Datei gelöscht: {file_path}", style="green")
deleted = True
break
if deleted:
break
return deleted
def main():
console = Console()
gesamt_speicherplatz_gb = 0
for directory in directories:
gesamt_speicherplatz_gb += get_total_space_gb(directory)
gesamt_mögliche_plots = int(gesamt_speicherplatz_gb / ziel_plot_groesse_gib)
# Initialisiere gesamt_vorhandene_plots hier, basierend auf der Summe der c30-Plots in allen Verzeichnissen
gesamt_vorhandene_plots = sum(count_c30_plots(directory) for directory in directories)
while True:
gesamt_speicherplatz_gb = 0
# Hier gesamt_vorhandene_plots erneut berechnen, falls sich die Anzahl der Plots ändert
gesamt_vorhandene_plots = sum(count_c30_plots(directory) for directory in directories)
gesamt_verbleibende_plots = gesamt_mögliche_plots - gesamt_vorhandene_plots # Korrekte Anzahl der verbleibenden Plots
min_rest_time_min, max_rest_time_min = calculate_rest_time(gesamt_verbleibende_plots, min_plotting_time_in_min, max_plotting_time_in_min)
min_rest_time_hours = min_rest_time_min / 60
max_rest_time_hours = max_rest_time_min / 60
min_rest_time_days = min_rest_time_hours / 24
max_rest_time_days = max_rest_time_hours / 24
# Initialisiere die Tabellen neu fĂĽr diesen Durchlauf
table_needs_action = Table(show_header=True, header_style="bold magenta")
table_needs_action.add_column("Verzeichnis", style="dim", width=12)
table_needs_action.add_column("Free Space(GB)", justify="right")
table_needs_action.add_column("Plots", justify="right")
table_needs_action.add_column("Status", justify="left")
table_fulfilled = Table(show_header=True, header_style="bold cyan")
table_fulfilled.add_column("Verzeichnis", style="dim", width=12)
table_fulfilled.add_column("Free Space(GB)", justify="right")
table_fulfilled.add_column("Plots", justify="right")
table_fulfilled.add_column("Status", justify="left")
for directory in directories:
total_space_gb = get_total_space_gb(directory)
gesamt_speicherplatz_gb += total_space_gb
free_space_gb = get_free_space_gb(directory)
free_space_gib = gb_to_gib(free_space_gb)
total_plots_possible = int(total_space_gb / ziel_plot_groesse_gib)
c30_plots_count = count_c30_plots(directory)
plots_info = f"{c30_plots_count}/{total_plots_possible}"
free_space_with_plots = f"{free_space_gb:.2f} ({int(free_space_gib / ziel_plot_groesse_gib)})"
if get_free_space_gb(directory) < min_free_space_gb and can_delete_any_file(directory):
delete_file(directory, console)
if free_space_gb < min_free_space_gb and can_delete_any_file(directory):
table_needs_action.add_row(directory, free_space_with_plots, plots_info, "[bold red]Benötigte Ursprünglich mehr Platz.")
elif free_space_gb >= min_free_space_gb:
table_needs_action.add_row(directory, free_space_with_plots, plots_info, "[bold green]GenĂĽgend Speicherplatz")
else:
table_fulfilled.add_row(directory, f"{free_space_gb:.2f}", plots_info, "[bold cyan]Die Vorgaben sind erfĂĽllt.")
gesamt_mögliche_plots = int(gesamt_speicherplatz_gb / ziel_plot_groesse_gib)
# NEUE Tabelle für zusätzliche Informationen
additional_info_table = Table(show_header=True, header_style="bold blue")
additional_info_table.add_column("Info", style="dim")
additional_info_table.add_column("Details", justify="left")
# HinzufĂĽgen der Informationen zur neuen Tabelle
additional_info_table.add_row("Gesamtspeicherplatz in GB", f"{format_number(gesamt_speicherplatz_gb).replace(',', '.')} GB")
additional_info_table.add_row("Gesamtspeicherplatz in TB", f"{format_number(gesamt_speicherplatz_gb / 1024).replace(',', '.')} TB")
if gesamt_speicherplatz_gb /1024 >= 500: # Verwende PB nur, wenn der Wert signifikant ist
additional_info_table.add_row("Gesamtspeicherplatz in PB", f"{format_number((gesamt_speicherplatz_gb/1024)/1024)} PB")
additional_info_table.add_row("", "") # Leerzeile
additional_info_table.add_row(f"Mögliche {plot_name_short}-Plots", format_number(gesamt_mögliche_plots))
additional_info_table.add_row(f"Vorhandene {plot_name_short}-Plots", format_number(gesamt_vorhandene_plots))
additional_info_table.add_row("", "") # Leerzeile
additional_info_table.add_row("Geschätzte Restlaufzeit in Min", f"{format_number(min_rest_time_min/60).replace(',', '.')} bis {format_number(max_rest_time_min/60).replace(',', '.')}")
additional_info_table.add_row("Geschätzte Restlaufzeit in Std", f"{str(int(min_rest_time_hours)).replace(',', '.')} bis {str(int(max_rest_time_hours)).replace(',', '.')}")
additional_info_table.add_row("Geschätzte Restlaufzeit in Tagen", f"{str(int(min_rest_time_days)).replace(',', '.')} bis {str(int(max_rest_time_days)).replace(',', '.')}")
additional_info_table.add_row("", "") # Leerzeile
# Erstelle die ĂĽbergeordnete Tabelle und fĂĽge die untergeordneten Tabellen hinzu
main_table = Table(box=None)
main_table.add_column("Aktive Laufwerke", justify="left")
main_table.add_column("Erfüllte Laufwerke + Zusätzliche Informationen", justify="left")
fulfilled_plus_additional = Table(box=None, show_header=False)
fulfilled_plus_additional.add_row(table_fulfilled)
fulfilled_plus_additional.add_row(additional_info_table)
main_table.add_row(table_needs_action, fulfilled_plus_additional)
console.print(main_table)
next_run_time = (datetime.datetime.now() + datetime.timedelta(minutes=wait_time_minutes)).strftime("%d.%m.%Y %H:%M")
console.print(f"Warte {wait_time_minutes} Minute(n), bevor der nächste Durchlauf beginnt... [white]{next_run_time}[/white]", style="bold blue")
time.sleep(wait_time_minutes * 60)
if __name__ == "__main__":
main()