From dea31eee6775369dc7eff0283026ee56c08676f2 Mon Sep 17 00:00:00 2001 From: Dedsec <293355188+Dedsec-Art@users.noreply.github.com> Date: Sat, 25 Jul 2026 21:17:29 +0200 Subject: [PATCH] Add English documentation --- .github/ISSUE_TEMPLATE/bug_report.yml | 36 +-- .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/ISSUE_TEMPLATE/feature_request.yml | 26 +- .github/ISSUE_TEMPLATE/order_detection.yml | 52 ++-- .github/pull_request_template.md | 42 ++-- .github/release.yml | 10 +- ANLEITUNG.en.md | 268 +++++++++++++++++++++ ANLEITUNG.md | 14 +- CHANGELOG.en.md | 25 ++ CHANGELOG.md | 3 + CODE_OF_CONDUCT.en.md | 17 ++ CODE_OF_CONDUCT.md | 2 + CONTRIBUTING.en.md | 83 +++++++ CONTRIBUTING.md | 2 + README.en.md | 109 +++++++++ README.md | 2 + SECURITY.en.md | 24 ++ SECURITY.md | 7 +- SUPPORT.en.md | 15 ++ SUPPORT.md | 2 + ripper_py/tests/test_community_contract.py | 40 +++ 21 files changed, 703 insertions(+), 80 deletions(-) create mode 100644 ANLEITUNG.en.md create mode 100644 CHANGELOG.en.md create mode 100644 CODE_OF_CONDUCT.en.md create mode 100644 CONTRIBUTING.en.md create mode 100644 README.en.md create mode 100644 SECURITY.en.md create mode 100644 SUPPORT.en.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8f170f7..5e8e2e8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ -name: Fehler melden -description: Einen reproduzierbaren Programmfehler ohne private Daten melden -title: "[Fehler] " +name: Fehler melden / Report a bug +description: Einen reproduzierbaren Fehler melden / Report a reproducible problem without private data +title: "[Bug] " labels: - bug body: @@ -9,51 +9,55 @@ body: value: | Danke für die Meldung. Bitte keine API-Schlüssel, Disc-Kennungen, persönlichen Pfade, vollständigen Logs oder Mediendateien hochladen. + Thank you for the report. Do not upload API keys, disc identifiers, + personal paths, complete logs, or media files. - type: input id: version attributes: - label: Ultra-Version - placeholder: "z. B. 2.0.0" + label: Ultra-Version / Ultra version + placeholder: "z. B. / e.g. 2.0.0" validations: required: true - type: input id: windows attributes: - label: Windows-Version - placeholder: "z. B. Windows 11 24H2" + label: Windows-Version / Windows version + placeholder: "z. B. / e.g. Windows 11 24H2" validations: required: true - type: textarea id: problem attributes: - label: Fehlerbeschreibung - description: Was ist passiert und was wurde erwartet? + label: Fehlerbeschreibung / Problem description + description: Was ist passiert und was wurde erwartet? / What happened, and what did you expect? validations: required: true - type: textarea id: reproduce attributes: - label: Reproduktionsschritte + label: Reproduktionsschritte / Steps to reproduce placeholder: | - 1. Quelle auswählen + 1. Quelle auswählen / Select a source 2. … - 3. Fehler tritt auf + 3. Fehler tritt auf / The problem occurs validations: required: true - type: textarea id: diagnostics attributes: - label: Bereinigte Diagnose + label: Bereinigte Diagnose / Sanitized diagnostics description: | Nur den kleinsten relevanten Ausschnitt einfügen. Schlüssel, Tokens, Benutzernamen, Laufwerks- und Mediennamen vorher vollständig ersetzen. + Include only the smallest relevant excerpt. Fully replace keys, tokens, + usernames, drive names, and media names first. render: text - type: checkboxes id: privacy attributes: - label: Datenschutzprüfung + label: Datenschutzprüfung / Privacy check options: - - label: Ich habe alle Zugangsdaten, persönlichen Pfade, Disc-Kennungen und privaten Medieninformationen entfernt. + - label: Ich habe alle Zugangsdaten, persönlichen Pfade, Disc-Kennungen und privaten Medieninformationen entfernt. / I removed all credentials, personal paths, disc identifiers, and private media information. required: true - - label: Für eine Sicherheitslücke verwende ich keine öffentliche Fehlermeldung, sondern den in SECURITY.md beschriebenen privaten Meldeweg. + - label: Für eine Sicherheitslücke verwende ich keine öffentliche Fehlermeldung, sondern den in SECURITY.md beschriebenen privaten Meldeweg. / For a vulnerability, I will use the private reporting process in SECURITY.md instead of this public form. required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index db442d4..15bdef6 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Fragen und gemeinsamer Austausch + - name: Fragen und gemeinsamer Austausch / Questions and discussion url: https://github.com/Dedsec-Art/Ultra/discussions - about: Für Bedienfragen, offene Ideen und Gespräche, die noch kein konkretes Issue benötigen. + about: Für Bedienfragen und offene Ideen / For usage questions and early ideas that do not require a concrete issue yet. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 4a089d0..70056ad 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ -name: Verbesserung vorschlagen -description: Eine neue Funktion oder Bedienverbesserung vorschlagen -title: "[Idee] " +name: Verbesserung vorschlagen / Suggest an improvement +description: Eine neue Funktion vorschlagen / Suggest a feature or usability improvement +title: "[Feature] " labels: - enhancement body: @@ -9,31 +9,33 @@ body: value: | Bitte den Anwendungsfall beschreiben, ohne private Disc-, Konto- oder Systemdaten zu veröffentlichen. + Describe the use case without disclosing private disc, account, or + system information. - type: textarea id: use_case attributes: - label: Anwendungsfall - description: Welches Problem soll gelöst werden? + label: Anwendungsfall / Use case + description: Welches Problem soll gelöst werden? / What problem should be solved? validations: required: true - type: textarea id: proposal attributes: - label: Gewünschte Lösung - description: Wie sollte sich Ultra verhalten? + label: Gewünschte Lösung / Proposed solution + description: Wie sollte sich Ultra verhalten? / How should Ultra behave? validations: required: true - type: textarea id: alternatives attributes: - label: Alternativen - description: Welche anderen Lösungen wurden bereits erwogen? + label: Alternativen / Alternatives + description: Welche anderen Lösungen wurden bereits erwogen? / What other solutions have you considered? - type: checkboxes id: safety attributes: - label: Sicherheitsprüfung + label: Sicherheitsprüfung / Safety check options: - - label: Der Vorschlag bewahrt den verlustfreien 1:1-Workflow oder kennzeichnet Abweichungen ausdrücklich. + - label: Der Vorschlag bewahrt den verlustfreien 1:1-Workflow oder kennzeichnet Abweichungen ausdrücklich. / The proposal preserves the lossless 1:1 workflow or clearly identifies any deviation. required: true - - label: Die Beschreibung enthält keine Zugangsdaten oder personenbezogenen Daten. + - label: Die Beschreibung enthält keine Zugangsdaten oder personenbezogenen Daten. / The description contains no credentials or personal data. required: true diff --git a/.github/ISSUE_TEMPLATE/order_detection.yml b/.github/ISSUE_TEMPLATE/order_detection.yml index e0d4882..990dd62 100644 --- a/.github/ISSUE_TEMPLATE/order_detection.yml +++ b/.github/ISSUE_TEMPLATE/order_detection.yml @@ -1,6 +1,6 @@ -name: Reihenfolge-Erkennung melden -description: Eine falsche oder unsichere Episodenreihenfolge mit anonymisierten Daten melden -title: "[Reihenfolge] " +name: Reihenfolge-Erkennung / Episode-order detection +description: Eine falsche Reihenfolge melden / Report an incorrect or uncertain order using anonymized data +title: "[Order] " labels: - bug - order-detection @@ -13,67 +13,73 @@ body: relevanten Ausschnitt des Voting-Reports verwenden. Keine Disc-Namen, Hashes, Seriennummern, persönlichen Pfade, vollständigen Logs, Screenshots aus Medien oder Mediendateien veröffentlichen. + Thank you for helping improve episode-order detection. Use neutral + labels, rounded runtimes, and only the smallest relevant voting-report + excerpt. Do not publish disc names, hashes, serial numbers, personal + paths, complete logs, media screenshots, or media files. - type: input id: version attributes: - label: Ultra-Version - placeholder: "z. B. 2.0.0" + label: Ultra-Version / Ultra version + placeholder: "z. B. / e.g. 2.0.0" validations: required: true - type: dropdown id: source attributes: - label: Quellentyp + label: Quellentyp / Source type options: - Blu-ray - DVD - ISO - - BDMV-Ordner - - Anderer anonymisierter Testfall + - BDMV-Ordner / BDMV folder + - Anderer anonymisierter Testfall / Other anonymized test case validations: required: true - type: dropdown id: confidence attributes: - label: Angezeigter Status + label: Angezeigter Status / Displayed status options: - - bestätigt - - wahrscheinlich - - unsicher - - ungeprüft - - nicht bekannt + - bestätigt / confirmed + - wahrscheinlich / likely + - unsicher / uncertain + - ungeprüft / unverified + - nicht bekannt / unknown validations: required: true - type: textarea id: observed attributes: - label: Erkannte Reihenfolge - description: Neutrale Titel wie A, B, C und gerundete Laufzeiten verwenden. + label: Erkannte Reihenfolge / Detected order + description: Neutrale Titel und gerundete Laufzeiten verwenden. / Use neutral labels such as A, B, C and rounded runtimes. placeholder: "A (ca. 24 min) → C (ca. 24 min) → B (ca. 24 min)" validations: required: true - type: textarea id: expected attributes: - label: Erwartete Reihenfolge und Prüfung - description: Wie lautet die richtige Folge und wie wurde sie ohne private Daten bestätigt? - placeholder: "A → B → C; durch manuelle Menüauswahl bestätigt" + label: Erwartete Reihenfolge und Prüfung / Expected order and verification + description: Wie wurde die richtige Folge ohne private Daten bestätigt? / What is the correct order, and how was it verified without private data? + placeholder: "A → B → C; durch manuelle Menüauswahl bestätigt / verified using manual menu selection" validations: required: true - type: textarea id: evidence attributes: - label: Bereinigte Stimmen und Widersprüche + label: Bereinigte Stimmen und Widersprüche / Sanitized votes and conflicts description: | Nur Quellennamen, Konfidenz und anonymisierte Reihenfolgen aus dem Voting-Report nennen, zum Beispiel „Menü: A-B-C; Laufzeit: stumm“. + Include only source names, confidence, and anonymized orders from the + voting report, for example “Menu: A-B-C; Runtime: abstained.” render: text - type: checkboxes id: privacy attributes: - label: Datenschutz und Rechte + label: Datenschutz und Rechte / Privacy and rights options: - - label: Ich habe alle Zugangsdaten, Disc-Kennungen, Hashes, persönlichen Pfade und privaten Medieninformationen entfernt. + - label: Ich habe alle Zugangsdaten, Disc-Kennungen, Hashes, persönlichen Pfade und privaten Medieninformationen entfernt. / I removed all credentials, disc identifiers, hashes, personal paths, and private media information. required: true - - label: Ich lade keine urheberrechtlich geschützten Medien, Screenshots oder vollständigen Logs hoch. + - label: Ich lade keine urheberrechtlich geschützten Medien, Screenshots oder vollständigen Logs hoch. / I will not upload copyrighted media, screenshots, or complete logs. required: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 2defd22..af76109 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,35 +1,45 @@ -## Änderung +## Änderung / Change - + -## Bezug +## Bezug / Related work - + -## Sicherheits- und Datenschutzwirkung +## Sicherheits- und Datenschutzwirkung / Security and privacy impact - + -## Nutzerwirkung und Dokumentation +## Nutzerwirkung und Dokumentation / User impact and documentation - + -## Reihenfolge und 1:1-Garantie +## Reihenfolge und 1:1-Garantie / Ordering and 1:1 guarantee + Workflow nennen. Bei keiner Auswirkung „keine“ schreiben. / + Describe effects on ordering votes, confidence, and the lossless workflow. + Write “none” when the change has no effect. --> -## Prüfung +## Prüfung / Verification - [ ] `python tools\check_public_tree.py` - [ ] `python -m ripper_py.tests.run_all` - [ ] Nicht zutreffend oder für Fehlerkorrekturen wurde ein Regressionstest - ergänzt. + ergänzt. / Not applicable, or a regression test was added for a bug fix. - [ ] Nicht zutreffend oder nutzerrelevante Änderungen sind dokumentiert. -- [ ] Tests und Beispiele verwenden ausschließlich synthetische Daten. + / Not applicable, or user-facing changes are documented. +- [ ] Tests und Beispiele verwenden ausschließlich synthetische Daten. / + Tests and examples use synthetic data only. - [ ] Es wurden keine API-Schlüssel, Tokens, persönlichen Pfade, Logs, - Disc-Kennungen oder Mediendateien aufgenommen. + Disc-Kennungen oder Mediendateien aufgenommen. / No API keys, tokens, + personal paths, logs, disc identifiers, or media files were included. - [ ] Der 1:1-Workflow lässt Video-, Audio- und Untertitelstreams byte-identisch; - optionale Transcodes bleiben klar davon getrennt. + optionale Transcodes bleiben klar davon getrennt. / The 1:1 workflow keeps + video, audio, and subtitle streams byte-identical; optional transcodes + remain clearly separate. - [ ] Unsichere Reihenfolgen werden nicht geraten und bleiben `None` oder - ausdrücklich „unsicher“. + ausdrücklich „unsicher“. / Uncertain orders are not guessed and remain + `None` or explicitly marked as uncertain. diff --git a/.github/release.yml b/.github/release.yml index 8c88256..9bef045 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -3,19 +3,19 @@ changelog: labels: - skip-changelog categories: - - title: Neue Funktionen + - title: Neue Funktionen / New features labels: - enhancement - - title: Fehlerbehebungen + - title: Fehlerbehebungen / Bug fixes labels: - bug - - title: Dokumentation + - title: Dokumentation / Documentation labels: - documentation - - title: Abhängigkeiten und Automatisierung + - title: Abhängigkeiten und Automatisierung / Dependencies and automation labels: - dependencies - github_actions - - title: Weitere Beiträge + - title: Weitere Beiträge / Other contributions labels: - "*" diff --git a/ANLEITUNG.en.md b/ANLEITUNG.en.md new file mode 100644 index 0000000..639e628 --- /dev/null +++ b/ANLEITUNG.en.md @@ -0,0 +1,268 @@ +# Ultra — User Guide + +**English** · [Deutsch](ANLEITUNG.md) + +A quick reference for using Ultra. + +> **Startup note:** Immediately after you double-click the launcher, a small +> “Ultra” startup window appears. The main window then opens in the source +> view while the remaining sections finish loading invisibly in the +> background. Ultra remembers the window size and position when you close it. + +## Starting Ultra + +- **First run: `Ultra setup.bat`** — accepts only Python 3.10–3.14, creates + the isolated `.venv` environment, and installs only the exactly pinned, + SHA-256-verified packages from `ripper_py\requirements.lock`. +- **`Ultra starten.bat`** — starts Ultra normally, without a black console + window. +- **`Ultra DEBUG.bat`** — starts Ultra with a black console window that + displays error messages. Use this version if something is not working. + +Ultra automatically enforces exactly **one instance per Windows user**, even +across local and RDP sessions. A second launch is safely rejected so that it +cannot mistake an active rip for a crashed one. + +## The new interface (Ultra design) + +The **sidebar** on the left contains **Quelle** (Source), **Titel** (Titles), +**Aktiver Rip** (Active rip), **Warteschlange** (Queue), **Verlauf** (History), +and **Einstellungen** (Settings). At the bottom is the drive card with its +spinning disc. The header at the top right contains **⏹ Stopp** (Stop), which +can cancel a scan or rip at any time; the **light/dark button**, which switches +themes immediately and remembers your choice; and the **Werkzeuge** (Tools) +button with all tools for **Datei · Disc · Tools · VLC**. This menu contains +the specialist functions that were previously in the menu bar. + +All primary actions use a shared design system with a visible keyboard-focus +indicator, semantic status colors, and standard controls that are at least +40 px high. Press **Alt+1 through Alt+6** to switch directly between sections. +The settings offer **System/Hell/Dunkel** (System/Light/Dark), interface +scaling from 90–150%, and **Bewegung reduzieren** (Reduce motion). + +## Typical workflow + +1. **Insert a disc** — the drive appears in the drive card at the bottom of + the sidebar and is usually detected automatically. +2. Under **Quelle** (Source), choose the **mode**: **Film** (Movie), + **Serie** (TV series), or **Anime**. +3. Click **🔍 Titel einlesen** (Read titles) at the top right. Ultra reads the + disc, automatically fills in its name, season, and disc number, and then + switches to **Titel-Auswahl** (Title selection). +4. In TV-series and anime modes, **episode titles** are loaded automatically: + - **TV series:** from TMDB, using German titles. + - **Anime:** from AniList. If AniList finds nothing—for example, because of + a typo in the disc name—Ultra automatically continues the search through + MyAnimeList. If there are multiple results, a selection appears; choose + the correct season (for example, “Tokyo Ghoul √A” = season 2). +5. **Select tracks:** under *Audiospuren* (Audio tracks) and *Untertitel* + (Subtitles) in **Titel-Auswahl** (Title selection), select the tracks you + want. Ultra remembers the selection for all subsequent episodes **and** + for the next launch. +6. Choose **▶ Rip starten** (Start rip) for one episode from the bar at the + bottom, or **⏩ Auto** for the entire disc as described below. During the + rip, **Aktiver Rip** (Active rip) displays progress, speed, and the log. + +## Fields under “Quelle” (Source) + +- **Name** — the TV-series or movie name. Ultra suggests it from the disc + name, but you can overwrite it. +- **Jahr** (Year) — optional; helps TMDB with the search. +- **Staffel / Episode / Disc** (Season / Episode / Disc) — detected from the + disc name, for example “Season 2 Disc 1”, “S2 P1”, or “2-1”. Adjust these + manually if necessary. +- **🔍 TMDB-Suche / AniList** (TMDB search / AniList) — manual search in case + the automatic result is not correct. +- **↺ vom Disc-Namen** (From disc name) — fills in the name and year again + from the disc name. +- **EP-Titel** (Episode title) — the title of the current episode, set + automatically. +- **Ausgabeordner / Profil** (Output folder / Profile) — the destination + folder and quick profiles, such as “Serie klein (NVENC)”. A preview of the + completed file path appears underneath. + +## Title list and “Alle Titel anzeigen” + +By default, Ultra displays only the **actual episodes**. It automatically +filters out extras, bonus material, and “Play All” playlists. + +Select **Alle Titel anzeigen** (Show all titles) if you really want to see +*every* playlist—for example, to rip an extra or select an episode manually. + +## Details card: what is saved? + +In **Titel-Auswahl** (Title selection), below Audio and Subtitles, the +**Details – wird in die MKV gespeichert** (Details — saved in the MKV) card +shows every property obtained from TMDB or AniList: title, year, genre, +description, director, actors, rating, studio, country, original title, +episode title, cover art, total bitrate, and the Windows details file (.xmp). + +- **✕** before a field means that it will **not** be saved during the rip. + Ultra remembers this choice permanently. **Alle wiederherstellen** (Restore + all) restores every field. +- At the bottom are the **technical provenance fields** that MakeMKV or + mkvmerge would otherwise write automatically: **writing/muxing application, + encoding date, track names,** and **track statistics**. You can also remove + these with **✕**. The writing application is scrubbed from the header in a + length-preserving operation, leaving the file 100% valid and its streams + byte-identical. +- **🔒 1:1 guarantee:** The selected video, audio, and subtitle streams remain + **byte-identical to their source streams** and are never re-encoded in the + 1:1 workflow. All details exist only in the container header (mkvpropedit) + or the adjacent .xmp file—nothing in the streams is changed. The card warns + you if **Automatisch komprimieren** (Compress automatically) or + **Lautstärke angleichen** (Normalize volume) is enabled, because either + option would change the content. +- **Windows:** File Explorer does not have its own MKV property reader. The + details are stored in Matroska tags, which Jellyfin, VLC, and MediaInfo can + all display, and in the adjacent .xmp file. To obtain the complete Details + tab in File Explorer, install the free **Icaros** property handler. + +## ▶ Ripping a single title + +Rips the currently selected title with the selected tracks. Output follows +the Jellyfin naming scheme, for example: + +```text +\\Staffel 02\S02E01 - Episodentitel.mkv +``` + +If **all** tracks are selected, the file is quickly renamed with all selected +streams preserved byte-for-byte. If you deselect tracks, the file is remuxed +without re-encoding the retained streams. + +### Backups and existing destinations + +- Ultra never overwrites a file that appears at the destination only after a + job has started. You must explicitly confirm an existing destination, and + it must remain unchanged until the commit. +- After a confirmed overwrite, the previous file is retained as + `ultra-original-*` or, for transcoding or normalization, as + `source-preserved-*`. Delete it manually only after performing your own + playback or hash verification. +- When a complete rip is split losslessly, the + `*_GESAMT-Sicherheitskopie-*.mkv` file remains in place even after all + episodes have been created successfully. This deliberately requires + additional storage space. +- If a crash leaves a recovery journal open, Ultra will not start another rip + until the recovery dialog has unambiguously resolved the files. An existing + but corrupted journal file also blocks operation fail-closed; a new job + never silently overwrites it. + +## ⏩ Auto mode (all episodes) + +Automatically rips **every episode from the currently selected episode +onward**, one after another and without prompting. The selected tracks apply +to all episodes. + +**Multiple discs:** When the final episode on a disc is complete, Ultra +**automatically ejects the disc** and asks for the next one. Insert the new +disc, click **Weiter (nächste Disc)** (Continue [next disc]), and Ultra rescans +it and automatically continues ripping. All settings remain unchanged. Click +**Fertig** (Done) to end the automatic run. + +## ⏹ Stopp (Stop) + +Stops **immediately and completely**: the active rip is aborted, and no +scheduled subsequent episodes or discs are started. + +## 📦 Extras + +Rips the currently selected title as **bonus material** into an Extras +subfolder: + +```text +\\Extras\.mkv +``` + +Procedure: select the title, enabling **Alle Titel anzeigen** (Show all titles) +if necessary → click **Extras** → enter a name, such as “Behind the Scenes”. +There is no episode number; Jellyfin recognizes the folder as bonus material. + +## ⚙ Einstellungen (Settings) + +This is a dedicated section in the sidebar. It contains **everything**: paths +to MakeMKV and MKVToolNix, the TMDB API key, the output format, episodes per +disc, and switches for Ultra's tools: **GPU-Encoding** (GPU encoding, including +hevc_nvenc), **Jellyfin-Sofortscan** (Immediate Jellyfin scan), +**Untertitel-Download** (Subtitle download), **Watch-Folder**, +**Reihenfolge/Kapitel-Split** (Order/chapter split), and **Profile**. +**Erscheinungsbild** (Appearance) contains System/Light/Dark, UI scaling, and +reduced motion. Save using the button at the top right of the header. Ultra +reports a write failure explicitly; it displays “saved” only after reading +the INI back and verifying it exactly. + +The Watch Folder no longer waits only for an unchanged file size. It also +checks nanosecond timestamps and file identity, and, for BDMV trees, the file +count and tree fingerprint. Its atomic +`stable/retry → queued → completed/failed` state prevents duplicate processing +after a restart. Each queue reservation contains a PID and process-start +token: only an owner that can be proven to have exited is automatically +released as `retry`; ambiguous states remain safely locked. Direct BDMV +folders are detected and reported once, but are not ripped automatically +without a secure Windows mount or menu identity. + +## DVDs and episode order + +DVDs now have their own order votes as well. Ultra reads the disc's table of +contents—the IFO files—and derives the **title order in the disc menu**, the +**physical positions** of the episodes on the disc, and, where present, the +**Play All chain**, which is the DVD equivalent of a Blu-ray Play All +playlist. These signals are supplemented by **runtime matching** against +TMDB or AniList and by **TheDiscDb**, using episode runtimes for DVDs. +Only when ALL of these signals remain silent—for example, when every episode +has exactly the same runtime—does Ultra honestly continue to report +**“unsicher” (uncertain)**. In that case, briefly inspect the first episode +with **🖼 Vorschau** (Preview). If the order is wrong, move the episodes with +**▲▼**; Ultra permanently remembers the result for that disc. + +Technically coupled votes are not counted more than once. For example, +Play All, marks, and chapters form one evidence family; menu, Java, and +Warner menu form another. **“Bestätigt” (confirmed)** requires at least two +independent families and the same robust order even when each complete family +is removed in turn as a test. A mere Borda indication from an uncertain +partial run does not count. Agreement based only on numeric sources remains, +at most, **“wahrscheinlich” (probable)**. + +## After an automatic rip: the order verifies itself + +If the order was only **“wahrscheinlich” (probable)**, Ultra checks it +automatically after the disc, in stages ordered by cost: + +1. **Preview chain (offline, without AI):** Anime episodes almost always end + with a preview of the next episode. Ultra compares a visual fingerprint of + the end of each episode against the main portion of every other episode. + If the episodes form a chain in exactly the ripped order, that order is + proven and remembered. The setting **Vorschau-Kette nach dem Auto-Rip** + (Preview chain after automatic rip) is enabled by default. To test a + completed season manually, choose + **⋯ → 🔗 Reihenfolge per Vorschau-Kette prüfen (offline)** + (Check order using preview chain [offline]). +2. **Single-anchor check:** Only the FIRST episode on the disc is identified + by content. With a Gemini key, this uses tvidentify—one request instead of + one for every episode. Without a key, it compares **subtitle timing** + against OpenSubtitles; this requires subliminal but no AI. If the anchor + matches, the entire disc order is considered confirmed. +3. Only for **“unsicher” (uncertain)** results or a contradiction does Ultra + perform the existing full content check of every episode + (**tvidentify · Gemini**). + +## If something is not working + +- **Disc is not detected:** Wait briefly and click **Scannen** (Scan) again; + make sure only one Ultra window is running. +- **Wrong anime or TV series found:** Correct the name in the field and search + again. +- **Check episode order:** Enable **Alle Titel anzeigen** (Show all titles) + and compare the runtimes. +- **More detailed troubleshooting:** Start Ultra through `Ultra DEBUG.bat`. + The `debug_scan.txt` file also contains the raw data from the most recent + scan. + +## Note: “Gesamtbitrate 0” in Windows File Explorer + +For MKV files, the Windows File Explorer Details tab often displays +*Gesamtbitrate* (Total bitrate) as “0”. This is a Windows/MKV limitation. The +individual video and audio values are stored correctly, and Jellyfin, VLC, +and MediaInfo display all of them correctly. This has no effect on playback +or quality. diff --git a/ANLEITUNG.md b/ANLEITUNG.md index 5c36657..b57ded6 100644 --- a/ANLEITUNG.md +++ b/ANLEITUNG.md @@ -1,5 +1,7 @@ # Ultra – Anleitung +**Sprache:** Deutsch · [English](ANLEITUNG.en.md) + Kurzer Spickzettel, wie Ultra bedient wird. > **Hinweis zum Start:** Direkt nach dem Doppelklick erscheint ein kleines @@ -78,9 +80,11 @@ und die Windows-Details-Datei (.xmp). **Track-Statistik**. Auch die lassen sich mit ✕ entfernen — das Erstell-Programm wird dabei längenerhaltend aus dem Header getilgt, die Datei bleibt zu 100 % gültig und die Streams byte-identisch. -- **🔒 1:1-Garantie:** Video, Audio und Untertitel bleiben **byte-identisch** - zur Disc. Alle Details liegen nur im Container-Kopf (mkvpropedit) bzw. in - der .xmp-Datei daneben — am Inhalt ändert sich nichts. Die Karte warnt, +- **🔒 1:1-Garantie:** Die gewählten Video-, Audio- und Untertitelstreams + bleiben **byte-identisch zu ihren Quellstreams** und werden im 1:1-Workflow + nie neu kodiert. Alle Details liegen nur im Container-Kopf (mkvpropedit) + bzw. in der .xmp-Datei daneben — an den Streams ändert sich nichts. Die Karte + warnt, falls „Automatisch komprimieren"/„Lautstärke angleichen" aktiv ist (das würde den Inhalt verändern). - **Windows:** Der Explorer hat für MKV keinen eigenen Eigenschaften-Leser — @@ -94,7 +98,9 @@ Rippt den aktuell gewählten Titel mit den gewählten Spuren. Ausgabe nach Jelly ``` \\Staffel 02\S02E01 - Episodentitel.mkv ``` -Sind **alle** Spuren ausgewählt, wird die Datei 1:1 schnell umbenannt (bitgenau). Wählst du Spuren ab, wird verlustfrei neu zusammengesetzt. +Sind **alle** Spuren ausgewählt, wird die Datei schnell umbenannt; die gewählten +Streams bleiben dabei byte-identisch. Wählst du Spuren ab, wird ohne +Neukodierung der verbleibenden Streams neu zusammengesetzt. ### Sicherheitskopien und vorhandene Ziele diff --git a/CHANGELOG.en.md b/CHANGELOG.en.md new file mode 100644 index 0000000..1f5d9de --- /dev/null +++ b/CHANGELOG.en.md @@ -0,0 +1,25 @@ +# Changelog + +**Language:** [Deutsch](CHANGELOG.md) · English + +## Unreleased + +Accepted community changes are collected here until the next release. + +## 2.0.0 — 2026-07-25 + +- modern, accessible CustomTkinter interface +- visible and cancellable progress for ISO and MakeMKV operations +- faster ISO validation with a safe Windows read lease +- robust episode-order detection using 13 conservative evidence sources +- virtual Blu-ray and DVD menu inspection +- support for BDMV, ISO, DVD, and physical-disc sources +- fail-closed source binding and atomic runtime state +- DPAPI-protected local API credentials +- comprehensive integrated test runner +- community collaboration through Issues, Discussions, and Pull Requests +- English project, user, and community documentation +- release under the MIT License + +Older internal development states were not imported into the Git history +before the first public release. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef48d5..5333f5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Änderungsprotokoll +**Sprache:** Deutsch · [English](CHANGELOG.en.md) + ## Unveröffentlicht Angenommene Community-Änderungen werden hier bis zum nächsten Release @@ -17,6 +19,7 @@ gesammelt. - DPAPI-geschützte lokale API-Zugänge - vollständiger integrierter Test-Runner - Community-Zusammenarbeit über Issues, Discussions und Pull Requests +- englische Projekt-, Benutzer- und Community-Dokumentation - Veröffentlichung unter der MIT-Lizenz Ältere interne Entwicklungsstände wurden vor der ersten öffentlichen diff --git a/CODE_OF_CONDUCT.en.md b/CODE_OF_CONDUCT.en.md new file mode 100644 index 0000000..5bc6f41 --- /dev/null +++ b/CODE_OF_CONDUCT.en.md @@ -0,0 +1,17 @@ +# Code of Conduct + +**Language:** [Deutsch](CODE_OF_CONDUCT.md) · English + +We want collaboration in this project to remain constructive, respectful, and +safe. + +- Treat others with respect and keep technical criticism specific. +- Do not engage in harassment or discrimination, or disclose private data. +- Do not share real credentials, logs, disc identifiers, or local media paths + in issues, pull requests, screenshots, or attachments. +- Report security vulnerabilities privately as described in + [SECURITY.en.md](SECURITY.en.md). + +Contributions that violate these rules may be rejected or removed. Moderation +decisions should be transparent, proportionate, and focused on protecting the +people involved. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 96645dc..1a174b3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,7 @@ # Verhaltenskodex +**Sprache:** Deutsch · [English](CODE_OF_CONDUCT.en.md) + Wir möchten eine sachliche, respektvolle und sichere Zusammenarbeit. - Andere Personen respektvoll behandeln und technische Kritik konkret halten. diff --git a/CONTRIBUTING.en.md b/CONTRIBUTING.en.md new file mode 100644 index 0000000..46c1aa4 --- /dev/null +++ b/CONTRIBUTING.en.md @@ -0,0 +1,83 @@ +# Contributing + +**Language:** [Deutsch](CONTRIBUTING.md) · English + +Thank you for helping us improve Ultra. We welcome bug reports, ideas, +documentation, tests, and code—including your first open-source contribution. + +## Where to Go + +- **Questions and early-stage ideas:** [GitHub Discussions](https://github.com/Dedsec-Art/Ultra/discussions) +- **Reproducible bugs:** [Open a bug report](https://github.com/Dedsec-Art/Ultra/issues/new/choose) +- **Specific improvements:** Link the relevant issue or discussion, then open a + pull request +- **Security vulnerabilities:** Use only the confidential reporting channel + described in [SECURITY.en.md](SECURITY.en.md) + +Please discuss larger features first. This allows us to agree on the goal, +security requirements, and user experience before substantial work begins. + +## Submitting a Contribution + +1. Fork the repository and create a focused branch, for example + `feature/better-order-detection` or `fix/scan-cancel`. +2. Install the dependencies with `Ultra setup.bat`. +3. Implement one cohesive change. Bug fixes require a regression test; visible + features also require appropriate documentation. +4. Run the privacy scanner and the complete test suite. +5. Open a pull request describing the problem, solution, impact, and test + results. Use `Fixes #123` when the pull request should close an issue. + +## Technical Guardrails + +1. Keep changes small and easy to review. +2. Do not commit real API keys, disc names, user paths, logs, or media files. +3. Never guess uncertain episode-order results: `None` is better than an + incorrect assignment. +4. Always write JSON and INI state atomically. +5. Never modify audio or video streams in the 1:1 workflow. +6. Core functions must uphold the “never raises” contract: catch errors and + return `None` or a safe default instead of propagating an uncertain state. +7. Collect credentials only through the user interface and store them with + Windows DPAPI; never put plaintext keys in code, examples, or tests. + +## Testing + +```powershell +python tools\check_public_tree.py +python -m unittest discover -s ripper_py\tests +python -m ripper_py.tests.run_all +``` + +Every bug fix must include a regression test in the same change. Tests must use +synthetic names, paths, and key placeholders. + +## Review and Release + +Pull requests are reviewed for correctness, readability, security, privacy, and +performance. All GitHub CI checks must pass. Questions and change requests are +part of collaborative development and will be communicated clearly and +respectfully. + +Accepted contributions are merged into `main`. User-facing changes appear in +the changelog and in a subsequent GitHub release; no specific release date can +be guaranteed. When creating a release, GitHub can generate an overview grouped +by labels for new features, bug fixes, documentation, and dependencies, and can +credit the contributors involved. + +## Commit Privacy + +Before your first commit, configure your preferred public display name and the +GitHub-provided `noreply` address locally for this repository. Otherwise, a +private email address may remain permanently visible in the Git history. + +## Pull Requests + +The description should state the problem, solution, security impact, and tests +performed. Do not include personal or confidential information in the pull +request, screenshots, attachments, or CI logs. + +By submitting a contribution, you confirm that you have the necessary rights to +it and that it may be published under the project's [MIT License](LICENSE). +Collaboration is governed by the +[Code of Conduct](CODE_OF_CONDUCT.en.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16af430..dbdb4de 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,7 @@ # Mitwirken +**Sprache:** Deutsch · [English](CONTRIBUTING.en.md) + Danke, dass du Ultra gemeinsam mit uns verbessern möchtest. Willkommen sind Fehlerberichte, Ideen, Dokumentation, Tests und Code – auch als erster Open-Source-Beitrag. diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..732bb2d --- /dev/null +++ b/README.en.md @@ -0,0 +1,109 @@ +# Ultra + +**English** · [Deutsch](README.md) + +Ultra is a Windows desktop application for archiving your own DVDs and Blu-rays +with MakeMKV while preserving the selected source streams. It supports +TV-series discs, ISO and BDMV sources, conservative episode-order detection, +track selection, metadata management, and verifiable 1:1 stream preservation. + +> The project documentation is available in English. The application interface +> itself is currently German. + +## Key features + +- stream-preserving MakeMKV workflow that never re-encodes audio, video, or + subtitle streams +- support for ISO, BDMV, DVD, and physical-disc sources +- weighted episode-order detection with fail-closed consensus +- visible progress during lengthy ISO checks and MakeMKV stages +- Windows DPAPI protection for locally stored API credentials +- atomic configuration and status files +- comprehensive test runner with no pytest dependency + +## Improve Ultra together + +Ultra is an open community project. Contributions of every size and from every +experience level are welcome, including bug reports, new ideas, documentation, +tests, and code: + +- [discuss questions and ideas with the community](https://github.com/Dedsec-Art/Ultra/discussions) +- [report a bug or request a feature](https://github.com/Dedsec-Art/Ultra/issues/new/choose) +- [submit a change as a pull request](https://github.com/Dedsec-Art/Ultra/pulls) +- read the [contribution guide](CONTRIBUTING.en.md) and the + [Code of Conduct](CODE_OF_CONDUCT.en.md) + +Accepted changes are merged into `main` after collaborative review and +successful CI checks. User-facing improvements and new features are documented +in the [changelog](CHANGELOG.en.md) and published through +[GitHub Releases](https://github.com/Dedsec-Art/Ultra/releases). +Never post credentials, personal paths, disc identifiers, complete logs, or +media files. Report security vulnerabilities privately as described in +[SECURITY.en.md](SECURITY.en.md). + +## Requirements + +- Windows 10 or 11 +- Python 3.10 through 3.14 +- [MakeMKV](https://www.makemkv.com/) and + [MKVToolNix](https://mkvtoolnix.download/) +- optional: ffmpeg, VLC, HandBrakeCLI, and Tesseract + +## Development installation + +```powershell +py -3.12 -m venv .venv +.\.venv\Scripts\python.exe -m pip install --upgrade pip +.\.venv\Scripts\python.exe -m pip install --require-hashes ` + --only-binary=:all: -r ripper_py\requirements.lock +.\.venv\Scripts\python.exe run_ultra.py +``` + +Alternatively, use the Windows launchers `Ultra setup.bat` and +`Ultra starten.bat`. + +## Configuration and secrets + +The local `ripper_py/ripper_config.ini` file is created on first launch and is +intentionally excluded from Git. API keys are entered through the user +interface and stored encrypted with Windows DPAPI. Configuration files, logs, +disc histories, cache files, and ripped media must never be included in +commits. + +Before every commit, run: + +```powershell +python tools\check_public_tree.py +python -m ripper_py.tests.run_all +``` + +The release scanner reports only the category, file, and line number. It never +prints the values of any detected keys. + +## Tests + +```powershell +python -m unittest discover -s ripper_py\tests +python -m ripper_py.tests.run_all +``` + +The second command is authoritative because it also discovers standalone +`test_*` functions. + +## Documentation + +- [User guide](ANLEITUNG.en.md) +- [Feature manual (German)](ripper_py/Ultra-Handbuch.md) +- [Security and robustness analysis (German)](ANALYSE_SICHERHEIT_ROBUSTHEIT.md) +- [UI design system (German)](UI_DESIGN_SYSTEM.md) + +## Legal notice + +Ultra is intended exclusively for media whose archival is lawful in the place +where it is used. Users are solely responsible for complying with copyright +law, copy-protection rules, and the license terms of external tools. + +## License + +Ultra is released under the [MIT License](LICENSE). +Copyright © 2026 Dedsec. diff --git a/README.md b/README.md index 5ffbc9b..4141810 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Ultra +**Sprache:** Deutsch · [English](README.en.md) + Ultra ist eine Windows-Desktopanwendung zum verlustfreien Archivieren eigener DVDs und Blu-rays mit MakeMKV. Die Anwendung unterstützt Serien-Discs, ISO-/BDMV-Quellen, eine konservative Reihenfolge-Erkennung, Spurwahl, diff --git a/SECURITY.en.md b/SECURITY.en.md new file mode 100644 index 0000000..e72f693 --- /dev/null +++ b/SECURITY.en.md @@ -0,0 +1,24 @@ +# Security Policy + +**Language:** [Deutsch](SECURITY.md) · English + +## Supported Versions + +Security fixes are prepared for the current `2.x` release. + +## Reporting a Vulnerability + +Do not post credentials, private disc information, or technical details of an +unresolved vulnerability in a public issue. Instead, use GitHub's enabled +[private vulnerability reporting](https://github.com/Dedsec-Art/Ultra/security/advisories/new) +feature so that the report reaches the project owner confidentially. + +A report should include the affected version, reproducible steps, the potential +impact, and, if available, a minimal test case. Remove or fully redact real API +keys, personal paths, logs, and media files before submitting the report. + +## Handling Accidentally Published Secrets + +Treat every published key as compromised: first revoke or rotate it with the +provider, then remove it from both the working tree and the Git history. Merely +deleting it in a later commit is not sufficient. diff --git a/SECURITY.md b/SECURITY.md index d209636..f76b442 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,7 @@ # Sicherheitsrichtlinie +**Sprache:** Deutsch · [English](SECURITY.en.md) + ## Unterstützte Versionen Sicherheitskorrekturen werden für die aktuelle `2.x`-Version vorbereitet. @@ -8,8 +10,9 @@ Sicherheitskorrekturen werden für die aktuelle `2.x`-Version vorbereitet. Bitte keine Zugangsdaten, privaten Disc-Informationen oder technischen Details einer noch nicht behobenen Schwachstelle in einem öffentlichen Issue posten. -Nach Veröffentlichung des Repositorys soll dafür GitHubs Funktion -**Private vulnerability reporting** im Bereich `Security` aktiviert werden. +Verwende stattdessen GitHubs aktivierte Funktion +[**Private vulnerability reporting**](https://github.com/Dedsec-Art/Ultra/security/advisories/new), +damit die Meldung vertraulich beim Projektinhaber eingeht. Eine Meldung sollte die betroffene Version, eine reproduzierbare Beschreibung, die mögliche Auswirkung und – falls vorhanden – einen minimalen Testfall diff --git a/SUPPORT.en.md b/SUPPORT.en.md new file mode 100644 index 0000000..f162125 --- /dev/null +++ b/SUPPORT.en.md @@ -0,0 +1,15 @@ +# Help and Community + +**Language:** [Deutsch](SUPPORT.md) · English + +For usage questions, experiences, and early-stage ideas, use +[GitHub Discussions](https://github.com/Dedsec-Art/Ultra/discussions). + +- Reproducible bugs and specific feature requests: + [Issue templates](https://github.com/Dedsec-Art/Ultra/issues/new/choose) +- Your own changes: [Contributing guide](CONTRIBUTING.en.md) +- Confidential security issues: [Security policy](SECURITY.en.md) + +Support and maintenance are community efforts, and no specific response time can +be guaranteed. Do not publish credentials, personal paths, disc identifiers, +complete logs, or media files. diff --git a/SUPPORT.md b/SUPPORT.md index 00db2f9..2de57c5 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,5 +1,7 @@ # Hilfe und Austausch +**Sprache:** Deutsch · [English](SUPPORT.en.md) + Für Bedienfragen, Erfahrungen und noch offene Ideen gibt es [GitHub Discussions](https://github.com/Dedsec-Art/Ultra/discussions). diff --git a/ripper_py/tests/test_community_contract.py b/ripper_py/tests/test_community_contract.py index 85c1768..d921c67 100644 --- a/ripper_py/tests/test_community_contract.py +++ b/ripper_py/tests/test_community_contract.py @@ -13,6 +13,7 @@ class TestCommunityContract(unittest.TestCase): def test_readme_verlinkt_alle_community_einstiege(self): text = (ROOT / "README.md").read_text(encoding="utf-8") for expected in ( + "(README.en.md)", "https://github.com/Dedsec-Art/Ultra/discussions", "https://github.com/Dedsec-Art/Ultra/issues/new/choose", "https://github.com/Dedsec-Art/Ultra/pulls", @@ -22,6 +23,40 @@ def test_readme_verlinkt_alle_community_einstiege(self): with self.subTest(expected=expected): self.assertIn(expected, text) + def test_englische_dokumentation_ist_vollstaendig_verlinkt(self): + pairs = ( + ("README.en.md", "README.md"), + ("ANLEITUNG.en.md", "ANLEITUNG.md"), + ("CHANGELOG.en.md", "CHANGELOG.md"), + ("CONTRIBUTING.en.md", "CONTRIBUTING.md"), + ("SECURITY.en.md", "SECURITY.md"), + ("SUPPORT.en.md", "SUPPORT.md"), + ("CODE_OF_CONDUCT.en.md", "CODE_OF_CONDUCT.md"), + ) + for english, german in pairs: + with self.subTest(document=english): + text = (ROOT / english).read_text(encoding="utf-8") + self.assertIn(f"({german})", text) + readme = (ROOT / "README.en.md").read_text(encoding="utf-8") + for expected in ( + "(ANLEITUNG.en.md)", + "(CONTRIBUTING.en.md)", + "(CODE_OF_CONDUCT.en.md)", + "(SECURITY.en.md)", + "https://github.com/Dedsec-Art/Ultra/discussions", + "https://github.com/Dedsec-Art/Ultra/issues/new/choose", + "https://github.com/Dedsec-Art/Ultra/pulls"): + with self.subTest(expected=expected): + self.assertIn(expected, readme) + + def test_security_verweist_auf_vertrauliches_meldeformular(self): + url = ("https://github.com/Dedsec-Art/Ultra/" + "security/advisories/new") + for document in ("SECURITY.md", "SECURITY.en.md"): + with self.subTest(document=document): + text = (ROOT / document).read_text(encoding="utf-8") + self.assertIn(url, text) + def test_codeowners_fordert_review_des_projektinhabers_an(self): text = (ROOT / ".github" / "CODEOWNERS").read_text( encoding="utf-8") @@ -69,6 +104,11 @@ def test_reihenfolge_formular_hat_strenge_datenschutz_wachen(self): "vollständigen logs", "keine urheberrechtlich"): with self.subTest(warning=warning): self.assertIn(warning, rendered) + for english_warning in ( + "episode-order detection", "personal paths", + "complete logs", "copyrighted media"): + with self.subTest(english_warning=english_warning): + self.assertIn(english_warning, rendered) def test_support_verweist_auf_diskussionen_issues_und_security(self): text = (ROOT / "SUPPORT.md").read_text(encoding="utf-8")