# AVI-Mover 3.7 — 04.08.2026

Überwacht den Aufnahme-Ordner des OBS-Plugins **Replay Source** und schiebt fertige
AVI/FLV-Dateien auf den Server. Schreibt `status.json` für die Web-Anzeige und ein
Turnier-Ergebnis-Log.

Version und Datum stehen **immer oben rechts im Fenster** und in jeder Log-Datei —
damit auf jedem Stream-Rechner erkennbar ist, welcher Stand läuft.

---

## 3.7 — Turnier **und** Matte am zusammengeführten Log

`Tuzla-Cup.json` allein sagt nicht, was drinsteckt. Jetzt:

**Der Dateiname nennt beides:**
```
Tuzla-Cup__Matte-1.json                        eine Matte
Tuzla-Cup__Matte-1+Matte-2+Matte-3.json        bis vier Matten
Gross-Cup__5-Matten_Matte-1-bis-Matte-10.json  ab fünf Matten
```
Matten werden **numerisch** sortiert — `Matte-10` kommt nach `Matte-9`, nicht davor.
Und zwei Durchläufe mit anderer Matten-Auswahl überschreiben sich nicht mehr gegenseitig.

**Jeder Eintrag bekommt `tournament` und `matte` gefüllt.** Beides steht im Namen der
Quelldatei (`<Turnier>__<Matte>.json`) und wird von dort ergänzt, falls es im Eintrag
fehlt oder leer ist. Danach ist jede Zeile für sich sprechend, egal aus welcher Datei
sie kam.

**Die Meldung nennt es auch:**
```
Tuzla-Cup · Matte-1, Matte-2: 3 Eintraege aus 2 Datei(en) -> Tuzla-Cup__Matte-1+Matte-2.json
```

---

## 3.6 — Knopf „Turnier-Log"

In der Setup-Fußzeile: **INI laden · INI speichern · Turnier-Log · Beenden · Starten**.

Der Knopf führt die Matten-Logs eines Turniers zu **einer** Gesamt-Datei zusammen —
dieselbe Logik wie `Merge-TurnierLog.ps1`, nur im laufenden Programm. Er steht
**absichtlich nur im Setup**, also wenn der Mover gestoppt ist: während einer Aufnahme
sollen die Matten-Logs nicht unter dem Betrieb weggelesen werden.

Der Dialog fragt: **wo liegen die Matten-Logs**, **wohin die Gesamt-Datei**, und
**nur dieses Turnier** (angekreuzt, wenn oben ein Turniername steht). Vorbelegt ist der
`status.json`-Ordner, sonst der lokale `Logs`-Ordner. Das Ergebnis kommt als Meldung und
landet im Protokoll.

### Warum sich `Merge-TurnierLog.ps1` nicht starten ließ

