Skip to main content

Archivar für Videoschnitt-Projekte: packt FCPXML-Bundles und iMovieMobile-Container ins Langzeit-Archiv, mit aggregierten Projekt-Metadaten und Video-Originalmedien-Inventar.

Project description

🎬 schnittprojekt-archivar

Archivar für Videoschnitt-Projekte. Verpackt FCPXML-Bundles und iMovieMobile-Container ins Langzeit-Archiv und schreibt zwei aggregierte Metadaten-Sidecars dazu: Projekt-Übersicht (.project.toml) und Clip-Inventar (.project.clips.jsonl) mit voller MediaFileMetadata pro referenziertem Quellclip.

Status: 2.1.0 (Beta) — Greenfield-Neuanfang nach Bounded-Context-Wechsel; die Versionsnummer setzt den Git-Tag-Stream des Repos fort (v1.x war fcplib-manager, siehe CHANGELOG). API-Vertrag startet mit 2.0.0; v2.1.0 ergänzt Konsumenten-Helpers (verify_archive, skip_if_target_exists, delete_source_after_archive) für die familienfilm-manager-Integration. Breaking Changes erst bei 3.0.0.

Hinweis: Bis Januar 2026 hiess dieses Repo fcplib-manager und archivierte Final-Cut-Pro-Libraries (FCPBundles) via tar+split+SSH. Mit der Umbenennung zu schnittprojekt-archivar ändert sich der Bounded Context komplett: Schnittprojekte im FCPXML-/iMovieMobile-Format statt FCP-Library-Bundles.

✨ Was es kann

  • Drei Schnittprojekt-Formate:
    • .fcpxmld (FCP-Bundle, Verzeichnis) → ZIP-Container mit ZIP_STORED+allowZip64 (kein erneutes Komprimieren, weil Bundle-Medien bereits HEVC/ProRes sind)
    • .fcpxml (Single-File) → 1:1-Kopie ohne Container
    • .iMovieMobile (ist schon ZIP) → 1:1-Kopie ohne erneutes Zippen
  • Atomares Schreiben überall (write-to-tempfile + os.replace). Crashes hinterlassen keine Halb-Dateien.
  • Aggregiertes Projekt-Manifest (<stem>.project.toml): Format, Sequenz, Aufnahmedatum mit Provenance, Clip-Anzahl, Bundle-Größe.
  • Clip-Inventar (<stem>.project.clips.jsonl): pro referenziertem Quellclip eine JSONL-Zeile mit voller MediaFileMetadata aus kurmann-medien-leser (Codec, Auflösung, GPS, Kamera-Modell, Production-Felder, etc.) — kompatibel zum kamera-einleser-Manifest-Format für Cross-References zwischen Schnittprojekt-Sicht und Originalmedien-Volumes.
  • rclone-Ziele unterstützt: lokal in work_dir aufbauen, dann via rclone copyto ins Archiv-Remote.
  • Flexibles Konsumenten-API: Suffixe sind Konstanten (keine hardcoded Implementierungs-Details). Drei Schichten — Daten, Bundle-Packaging, Persistierung — können separat oder als Convenience zusammen genutzt werden.

📋 Voraussetzungen

  • Python 3.11 oder höher
  • exiftool (Pflicht, für Clip-Inventar) — brew install exiftool auf macOS
  • rclone (optional, für rclone-Ziele) — brew install rclone auf macOS

Quelle = lokaler Pfad. Der Archivar liest das Schnittprojekt heute ausschliesslich vom lokalen Filesystem (echte lokale Pfade oder gemountete Netzpfade wie /Volumes/<share>/...). rclone-URIs (remote:path/...) sind nur als Ziel (--target-dir) erlaubt, nicht als Quelle. Wer ein Projekt vom NAS archivieren will, ohne den Share gemountet zu haben, holt es vorher via rclone copy ins lokale Work-Dir.

Archivieren = kopieren, nicht verschieben. Die Originalquelle wird nie gelöscht oder verändert. Der Archivar arbeitet ausschliesslich Copy-and-Verify; Aufräumen der Quelle ist Aufgabe des Konsumenten (z. B. familienfilm-manager).

