Ein grosser Commit, weil die Punkte einander bedingen: ohne lesbare Fehlermeldung war die Serienerkennung nicht zu diagnostizieren, und ohne Build-Kennung nicht einmal festzustellen, ob überhaupt der gebaute Stand läuft. Zwei der neun Meldungen betrafen Funktionen, die seit Stunden im Quelltext stehen. Version und Build. Die Version steht fest; daneben eine Kennung aus sechs Zeichen, die sich bei jedem Docker-Bau ändert. Sie steht in der Verwaltung, unter /health und im Protokoll bei jedem Start. Damit ist "reden wir vom selben Build?" in zwei Sekunden beantwortet statt in einem halben Tag. Serien. Lag eine Datei direkt im Serienordner und trug vor der Folgennummer nichts, wurde der ganze Dateiname zum Serientitel: aus 95 Serien wurden 737, jede mit einer Folge, bei jedem Lauf neu. Dazu lief der Scan in Verweise hinein — derselbe Ordner unter zwei Namen ergab zwei Serien. Und weder neue noch umgezogene Dateien standen in der Pfadliste des Laufs, weshalb ein doppelt gesehener Pfad eine zweite Zeile mit gleichem (LibraryId, Path) anlegte und der Eindeutigkeitsindex den ganzen Speichervorgang scheitern liess. Jede Serienanlage wird jetzt im Tagesprotokoll begründet. Fehlermeldungen. "An error occurred while saving the entity changes" stand englisch in einer deutschen Oberfläche und nannte weder Ursache noch nächsten Schritt. Jetzt geht der vollständige Text ins Protokoll und ein deutscher Satz ohne Fehlercode in die Anzeige — auch für "Failed to fetch", das aus dem Browser kam und nie übersetzt wurde. Protokolle. Die Ansicht holte die ganze Datei und zeigte 800 Zeilen davon; bei zwei Megabyte brach die Verbindung ab. Gelesen wird jetzt serverseitig rückwärts, mit einem Knopf für mehr. Auswahlfelder. Die drei <select> zeichnete das Betriebssystem: ein helles Systemmenü mitten in der dunklen Oberfläche. Ersetzt durch ein eigenes Listenfeld mit Tastaturbedienung. Bildwahl. Drei Raster untereinander in einem scrollenden Dialog hiess zwei Scrollebenen übereinander. Jetzt ein Reiter je Bildtyp. Sprache. Die Serversprache stand in der Serverliste zwischen Name, Metadaten und Fassung — gesucht und nicht gefunden. Sie hat jetzt einen eigenen Abschnitt ganz oben. Dazu: ein Knopf, der den erfassten Inhalt einer Mediathek verwirft, ohne Name und Pfad mitzunehmen; ein Abschnitt Speicher mit den drei Pfaden, ihrer Belegung und dem Leeren des Bildspeichers; und die Korrektur einer Zuordnung frischt nur noch die Kachel auf statt die ganze Seite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
87 lines
3.2 KiB
C#
87 lines
3.2 KiB
C#
namespace Flaro.Core.Library;
|
||
|
||
/// <summary>Woran ein Lauf gerade ist.</summary>
|
||
public enum Scanphase
|
||
{
|
||
/// <summary>Das Dateisystem wird durchgegangen.</summary>
|
||
Suchen,
|
||
|
||
/// <summary>Eine Datei wird gelesen und vermessen.</summary>
|
||
Pruefen,
|
||
|
||
/// <summary>Ein Titel wird bei der Metadatenquelle gesucht.</summary>
|
||
Nachschlagen,
|
||
|
||
/// <summary>Die Angaben zu einem gefundenen Titel werden geholt.</summary>
|
||
Holen,
|
||
|
||
/// <summary>Plakate und Hintergründe werden geladen.</summary>
|
||
Bilder,
|
||
|
||
/// <summary>Verwaistes wird entfernt, Doppeltes zusammengelegt.</summary>
|
||
Aufraeumen,
|
||
|
||
/// <summary>Eine Notiz fürs Protokoll — nicht für die Fortschrittszeile.</summary>
|
||
///
|
||
/// <remarks>
|
||
/// <b>Warum getrennt.</b> „Serie ‚Pingu' neu angelegt, aus dem Ordner" ist
|
||
/// beim Suchen eines Fehlers Gold wert und in einer Zeile, die im
|
||
/// Sekundentakt wechselt, nur Flackern. Die Oberfläche überspringt diese
|
||
/// Schritte, die Tagesdatei nimmt sie auf.
|
||
/// </remarks>
|
||
Vermerk,
|
||
}
|
||
|
||
/// <summary>Ein Zwischenstand: was gerade passiert, und wie weit.</summary>
|
||
///
|
||
/// <remarks>
|
||
/// <para>
|
||
/// <b>Mit Namen, nicht nur mit Zahlen.</b> Vorher stand in der Verwaltung
|
||
/// minutenlang „Wird durchsucht…" — ohne Hinweis, ob überhaupt etwas
|
||
/// passiert. Wer bei vierzigtausend Dateien zusieht, braucht zu sehen, dass
|
||
/// sich etwas bewegt, und woran es gerade hängt, wenn es hängt.
|
||
/// </para>
|
||
/// <para>
|
||
/// Ein <c>record struct</c>, weil davon im Sekundentakt viele entstehen und
|
||
/// keiner davon überlebt.
|
||
/// </para>
|
||
/// </remarks>
|
||
/// <param name="Phase">Welcher Abschnitt des Laufs.</param>
|
||
/// <param name="Was">Woran genau — ein Titel oder ein Pfad.</param>
|
||
/// <param name="Erledigt">Wie viele Stücke schon durch sind.</param>
|
||
/// <param name="Gesamt">Wie viele es insgesamt sind; <c>0</c>, wenn unbekannt.</param>
|
||
public readonly record struct Scanschritt(Scanphase Phase, string Was, int Erledigt = 0, int Gesamt = 0)
|
||
{
|
||
/// <summary>Der Satz, der in der Oberfläche steht.</summary>
|
||
///
|
||
/// <remarks>
|
||
/// <b>Hier und nicht in der Oberfläche.</b> Die Apps brauchen denselben
|
||
/// Satz, und zweimal formuliert driftet er auseinander.
|
||
/// </remarks>
|
||
public string Text()
|
||
{
|
||
var zaehler = Gesamt > 0 ? $" — {Erledigt} von {Gesamt}" : "";
|
||
|
||
return Phase switch
|
||
{
|
||
Scanphase.Suchen => $"Suche Medien in {Kurz(Was)}",
|
||
Scanphase.Pruefen => $"Prüfe {Kurz(Was)}{zaehler}",
|
||
Scanphase.Nachschlagen => $"Suche „{Was}“ bei der Metadatenquelle{zaehler}",
|
||
Scanphase.Holen => $"Hole Metadaten zu {Was}{zaehler}",
|
||
Scanphase.Bilder => $"Lade Bilder zu {Was}{zaehler}",
|
||
Scanphase.Aufraeumen => "Räume auf und lege Doppeltes zusammen",
|
||
Scanphase.Vermerk => Was,
|
||
_ => Was,
|
||
};
|
||
}
|
||
|
||
/// <summary>Die letzten zwei Pfadbestandteile — ein ganzer Pfad sprengt die Zeile.</summary>
|
||
private static string Kurz(string pfad)
|
||
{
|
||
if (string.IsNullOrEmpty(pfad)) return pfad;
|
||
|
||
var teile = pfad.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||
return teile.Length <= 2 ? pfad : string.Join('/', teile[^2..]);
|
||
}
|
||
}
|