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.

250 lines
11 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 Zeichen bleiben gleich erhalten.
**Schreibweisen:** Das Format darf groß oder klein (`9x16`, `9X16`, `9×16`) und mit `-`, `_` oder Leerzeichen abgetrennt sein; die Trenner bleiben in der Zielfassung erhalten (`Kampagne_9X16_v2` → `Kampagne_4x5_v2`). Ein Rest hinter dem Format ist nicht nötig.
**Kein Format im Namen:** Die App zeigt das schon beim Reinziehen und bietet „4x5 anhängen“ an. Dann wird der ganze Dateistamm zum Projekt, und `4x5` wird mit dem Trenner angehängt, den der Name schon benutzt (`Sommerfest Teaser.mov` → `Sommerfest Teaser/Sommerfest Teaser 4x5.mp4`). Ohne diese Wahl wird die Datei übersprungen.
**Abbruchbedingungen** — die App verarbeitet nicht und meldet es sichtbar:
- Kein `9x16` mit Projektnamen davor im Namen (Ausweg: „4x5 anhängen“, s. o.)
- 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 (pro Datei verschiebbar, s. u.)
```
**Ausschnitt verschieben:** In der Review-Ansicht lässt sich der 4:5-Rahmen mit der Maus nach oben oder unten ziehen. Für Clips mit Szenenwechsel gibt es **Positionsmarken**: an die Stelle spulen, *Marke setzen* (Taste `M`), Rahmen ziehen. Jede Marke gilt ab ihrem Frame bis zur nächsten, als harter Schnitt ohne Fahrt dazwischen. Tasten: Leertaste spielt ab, `←`/`→` springen um ein Frame. Der Plan gilt pro Datei und wird mit *Übernehmen* gesetzt; die Dateiliste zeigt angepasste Ausschnitte in Gold.
| Quelle | Ziel |
|---|---|
| 1080 × 1920 | 1080 × 1350 |
| 2160 × 3840 | 2160 × 2700 |
**Codec-Verhalten:** Die 4:5-Fassung ist immer MP4 mit H.264 (High Profile) und AAC 128 kbit/s, das Zielformat für Feed und Meta Ads, egal ob ProRes, H.264 oder HEVC reinkommt. Die Bitrate richtet sich nach Auflösung und Framerate. Framerate 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
- [x] Vertikaler Crop-Offset pro Datei justierbar, mit Positionsmarken für Szenenwechsel
- [x] In-App-Updates über Sparkle (automatisch plus „Nach Updates suchen …“ im App-Menü)
- [ ] Batch-Verlauf der letzten Durchläufe
- [ ] Hilfe-Bereich: klickbare Kurzanleitung zur Bedienung der App
- [x] Rechtliche Angaben: Website verlinkt Impressum & Datenschutz von zielke.studio (wie Patchcord)
## 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
├── CropPlan Ausschnitt-Position(en) über die Laufzeit
├── 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=D755,F644 site/index.html site/favicon.svg site/fonts site/og samuelzielke@10.0.5.223:/var/www/updates/droptwo/
```
Schriften liegen selbst gehostet in `site/fonts/` (keine Anfragen an Google). Das Vorschaubild für geteilte Links `site/og/og-de.png` entsteht aus `og-de.html`:
```bash
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless=new --hide-scrollbars \
--window-size=1200,630 --screenshot="$PWD/site/og/og-de.png" "file://$PWD/site/og/og-de.html"
```
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
## 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.