.fcpxml vs. .fcpxmld — was archiviert wird: FCP exportiert oft beides nebeneinander: eine Flat-.fcpxml (paar KB XML) und ein .fcpxmld/-Bundle (Verzeichnis mit Info.fcpxml + Resources). Wenn beide mit gleichem Stem nebeneinander liegen, bricht der Archivar mit Fehler ab, statt zu raten — du gibst gezielt das .fcpxmld/-Verzeichnis an, wenn du das Bundle willst. Override: --allow-flat-fcpxml.

Self-contained, wenn die Quelle es ist. Bei .fcpxmld-Bundles (LumaFusion-Export, typisch auch FCP-Mac) und .iMovieMobile-Containern liegen die Originalmedien direkt im Bundle/Container neben der Projekt-XML, mit relativen src="./..."-Pfaden. Der Archivar packt den gesamten Bundle-Inhalt mit ins ZIP — das Archiv ist also self-contained: Entpacken → in FCP/LumaFusion/iMovie öffnen, läuft. Bei der Flat-.fcpxml-Variante (nur die XML, keine Medien-Files daneben) wird nur die XML kopiert; das ist als Live-Workflow-Sicht gedacht, nicht als Langzeit-Archiv. Das .project.clips.jsonl-Inventar dokumentiert zusätzlich, aus welchen ISO-Manifests / Volumes die Clips ursprünglich stammen — Cross-Reference zur Originalmedien-Sicht, nicht Ersatz für Mitarchivierung.

🚀 Installation

uv add kurmann-schnittprojekt-archivar
# oder
pipx install kurmann-schnittprojekt-archivar
# oder
pip install kurmann-schnittprojekt-archivar

🎯 Quick Start

CLI

schnittprojekt-archivar archive \
    "/Volumes/Videoschnitt/Familienfilme/Projekte/Mädchen spazieren.fcpxmld" \
    --target-dir "lyssach-nas:/Archiv/2026/Projekte" \
    --target-stem "2026-05-10-Maedchen-spazieren" \
    --timezone Europe/Zurich

Erzeugt im Ziel:

2026-05-10-Maedchen-spazieren.fcpxmld.zip   ← Bundle als ZIP
2026-05-10-Maedchen-spazieren.project.toml  ← Projekt-Metadaten
2026-05-10-Maedchen-spazieren.project.clips.jsonl   ← Clip-Inventar

Als Bibliothek

from pathlib import Path
from schnittprojekt_archivar import archive_project
from schnittprojekt_archivar.models import ArchiveProjectRequest, RuntimeOptions

result = archive_project(
    ArchiveProjectRequest(
        project_path=Path("Mädchen spazieren.fcpxmld"),
        target_dir="lyssach-nas:/Archiv/2026/Projekte",
        target_stem="2026-05-10-Maedchen-spazieren",
        timezone_assumption="Europe/Zurich",
    ),
    RuntimeOptions(),
)
if result.success:
    print(result.bundle.target_uri, result.bundle.bundle_size_bytes)
else:
    print("Fehler:", result.error_message)

🧾 Was kommt zurück? Beispiel-Output

<stem>.project.toml (aggregiert)

[meta]
schema_version = 1
generator = "Kurmann Schnittprojekt-Archivar 2.1.0"
created_at = "2026-05-21T10:00:00+02:00"

[project]
name = "Fünffacher Büsi-Nachwuchs bei Tagesmutter Karin"
format = "fcpxml_bundle"
schema_version = "1.8"
original_filename = "Fünffacher Büsi-Nachwuchs bei Tagesmutter Karin poster-13s080.fcpxmld"
mtime = "2026-05-10T20:02:57+02:00"

[recording]
first_clip_date = "2026-05-05"
first_clip_datetime = "2026-05-05T17:43:51+02:00"
first_clip_source_label = "exif:Keys:CreationDate"
first_clip_confidence = "high"

[sequence]
width = 3840
height = 2160
color_space = "9-16-9 (Rec. 2020 PQ)"
audio_layout = "stereo"

[counts]
clips_primary = 6
clips_total = 7

[bundle]
archive_filename = "2026-05-05-Buesi-Nachwuchs.fcpxmld.zip"
archive_size_bytes = 421857393

<stem>.project.clips.jsonl (Inventar)