**Windows führt `.ps1`-Dateien per Doppelklick absichtlich nicht aus** — der Doppelklick
öffnet den Editor. Dazu kommen zwei weitere Bremsen: die **Ausführungsrichtlinie**
(`ExecutionPolicy`) und die **Herkunftsmarkierung**, die Dateien aus einer
Netzwerkfreigabe mitbringen („… ist nicht digital signiert").

Von Hand geht es so:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\Merge-TurnierLog.ps1" `
               -BasePath "\\192.168.9.10\www-root\avi-mover"
```
Oder Rechtsklick → **„Mit PowerShell ausführen"**. Bei der Herkunftsmarkierung hilft
Rechtsklick → Eigenschaften → **„Zulassen"**.

Mit dem Knopf entfällt das alles. Das Skript bleibt für die Kommandozeile liegen.

---

## 3.5 — Zähler für misslungene Dateien, leere Aufnahmen werden gelöscht

* **Nur noch ein Logo, links.** Das zweite oben rechts ist weg — die Fläche gehört
  Version, Datum und PID.
* **Kachel „MISSLUNGEN".** Gezählt wird alles, was **nicht im Ziel angekommen** ist:
  übersprungen (nicht stabil, zu lange gesperrt), verschwunden, Robocopy-Fehler — und
  die gelöschten leeren Aufnahmen. Die Zahl bleibt **grau bei 0** und wird **rot**,
  sobald etwas schiefging. Darunter klein: `davon leer: N`.
* **Null-Byte-Dateien werden gelöscht, nicht kopiert.** Geprüft wird genau dann, wenn
  die Datei **freigegeben** ist — dann ist klar, dass Replay Source sie angelegt, aber
  nichts hineingeschrieben hat. Solche Dateien übers Netz zu schieben kostet nur Zeit
  und müllt den Server zu. Lässt sich eine nicht löschen, bleibt sie liegen und das
  Protokoll sagt es.

```
  VERSCHOBEN   MISSLUNGEN   AKTUELLE DATEI        TURNIER · MATTE
      12            3        Matte1 - 2026-…      Tuzla-Cup
                davon leer: 2                     Matte-1
```

In `status.json` stehen zusätzlich `FailCount` und `EmptyCount`. `Status.html` liest nur
die sechs bekannten Felder und ignoriert unbekannte — die Kompatibilität bleibt.

---

## 3.4 — Status kam in Status.html nicht an

Zwei Fehler, beide meine:

**1. Der Fehlerstatus wurde sofort wieder überschrieben.** Die Fehlerzweige schrieben
erst ihren Status und riefen **danach** `Auftrag-Abschliessen` — und das schrieb
bedingungslos „AVI-Mover läuft" darüber. Der Fehler stand also **Mikrosekunden** in der
Datei; `Status.html` fragt alle paar Sekunden und hat ihn nie gesehen.
Jetzt wird der Status **genau einmal** geschrieben, und der Aufrufer bestimmt den
Inhalt. Ein Fehler **bleibt stehen**, bis der nächste Erfolg ihn ersetzt.

| Ausgang | Bild | StatusText |
|---|---|---|
| verschoben | `on-mover.png` | AVI-Mover läuft |
| übersprungen (nicht stabil / gesperrt / verschwunden) | `on-mover.png` | AVI-Mover läuft, Grund im DetailText |
| Robocopy-Fehler | `off-mover.png` | Robocopy-Fehler |
| Robocopy startet nicht | `off-mover.png` | Fehler: Robocopy startet nicht |
| Umbenennen fehlgeschlagen | `off-mover.png` | Fehler beim Umbenennen |
| Ordner weg (Netzlaufwerk) | `off-mover.png` | Fehler: Ordner nicht erreichbar |

*(Status.html färbt nach Stichwörtern: „läuft" grün, „gestoppt" grau, „fehler" rot —
deshalb steht in allen Fehlertexten das Wort „Fehler".)*

**2. Der Ordner für `status.json` fiel stillschweigend auf den Programmordner zurück.**
War der Netzwerkpfad nicht erreichbar, schrieb der Mover einfach lokal weiter und
behauptete, alles sei in Ordnung — die Web-Anzeige bekam nie etwas zu sehen. Jetzt:

* **erreichbar** und **beschreibbar** werden getrennt geprüft, der Grund kommt im Klartext
* beim Rückfall gibt es **Protokolleintrag und Hinweisfenster** mit den häufigen Ursachen
* ein Knopf **„Prüfen"** direkt am Feld, damit sich ein Netzwerkpfad **vor** dem Start
  testen lässt
* die Werte aus der INI werden **getrimmt** — ein einzelnes Leerzeichen ließ `Test-Path`
  scheitern, während der Pfad im Feld völlig richtig aussah

> **Bei `\\192.168.9.10\www-root\avi-mover\matte1` zuerst prüfen:** Freigabe einmal im
> Explorer öffnen (damit die Anmeldung steht), und **nicht** mit Administrator-Rechten
> starten — ein erhöhter Prozess hat eine andere Anmeldung und kommt an die Freigabe
> nicht heran. Genau dasselbe gilt für `V:\`.

---

## 3.3 — vorgefundene Dateien: fragen statt nehmen

Beim Starten wird der Quell-Ordner durchgesehen. Liegen dort schon Dateien, kommt ein
eigener Dialog:

* Liste der Dateien mit Größe
* **„Wohin sollen diese Dateien?"** — Vorschlag ist der Ziel-Ordner aus dem Setup,
  änderbar mit Ordner-Knopf. Für Nachzügler eines alten Turniers also ein anderes Ziel
  als für die Aufnahmen, die jetzt entstehen.
* **Uhr: 5 Sekunden.** Ohne Antwort schließt sich der Dialog von selbst mit „Nein" —
  der Mover läuft weiter und wartet auf neue Dateien. Ein Dialog darf den Start am
  Turniertag nicht aufhalten.
* Tippt jemand im Zielfeld, **hält die Uhr an** — wer da ist, soll nicht vom
  Zeitablauf überrascht werden.
* Vor der Übernahme wird das gewählte Ziel auf Schreibrecht geprüft.

Das Ziel hängt jetzt am **einzelnen Auftrag**, nicht mehr global.

### QUOTEFIX-V1 — beim Bauen aufgefallen

PowerShell behandelt die typografischen Anführungszeichen **„ (U+201E), “ (U+201C) und
” (U+201D) als String-Begrenzer.** Jedes `„` in einem doppelt gequoteten Text beendet
die Zeichenkette vorzeitig. In **3.0 bis 3.2 waren dadurch alle Protokollmeldungen mit
Anführung still verstümmelt** — nur an einer einzigen Stelle gab es deswegen einen
Syntaxfehler, der es verraten hat. Im Code stehen jetzt `»` und `«` (mit PowerShell
nachgewiesen unbedenklich); in Kommentaren dürfen `„` und `“` bleiben.

---

## 3.2 — „warum kann er auf V:\ nicht schreiben?"

Robocopy meldete einen Fehler, obwohl der Explorer dort problemlos Dateien anlegt.
**Drei Ursachen, alle im Code gefunden:**

1. **`"V:\"` ist als Argument kaputt.** Auf Windows liest die C-Laufzeit `\"` als
   *maskiertes* Anführungszeichen — das Argument wird zerlegt und Robocopy bekommt
   Unsinn. Betrifft **jeden Pfad, der auf `\` endet**: eine Laufwerkswurzel oder ein
   Schrägstrich am Ende des Eingabefeldes. Im Explorer fällt das nicht auf, weil der
   ganz anders aufruft. Jetzt räumt `Robo-Pfad` das auf:
   `V:\` → `"V:\\"`, `V:\Replay\Matte 1\` → `"V:\Replay\Matte 1"`.
2. **Robocopy kann nicht umbenennen.** Bei Namensgleichheit hängte der Code einen
   zweiten Dateinamen an — weitere Namen sind bei Robocopy aber **Suchmuster für die
   Quelle**, kein Zielname. Das Muster existierte dort nicht → Fehler. Jetzt wird die
   **Quelldatei vorher umbenannt**, danach kopiert Robocopy genau einen Namen.
   *(Dieser Fehler steckte schon in Version 2.)*
3. **Exitcode 0 heißt „nichts kopiert"** — die Prüfung war „Code < 4 = Erfolg". Damit
   galt 0 als Erfolg, der Zähler lief hoch und die Datei lag weiter in der Quelle.
   Jetzt wird nachgesehen, ob die Datei **wirklich im Ziel** liegt.

**Damit du beim nächsten Mal nicht raten musst:** Robocopys eigene Meldung, die
komplette Befehlszeile und der Exitcode im Klartext landen im Protokoll:

```
14:22:07 X Robocopy-Code 16: SCHWERER FEHLER — Aufrufsyntax falsch oder keine Rechte
14:22:07 X Robocopy sagt: ERROR 5 (0x00000005) Zugriff verweigert
14:22:07   Befehl war: robocopy.exe "D:\Replay Aufnahmen" "V:\Replay\Matte 1" "x.avi" /MOV …
14:22:07   Im Ziel angekommen: NEIN · Quelle geleert: nein
14:22:07 ! Bei Code 16 zuerst prüfen: Schreibrecht im Ziel, und ob der Zielpfad auf „\" endet.
```

**Und eine Schreibprobe beim Starten.** Bevor die Überwachung anläuft, wird im Ziel
eine Testdatei angelegt und gelöscht. Klappt das nicht, kommt sofort der echte
Windows-Fehlertext mit den häufigsten Gründen — statt erst beim ersten Replay.

> **Der häufigste Grund überhaupt:** läuft das Programm **mit Administrator-Rechten**,
> sind verbundene Netzlaufwerke wie `V:\` für den Prozess **nicht sichtbar**. Deshalb
> beim Bauen `-requireAdmin` **aus** lassen. Zur Gegenprobe im Zweifel den vollen
> Netzwerkpfad eintragen: `\\Server\Freigabe\Replay\Matte 1`.

---

## 3.1 — was nach dem ersten Lauf auf Windows korrigiert wurde

Gernots Rückmeldung, Punkt für Punkt:

1. **„tausend Msgbox: Ampelfarbe und Art usw"** — zwei Ursachen:
   * Die Datei war **UTF-8 ohne BOM**. PowerShell 5.1 liest eine `.ps1` ohne BOM als
     Windows-1252; jede Zeile mit Umlaut, Gedankenstrich oder Anführungszeichen wird
     dabei verfälscht — hier 147 Zeilen. Die Dateien von Version 2 hatten das BOM,
     meine neue nicht. **Jetzt UTF-8 mit BOM.**
   * **`[ValidateSet]`** in den Hilfsfunktionen. Schlägt eine Prüfung fehl, wirft
     PowerShell einen Fehler — und PS2EXE mit `-noConsole` macht aus **jedem** Fehler
     eine MessageBox. Im 250-ms-Takt sind das endlos viele. Die Prüfattribute sind
     raus, und **jeder Ereignis-Block läuft in `try/catch`**: Fehler landen im
     Protokoll und in der Zeile „Letzter Fehler", nie mehr in einem Dialog.
     MessageBoxen gibt es jetzt nur noch dort, wo *du* etwas angeklickt hast
     (INI, fehlender Turniername, fehlender Ordner).
2. **Ordner-Icons und Logo fehlten** — WinForms zeichnet Emoji (📁, 🥋) nicht
   zuverlässig. Jetzt echte Bilder: `pfad.ico` auf den Ordner-Knöpfen, `Logo.png` vor
   der Überschrift. Fehlt eine Bilddatei, erscheint ein Textzeichen als Ersatz.
3. **Judo-Fanpage-Logo** — `Datei-Logo.png` steht jetzt rechts in der Kopfzeile.
4. **„Eingabefeld überdeckt den Text, ein Stück Rahmen fehlt"** — richtig erkannt:
   die Beschreibung endete genau auf der Oberkante des Feldes. Jetzt 43 px Abstand
   statt 36, jede Beschriftung mit fester Höhe. Beim Nachrechnen fiel noch auf, dass
   die **dritte Pfad-Zeile 7 px unten aus dem Kasten ragte** — Raster jetzt 72 px.
5. **Titel „Quelle / Ziel / Status-Anzeige" in Gold** statt weiß.
6. **„ein wenig trostlos"** — abgesetzte Blöcke „VERANSTALTUNG" und „ORDNER" mit
   goldenen Überschriften, Goldlinie unter der Kopfzeile, Version und Datum auch in
   der Fußzeile. Fenster 620 × 470 (statt 450), damit es nicht gedrängt wirkt.

---

## Was sich gegenüber 2.x geändert hat

**Keine Konsole mehr.** Version 2 zeigte erst ein Fenster und lief danach in einer
Konsole. Version 3 hat ein Fenster mit zwei Ansichten:

* **Setup** — Turnier, Matte, Quelle, Ziel, Ordner für `status.json`
* **Betrieb** — Ampel, Zähler, aktuelle Datei, Protokoll (neueste Meldung oben)

620 × 470 Punkte, dunkel, Schrift ab 8,25 pt, Texte nicht dunkler als `#ccc`.

**Der eigentliche Umbau — und warum früher der Watcher abstarb.**
`Register-ObjectEvent -Action` führt seinen Block **nur aus, wenn die
PowerShell-Engine im Leerlauf ist.** Deshalb stand in Version 2 am Ende des
Start-Knopfes `while($true){ Start-Sleep 1 }` — das war kein Platzhalter, das war
der Motor. Wer die Konsole abschaltet und stattdessen nur die Fenster-Schleife
laufen lässt, nimmt der Engine die Leerlaufzeit: der Watcher ist noch registriert,
feuert aber nie mehr, und die Dateien bleiben liegen.

Version 3 braucht diesen Motor nicht:

| | Version 2 | Version 3 |
|---|---|---|
| Ereignisse | `Register-ObjectEvent -Action` | `Register-ObjectEvent` **ohne** `-Action` |
| Motor | `while($true){ Start-Sleep 1 }` | `Forms.Timer`, 250 ms, holt per `Get-Event` ab |
| Ablauf je Datei | ein Block, blockiert bis zu Minuten | Zustandsmaschine: entdeckt → stabil? → frei? → Robocopy → fertig? |
| Fenster während des Kopierens | war versteckt (Konsole) | bleibt bedienbar |
| Anzeige | Konsole | Protokoll im Fenster **und** `Logs\AVI-Mover_<Datum>.log` |

**Dazugekommen:**

* Beim Start liegende Dateien werden mitgenommen (vorher blieben sie liegen, bis
  OBS die nächste schrieb).
* Wache über die Ordner: fällt Quelle oder Ziel weg (Netzlaufwerk!), erscheint eine
  Meldung im Protokoll und in `status.json` — statt stummer Weiterlauf.
* Zielordner und Protokolldatei per Knopf öffnen.
* Zwei Knöpfe für die INI: laden und speichern.

**Absichtlich unverändert** (Kompatibilität):

* `status.json` mit genau den Feldern, die `Server/Status.html` liest —
  `Image`, `StatusText`, `DetailText`, `FileCount`, `Timestamp`, `CurrentFile`,
  UTF-8 **ohne** BOM.
* Ergebnis-Log `<Turnier>__<Matte>.json`, atomar über `.tmp` + Move, lokal als
  Wahrheitsquelle plus Spiegel im Web-Ordner.
* `Watchdog.ps1` mit `-MainPID` und `-JsonTargetDirectory`.
* `AVI-Mover.ini` im gleichen Zeilenformat wie Version 2 — alte Dateien passen.
* Robocopy-Schalter identisch: `/MOV /NFL /NDL /NJH /NJS /nc /ns /np /MT:1`.

---

## Als .exe bauen — ohne Konsole

Solange die .exe als **Konsolen**-Anwendung kompiliert ist, blitzt beim Start immer
ein schwarzes Fenster auf. Die alte `AVI-Mover.exe` war so gebaut.

**Win-PS2EXE** (die grafische Oberfläche) — nach Parameternamen gehen, der Wortlaut
schwankt je Version:

| Einstellung | Wert | Warum |
|---|---|---|
| `-noConsole` | **an** | ohne das blitzt die Konsole weiter auf |
| `-STA` | **an** | WinForms braucht Single-Threaded Apartment |
| `-runtime40` | **an** | `Add-Type` mit C# und WinForms brauchen .NET 4 |
| `-requireAdmin` | **aus** | ein erhöhter Prozess **sieht verbundene Netzlaufwerke nicht** — `V:\` wäre plötzlich weg |
| `-DPIAware` | **aus** | festes Koordinaten-Layout; mit DPI-Awareness wächst nur die Schrift und Beschriftungen überlappen |
| `-noOutput`, `-noError` | **aus** | nicht unterdrücken — echte Fehler will man sehen |
| x86 / x64 | **x64** | bzw. x86, wenn dasselbe .exe auch auf einem alten Rechner laufen soll |

```powershell
Install-Module ps2exe -Scope CurrentUser      # einmalig
Invoke-PS2EXE .\AVI-Mover.ps1 .\AVI-Mover.exe `
    -noConsole -STA -runtime40 -x64 `
    -iconFile .\Logo.ico `
    -title "AVI-Mover" -product "AVI-Mover" -version 3.7.0.0 `
    -company "Judo Fanpage Nürnberg" -copyright "(c) 2026"
```

`-noConsole` ist der entscheidende Schalter, `-STA` gehört bei WinForms dazu.

Ohne .exe geht es auch:
```
powershell.exe -NoProfile -ExecutionPolicy Bypass -STA -WindowStyle Hidden -File "AVI-Mover.ps1"
```
Das Skript versteckt eine vorhandene Konsole zusätzlich selbst.

---

## Testreihenfolge auf dem Stream-Rechner

Bitte in dieser Reihenfolge, dann sieht man sofort, wo es klemmt:

1. **Start** — Fenster kommt, **keine** Konsole. Oben rechts steht `Version 3.7 · 04.08.2026`.
2. **INI laden** — die Werte aus `AVI-Mover.ini` stehen in den Feldern.
3. **Starten ohne Turniername** — es muss die Meldung „Turnier fehlt" kommen.
4. **Starten mit falschem Quellpfad** — Meldung „Quelle fehlt", kein Absturz.
5. **Richtig starten** — Ansicht wechselt auf Betrieb, Ampel grün,
   `status.json` sagt „AVI-Mover läuft", `Status.html` zeigt es an.
6. **Datei vorher hineinlegen, dann starten** — es muss der Dialog „Dateien liegen
   schon im Ordner" kommen. Drei Fälle prüfen:
   a) **nichts tun** → nach 5 s schließt er sich, Protokoll sagt „Keine Antwort in 5 s",
      die Datei bleibt liegen;
   b) **„Nein, nur neue"** → gleiches Ergebnis, sofort;
   c) **„Ja, übernehmen"** mit einem *anderen* Zielordner → die Datei landet dort,
      nicht im Setup-Ziel.
   Und: im Zielfeld tippen muss die Uhr anhalten.
7. **Eine Testdatei** (`.avi`) in den Quellordner kopieren:
   Protokoll → „Neue Datei entdeckt" → „ist fertig geschrieben" → „verschoben (Nr. 1)",
   Zähler springt auf 1, Datei liegt im Zielordner.
   **Wichtig dabei:** während des Kopierens muss sich das Fenster noch bedienen
   lassen (Knöpfe reagieren, Protokoll läuft weiter). Genau das war in Version 2
   nicht möglich.
8. **Echter Replay aus OBS** — die Datei wird während des Schreibens gesperrt;
   im Protokoll muss „stabil x/3" hochzählen, danach verschieben.
9. **Zwei Dateien gleichzeitig** — die zweite wartet in der Warteschlange und
   kommt danach dran.
10. **Namensgleichheit** — dieselbe Datei zweimal: die zweite wird `name_(1).avi`.
11. **Netzlaufwerk trennen** — nach höchstens 30 s meldet das Protokoll
    „Ordner nicht erreichbar". Wieder verbinden → „Ordner wieder erreichbar".
12. **Stopp** — zurück zum Setup, `status.json` sagt „AVI-Mover gestoppt".
13. **Fenster schließen** — Schlussstatus wird geschrieben, Zähler bleibt erhalten
    (in Version 2 hing er zeitweise auf „unerwartet beendet / -1").
14. **Absturz simulieren** — Prozess im Task-Manager beenden. Der Watchdog muss
    innerhalb von ~5 s den Absturzstatus schreiben.

---

## Was ich **nicht** habe testen können

Dieses Paket ist auf dem Linux-Server gebaut worden. Dort läuft PowerShell 7,
aber **kein WinForms** — die Oberfläche konnte ich nicht starten.

Geprüft ist:
* die Syntax aller drei Skripte mit dem PowerShell-Parser (fehlerfrei),
* die statische Durchsicht auf die üblichen Fallen (automatische Variable `$args`,
  `Add-Type`-Namensraum, mehrzeilige Beschriftung, Ereignis-Abholung).

Nicht geprüft ist alles, was ein Fenster oder Windows braucht: Darstellung,
Robocopy, Sperrverhalten, Watchdog. Genau dafür ist die Liste oben.

---

## Dateien

| Datei | Zweck |
|---|---|
| `AVI-Mover.ps1` | das Programm |
| `Watchdog.ps1` | Absturzwache, wird beim Start automatisch mitgestartet |
| `Merge-TurnierLog.ps1` | führt die Ergebnis-Logs mehrerer Matten zusammen |
| `AVI-Mover.ini` | letzte Einstellungen (Zeilenformat wie 2.x) |
| `Logs\` | Protokolle je Tag **und** die Ergebnis-Logs je Turnier/Matte |
| `Server\Status.html` | Web-Anzeige, liest `status.json` |
| `on-mover.png`, `off-mover.png`, `Pocessing.gif` | Bilder für die Web-Anzeige |
| `Logo.ico` | Fenster- und Programmsymbol |

Die alte Fassung liegt unangetastet in `..\AVI-Mover\` — nichts daran wurde geändert.
