You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
9.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<div align="center">
<img src="assets/icon.svg" width="120" alt="drop.two">
<h1>drop.two</h1>
<p><strong>9:16 rein. 9:16 und 4:5 raus.</strong></p>
</div>
---
## Warum
Alle Videos werden im Format 9:16 geschnitten. Nach der Freigabe müssen sie zusätzlich als 4:5 abgelegt werden. Das Framing wird beim Schnitt bereits so angelegt, dass der 4:5-Ausschnitt funktioniert — es braucht also keine zweite Timeline, sondern nur einen sauberen, mittigen Beschnitt des fertigen Masters.
Bisher passiert das über ein selbstgebautes Python-CLI. `drop.two` macht daraus ein Werkzeug, das auch Kolleginnen und Kollegen ohne Terminal benutzen können: Dateien reinziehen, Ziel prüfen, fertig.
## Was die App macht
1. Eine oder mehrere 9:16-Dateien werden ausgewählt oder per Drag & Drop übergeben.
2. Aus dem Dateinamen wird das Projekt gelesen.
3. Im Zielordner entsteht ein Unterordner mit dem Projektnamen.
4. Dort landen beide Fassungen: das unveränderte 9:16-Original und die neu gerenderte 4:5-Version.
Kein Preset-Dschungel, keine Timeline, kein Export-Dialog.
## Namenskonvention
```
[Projekt]-[Format]-[Version]-[Sprache].[ext]
```
Beispiel:
```
SOMOS-9x16-v3-DE.mp4 → SOMOS/SOMOS-9x16-v3-DE.mp4
SOMOS/SOMOS-4x5-v3-DE.mp4
```
**Parsing-Regel:** Es wird **von rechts** gelesen. Die letzten drei Segmente sind Sprache, Version und Format; alles davor ist der Projektname. Nur so bleiben Projektnamen mit eigenem Bindestrich intakt:
```
Somos-Pendant-9x16-v3-DE.mp4
└──── Projekt ────┘ └Fmt┘└Ver┘└Spr┘
```
Für die Zielversion wird ausschließlich das Format-Segment ersetzt: `9x16` → `4x5`. Alle anderen Segmente bleiben zeichengleich erhalten.
**Abbruchbedingungen** — die App verarbeitet nicht und meldet es sichtbar:
- Dateiname entspricht nicht dem Schema (weniger als vier Segmente)
- Format-Segment ist nicht `9x16`
- Quelldatei hat kein 9:16-Seitenverhältnis
- Zieldatei existiert bereits (überschreiben nur nach Rückfrage)
## Crop-Logik
Der 4:5-Ausschnitt behält die **volle Breite** und beschneidet oben und unten:
```
Breite bleibt unverändert
Höhe = Breite × 5 ÷ 4 (auf gerade Zahl gerundet)
Anker vertikal zentriert (Offset später konfigurierbar)
```
| Quelle | Ziel |
|---|---|
| 1080 × 1920 | 1080 × 1350 |
| 2160 × 3840 | 2160 × 2700 |
**Codec-Verhalten:** Der Quell-Codec wird erkannt und passend ausgespielt — ProRes bleibt ProRes, H.264 bleibt H.264 mit vergleichbarer Bitrate. Die Audiospur läuft per Passthrough durch, ohne Neukodierung. Framerate, Farbraum und Dauer bleiben unangetastet.
## Funktionsumfang
**MVP**
- [x] Dateiauswahl und Drag & Drop
- [x] Einstellbarer Quellordner (Dialog öffnet direkt dort)
- [x] Einstellbarer Zielordner, Projekt-Unterordner wird automatisch angelegt
- [x] Dateiauswahl vorsortiert nach *zuletzt geändert*
- [x] Fortschrittsanzeige pro Datei und gesamt
- [x] Fehlerliste statt stiller Abbrüche
**Danach**
- [x] Review-Ansicht: 9:16-Master mit eingeblendetem 4:5-Rahmen zur Framing-Kontrolle, scrubbar
- [ ] Menu-Bar-Betrieb mit Drop-Target
- [ ] Vertikaler Crop-Offset pro Datei justierbar
- [ ] In-App-Updates über Sparkle
- [ ] Batch-Verlauf der letzten Durchläufe
- [ ] Hilfe-Bereich: klickbare Kurzanleitung zur Bedienung der App
- [ ] Rechtlich erforderliche Angaben (Impressum o.ä.) einbinden — Absicherung, wo genau (in-App, Download-Seite) noch offen
## Tech-Stack
**Swift + SwiftUI**, macOS 13+.
| Baustein | Lösung |
|---|---|
| Oberfläche | SwiftUI, `MenuBarExtra` für den Hintergrundbetrieb |
| Video | **AVFoundation** — hardwarebeschleunigt über VideoToolbox |
| Review-Player | `AVPlayer` mit Overlay |
| Updates | **Sparkle 2** gegen `appcast.xml` auf eigenem Server |
| Einstellungen | `@AppStorage` + Security-Scoped Bookmarks für Ordnerzugriff |
| Projektdatei | **XcodeGen** (`project.yml`) — textbasiert, merge-freundlich |
| Paket | Signiertes `.dmg`, ca. 5 MB |
**Warum kein ffmpeg:** Der Beschnitt ist rein geometrisch. AVFoundation erledigt ihn nativ über eine `AVMutableVideoComposition`. Das spart rund 80 MB Bundle-Größe, die GPL-Frage und ein mitzulieferndes Binary.
**Warum nicht Python:** py2app- und PyInstaller-Bundles sind fragil, starten träge, wiegen ein Vielfaches und machen Code-Signing sowie Notarisierung unnötig schwer. Für ein Werkzeug, das Kollegen installieren sollen, ist das der falsche Unterbau.
## Architektur
```
DropTwoCore Framework, komplett UI-frei
├── FileNameParser zerlegt und baut Dateinamen
├── VideoInspector liest Dimension, Codec, Framerate, Dauer
├── CropEngine AVAsset → VideoComposition → Export
└── JobQueue async/await, 1–2 parallele Exports
DropTwo App-Target
├── Settings Pfade, Bookmarks, Presets
├── DropZone Auswahl und Drag & Drop
├── ProgressView Fortschritt und Fehlerliste
└── ReviewSheet AVPlayer mit 4:5-Overlay
droptwo-cli Kommandozeilen-Target gegen denselben Core
```
Der Kern kennt keine Oberfläche. Das hält ihn testbar und macht das CLI-Target zum ehrlichen Prüfstein: Was dort funktioniert, funktioniert in der App.
## Projektstruktur
```
drop.two/
├── project.yml XcodeGen-Konfiguration
├── Sources/
│ ├── DropTwoCore/
│ ├── DropTwo/
│ └── DropTwoCLI/
├── Tests/
│ └── DropTwoCoreTests/
├── assets/
│ ├── icon.svg Bildmarke
│ └── icon-menubar.svg Template-Variante für die Menu-Bar
├── scripts/
│ ├── build.sh
│ └── release.sh
└── docs/
```
Die `.xcodeproj` wird **nicht** eingecheckt — sie entsteht aus `project.yml`.
## Einrichtung
**Voraussetzungen**
- Xcode (vollständig, aus dem App Store) — wegen macOS-SDK, `xcodebuild` und `notarytool`
- Homebrew
```bash
brew install xcodegen swiftformat
git clone https://git.samuelzielke.de/samuelzielke/drop.two.git
cd drop.two
xcodegen generate
open DropTwo.xcodeproj # nur bei Bedarf
```
**Arbeiten ohne Xcode-Oberfläche:** VS Code mit der offiziellen Swift-Extension (SourceKit-LSP) deckt Autovervollständigung, Fehleranzeige und Navigation ab. Gebaut wird per `xcodebuild`. Xcode selbst braucht es für SwiftUI-Previews, Zertifikate und Instruments.
```bash
xcodebuild -scheme DropTwo -configuration Debug build
xcodebuild -scheme DropTwoCoreTests test
```
## Release
Vor dem ersten Release einmalig einzurichten:
1. **Apple Developer Program** (99 €/Jahr, Anmeldung als Einzelperson). Liefert das *Developer ID Application*-Zertifikat. Ohne Signatur und Notarisierung blockiert Gatekeeper die App bei allen anderen.
2. **Sparkle-Schlüsselpaar** per `generate_keys`. Der private Schlüssel bleibt im macOS-Schlüsselbund und **niemals im Repo**; der öffentliche wandert als `SUPublicEDKey` in die `Info.plist`.
3. **Team-ID** in `project.yml` unter `DEVELOPMENT_TEAM` eintragen.
> **Den privaten Sparkle-Schlüssel sichern.** Geht er verloren, lassen sich bereits installierte Kopien nie wieder aktualisieren — alle müssten neu installieren.
Ablauf pro Release:
```bash
xcodebuild -scheme DropTwo -configuration Release archive …
codesign --deep --options runtime --sign "Developer ID Application: …" DropTwo.app
create-dmg …
xcrun notarytool submit drop.two-1.0.dmg --keychain-profile "notary" --wait
xcrun stapler staple drop.two-1.0.dmg
sign_update drop.two-1.0.dmg # Signatur in appcast.xml eintragen
```
DMG und `appcast.xml` landen anschließend auf dem eigenen Server. Der Code liegt auf Gitea, die Release-Artefakte nicht.
### Landingpage (`site/`)
Die Seite unter [droptwo.zielke.studio](https://droptwo.zielke.studio) liegt in `site/` und wird nicht von `publish-release.sh` hochgeladen. Die Versionsnummer liest sie selbst aus `appcast.xml`, nach einem Release muss sie also nicht angefasst werden. Nach Änderungen an der Seite:
```bash
rsync -a --chmod=F644 site/index.html site/favicon.svg samuelzielke@10.0.5.223:/var/www/updates/droptwo/
```
Die Übersicht aller Apps und das Statistik-Dashboard liegen im Repo `zielke-apps`.
## Umsetzungsreihenfolge
Die Reihenfolge ist bewusst gewählt:
1. `FileNameParser` samt Unit-Tests — inklusive Bindestrich-Kantenfällen
2. `VideoInspector` und `CropEngine`
3. `droptwo-cli` als Prüfstein, echte Datei durchjagen, **Ausgabequalität bewerten**
4. Erst danach die Oberfläche
5. Review-Ansicht
6. Signierung, Notarisierung, Sparkle
Schritt 3 entscheidet über das Projekt. Liefert AVFoundation nicht die nötige Qualität, muss das am ersten Tag auffallen — nicht nachdem die halbe App steht.
## Offene Punkte
- Zielpfad-Schema bei mehreren Sprachen oder Versionen desselben Projekts
- Verhalten bei bereits vorhandenem Zielordner: ergänzen oder warnen
- Ob das 9:16-Original kopiert oder verschoben wird
- Bitrate-Strategie bei H.264: Quellbitrate übernehmen oder fester Qualitätsfaktor
- Vertikaler Offset — global, pro Projekt oder pro Datei
## Gestaltung
Bildmarke: ein 9:16-Rahmen, darin der 4:5-Ausschnitt in voller Breite und vertikal zentriert — exakt das, was die App tut.
| | |
|---|---|
| Dark | `#0B0B0C` |
| Light | `#F5F5F4` |
| Gold | `#C8A96A` |
| Mid Gray | `#B8B5B0` |
Gold ist der einzige Akzent und bleibt sparsam eingesetzt.

Powered by TurnKey Linux.