{"_type":"header","manifest_version":1,"project_name":"Fünffacher Büsi-Nachwuchs bei Tagesmutter Karin","project_format":"fcpxml_bundle","clip_count":6,"generator":"Kurmann Schnittprojekt-Archivar 2.1.0","created_at":"2026-05-21T10:00:00+02:00"}
{"spine_index":0,"relative_path":"./A001_05051743_C491.mov","asset_id":"p1997","clip_name":"A001_05051743_C491","is_video":true,"resolution_status":"resolved","resolved_uri":"/.../A001_05051743_C491.mov","media_metadata":{"recorded_at":"2026-05-05T17:43:51+02:00","recorded_at_source":"exif:Keys:CreationDate","source_app":"Blackmagic Camera","video":{"codec":"HEVC","resolution":"3840x2160","fps":60.007},"camera":{"model":"Apple iPhone 15 Pro Max 120mm","software":"Blackmagic Cam 3.3.100001"},"gps":{"lat":47.06675,"lon":7.58025}}}
{"spine_index":1,"relative_path":"./A001_05051744_C492.mov",...}

🏛 Architektur — drei Schichten + ein Wrapper

┌─────────────────────────────────────────────────────────────────┐
│ Convenience / CLI                                               │
│ ─────────────────                                               │
│ archive_project(request, runtime)                               │
│   opinion-getriebener Happy-Path: liest, packt, persistiert.    │
└─────────────────────────────────────────────────────────────────┘
              │
        ┌─────┼─────┐
        ▼     ▼     ▼
 ┌──────────┐ ┌──────────────┐ ┌────────────────────┐
 │ Daten    │ │ Bundle       │ │ Persistierung      │
 │ ─────    │ │ ──────       │ │ ──────────────     │
 │ read_    │ │ package_     │ │ write_manifest_    │
 │ project_ │ │ project_     │ │ toml(m, path)      │
 │ manifest │ │ bundle       │ │ write_clips_jsonl( │
 │  → in-   │ │  → ZIP /     │ │   m, path)         │
 │   memory │ │   1:1-Kopie  │ │ Suffix-Konstanten  │
 │ Mani-    │ │   nach Ziel  │ │ als Empfehlung,    │
 │ fest     │ │              │ │ nicht Pflicht      │
 └──────────┘ └──────────────┘ └────────────────────┘

Konsumenten können nach Bedarf entweder den Convenience-Wrapper nutzen oder die einzelnen Schichten kombinieren — siehe „Konsumenten-Szenarien" weiter unten.

📚 Public API

Symbol Beschreibung
archive_project(request, runtime) → ArchiveProjectResult Convenience-Orchestrator: Manifest lesen + Bundle packen + Sidecars schreiben
verify_archive(target_dir, target_stem, runtime) → VerifyArchiveResult v2.1.0 Read-only-Idempotenz-Check: liegen alle erwarteten Artefakte am Ziel?
read_project_manifest(path, runtime) → ProjectManifest Liest Schnittprojekt + Clips, liefert in-memory Objekt (keine Side-Effects)
package_project_bundle(path, target_dir, filename, runtime) → PackageResult Verpackt Bundle ins Ziel (Caller wählt Filename)
write_manifest_toml(manifest, path) Aggregiertes Manifest als TOML (atomar)
write_clips_jsonl(manifest, path) Clip-Inventar als JSONL (atomar)
to_archive_stem(text) → str, is_archive_safe_stem(text) → bool ASCII-Slug-Helper (v2.0.0+, idempotent)
PROJECT_TOML_SUFFIX, CLIPS_JSONL_SUFFIX, FCPXML_BUNDLE_ZIP_SUFFIX, IMOVIE_MOBILE_SUFFIX, FCPXML_SINGLE_SUFFIX Empfohlene Suffixe als Konstanten
ArchiveProjectRequest, ArchiveProjectResult, PackageResult, RuntimeOptions, ProjectManifest, ClipEntry, ProjectHeader, SequenceInfo, ArchivarEvent Dataclasses (Type-Hints + Serialisierungs-Helpers)
SchnittprojektArchivarError, BundleError, ManifestReadError, ArchiveTargetError, ArchiveTargetExistsError Exception-Hierarchie

🏷 Begriffe und Suffix-Konventionen

Die Suffixe sind so gewählt, dass sie auch ohne diese README verständlich sind und nicht mit anderen kurmann-Sidecars kollidieren.

Quellformate: .fcpxml, .fcpxmld, .iMovieMobile

Suffix Was es ist Wie's der Archivar verpackt
.fcpxml Flat-XML, Single-File. Reine Edit-Decision-XML, paar KB bis paar MB. 1:1-Kopie.
.fcpxmld FCPXML-Document = macOS-Package (Verzeichnis). Enthält Info.fcpxml + optional Resources/ mit eingebetteten Vorschau-Daten. Das d-Suffix ist Apples Konvention für „Bundle-Variante eines flachen Formats" (analog .rtf.rtfd). ZIP-Container .fcpxmld.zip mit ZIP_STORED+allowZip64, alphabetisch sortierte Member (deterministisch).
.iMovieMobile iMovie-iOS-Export — bereits ein ZIP-Container. 1:1-Kopie (kein Re-Zip).

Wenn FCP beides exportiert (.fcpxml und .fcpxmld mit gleichem Stem): immer das .fcpxmld archivieren — das ist die vollständige Variante. Der Archivar erkennt diese Mehrdeutigkeit und bricht ab, wenn man die Flat-Variante als Quelle angibt, während ein Bundle daneben liegt. Override falls bewusst nur die Flat-XML gewünscht: --allow-flat-fcpxml.

Namespace .project.* (Archivar) vs. .video.* (familienfilm-manager)

Wenn ein Familienfilm gleichzeitig als Schnitt-Export und als Schnittprojekt archiviert wird, leben beide Sätze problemlos im selben Verzeichnis nebeneinander — gleicher <stem>, unterschiedliche Domäne-Präfixe:

2026-05-10-Maedchen-spazieren.mov                       ← FFM-Video-Export
2026-05-10-Maedchen-spazieren.video.toml                ← FFM-Sidecar (Recording, Publishing)
2026-05-10-Maedchen-spazieren.fcpxmld.zip               ← Archivar-Bundle
2026-05-10-Maedchen-spazieren.project.toml              ← Archivar-Projekt-Manifest
2026-05-10-Maedchen-spazieren.project.clips.jsonl       ← Archivar-Clip-Inventar
Namespace Domäne Verantwortlich
.video.* exportierter Schnitt-Stream (was publiziert wird) familienfilm-manager
.project.* Schnittprojekt-Quelldatei (woraus exportiert wurde) dieser Archivar

<domäne>.toml ohne weiteren Zusatz = Haupt-Manifest dieser Domäne (= „Metadaten"). Zusatz-Suffixe wie .clips qualifizieren spezialisierte Inventare.

Warum „Clips" und nicht „Originalmedien"?

Zwei legitime Vokabulare treffen aufeinander:

  • Schnittprojekt-Sicht (im FCPXML als <asset-clip>, im iMovieMobile als editList[i] mit clipType): hier sind die referenzierten Asset-Einheiten Clips. Das ist die Sprache, in der das Projekt selbst über sein Material spricht. Auch Audio-Subspuren wären „Audio-Clips" im Schnitt-Sinne.
  • NAS-Sicht (/Volumes/Originalmedien/, kamera-einleser-ISO-Manifests): hier heisst dasselbe Material Originalmedien — die unbeschnittenen Aufnahmen von der Kamera, bevor sie ein Projekt sehen.

Beide Begriffe widersprechen sich nicht, sie zeigen dasselbe Material aus zwei Schichten. In diesem Archivar gilt die Schnittprojekt-Sicht — daher .project.clips.jsonl. Cross-References zwischen kamera-einleser-ISO-Manifest (Originalmedien-Sicht) und <stem>.project.clips.jsonl (Schnittprojekt-Sicht) bleiben über die gemeinsame MediaFileMetadata-Struktur möglich (gleiche Felder, gleiche Schemas, beide aus kurmann-medien-leser).

🎯 Scope von include_clips (v2.0.0)

Standardmässig (include_clips=True) wird das vollständige Inventar aller referenzierten Video-Clips in <stem>.project.clips.jsonl geschrieben.

Enthalten: Top-Level-Spine-Video-Clips mit Asset-Backing — bei FCPXML alles, was asset-clip mit echter Quelldatei referenziert; bei iMovieMobile editList-Einträge mit clipType=1.

Bewusst NICHT enthalten (Stand v2.0.0):

  • Audio-Subspuren / separate Audio-Synchronspuren
  • Foto-Clips (clipType=5 iMovieMobile)
  • Transitions (clipType=3)
  • Sekundäre Tracks / Picture-in-Picture
  • Generators, Titles, Effekte ohne Asset-Backing

Hintergrund: Die Detail-Metadaten pro Clip werden vom kurmann-medien-leser gelesen, der heute auf Video-Metadaten ausgerichtet ist. Sobald Audio-Schemas dort verfügbar sind, wird include_audio_tracks=True als additives Flag ergänzt — kein Schema-Bruch nötig, weil „Clip" konzeptuell auch Audio-Clips abdecken kann.

Use-Case: Cross-References zwischen Schnittprojekten und Originalmedien-Volumes (z.B. ISO-Manifests aus kamera-einleser). Fragen wie „welche Clips aus ISO XYZ wurden in welchem Schnittprojekt verwendet?" sind mit beiden JSONL-Manifesten gemeinsam beantwortbar — gleiches MediaFileMetadata-Schema.

🤝 Konsumenten-Szenarien

Szenario α: Standalone-Aufruf via CLI

schnittprojekt-archivar archive <projekt> \
    --target-dir <archiv-uri> --target-stem <slug>

Alles ins Ziel, drei Sidecars nebeneinander.

Szenario β: Bundle packen, Manifest in eigene Struktur einbetten

Für Konsumenten wie den familienfilm-manager, die ihr eigenes Sidecar-Schema haben:

from schnittprojekt_archivar import (
    read_project_manifest,
    package_project_bundle,
)

# 1. Manifest als in-memory-Objekt lesen
manifest = read_project_manifest(project_path, runtime)

# 2. Bundle separat verpacken (Konsument wählt Filename)
package_project_bundle(
    project_path,
    target_dir="nas:/Archiv/2026/Videoschnitt",
    target_filename="2026-05-10-Maedchen.fcpxmld.zip",
    runtime=runtime,
)

# 3. Konsument bettet Manifest in eigene .video.toml-Sektion ein —
#    schreibt KEIN .project.toml oder .project.clips.jsonl daneben.
ffm_sidecar.schnittprojekt = {
    "bundle_filename": "2026-05-10-Maedchen.fcpxmld.zip",
    "first_clip_date": manifest.header.first_clip_date,
    "clip_count": len(manifest.clips),
    # ... etc
}

Szenario γ: Convenience, aber kein project.clips.jsonl

from schnittprojekt_archivar import archive_project
from schnittprojekt_archivar.models import ArchiveProjectRequest

archive_project(
    ArchiveProjectRequest(
        project_path=project_path,
        target_dir=target_dir,
        target_stem="2026-05-10-Maedchen",
        write_clips_jsonl_file=False,  # nur .project.toml + Bundle
    ),
    runtime,
)

🐚 CLI-Disziplin (Unix-Style)

Der schnittprojekt-archivar-CLI folgt klassischer Unix-Philosophie: Stille ist Erfolg.

Kanal Default --verbose --json
stdout (leer) (leer) Result-JSON
stderr (leer); Fehler bei Misserfolg Event-Trace + Slug-Hinweis + Sub-Prozess-Output wie ohne --json
Exit-Code 0 (Erfolg) / 1 (Fehler) wie Default wie Default

Beispiele:

# Stiller Aufruf — Erfolg erkennt man am Exit-Code
schnittprojekt-archivar archive <projekt> --target-dir <ziel>
echo $?    # 0

# Pipeline-Konsument
schnittprojekt-archivar archive <projekt> --target-dir <ziel> --json \
  | jq -r .target_uri

# Diagnose
schnittprojekt-archivar archive <projekt> --target-dir <ziel> -v
# stderr zeigt: [stem_slugified] target_stem »...« → »...«
#               [bundle_build_started] ...
#               [bundle_upload_completed] ...

Fehler landen immer auf stderr, unabhängig von --verbose. --verbose und --json sind orthogonal kombinierbar.

🏷 ASCII-Slug-Disziplin

Der Archivar wendet per Default eine Archivierungs-Disziplin auf den Ziel-Dateinamen an: target_stem wird durch to_archive_stem() geschickt und damit ASCII-safe gemacht. So bleiben die Archiv-Dateinamen filesystem-, cloud- und Tooling-neutral lesbar.

Algorithmus (in schnittprojekt_archivar.models.slug):

  1. Unicode-Normalisierung NFC.
  2. Deutsche Transliteration: ä→ae, ö→oe, ü→ue, ß→ss (Gross-Schreibung analog).
  3. NFKD + ASCII-Encode errors="ignore" (entfernt restliche Diakritika und Nicht-ASCII).
  4. Regex [^a-zA-Z0-9]+ → '-', dann führende/abschliessende - strippen.

Beispiele:

Eingabe Ergebnis
Mädchen spazieren Maedchen-spazieren
2026-05-10 – Höhenflug 2026-05-10-Hoehenflug
Café crème Cafe-creme
2026-05-10-Maedchen 2026-05-10-Maedchen (unverändert)

Die Funktion ist idempotent — doppelte Anwendung ändert nichts.

Public-API:

from schnittprojekt_archivar import to_archive_stem, is_archive_safe_stem

to_archive_stem("Mädchen spazieren")        # "Maedchen-spazieren"
is_archive_safe_stem("Mädchen spazieren")   # False
is_archive_safe_stem("Maedchen-spazieren")  # True

Default-Verhalten in archive_project: Umlaute werden still umgeformt, das Ergebnis steht in ArchiveProjectResult.effective_stem, das Original in original_stem, das Flag stem_was_slugified=True. Zusätzlich emittiert der Archivar eine Warnung und ein stem_slugified-Event.

Strict-Modus mit strict_stem=True (CLI: --strict-stem): der Archivar slugifiziert nicht, sondern verlangt, dass der gelieferte Stem bereits archivtauglich ist. Andernfalls bricht er mit klarer Fehlermeldung ab, bevor irgendetwas geschrieben wird — sinnvoll für Konsumenten, die selbst über die finale Namensgebung bestimmen wollen (z. B. familienfilm-manager, der seine eigene Slug-Logik hat).

Diese Slug-Logik existiert 1:1 auch im familienfilm-manager (Code-Spiegelung). Sobald ein dritter Konsument auftaucht oder Archiv-Helpers gebündelt werden sollen (PAR2, ZIP64, Indexierung), lohnt sich ein kurmann-archiv-utils-Helper-Repo. Heute YAGNI.

🛣️ Roadmap

  • 0.x: API-Stabilisierung mit dem ersten Konsumenten (familienfilm-manager v1.5+).
  • 0.2.x: extract-Subcommand für Retrieval aus dem Archiv (Architektur ist eingeplant, Schemas tragen die nötigen Felder bereits).
  • 0.3.x: Indexierung über mehrere Projekte (optional — Discovery via externe jq-Queries reicht heute).
  • 1.0.0: API-Lock nach SemVer.
  • Später: include_audio_tracks=True, sobald kurmann-medien-leser Audio-Schemas unterstützt.

📝 Lizenz

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kurmann_schnittprojekt_archivar-2.1.0.tar.gz (57.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kurmann_schnittprojekt_archivar-2.1.0-py3-none-any.whl (55.3 kB view details)

Uploaded Python 3

File details

Details for the file kurmann_schnittprojekt_archivar-2.1.0.tar.gz.

File metadata

File hashes

Hashes for kurmann_schnittprojekt_archivar-2.1.0.tar.gz
Algorithm Hash digest
SHA256 d6bbfb59201e19e4286d3724c518c246b0120e60e23b3ec368239f0ae7538d2d
MD5 b3303518b25b8399eab905f987e97abd
BLAKE2b-256 c723dcb6abb4f83c1a8e901a1d65a023d8c3ae20f48a60aff6333a08c139f4c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for kurmann_schnittprojekt_archivar-2.1.0.tar.gz:

Publisher: publish.yml on kurmann/schnittprojekt-archivar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kurmann_schnittprojekt_archivar-2.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for kurmann_schnittprojekt_archivar-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c4bec46b09f5293cea33e41200a22b653ad66d77b4d726c432cfe3c80f9e0152
MD5 4b4d9aefbc08c6be16da5b9781f835fe
BLAKE2b-256 431f754ac06ab33f9cc64bff81195d322ac0dd254b946201988a4b07a0b14ee2

See more details on using hashes here.

Provenance

The following attestation bundles were made for kurmann_schnittprojekt_archivar-2.1.0-py3-none-any.whl:

Publisher: publish.yml on kurmann/schnittprojekt-archivar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page