Compare commits
5
Commits
89c2cda81c
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9df5da50b0 | ||
|
|
5fb4db5069 | ||
|
|
6c69eeaf4b | ||
|
|
1d91966d5f | ||
|
|
455245664f |
@@ -0,0 +1,161 @@
|
|||||||
|
## 1. Die Basis: Modi & Navigation
|
||||||
|
Vim basiert auf dem Konzept von Modi. Um Befehle auszuführen, musst du fast immer im **Normal Mode** sein.
|
||||||
|
|
||||||
|
### Modi-Wechsel
|
||||||
|
* `i` / `a`: Insert-Modus (vor/nach Cursor).
|
||||||
|
* `I` / `A`: Insert am Zeilenanfang / Zeilenende.
|
||||||
|
* `o` / `O`: Neue Zeile unterhalb / oberhalb einfügen.
|
||||||
|
* `Esc`: Zurück in den Normal-Modus.
|
||||||
|
* `v` / `V` / `Ctrl+v`: Visueller Modus (Zeichen / Zeile / Block).
|
||||||
|
|
||||||
|
### Navigation (Normal Mode)
|
||||||
|
* **Grundbewegung:** `h` (links), `j` (runter), `k` (hoch), `l` (rechts).
|
||||||
|
* **Wortweise:** `w` (nächstes Wort), `b` (vorheriges), `e` (Wortende).
|
||||||
|
* **Zeilenweise:** `0` (Anfang), `^` (erstes Zeichen), `$` (Ende).
|
||||||
|
* **Datei-Sprünge:** `gg` (Anfang), `G` (Ende), `:n` (Zeile n).
|
||||||
|
* **Scrollen:** `Ctrl+u` / `Ctrl+d` (Halbe Seite hoch/runter).
|
||||||
|
* **Klammern:** `%` springt zur korrespondierenden Klammer `()`, `[]`, `{}`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Bearbeitung & Text-Objekte
|
||||||
|
Die wahre Stärke von Vim liegt in der Kombination von **Operatoren** und **Bewegungen/Objekten**.
|
||||||
|
|
||||||
|
### Basis-Operationen
|
||||||
|
* `x`: Zeichen löschen.
|
||||||
|
* `dd`: Ganze Zeile löschen (Ausschneiden).
|
||||||
|
* `yy`: Zeile kopieren (Yank).
|
||||||
|
* `p` / `P`: Einfügen nach / vor dem Cursor.
|
||||||
|
* `u` / `Ctrl+r`: Undo / Redo.
|
||||||
|
* `.`: Die letzte Aktion wiederholen.
|
||||||
|
|
||||||
|
### Das "Verb + Adjektiv + Nomen" Prinzip
|
||||||
|
Viele Befehle folgen dem Muster: `[Zahl] + [Operator] + [Textobjekt/Bewegung]`.
|
||||||
|
* `3dw`: Lösche 3 Wörter.
|
||||||
|
* `ci"`: **C**hange **I**nside **"**: Löscht den Inhalt zwischen Anführungszeichen und geht in den Insert-Modus.
|
||||||
|
* `da(`: **D**elete **A**round **(**: Löscht die Klammern inklusive Inhalt.
|
||||||
|
* `yiw`: Kopiere das aktuelle Wort (**Y**ank **I**nside **W**ord).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Suche & Ersetzen (Regex & "Magic")
|
||||||
|
|
||||||
|
### Suchen in der aktuellen Datei
|
||||||
|
* `/muster`: Vorwärts suchen.
|
||||||
|
* `?muster`: Rückwärts suchen.
|
||||||
|
* `n` / `N`: Nächster / Vorheriger Treffer.
|
||||||
|
* `*` / `#`: Sucht das Wort unter dem Cursor vorwärts / rückwärts.
|
||||||
|
|
||||||
|
### Ersetzen (Substituieren)
|
||||||
|
* `:%s/alt/neu/g`: Ersetzt alle Vorkommen in der Datei.
|
||||||
|
* `:%s/alt/neu/gc`: Ersetzt mit Bestätigung für jeden Treffer.
|
||||||
|
|
||||||
|
### RegEx & Very Magic
|
||||||
|
Vim nutzt standardmäßig eine eigene RegEx-Syntax. Mit `\v` (very magic) nutzt du eine Syntax, die moderneren Sprachen (wie Python/JS) ähnelt.
|
||||||
|
```vim
|
||||||
|
" Findet abc oder ac (das ? ist in very magic ein Metazeichen)
|
||||||
|
/\vab?c
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Projektweites Find & Replace (Neovim & Telescope)
|
||||||
|
Dies ist ein Workflow für umfassendes Refactoring über viele Dateien hinweg.
|
||||||
|
|
||||||
|
### Schritt 1: Suchen & Filtern
|
||||||
|
1. Starte Telescope: `:Telescope live_grep`.
|
||||||
|
2. Suche nach dem Begriff.
|
||||||
|
3. Sende Ergebnisse an die Quickfix-Liste: `Ctrl + q`.
|
||||||
|
|
||||||
|
### Schritt 2: Massen-Ersetzung mit `:cdo`
|
||||||
|
Der Befehl `:cdo` führt ein Kommando für jeden Eintrag in der Quickfix-Liste aus.
|
||||||
|
```vim
|
||||||
|
:cdo s/alter_begriff/neuer_begriff/gc | update
|
||||||
|
```
|
||||||
|
* `gc`: Global in der Zeile ersetzen, mit Bestätigung.
|
||||||
|
* `| update`: Speichert die Datei sofort, wenn eine Änderung vorgenommen wurde.
|
||||||
|
|
||||||
|
### Schritt 3: Zeilen löschen (Spezialfall)
|
||||||
|
Wenn du Zeilen, die ein Muster enthalten, komplett löschen willst, ist `:cfdo` (pro Datei) robuster als `:cdo` (pro Treffer).
|
||||||
|
```vim
|
||||||
|
:cfdo g/muster/d | update
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Multi-File Suche mit `:vimgrep`
|
||||||
|
Wenn du kein Telescope nutzt, ist `:vimgrep` der integrierte Weg.
|
||||||
|
* `:vimgrep /muster/ **/*.py`: Sucht rekursiv in allen Python-Dateien.
|
||||||
|
* `:copen`: Öffnet das Quickfix-Fenster, um die Ergebnisse zu sehen.
|
||||||
|
* `:cn` / `:cp`: Springe zum nächsten/vorherigen Treffer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Register & Clipboard
|
||||||
|
Vim hat mehrere "Ablagen" (Register).
|
||||||
|
* `"ayw`: Kopiere Wort in Register `a`.
|
||||||
|
* `"ap`: Füge Inhalt aus Register `a` ein.
|
||||||
|
* `"+y`: Kopiere in das **System-Clipboard** (Wichtig für Austausch mit anderen Apps!).
|
||||||
|
* `:reg`: Zeige alle aktuellen Registerinhalte an.
|
||||||
|
* `"%`: Enthält den Pfad der aktuellen Datei.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Effizienz-Booster: Makros & Markierungen
|
||||||
|
|
||||||
|
### Makros (Automatisierung)
|
||||||
|
* `qa`: Aufnahme in Register `a` starten.
|
||||||
|
* `q`: Aufnahme stoppen.
|
||||||
|
* `@a`: Makro `a` abspielen.
|
||||||
|
* `@@`: Das letzte Makro wiederholen.
|
||||||
|
|
||||||
|
### Markierungen (Ergänzung)
|
||||||
|
Mit Markierungen kannst du schnell zu bestimmten Stellen springen.
|
||||||
|
* `ma`: Setzt eine Markierung `a` an der aktuellen Position.
|
||||||
|
* `'a`: Springt direkt zur Markierung `a`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Fenster, Tabs & Buffer
|
||||||
|
Vim verwaltet Dateien in **Buffern**. **Windows** (Splits) und **Tabs** sind nur Ansichten darauf.
|
||||||
|
|
||||||
|
* `:ls`: Alle offenen Buffer anzeigen.
|
||||||
|
* `:b 3`: Zum 3. Buffer wechseln.
|
||||||
|
* `:split` / `:vsplit`: Horizontaler / Vertikaler Split.
|
||||||
|
* `Ctrl+w w`: Zwischen Fenstern wechseln.
|
||||||
|
* `:tabnew`: Neuer Tab.
|
||||||
|
* `gt` / `gT`: Nächster / Vorheriger Tab.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Visual Block Mode & Kommentieren
|
||||||
|
Der Block-Modus (`Ctrl+v`) ist ideal, um Textspalten zu bearbeiten.
|
||||||
|
|
||||||
|
### Block-Kommentieren (Manuell)
|
||||||
|
1. `Ctrl+v` drücken und Zeilen nach unten markieren.
|
||||||
|
2. `Shift+i` (Insert am Anfang des Blocks).
|
||||||
|
3. Kommentarzeichen eingeben (z. B. `# `).
|
||||||
|
4. `Esc` drücken – die Änderung wird auf alle Zeilen angewendet.
|
||||||
|
|
||||||
|
### Plugin-Empfehlung: `vim-commentary`
|
||||||
|
Mit diesem Plugin reicht ein Befehl:
|
||||||
|
* `gcc`: Kommentiert die aktuelle Zeile um/aus.
|
||||||
|
* `gc` (im Visual Mode): Kommentiert den markierten Block.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Konfiguration (.vimrc / init.lua)
|
||||||
|
Einige Standard-Einstellungen, die jeder Power-User haben sollte:
|
||||||
|
```vim
|
||||||
|
set number " Absolute Zeilennummer der aktuellen Zeile
|
||||||
|
set relativenumber " Relative Nummern für alle anderen Zeilen (ideal für 5j, 3k)
|
||||||
|
set expandtab " Leerzeichen statt Tabs
|
||||||
|
set tabstop=4 " Tab-Breite
|
||||||
|
set ignorecase " Suche ignoriert Groß/Kleinschreibung...
|
||||||
|
set smartcase " ...außer du tippst einen Großbuchstaben
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Profi-Tipp: Befehlsbuffer
|
||||||
|
Wenn du einen komplexen Ex-Befehl (mit `:`) getippt hast und ihn bearbeiten willst, drücke im Normal-Modus `q:`. Es öffnet sich ein Fenster mit der Historie deiner Befehle, die du wie normalen Text bearbeiten und mit `Enter` neu ausführen kannst.
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
## Introduction[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#introduction)
|
||||||
|
|
||||||
|
Maintaining an organized and efficient codebase is essential for every developer. Neovim, a powerful text editor, offers a range of tools that can help you make global changes throughout your project with ease.
|
||||||
|
|
||||||
|
In this blog post, we’ll explore how to perform a project-wide find and replace using Neovim, Telescope, the Quickfix List, and the `:cdo` command. No complicated jargon, just straightforward guidance to enhance your coding experience.
|
||||||
|
|
||||||
|
## Prerequisites[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#prerequisites)
|
||||||
|
|
||||||
|
Before you start, ensure you have the following prerequisites in place:
|
||||||
|
|
||||||
|
1. Neovim installed.
|
||||||
|
2. The Telescope plugin installed.
|
||||||
|
3. A project directory opened in Neovim.
|
||||||
|
|
||||||
|
## Using Telescope for Live Grep[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#using-telescope-for-live-grep)
|
||||||
|
|
||||||
|
### 1. Initiate Telescope[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#1-initiate-telescope)
|
||||||
|
|
||||||
|
In Neovim’s Normal mode, execute the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
:Telescope live_grep
|
||||||
|
```
|
||||||
|
|
||||||
|
This opens the Telescope live grep prompt, ready for your query.
|
||||||
|
|
||||||
|
### 2. Enter Your Search Query[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#2-enter-your-search-query)
|
||||||
|
|
||||||
|
Type your search query. Telescope will display a list of search results throughout your project.
|
||||||
|
|
||||||
|
### 3. Open Results in Quickfix List[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#3-open-results-in-quickfix-list)
|
||||||
|
|
||||||
|
After searching for your query, press `Ctrl + q` to open the search results in the Quickfix List.
|
||||||
|
|
||||||
|
## Utilizing `:cdo` for Find and Replace[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#utilizing-cdo-for-find-and-replace)
|
||||||
|
|
||||||
|
### 4. Run the `:cdo` Command[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#4-run-the-cdo-command)
|
||||||
|
|
||||||
|
With the Quickfix List open, you can now perform the find and replace operation. Execute the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
:cdo s/query_string/replacement_string/gc
|
||||||
|
```
|
||||||
|
|
||||||
|
- `:cdo` applies a command to each entry in the Quickfix List.
|
||||||
|
- `s/query_string/replacement_string/gc` is the find and replace command, with `g` for global replacement.
|
||||||
|
- The `/c` flag provides confirmation before each replacement.
|
||||||
|
|
||||||
|
Press Enter to initiate the find and replace with confirmation.
|
||||||
|
|
||||||
|
### 5. Save Changes[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#5-save-changes)
|
||||||
|
|
||||||
|
If you’re satisfied with the changes and want to save them across all files in your project, you can use the `:wa` command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
:wa
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion[](https://blog.chaitanyashahare.com/posts/project-wide-find-and-replace-in-neovim/#conclusion)
|
||||||
|
|
||||||
|
Performing a project-wide find and replace in Neovim using Telescope, the Quickfix List, and the `:cdo` command is a potent approach that simplifies codebase maintenance. It allows you to make comprehensive changes while retaining full control over the replacement process, with the added `/c` flag providing a confirmation step for each replacement. By incorporating these techniques into your Neovim workflow, you’ll significantly improve your coding experience and efficiency. Use `:wa` to save your changes across all files and ensure your project is up to date.
|
||||||
|
|
||||||
|
# Bsp Zeilen mit Treffern löschen
|
||||||
|
|
||||||
|
Es gibt zwei leicht verschiedene Dinge:
|
||||||
|
|
||||||
|
1. Zeilen **in den Dateien** löschen
|
||||||
|
2. Einträge **aus der Quickfix‑Liste** löschen
|
||||||
|
|
||||||
|
Ich nehme an, du meinst 1., also die Zeilen in den Dateien entfernen, wo `live_grep` dein Wort gefunden hat. Ich zeige aber beide Varianten.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Zeilen in den Dateien löschen (empfohlen)
|
||||||
|
|
||||||
|
Du hast `live_grep` mit z.B. `wits` gemacht und die Treffer in die Quickfix-Liste geschickt (`<C-q>`).
|
||||||
|
|
||||||
|
Jetzt willst du **alle Zeilen in den Dateien löschen, die `wits` enthalten**.
|
||||||
|
Das geht am saubersten mit `:cfdo` + `:global`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:cfdo g/wits/d | update
|
||||||
|
```
|
||||||
|
|
||||||
|
Erklärung:
|
||||||
|
|
||||||
|
- `cfdo` – führe den folgenden Befehl für jede **Datei** aus, die in der Quickfix-Liste vorkommt
|
||||||
|
- `g/wits/d` – in dieser Datei: lösche **alle Zeilen**, die `wits` enthalten
|
||||||
|
- `| update` – speichere die Datei, wenn sie geändert wurde
|
||||||
|
|
||||||
|
Damit sind nachher in allen Dateien, die in der Quickfix-Liste sind, sämtliche Zeilen mit `wits` weg.
|
||||||
|
|
||||||
|
### Variante ohne hartkodiertes Muster
|
||||||
|
|
||||||
|
Wenn du das Suchmuster noch einmal mit `/` gesetzt hast, kannst du es statt `wits` auch aus der letzten Suche nehmen:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
/"dein muster"
|
||||||
|
:cfdo g//d | update
|
||||||
|
```
|
||||||
|
|
||||||
|
`g//` benutzt dann das aktuelle Suchmuster aus `/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Zeilen *aus der Quickfix-Liste* löschen
|
||||||
|
|
||||||
|
Falls du **nur die Einträge in der Quickfix-Liste selbst** filtern oder löschen willst (nicht die Dateien):
|
||||||
|
|
||||||
|
Quickfix-Fenster öffnen:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:copen
|
||||||
|
```
|
||||||
|
|
||||||
|
### Einträge mit bestimmtem Muster entfernen
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:cfilter! wits
|
||||||
|
```
|
||||||
|
|
||||||
|
- `:cfilter {pat}` – behält nur Einträge, die `{pat}` matchen
|
||||||
|
- `:cfilter! {pat}` – entfernt Einträge, die `{pat}` matchen
|
||||||
|
|
||||||
|
Mit `:cfilter! wits` würdest du also alle Quickfix-Einträge wegwerfen, die `wits` enthalten (die Dateien bleiben unverändert).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Warum nicht `:cdo normal! dd`?
|
||||||
|
|
||||||
|
Rein technisch könntest du auch:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:cdo normal! dd
|
||||||
|
```
|
||||||
|
|
||||||
|
Das löscht in jeder Datei die jeweilige Trefferzeile.
|
||||||
|
Aber: `:cdo` läuft pro **Quickfix-Eintrag**; wenn du Zeilen löschst, können die nachfolgenden Einträge (mit alten Zeilennummern) verrutschen. Deshalb ist `:cfdo g/pattern/d` robuster – da wird pro Datei einmal gearbeitet, nicht pro Eintrag.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Kurzfassung für dein konkretes Beispiel (`wits` aus den Dateien löschen):
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:cfdo g/wits/d | update
|
||||||
|
```
|
||||||
@@ -0,0 +1,476 @@
|
|||||||
|
Hier ist ein kompaktes, aber vollständiges **VIM Cheat Sheet** 📝
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Modi in VIM
|
||||||
|
|
||||||
|
|Modus|Bedeutung|Wechsel|
|
||||||
|
|---|---|---|
|
||||||
|
|**Normal Mode**|Navigation & Befehle|`Esc`|
|
||||||
|
|**Insert Mode**|Texteingabe|`i`, `a`, `o`, etc.|
|
||||||
|
|**Visual Mode**|Text markieren|`v`, `V`, `Ctrl+v`|
|
||||||
|
|**Command Mode**|Speichern, Beenden, etc.|`:`|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Insert Mode Befehle
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`i`|Vor Cursor einfügen|
|
||||||
|
|`a`|Nach Cursor einfügen|
|
||||||
|
|`I`|Am Zeilenanfang einfügen|
|
||||||
|
|`A`|Am Zeilenende einfügen|
|
||||||
|
|`o`|Neue Zeile unterhalb|
|
||||||
|
|`O`|Neue Zeile oberhalb|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Navigation (Normal Mode)
|
||||||
|
|
||||||
|
### Zeichenweise
|
||||||
|
|
||||||
|
```
|
||||||
|
h ← j ↓ k ↑ l →
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wortweise
|
||||||
|
|
||||||
|
```
|
||||||
|
w nächstes Wort
|
||||||
|
b vorheriges Wort
|
||||||
|
e Wortende
|
||||||
|
```
|
||||||
|
|
||||||
|
### Zeilenweise
|
||||||
|
|
||||||
|
```
|
||||||
|
0 Zeilenanfang
|
||||||
|
^ Erstes Nicht-Leerzeichen
|
||||||
|
$ Zeilenende
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datei
|
||||||
|
|
||||||
|
```
|
||||||
|
gg Anfang der Datei
|
||||||
|
G Ende der Datei
|
||||||
|
:n Gehe zu Zeile n
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Löschen
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`x`|Zeichen löschen|
|
||||||
|
|`dd`|Zeile löschen|
|
||||||
|
|`dw`|Wort löschen|
|
||||||
|
|`d$`|Bis Zeilenende löschen|
|
||||||
|
|`d0`|Bis Zeilenanfang löschen|
|
||||||
|
|
||||||
|
💡 Kombination: `d` + Bewegung funktioniert immer
|
||||||
|
(z.B. `d3w` = 3 Wörter löschen)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Kopieren & Einfügen
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`yy`|Zeile kopieren|
|
||||||
|
|`yw`|Wort kopieren|
|
||||||
|
|`p`|Nach Cursor einfügen|
|
||||||
|
|`P`|Vor Cursor einfügen|
|
||||||
|
|
||||||
|
#### Register
|
||||||
|
Vor alle Kopieren oder Einfügen Befehle kann ein `"3` gestellt werden, um ins 3. Register zu schreiben bzw. daraus heraus zu lesen. Z.b. kopiert `"7yw` das Wort ins 7. Register und `"4p` fügt das 4. Register nach dem Curser ein.
|
||||||
|
💡 Das spezielle Register `+`/`*` ist das System-Clipboard, sehr Praktisch zum Austausch von Text mit anderen Programmen
|
||||||
|
Alle Register ansehen: `:reg`
|
||||||
|
💡 Das spezielle Register `%` enthält den aktuellen Dateipfad -> aktuelle Dateipfad in System-Clipboard: `:let @+=@%`.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Undo / Redo
|
||||||
|
|
||||||
|
```
|
||||||
|
u Undo
|
||||||
|
Ctrl+r Redo
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Visual Mode
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`v`|Zeichenweise markieren|
|
||||||
|
|`V`|Ganze Zeile markieren|
|
||||||
|
|`Ctrl+v`|Block markieren|
|
||||||
|
|
||||||
|
Nach Markierung:
|
||||||
|
|
||||||
|
```
|
||||||
|
d löschen
|
||||||
|
y kopieren
|
||||||
|
> einrücken
|
||||||
|
< ausrücken
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Suchen & Ersetzen
|
||||||
|
|
||||||
|
```
|
||||||
|
/text Vorwärts suchen
|
||||||
|
?text Rückwärts suchen
|
||||||
|
n Nächstes Ergebnis
|
||||||
|
N Vorheriges Ergebnis
|
||||||
|
```
|
||||||
|
|
||||||
|
Ersetzen:
|
||||||
|
|
||||||
|
```
|
||||||
|
:%s/alt/neu/g Ganze Datei
|
||||||
|
:s/alt/neu/g Aktuelle Zeile
|
||||||
|
:%s/alt/neu/gc Mit Bestätigung
|
||||||
|
```
|
||||||
|
|
||||||
|
Nutze "echtes" RegEx ("very magic"):
|
||||||
|
```
|
||||||
|
/\v...
|
||||||
|
```
|
||||||
|
zB
|
||||||
|
```
|
||||||
|
/\vab?c
|
||||||
|
```
|
||||||
|
findet `abc` und `ac` . Das würde mit herkömmlicher Vim RegEx nicht funktionieren
|
||||||
|
|
||||||
|
Suchen und ersetzen
|
||||||
|
```
|
||||||
|
:%s/\vfoo (ab?c)(bar)/bas \1 \2/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Speichern & Beenden
|
||||||
|
|
||||||
|
```
|
||||||
|
:w Speichern
|
||||||
|
:q Beenden
|
||||||
|
:wq Speichern & Beenden
|
||||||
|
:x Speichern & Beenden
|
||||||
|
:q! Ohne Speichern beenden
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Fenster & Tabs
|
||||||
|
|
||||||
|
```
|
||||||
|
:split Horizontal teilen
|
||||||
|
:vsplit Vertikal teilen
|
||||||
|
Ctrl+w w Zwischen Fenstern wechseln
|
||||||
|
:tabnew Neuer Tab
|
||||||
|
gt Nächster Tab
|
||||||
|
gT Vorheriger Tab
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Nützliche Shortcuts
|
||||||
|
|
||||||
|
```
|
||||||
|
. Letzte Aktion wiederholen
|
||||||
|
>> Zeile einrücken
|
||||||
|
<< Zeile ausrücken
|
||||||
|
ciw Wort ändern
|
||||||
|
cc Zeile ändern
|
||||||
|
J Zeilen zusammenführen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Makros
|
||||||
|
|
||||||
|
```
|
||||||
|
qa Aufnahme in Register a starten
|
||||||
|
q Aufnahme stoppen
|
||||||
|
@a Makro a ausführen
|
||||||
|
@@ Letztes Makro wiederholen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Zahlen-Präfixe (Sehr wichtig!)
|
||||||
|
|
||||||
|
Viele Befehle lassen sich multiplizieren:
|
||||||
|
|
||||||
|
```
|
||||||
|
3dd 3 Zeilen löschen
|
||||||
|
5w 5 Wörter vor
|
||||||
|
2yy 2 Zeilen kopieren
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
# Zeilennummern aus- und anschalten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Absolute Zeilennummern
|
||||||
|
|
||||||
|
### Einschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set number
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ausschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set nonumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Toggle:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set number!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Relative Zeilennummern
|
||||||
|
|
||||||
|
### Einschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set relativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ausschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set norelativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Toggle:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set relativenumber!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Absolute + Relative kombinieren (Sehr beliebt 🔥)
|
||||||
|
|
||||||
|
Viele nutzen diese Kombination:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set number relativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
👉 Ergebnis:
|
||||||
|
|
||||||
|
* Aktuelle Zeile = **absolute Nummer**
|
||||||
|
* Alle anderen Zeilen = **relative Nummern**
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```
|
||||||
|
8
|
||||||
|
2
|
||||||
|
1
|
||||||
|
10 ← aktuelle Zeile
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
Das ist perfekt für Bewegungen wie:
|
||||||
|
|
||||||
|
```
|
||||||
|
5j
|
||||||
|
3k
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Dauerhaft aktivieren (.vimrc)
|
||||||
|
|
||||||
|
In deiner `~/.vimrc`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
set number
|
||||||
|
set relativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Smart Toggle Mapping (Optional ⭐)
|
||||||
|
|
||||||
|
Viele nutzen ein Keybinding:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
nnoremap <leader>n :set number! relativenumber!<CR>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann kannst du mit:
|
||||||
|
|
||||||
|
```
|
||||||
|
\ n
|
||||||
|
```
|
||||||
|
|
||||||
|
(beim Standard-`leader`) beide gleichzeitig toggeln.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Block Aus- und Einkommentieren
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 1️⃣ Rein mit Vim (ohne Plugin)
|
||||||
|
|
||||||
|
## ✅ Ganze Zeilen im Visual Mode kommentieren
|
||||||
|
|
||||||
|
### Schritt 1: Block markieren
|
||||||
|
|
||||||
|
* `V` → Zeilenweise markieren
|
||||||
|
* `j / k` → Bereich wählen
|
||||||
|
|
||||||
|
### Schritt 2: Kommentarzeichen einfügen
|
||||||
|
|
||||||
|
Beispiel für `#`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:s/^/# /
|
||||||
|
```
|
||||||
|
|
||||||
|
Im Visual Mode einfach:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:'<,'>s/^/# /
|
||||||
|
```
|
||||||
|
|
||||||
|
👉 Fügt `# ` am Anfang jeder markierten Zeile ein.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Auskommentieren
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:'<,'>s/^# //
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Noch schneller (ohne `:` tippen)
|
||||||
|
|
||||||
|
Markieren mit `V`, dann:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:s/^/# /
|
||||||
|
```
|
||||||
|
|
||||||
|
Vim setzt `'<,'>` automatisch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 2️⃣ Noch effizienter: Visual Block Mode (Sehr elegant ⚡)
|
||||||
|
|
||||||
|
Perfekt für feste Kommentarzeichen wie `#`, `//`, `--`.
|
||||||
|
|
||||||
|
### Schritt 1
|
||||||
|
|
||||||
|
```
|
||||||
|
Ctrl + v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schritt 2
|
||||||
|
|
||||||
|
Mit `j/k` mehrere Zeilen markieren (nur Spalte 0)
|
||||||
|
|
||||||
|
### Schritt 3
|
||||||
|
|
||||||
|
```
|
||||||
|
Shift + i
|
||||||
|
#
|
||||||
|
Esc
|
||||||
|
```
|
||||||
|
|
||||||
|
💥 Vim fügt das in alle markierten Zeilen ein.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Entfernen mit Block Mode
|
||||||
|
|
||||||
|
1. `Ctrl + v`
|
||||||
|
2. Erste 2 Zeichen (`# `) markieren
|
||||||
|
3. `d`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 3️⃣ Beste Lösung: Plugin (Empfohlen 🔥)
|
||||||
|
|
||||||
|
Wenn du regelmäßig kommentierst → nimm ein Plugin.
|
||||||
|
|
||||||
|
Sehr beliebt:
|
||||||
|
|
||||||
|
* vim-commentary von Tim Pope
|
||||||
|
|
||||||
|
### Installation (mit vim-plug):
|
||||||
|
|
||||||
|
```vim
|
||||||
|
Plug 'tpope/vim-commentary'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nutzung:
|
||||||
|
|
||||||
|
* `gcc` → aktuelle Zeile toggeln
|
||||||
|
* `gc` (im Visual Mode) → Block toggeln
|
||||||
|
|
||||||
|
💎 Vorteil:
|
||||||
|
|
||||||
|
* erkennt automatisch Kommentarzeichen je nach Dateityp
|
||||||
|
* funktioniert mit `//`, `#`, `--`, `/* */`, etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 4️⃣ Absolute Power-User Lösung (Ohne Plugin, aber smart)
|
||||||
|
|
||||||
|
In `.vimrc`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
vnoremap <leader>c :s/^/# /<CR>
|
||||||
|
vnoremap <leader>u :s/^# //<CR>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann:
|
||||||
|
|
||||||
|
```
|
||||||
|
\c → kommentieren
|
||||||
|
\u → auskommentieren
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔥 Meine Empfehlung
|
||||||
|
|
||||||
|
| Wenn du... | Lösung |
|
||||||
|
| ----------------------------- | ----------------- |
|
||||||
|
| Nur selten kommentierst | Visual Block Mode |
|
||||||
|
| Viel programmierst | vim-commentary |
|
||||||
|
| Minimalistisch bleiben willst | eigenes Mapping |
|
||||||
|
|
||||||
|
---
|
||||||
|
# Verschiedenes
|
||||||
|
- `%`: zur nächsten Klammer
|
||||||
|
- `TOhtml`: HTML Export
|
||||||
|
- `:ls`: Buffer anzeigen -> `:b 3` den 3. Buffer öffnen
|
||||||
|
- `.` : letzte Aktion wiederholen
|
||||||
|
- `:e path/to/file` öffnet Datei, nur `:e` aktualisiert die geöffnete Datei, `:e!` verwirft dabei alle Änderungen
|
||||||
|
- `q:` : öffne Befehlsbuffer
|
||||||
|
- Dort kann man z.B. mit `"+yy` Befehle ins Clipboard kopieren
|
||||||
|
-
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
## Modi
|
||||||
|
```text
|
||||||
|
i In den Insert-Modus (vor Cursor)
|
||||||
|
I Insert am Zeilenanfang
|
||||||
|
a Insert nach Cursor
|
||||||
|
A Insert am Zeilenende
|
||||||
|
o Neue Zeile unterhalb + Insert
|
||||||
|
O Neue Zeile oberhalb + Insert
|
||||||
|
|
||||||
|
<Esc> Zurück in Normalmodus
|
||||||
|
|
||||||
|
v Visueller Modus (Zeichenweise)
|
||||||
|
V Visueller Modus (Zeilenweise)
|
||||||
|
<C-v> Visueller Blockmodus
|
||||||
|
```
|
||||||
|
## Navigation (Normalmodus)
|
||||||
|
```text
|
||||||
|
h j k l Links / runter / hoch / rechts
|
||||||
|
|
||||||
|
0 Zeilenanfang
|
||||||
|
^ Erstes nicht-leer Zeichen
|
||||||
|
$ Zeilenende
|
||||||
|
|
||||||
|
w Zum nächsten Wortanfang
|
||||||
|
b Zum vorherigen Wortanfang
|
||||||
|
e Zum Wortende
|
||||||
|
W B E Wie oben, aber Worte durch Leerzeichen getrennt
|
||||||
|
|
||||||
|
gg Erste Zeile
|
||||||
|
G Letzte Zeile
|
||||||
|
ngg / nG Zu Zeile n
|
||||||
|
|
||||||
|
H Oberer Bildschirmrand
|
||||||
|
M Mittlerer Bildschirmrand
|
||||||
|
L Unterer Bildschirmrand
|
||||||
|
|
||||||
|
Ctrl-u Halbe Seite hoch
|
||||||
|
Ctrl-d Halbe Seite runter
|
||||||
|
Ctrl-b Seite hoch
|
||||||
|
Ctrl-f Seite runter
|
||||||
|
```
|
||||||
|
## Basis-Bearbeitung
|
||||||
|
```text
|
||||||
|
x Zeichen unter Cursor löschen
|
||||||
|
X Zeichen links vom Cursor löschen
|
||||||
|
r<char> Zeichen ersetzen
|
||||||
|
|
||||||
|
dd Zeile löschen (cut)
|
||||||
|
D Bis zum Zeilenende löschen
|
||||||
|
cc Zeile ändern (delete + insert)
|
||||||
|
C Bis zum Zeilenende ändern
|
||||||
|
|
||||||
|
yy Zeile kopieren
|
||||||
|
Y Alias für yy
|
||||||
|
p Einfügen NACH Cursor/Zeile
|
||||||
|
P Einfügen VOR Cursor/Zeile
|
||||||
|
|
||||||
|
u Undo
|
||||||
|
Ctrl-r Redo
|
||||||
|
|
||||||
|
J Nächste Zeile an aktuelle anhängen
|
||||||
|
>> Zeile einrücken (indent)
|
||||||
|
<< Zeile ausrücken (unindent)
|
||||||
|
```
|
||||||
|
## Mit Counts & Bewegungen
|
||||||
|
Viele Befehle funktionieren mit einer Anzahl (count) und einer Bewegung:
|
||||||
|
```text
|
||||||
|
3w 3 Wörter vor
|
||||||
|
5j 5 Zeilen runter
|
||||||
|
|
||||||
|
d3w 3 Wörter löschen
|
||||||
|
c$ Bis Zeilenende ändern
|
||||||
|
y0 Bis Zeilenanfang kopieren
|
||||||
|
```
|
||||||
|
## Textobjekte (im Normal- / Visuellen Modus)
|
||||||
|
```text
|
||||||
|
aw A word (inkl. Leerzeichen)
|
||||||
|
iw Inner word
|
||||||
|
as A sentence
|
||||||
|
is Inner sentence
|
||||||
|
ap A paragraph
|
||||||
|
ip Inner paragraph
|
||||||
|
|
||||||
|
a" / i" Text in Anführungszeichen
|
||||||
|
a' / i' Text in einfachen Quotes
|
||||||
|
a) / i) Text in Klammern (usw. für {}, [], <>)
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
ci" Inhalt von "..." ändern
|
||||||
|
da( Klammerausdruck inklusive Klammern löschen
|
||||||
|
viw Wort unter Cursor markieren
|
||||||
|
```
|
||||||
|
## Suchen & Ersetzen
|
||||||
|
```text
|
||||||
|
/word Vorwärts nach „word“ suchen
|
||||||
|
?word Rückwärts suchen
|
||||||
|
n Nächster Treffer
|
||||||
|
N Vorheriger Treffer
|
||||||
|
|
||||||
|
* Wort unter Cursor vorwärts suchen
|
||||||
|
# Wort unter Cursor rückwärts suchen
|
||||||
|
|
||||||
|
:%s/alt/neu/g In gesamter Datei ersetzen
|
||||||
|
:%s/alt/neu/gc Mit Bestätigung
|
||||||
|
:.,$s/alt/neu/g Von aktueller Zeile bis Ende
|
||||||
|
:10,20s/alt/neu/g In Zeilen 10–20
|
||||||
|
```
|
||||||
|
## Dateien, Buffers, Splits & Tabs
|
||||||
|
```text
|
||||||
|
:e datei Datei öffnen
|
||||||
|
:w Speichern
|
||||||
|
:w name Unter anderem Namen speichern
|
||||||
|
:q Beenden
|
||||||
|
:q! Beenden ohne Speichern
|
||||||
|
:wq / :x Speichern und beenden
|
||||||
|
:qa Alle Fenster schließen
|
||||||
|
:qa! Alle schließen ohne Speichern
|
||||||
|
|
||||||
|
" Buffer (Dateien im Speicher)
|
||||||
|
:ls Buffer-Liste
|
||||||
|
:buffer n Buffer n öffnen
|
||||||
|
:bnext / :bn Nächster Buffer
|
||||||
|
:bprev / :bp Vorheriger Buffer
|
||||||
|
:bdelete Buffer schließen
|
||||||
|
|
||||||
|
" Splits
|
||||||
|
:split datei Horizontaler Split
|
||||||
|
:vsplit datei Vertikaler Split
|
||||||
|
Ctrl-w s Split horizontal
|
||||||
|
Ctrl-w v Split vertikal
|
||||||
|
Ctrl-w w Zum nächsten Split
|
||||||
|
Ctrl-w h/j/k/l Split wechseln
|
||||||
|
Ctrl-w q Split schließen
|
||||||
|
|
||||||
|
" Tabs
|
||||||
|
:tabnew Neuer Tab
|
||||||
|
:tabclose Tab schließen
|
||||||
|
:tabnext / :tn Nächster Tab
|
||||||
|
:tabprev / :tp Vorheriger Tab
|
||||||
|
```
|
||||||
|
## Visual Mode Aktionen
|
||||||
|
```text
|
||||||
|
v / V / Ctrl-v Auswahl starten
|
||||||
|
y Auswahl kopieren
|
||||||
|
d Auswahl löschen
|
||||||
|
c Auswahl ändern
|
||||||
|
|
||||||
|
> Einrücken
|
||||||
|
< Ausrücken
|
||||||
|
= Auto-Indent (z.B. für Code)
|
||||||
|
|
||||||
|
: Befehl auf Auswahl anwenden
|
||||||
|
(Bereich wird automatisch eingetragen)
|
||||||
|
```
|
||||||
|
## Makros & Wiederholung
|
||||||
|
```text
|
||||||
|
. Letzte Änderung wiederholen
|
||||||
|
|
||||||
|
q<a> Macro in Register a aufzeichnen
|
||||||
|
(z.B. qa)
|
||||||
|
... Aktionen ausführen
|
||||||
|
q Aufzeichnung beenden
|
||||||
|
|
||||||
|
@a Macro a ausführen
|
||||||
|
3@a Macro 3x ausführen
|
||||||
|
@@ Letztes Macro wiederholen
|
||||||
|
```
|
||||||
|
## Register
|
||||||
|
```text
|
||||||
|
"0 Zuletzt kopiertes (y) ohne delete
|
||||||
|
"1–"9 Verlaufsregister
|
||||||
|
"" Default-Register
|
||||||
|
|
||||||
|
"+ System-Clipboard (kopieren/einfügen mit OS)
|
||||||
|
"* Auswahl-Clipboard (unter Linux/X11)
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
"ayw Wort in Register a kopieren
|
||||||
|
"ap Inhalt von Register a einfügen
|
||||||
|
"+y In System-Clipboard kopieren
|
||||||
|
"+p Aus System-Clipboard einfügen
|
||||||
|
```
|
||||||
|
## Kommandomodus (Ex-Befehle)
|
||||||
|
```text
|
||||||
|
:!cmd Externen Befehl ausführen
|
||||||
|
:r !cmd Ausgabe von cmd einfügen
|
||||||
|
:r datei Datei unter Cursor-Zeile einfügen
|
||||||
|
|
||||||
|
:set nu Zeilennummern an
|
||||||
|
:set nonu Zeilennummern aus
|
||||||
|
:set relativenumber Relative Nummern
|
||||||
|
:set tabstop=4 shiftwidth=4 expandtab
|
||||||
|
```
|
||||||
|
## Einfache .vimrc-Beispiele
|
||||||
|
```vim
|
||||||
|
" Zeilennummern
|
||||||
|
set number
|
||||||
|
set relativenumber
|
||||||
|
|
||||||
|
" Einrückung
|
||||||
|
set tabstop=4
|
||||||
|
set shiftwidth=4
|
||||||
|
set expandtab
|
||||||
|
set smartindent
|
||||||
|
|
||||||
|
" Suche
|
||||||
|
set ignorecase
|
||||||
|
set smartcase
|
||||||
|
set hlsearch
|
||||||
|
set incsearch
|
||||||
|
|
||||||
|
" Maus
|
||||||
|
set mouse=a
|
||||||
|
```
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
In Vim kannst du mit regulären Ausdrücken über *mehrere Dateien* suchen, typischerweise über das Quickfix-/Location-List-System. Die wichtigsten Befehle dafür sind `:vimgrep` und `:grep`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Mehrdatei-Suche mit `:vimgrep`
|
||||||
|
|
||||||
|
Grundform:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:vimgrep /MUSTER/ {Dateiliste}
|
||||||
|
```
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
" In allen .py-Dateien im aktuellen Verzeichnis
|
||||||
|
:vimgrep /foo/ *.py
|
||||||
|
|
||||||
|
" Rekursiv in allen .py-Dateien
|
||||||
|
:vimgrep /foo/ **/*.py
|
||||||
|
|
||||||
|
" In allen Dateien des aktuellen Git-Repos (falls du Pfade generierst)
|
||||||
|
:vimgrep /foo/ `git ls-files`
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach:
|
||||||
|
|
||||||
|
- Quickfix-Fenster öffnen:
|
||||||
|
```vim
|
||||||
|
:copen
|
||||||
|
```
|
||||||
|
- Zum nächsten Treffer springen:
|
||||||
|
```vim
|
||||||
|
:cn
|
||||||
|
```
|
||||||
|
- Zum vorherigen Treffer springen:
|
||||||
|
```vim
|
||||||
|
:cp
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Regex-Varianten: Standard vs. „very magic“
|
||||||
|
|
||||||
|
Vim-Regex kann per Präfix gesteuert werden:
|
||||||
|
|
||||||
|
- Standard (abhängig von `'magic'`-Option)
|
||||||
|
- `\v` = *very magic* (fast alles ist Meta-Zeichen)
|
||||||
|
- `\m` = *magic*
|
||||||
|
- `\M` = *nomagic*
|
||||||
|
- `\V` = *very nomagic*
|
||||||
|
|
||||||
|
Du kannst das direkt im Suchmuster verwenden:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
" Very magic: ( ) + ? | etc. sind sofort Metazeichen
|
||||||
|
:vimgrep /\vfoo(bar|baz)\d+/ **/*.txt
|
||||||
|
|
||||||
|
" Standard-/Default-Verhalten (meistens wie :set magic)
|
||||||
|
:vimgrep /foo\(bar\|baz\)\d\+/ **/*.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Kurz gesagt:
|
||||||
|
- Wenn du „normale“ moderne RegEx-Syntax willst, nimm einfach `\v` am Anfang des Patterns.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Suche mit `:grep` (externes Tool)
|
||||||
|
|
||||||
|
Wenn `grepprg` entsprechend gesetzt ist (z.B. auf `rg`, `ag` oder `grep`):
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:grep foo **/*.py
|
||||||
|
:copen
|
||||||
|
```
|
||||||
|
|
||||||
|
Auch hier gilt: das Muster ist in vielen Fällen *nicht* Vim-Regex, sondern die Regex-Syntax des externen Tools (z.B. ripgrep).
|
||||||
|
|
||||||
|
Wenn du explizit Vim-Regex willst, bleib bei `:vimgrep`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Dateien vorher definieren und dann suchen
|
||||||
|
|
||||||
|
Du kannst zuerst eine Dateiliste definieren und dann in dieser Liste suchen:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
" Alle C-Dateien rekursiv in die Argumentliste
|
||||||
|
:args **/*.c
|
||||||
|
|
||||||
|
" Jetzt in allen Dateien aus :args suchen
|
||||||
|
:vimgrep /\vmy_func\(/ ##
|
||||||
|
|
||||||
|
" ## bedeutet: alle Dateien in der aktuellen Argumentliste
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Treffern zur bestehenden Liste hinzufügen
|
||||||
|
|
||||||
|
Wenn du mehrere Suchläufe kombinieren willst:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:vimgrep /foo/ **/*.py
|
||||||
|
:vimgrepadd /bar/ **/*.py " fügt Treffer für bar hinzu
|
||||||
|
:copen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Wenn du mir sagst, ob du eher mit `rg`/`ag` arbeitest oder nur mit purem Vim, kann ich dir ein paar konkrete Konfig-/Mapping-Beispiele geben.
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,780 @@
|
|||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🐳 Einführung in Docker
|
||||||
|
|
||||||
|
## 1. Was ist Docker?
|
||||||
|
|
||||||
|
Docker ist eine Plattform, mit der du **Container** erstellen, starten und verwalten kannst.
|
||||||
|
Ein Container ist eine Art "leichtgewichtige virtuelle Maschine":
|
||||||
|
|
||||||
|
- Enthält **nur das Nötigste** (Programm, Abhängigkeiten, Bibliotheken).
|
||||||
|
- Läuft isoliert, aber nutzt den Kernel des Host-Systems (kein eigener Kernel wie bei einer VM).
|
||||||
|
- Ist **schneller** und **ressourcenschonender** als klassische VMs.
|
||||||
|
|
||||||
|
👉 Bildlich: Statt für jedes Programm einen eigenen PC (VM) aufzubauen, packst du nur das Programm in eine "Transportbox" (Container), die überall läuft, solange Docker installiert ist.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Vorteile und typische Anwendungsfälle
|
||||||
|
|
||||||
|
### Vorteile
|
||||||
|
|
||||||
|
- **Portabilität**: „Läuft auf meinem Rechner“ = „läuft auch auf Servern“.
|
||||||
|
- **Isolierung**: Verschiedene Programme/Versionen stören sich nicht.
|
||||||
|
- **Leichtgewicht**: Start in Sekunden statt Minuten wie bei VMs.
|
||||||
|
- **Reproduzierbarkeit**: Gleiche Umgebung für Entwicklung, Test und Produktion.
|
||||||
|
- **Einfache Verteilung**: Images können über Docker Hub oder private Registries geteilt werden.
|
||||||
|
|
||||||
|
### Typische Anwendungsfälle
|
||||||
|
|
||||||
|
- 🚀 **Entwicklung**: Z. B. [[Python]] 3.10 testen, obwohl auf dem System Python 3.12 läuft.
|
||||||
|
- 🗄️ **Datenbanken**: [[MySQL]], PostgreSQL, Redis, MongoDB zum Testen ohne Installation.
|
||||||
|
- 🌐 **Web-Apps**: Schnell mal eine fertige Anwendung ausprobieren (WordPress, Nextcloud, GitLab etc.).
|
||||||
|
- 🧪 **Testing**: Mehrere Umgebungen simulieren (verschiedene OS, Bibliotheksversionen).
|
||||||
|
- 📦 **Deployment**: Gleiche App auf mehreren Servern identisch bereitstellen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Hauptfunktionalitäten von Docker
|
||||||
|
|
||||||
|
- **Docker Engine**: Herzstück, das Container ausführt.
|
||||||
|
- **Docker Images**: Baupläne (Templates) für Container (z. B. Python 3.12 + Flask).
|
||||||
|
- **Docker Containers**: Laufende Instanzen von Images.
|
||||||
|
- **Docker Hub/Registry**: Cloud-Marktplatz für fertige Images.
|
||||||
|
- **Docker Compose**: Orchestrierung mehrerer Container (z. B. App + DB + Cache).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Installation unter Linux (Beispiel: Ubuntu/Debian)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Alte Versionen entfernen
|
||||||
|
sudo apt-get remove docker docker-engine docker.io containerd runc
|
||||||
|
|
||||||
|
# 2. Repository vorbereiten
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y ca-certificates curl gnupg
|
||||||
|
|
||||||
|
# Docker GPG-Key hinzufügen
|
||||||
|
sudo install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
|
||||||
|
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
|
||||||
|
# Repository einrichten
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
||||||
|
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
|
||||||
|
# 3. Docker installieren
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
|
|
||||||
|
# 4. Testen
|
||||||
|
sudo docker run hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
👉 Danach kannst du optional dich in die `docker`-Gruppe aufnehmen (sonst musst du immer `sudo` schreiben):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
# Abmelden/neu anmelden, damit es wirkt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Erste Schritte in der Praxis
|
||||||
|
|
||||||
|
### Beispiel 1: Linux — Container starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Einen Ubuntu-Container starten (interaktiv)
|
||||||
|
docker run -it ubuntu bash
|
||||||
|
|
||||||
|
# Danach bist du im Container:
|
||||||
|
root@<id>:/# cat /etc/os-release
|
||||||
|
```
|
||||||
|
|
||||||
|
Wenn du rausgehst (`exit`), bleibt der Container gespeichert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Beispiel 2: Linux — Nginx-Webserver starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Nginx starten, Port 8080 weiterleiten
|
||||||
|
docker run -d -p 8080:80 nginx
|
||||||
|
|
||||||
|
# Nun im Browser: http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Beispiel 3: Python im Container
|
||||||
|
|
||||||
|
Nehmen wir an, du willst ein Python-Skript in einer isolierten Umgebung ausführen.
|
||||||
|
|
||||||
|
**hello.py**
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Hello from Dockerized Python!")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dockerfile**
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Skript ins Image kopieren
|
||||||
|
COPY hello.py /app/hello.py
|
||||||
|
|
||||||
|
# Arbeitsverzeichnis setzen
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Default-Befehl
|
||||||
|
CMD ["python", "hello.py"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bauen und starten**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Image bauen
|
||||||
|
docker build -t mypythonapp .
|
||||||
|
|
||||||
|
# Container starten
|
||||||
|
docker run --rm mypythonapp
|
||||||
|
```
|
||||||
|
|
||||||
|
Ausgabe:
|
||||||
|
|
||||||
|
```
|
||||||
|
Hello from Dockerized Python!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Beispiel 4: Python mit externer Bibliothek
|
||||||
|
|
||||||
|
```python
|
||||||
|
# requirements.txt
|
||||||
|
flask==3.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
**app.py**
|
||||||
|
|
||||||
|
```python
|
||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello():
|
||||||
|
return "Hello, Docker!"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host="0.0.0.0", port=5000)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dockerfile**
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
|
COPY app.py .
|
||||||
|
|
||||||
|
CMD ["python", "app.py"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Starten**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t flaskapp .
|
||||||
|
docker run -d -p 5000:5000 flaskapp
|
||||||
|
```
|
||||||
|
|
||||||
|
👉 Browser öffnen: `http://localhost:5000`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Nützliche Docker-Befehle (Cheatsheet)
|
||||||
|
|
||||||
|
- `docker ps` – laufende Container
|
||||||
|
- `docker ps -a` – alle Container (inkl. gestoppter)
|
||||||
|
- `docker images` – vorhandene Images
|
||||||
|
- `docker stop <id>` – Container stoppen
|
||||||
|
- `docker rm <id>` – Container löschen
|
||||||
|
- `docker rmi <image>` – Image löschen
|
||||||
|
- `docker exec -it <id> bash` – in Container einsteigen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ Damit hast du einen vollständigen Überblick über Docker:
|
||||||
|
|
||||||
|
- **Grundidee**
|
||||||
|
- **Vorteile/Anwendungsfälle**
|
||||||
|
- **Installation**
|
||||||
|
- **Praxis mit Linux und Python**
|
||||||
|
|
||||||
|
---
|
||||||
|
# Anwendungsbeispiel
|
||||||
|
# 🐳 Docker Anwendungsbeispiel - Detaillierte Erklärung für Einsteiger
|
||||||
|
|
||||||
|
## 📚 Was ist Docker überhaupt?
|
||||||
|
|
||||||
|
**Docker** ist wie ein **"Umzugskarton für Software"**:
|
||||||
|
- Stell Dir vor, Du willst Deine App an einen Freund verschicken
|
||||||
|
- Statt nur den Code zu senden, packst Du **alles** ein: Code, Python, alle Bibliotheken, Konfiguration
|
||||||
|
- Dein Freund öffnet den "Karton" (Container) und alles läuft sofort - egal welches Betriebssystem er hat
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Projektstruktur mit Erklärungen
|
||||||
|
|
||||||
|
```
|
||||||
|
python-docker-project/
|
||||||
|
├── app/ # 📂 Unser Python-Code
|
||||||
|
│ ├── __init__.py # (macht 'app' zu einem Python-Paket)
|
||||||
|
│ ├── main.py # Hauptprogramm
|
||||||
|
│ ├── data_processor.py # Modul für Datenverarbeitung
|
||||||
|
│ └── database.py # Modul für Datenbankzugriff
|
||||||
|
├── input/ # 📁 Hier liegen die Input-Dateien (vom Host)
|
||||||
|
│ └── sample_data.csv # Beispieldatei
|
||||||
|
├── output/ # 📁 Hier kommen verarbeitete Dateien rein
|
||||||
|
├── requirements.txt # 📝 Liste aller Python-Pakete die wir brauchen
|
||||||
|
├── Dockerfile # 🐳 "Bauanleitung" für unseren Container
|
||||||
|
├── docker-compose.yml # 🎼 "Dirigent" für mehrere Container
|
||||||
|
└── .env # 🔐 Geheime Einstellungen (Passwörter etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐍 Python-Code (wie gewohnt)
|
||||||
|
|
||||||
|
### **requirements.txt** - "Einkaufsliste" für Python-Pakete
|
||||||
|
```txt
|
||||||
|
# 🛒 Diese Pakete braucht unser Programm
|
||||||
|
pandas==2.1.4 # Für Excel/CSV-Verarbeitung
|
||||||
|
psycopg2-binary==2.9.9 # Um mit PostgreSQL zu sprechen
|
||||||
|
python-dotenv==1.0.0 # Um .env-Dateien zu lesen
|
||||||
|
sqlalchemy==2.0.23 # Einfache Datenbankanbindung
|
||||||
|
```
|
||||||
|
|
||||||
|
**💡 Warum brauche ich das?**
|
||||||
|
- Ohne Docker müsstest Du auf jedem PC manuell `pip install pandas` etc. machen
|
||||||
|
- Mit Docker installiert sich das automatisch im Container
|
||||||
|
|
||||||
|
### **app/main.py** - Unser Hauptprogramm
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
🎯 Das macht unser Programm:
|
||||||
|
1. Schaut in /app/input nach CSV-Dateien
|
||||||
|
2. Verarbeitet sie (quadriert Werte, etc.)
|
||||||
|
3. Speichert Ergebnis in PostgreSQL-Datenbank
|
||||||
|
4. Exportiert auch als CSV in /app/output
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from .data_processor import DataProcessor
|
||||||
|
from .database import DatabaseManager
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("🚀 Starte Data Processing Pipeline...")
|
||||||
|
|
||||||
|
# 📁 Diese Pfade sind INSIDE dem Container!
|
||||||
|
input_dir = Path("/app/input") # Gemountet von Host ./input/
|
||||||
|
output_dir = Path("/app/output") # Gemountet von Host ./output/
|
||||||
|
output_dir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# 🗄️ Verbindung zur Datenbank (anderer Container!)
|
||||||
|
db_manager = DatabaseManager()
|
||||||
|
processor = DataProcessor(db_manager)
|
||||||
|
|
||||||
|
# 📊 Alle CSV-Dateien finden und verarbeiten
|
||||||
|
csv_files = list(input_dir.glob("*.csv"))
|
||||||
|
|
||||||
|
if not csv_files:
|
||||||
|
print("❌ Keine CSV-Dateien im Input-Verzeichnis gefunden!")
|
||||||
|
return
|
||||||
|
|
||||||
|
for csv_file in csv_files:
|
||||||
|
print(f"📄 Verarbeite: {csv_file.name}")
|
||||||
|
|
||||||
|
# 1️⃣ Daten aus CSV laden und verarbeiten
|
||||||
|
result_data = processor.process_file(csv_file)
|
||||||
|
|
||||||
|
# 2️⃣ In PostgreSQL-Container speichern
|
||||||
|
processor.save_to_database(result_data, csv_file.stem)
|
||||||
|
|
||||||
|
# 3️⃣ Als neue CSV-Datei exportieren
|
||||||
|
output_file = output_dir / f"processed_{csv_file.name}"
|
||||||
|
result_data.to_csv(output_file, index=False)
|
||||||
|
print(f"💾 Gespeichert als: {output_file}")
|
||||||
|
|
||||||
|
print("✅ Pipeline abgeschlossen!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
### **app/database.py** - Spricht mit der Datenbank
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
from sqlalchemy import create_engine, text
|
||||||
|
|
||||||
|
class DatabaseManager:
|
||||||
|
def __init__(self):
|
||||||
|
# 🔌 Diese Werte kommen aus der docker-compose.yml!
|
||||||
|
self.host = os.getenv('DB_HOST', 'postgres') # Name des DB-Containers!
|
||||||
|
self.port = os.getenv('DB_PORT', '5432')
|
||||||
|
self.database = os.getenv('DB_NAME', 'dataprocessing')
|
||||||
|
self.user = os.getenv('DB_USER', 'postgres')
|
||||||
|
self.password = os.getenv('DB_PASSWORD', 'password')
|
||||||
|
|
||||||
|
# 🌐 Connection String - wie eine Adresse zur Datenbank
|
||||||
|
self.connection_string = (
|
||||||
|
f"postgresql://{self.user}:{self.password}@"
|
||||||
|
f"{self.host}:{self.port}/{self.database}"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.engine = None
|
||||||
|
self._connect()
|
||||||
|
|
||||||
|
def _connect(self):
|
||||||
|
"""Verbindung zur Datenbank herstellen"""
|
||||||
|
try:
|
||||||
|
self.engine = create_engine(self.connection_string)
|
||||||
|
# 🏓 Kurzer Test: "Hallo Datenbank!"
|
||||||
|
with self.engine.connect() as conn:
|
||||||
|
conn.execute(text("SELECT 1"))
|
||||||
|
print("✅ Datenbankverbindung erfolgreich")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Datenbankverbindung fehlgeschlagen: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def save_dataframe(self, df: pd.DataFrame, table_name: str):
|
||||||
|
"""Speichert DataFrame als Tabelle in PostgreSQL"""
|
||||||
|
df.to_sql(
|
||||||
|
name=table_name,
|
||||||
|
con=self.engine,
|
||||||
|
if_exists='replace', # Überschreibt existierende Tabelle
|
||||||
|
index=False
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
*(Die anderen Python-Dateien bleiben gleich)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐳 Dockerfile - "Bauanleitung" für unseren Container
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# 🏗️ SCHRITT 1: Basis-Image wählen
|
||||||
|
# Das ist wie ein "Rohbau" - Linux + Python sind schon installiert
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# 🛠️ SCHRITT 2: System-Tools installieren
|
||||||
|
# Wir brauchen gcc und libpq-dev für PostgreSQL-Verbindung
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
gcc \
|
||||||
|
libpq-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# 💡 WARUM: psycopg2 (PostgreSQL-Driver) braucht diese Tools zum Kompilieren
|
||||||
|
|
||||||
|
# 📂 SCHRITT 3: Arbeitsverzeichnis setzen
|
||||||
|
WORKDIR /app
|
||||||
|
# Das ist wie "cd /app" - alle folgenden Befehle laufen hier
|
||||||
|
|
||||||
|
# 📦 SCHRITT 4: Python-Pakete installieren
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
# 💡 WARUM separat? Docker cached diesen Layer - muss nur neu gebaut werden wenn requirements.txt ändert
|
||||||
|
|
||||||
|
# 📋 SCHRITT 5: Unseren Code ins Container kopieren
|
||||||
|
COPY app/ ./app/
|
||||||
|
# Kopiert alles aus Host-Ordner "app/" nach Container "/app/app/"
|
||||||
|
|
||||||
|
# 📁 SCHRITT 6: Verzeichnisse erstellen
|
||||||
|
RUN mkdir -p /app/input /app/output
|
||||||
|
# Diese werden später durch Volume-Mounts "überschrieben"
|
||||||
|
|
||||||
|
# ⚙️ SCHRITT 7: Umgebungsvariablen setzen
|
||||||
|
ENV PYTHONPATH=/app # Python findet unsere Module
|
||||||
|
ENV PYTHONUNBUFFERED=1 # Print-Ausgaben erscheinen sofort
|
||||||
|
|
||||||
|
# 🚀 SCHRITT 8: Was soll beim Container-Start passieren?
|
||||||
|
CMD ["python", "-m", "app.main"]
|
||||||
|
# Startet unser Hauptprogramm
|
||||||
|
```
|
||||||
|
|
||||||
|
**🤔 Was passiert beim `docker build`?**
|
||||||
|
1. Docker lädt `python:3.11-slim` herunter (falls nicht da)
|
||||||
|
2. Installiert gcc und PostgreSQL-Tools
|
||||||
|
3. Kopiert `requirements.txt` und installiert Python-Pakete
|
||||||
|
4. Kopiert unseren Code rein
|
||||||
|
5. Setzt Umgebungsvariablen
|
||||||
|
6. **Ergebnis:** Ein fertiger Container mit allem was wir brauchen!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎼 docker-compose.yml - "Dirigent" für mehrere Container
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# 🎯 docker-compose orchestriert MEHRERE Container gleichzeitig
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# 🗄️ CONTAINER 1: PostgreSQL-Datenbank
|
||||||
|
postgres:
|
||||||
|
image: postgres:15 # Fertiges PostgreSQL-Image von Docker Hub
|
||||||
|
environment: # Umgebungsvariablen für PostgreSQL
|
||||||
|
POSTGRES_DB: dataprocessing # Name der Datenbank die erstellt wird
|
||||||
|
POSTGRES_USER: postgres # Benutzername
|
||||||
|
POSTGRES_PASSWORD: password # 🔐 Passwort (in Produktion geheimer!)
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data # 💾 Daten persistent speichern
|
||||||
|
- ./db_init:/docker-entrypoint-initdb.d # 📂 Optional: SQL-Skripts beim Start
|
||||||
|
ports:
|
||||||
|
- "5432:5432" # Port freigeben (Host:Container)
|
||||||
|
networks:
|
||||||
|
- app_network # 🌐 Internes Netzwerk für Container-Kommunikation
|
||||||
|
|
||||||
|
# 🐍 CONTAINER 2: Unsere Python-Anwendung
|
||||||
|
python_app:
|
||||||
|
build: . # 🏗️ Baue Container aus Dockerfile in diesem Verzeichnis
|
||||||
|
environment: # Diese Variablen kann unser Python-Code lesen
|
||||||
|
DB_HOST: postgres # ❗ WICHTIG: Name des DB-Containers (nicht localhost!)
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_NAME: dataprocessing
|
||||||
|
DB_USER: postgres
|
||||||
|
DB_PASSWORD: password
|
||||||
|
volumes: # 📂 Verbinde Host-Verzeichnisse mit Container
|
||||||
|
- ./input:/app/input:ro # Host ./input → Container /app/input (read-only)
|
||||||
|
- ./output:/app/output # Host ./output → Container /app/output (read-write)
|
||||||
|
depends_on: # ⏱️ Warte bis postgres-Container läuft
|
||||||
|
- postgres
|
||||||
|
networks:
|
||||||
|
- app_network # 🌐 Gleiches Netzwerk = können miteinander sprechen
|
||||||
|
restart: unless-stopped # 🔄 Automatisch neu starten bei Absturz
|
||||||
|
|
||||||
|
# 🌐 CONTAINER 3: pgAdmin (Web-Interface für PostgreSQL)
|
||||||
|
pgadmin:
|
||||||
|
image: dpage/pgadmin4:8
|
||||||
|
environment:
|
||||||
|
PGADMIN_DEFAULT_EMAIL: admin@example.com
|
||||||
|
PGADMIN_DEFAULT_PASSWORD: admin
|
||||||
|
ports:
|
||||||
|
- "8080:80" # 🌐 Zugriff via http://localhost:8080
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
networks:
|
||||||
|
- app_network
|
||||||
|
|
||||||
|
# 💾 VOLUMES: Persistente Datenspeicherung
|
||||||
|
volumes:
|
||||||
|
postgres_data: # Docker verwaltet diesen Speicher automatisch
|
||||||
|
# 💡 Auch wenn Container gelöscht wird, bleiben Daten erhalten
|
||||||
|
|
||||||
|
# 🌐 NETWORKS: Virtuelle Netzwerke für Container-Kommunikation
|
||||||
|
networks:
|
||||||
|
app_network:
|
||||||
|
driver: bridge # Standard-Netzwerk-Typ
|
||||||
|
# 💡 Alle Container in diesem Netzwerk können sich über Namen erreichen
|
||||||
|
```
|
||||||
|
|
||||||
|
**🤔 Warum docker-compose?**
|
||||||
|
- **Ohne compose:** `docker run postgres`, dann `docker run python_app` - sehr umständlich!
|
||||||
|
- **Mit compose:** Ein Befehl (`docker-compose up`) startet ALLES automatisch
|
||||||
|
- **Networks:** Container können sich über Namen finden (`postgres` statt IP-Adresse)
|
||||||
|
- **Volumes:** Daten gehen nicht verloren beim Container-Neustart
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 .env - Geheime Konfiguration
|
||||||
|
|
||||||
|
```env
|
||||||
|
# 🔐 Sensible Daten sollten NICHT in docker-compose.yml stehen
|
||||||
|
# Diese Datei wird von docker-compose automatisch gelesen
|
||||||
|
|
||||||
|
# Datenbankverbindung
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=dataprocessing
|
||||||
|
DB_USER=postgres
|
||||||
|
DB_PASSWORD=password # ❗ In Produktion: sicheres Passwort!
|
||||||
|
|
||||||
|
# Python-Einstellungen
|
||||||
|
PYTHONPATH=/app
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
```
|
||||||
|
|
||||||
|
**💡 Wichtig:** Die `.env`-Datei niemals in Git committen! (→ `.gitignore`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Beispiel-Daten
|
||||||
|
|
||||||
|
### **input/sample_data.csv**
|
||||||
|
```csv
|
||||||
|
id,name,value,category
|
||||||
|
1,Item A,10,electronics
|
||||||
|
2,Item B,25,clothing
|
||||||
|
3,Item C,15,electronics
|
||||||
|
4,Item D,30,books
|
||||||
|
5,Item E,8,clothing
|
||||||
|
```
|
||||||
|
|
||||||
|
**💡 Das ist eine normale CSV-Datei auf Deinem Host-PC**
|
||||||
|
- Liegt in `./input/sample_data.csv`
|
||||||
|
- Wird in den Container als `/app/input/sample_data.csv` "gemountet"
|
||||||
|
- Unser Python-Code kann sie lesen, als wäre sie im Container
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Schritt-für-Schritt Anleitung
|
||||||
|
|
||||||
|
### **1. Projekt erstellen**
|
||||||
|
```bash
|
||||||
|
# Verzeichnis erstellen
|
||||||
|
mkdir python-docker-project
|
||||||
|
cd python-docker-project
|
||||||
|
|
||||||
|
# Struktur erstellen
|
||||||
|
mkdir -p app input output
|
||||||
|
touch requirements.txt Dockerfile docker-compose.yml .env
|
||||||
|
touch app/__init__.py app/main.py app/data_processor.py app/database.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. Code schreiben**
|
||||||
|
- Alle Dateien wie oben gezeigt erstellen und befüllen
|
||||||
|
|
||||||
|
### **3. Container bauen und starten**
|
||||||
|
```bash
|
||||||
|
# Alle Container bauen und starten
|
||||||
|
docker-compose up --build
|
||||||
|
|
||||||
|
# 🔍 Was passiert:
|
||||||
|
# 1. Docker baut unseren Python-Container (aus Dockerfile)
|
||||||
|
# 2. Lädt PostgreSQL-Image herunter
|
||||||
|
# 3. Lädt pgAdmin-Image herunter
|
||||||
|
# 4. Erstellt Netzwerk "app_network"
|
||||||
|
# 5. Startet postgres-Container
|
||||||
|
# 6. Startet python_app-Container (wartet auf postgres)
|
||||||
|
# 7. Startet pgAdmin-Container
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4. Überprüfen ob alles läuft**
|
||||||
|
```bash
|
||||||
|
# Laufende Container anzeigen
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# Logs ansehen
|
||||||
|
docker-compose logs python_app
|
||||||
|
docker-compose logs postgres
|
||||||
|
|
||||||
|
# In pgAdmin einloggen: http://localhost:8080
|
||||||
|
# Email: admin@example.com, Passwort: admin
|
||||||
|
```
|
||||||
|
|
||||||
|
### **5. Neue Daten verarbeiten**
|
||||||
|
```bash
|
||||||
|
# Neue CSV-Datei ins input-Verzeichnis kopieren
|
||||||
|
cp neue_daten.csv input/
|
||||||
|
|
||||||
|
# Python-App neu starten um neue Dateien zu verarbeiten
|
||||||
|
docker-compose restart python_app
|
||||||
|
|
||||||
|
# Ergebnis ansehen
|
||||||
|
ls -la output/
|
||||||
|
```
|
||||||
|
|
||||||
|
### **6. System stoppen**
|
||||||
|
```bash
|
||||||
|
# Alle Container stoppen
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Container stoppen UND Daten löschen (Vorsicht!)
|
||||||
|
docker-compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Docker-Befehle erklärt
|
||||||
|
|
||||||
|
### **Grundlegende Container-Befehle**
|
||||||
|
```bash
|
||||||
|
# 📋 Alle laufenden Container anzeigen
|
||||||
|
docker ps
|
||||||
|
|
||||||
|
# 📋 Alle Container anzeigen (auch gestoppte)
|
||||||
|
docker ps -a
|
||||||
|
|
||||||
|
# 🔍 Container-Logs ansehen
|
||||||
|
docker logs <container-name>
|
||||||
|
|
||||||
|
# 🔑 In laufenden Container "einsteigen"
|
||||||
|
docker exec -it <container-name> bash
|
||||||
|
|
||||||
|
# 🗑️ Container stoppen
|
||||||
|
docker stop <container-name>
|
||||||
|
|
||||||
|
# 🗑️ Container löschen
|
||||||
|
docker rm <container-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Image-Befehle**
|
||||||
|
```bash
|
||||||
|
# 📋 Alle Images anzeigen
|
||||||
|
docker images
|
||||||
|
|
||||||
|
# 🏗️ Image aus Dockerfile bauen
|
||||||
|
docker build -t mein-python-app .
|
||||||
|
|
||||||
|
# 🗑️ Image löschen
|
||||||
|
docker rmi <image-name>
|
||||||
|
|
||||||
|
# 🧹 Unbenutzte Images löschen
|
||||||
|
docker image prune
|
||||||
|
```
|
||||||
|
|
||||||
|
### **docker-compose-Befehle**
|
||||||
|
```bash
|
||||||
|
# 🚀 Alle Services starten
|
||||||
|
docker-compose up
|
||||||
|
|
||||||
|
# 🚀 Im Hintergrund starten
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# 🏗️ Images neu bauen und starten
|
||||||
|
docker-compose up --build
|
||||||
|
|
||||||
|
# 🔄 Einzelnen Service neu starten
|
||||||
|
docker-compose restart python_app
|
||||||
|
|
||||||
|
# 📋 Status aller Services
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# 🔍 Logs aller Services
|
||||||
|
docker-compose logs
|
||||||
|
|
||||||
|
# 🔍 Logs eines bestimmten Service
|
||||||
|
docker-compose logs python_app
|
||||||
|
|
||||||
|
# 📈 Live-Logs verfolgen
|
||||||
|
docker-compose logs -f python_app
|
||||||
|
|
||||||
|
# 🔑 In Container einsteigen
|
||||||
|
docker-compose exec python_app bash
|
||||||
|
docker-compose exec postgres psql -U postgres -d dataprocessing
|
||||||
|
|
||||||
|
# ⏹️ Alle Services stoppen
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# 🗑️ Services stoppen und Volumes löschen
|
||||||
|
docker-compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌟 Die wichtigsten Docker-Konzepte
|
||||||
|
|
||||||
|
### **1. Images vs Container**
|
||||||
|
- **Image** = "Bauplan" (wie ein Kuchenrezept)
|
||||||
|
- **Container** = "Laufende Instanz" (wie ein gebackener Kuchen)
|
||||||
|
- Ein Image kann viele Container erstellen
|
||||||
|
|
||||||
|
### **2. Volumes**
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- ./input:/app/input # Host-Verzeichnis → Container-Verzeichnis
|
||||||
|
```
|
||||||
|
- **Warum?** Container-Dateisystem ist temporär
|
||||||
|
- **Volume** = persistenter Speicher der überlebt
|
||||||
|
|
||||||
|
### **3. Networks**
|
||||||
|
- Container in gleichem Netzwerk können sich über Namen erreichen
|
||||||
|
- `python_app` kann `postgres` kontaktieren (nicht IP-Adresse!)
|
||||||
|
|
||||||
|
### **4. Environment Variables**
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
DB_HOST: postgres # Diese Variable kann Python-Code lesen
|
||||||
|
```
|
||||||
|
|
||||||
|
### **5. Ports**
|
||||||
|
```yaml
|
||||||
|
ports:
|
||||||
|
- "8080:80" # Host-Port : Container-Port
|
||||||
|
```
|
||||||
|
- Container-Port 80 wird auf Host-Port 8080 freigegeben
|
||||||
|
- Zugriff: `http://localhost:8080`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❓ Häufige Anfänger-Probleme
|
||||||
|
|
||||||
|
### **Problem 1: "Connection refused" zur Datenbank**
|
||||||
|
```
|
||||||
|
❌ FALSCH: DB_HOST=localhost
|
||||||
|
✅ RICHTIG: DB_HOST=postgres
|
||||||
|
```
|
||||||
|
- In Docker ist `localhost` der Container selbst
|
||||||
|
- Verwende den Service-Namen aus `docker-compose.yml`
|
||||||
|
|
||||||
|
### **Problem 2: "File not found"**
|
||||||
|
```
|
||||||
|
❌ FALSCH: input_dir = Path("./input")
|
||||||
|
✅ RICHTIG: input_dir = Path("/app/input")
|
||||||
|
```
|
||||||
|
- Pfade sind INSIDE dem Container, nicht auf dem Host
|
||||||
|
|
||||||
|
### **Problem 3: "Module not found"**
|
||||||
|
```
|
||||||
|
❌ FALSCH: Umgebungsvariable vergessen
|
||||||
|
✅ RICHTIG: ENV PYTHONPATH=/app in Dockerfile
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Problem 4: Änderungen nicht sichtbar**
|
||||||
|
```bash
|
||||||
|
# Nach Code-Änderungen Container neu bauen:
|
||||||
|
docker-compose up --build
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Problem 5: Port bereits belegt**
|
||||||
|
```
|
||||||
|
❌ Error: Port 5432 already in use
|
||||||
|
✅ Lösung: Anderen Port verwenden: "5433:5432"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Zusammenfassung - Was macht was?
|
||||||
|
|
||||||
|
| Datei/Komponente | Was es macht | Warum wichtig |
|
||||||
|
|------------------|--------------|---------------|
|
||||||
|
| **Dockerfile** | "Bauanleitung" für Python-Container | Definiert was IN den Container kommt |
|
||||||
|
| **docker-compose.yml** | Orchestriert mehrere Container | Ein Befehl startet alles |
|
||||||
|
| **requirements.txt** | Liste der Python-Pakete | Automatische Installation |
|
||||||
|
| **.env** | Geheime Konfiguration | Passwörter nicht in Code |
|
||||||
|
| **volumes** | Datenaustausch Host ↔ Container | Input/Output-Dateien |
|
||||||
|
| **networks** | Container-Kommunikation | python_app kann postgres erreichen |
|
||||||
|
| **ports** | Zugriff von außen | Web-Interface erreichbar |
|
||||||
|
|
||||||
|
**🚀 Mit einem Befehl hast Du:**
|
||||||
|
- ✅ Python-Umgebung mit allen Paketen
|
||||||
|
- ✅ PostgreSQL-Datenbank
|
||||||
|
- ✅ Web-Interface für DB
|
||||||
|
- ✅ Automatische File-Verarbeitung
|
||||||
|
- ✅ Persistente Datenspeicherung
|
||||||
|
|
||||||
|
**Das ist die Macht von Docker! 🐳**
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
https://www.librechat.ai/
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
Ich hab ein bisschen recherchiert und ein paar gute Optionen gefunden — sowohl Open Source / native [[Linux]]-PlugIns als auch Tipps, wie man bewährte Windows/Proprietär-Drum-Libraries unter Linux laufen lassen kann. Wenn du willst, kann ich auch ein paar kommerzielle Kandidaten heraussuchen, die unter Linux getestet sind. Hier zunächst ein Überblick:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Native bzw. sehr gut unter Linux laufende Drum-Sampler / Drum-PlugIns
|
||||||
|
|
||||||
|
Diese Tools/Plugins laufen nativ unter Linux / oder haben Linux-Versionen, und sind gute Alternativen oder Ergänzungen zu EZ-Drummer:
|
||||||
|
|
||||||
|
| Plugin / Tool | Format / Linux-Support | Vorteile | Einschränkungen / Punkte, auf die man achten sollte |
|
||||||
|
| -------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| **[[DrumGizmo]]** | VSTi & LV2 Version, stand-alone auch; multichannel, multilayered. | Sehr gute Drumsounds mit mehreren Velocity-Schichten; man kann einzelne Mikros / Kanäle nutzen, also gute Flexibilität beim Mischen. | Die Drums werden nicht immer sofort so fett wie bei kommerziellen Tools; erfordert gutes Setup (Routing, Mix) und ggf. eigene Kits. |
|
||||||
|
| **[[LinuxSampler]]** | VST, LV2, DSSI etc. | Sehr mächtig, kann große Sample-Libraries nutzen; volle Kontrolle. | Bedienung nicht so „slick“ wie bei Markenprodukten, evtl. Lernkurve; große Sample-Bibliotheken nötig für gute Vielfalt. |
|
||||||
|
| **[[drumkv1]]** | LV2 / Standalone (JACK / ALSA MIDI)-Client; native Linux. | Leichtgewichtig, einfach einzurichten; ideal wenn man nicht so viele Features braucht. | Kein High-End-Drumkit mit riesiger Bibliothek; klingt eher sauber/klassisch, nicht unbedingt super „produziert“. |
|
||||||
|
| **Geonkick** | Synthesizer Drum / Percussion; VST3 und LV2 auf Linux. | Sehr flexibel bei perkussiven Sounds, interessant wenn man eigene, eher synthetische Drums bauen will. | Eher auf Drum-Synthese fokussiert, nicht ein „Drumkit-Sammler“ mit kompletten Kits wie bei EZ Drummer etc. Kann sein, dass man noch eigene Samples oder Bearbeitung braucht, damit’s wirklich gut passt. |
|
||||||
|
| **Sitala** | Stand-alone / PlugIn Version, unterstützt Linux in früheren Versionen (V1) zumindest; sehr leicht zu bedienen. | Schnelle Ergebnisse; ideal für kreative Ideen, wenn man schnell Drums triggern möchte; UI ist simpel und effizient. | Wenn man ganz spezifische Kits oder sehr aufwendige Layer/Velocity braucht, stößt man evtl. an Grenzen; neuere Versionen evtl. eingeschränkter Linux-Support. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Kommerzielle PlugIns / Windows-Drum-Libraries unter Linux verwenden
|
||||||
|
|
||||||
|
Wenn dir die Qualität / Klang von EZ-Drummer oder ähnlichen wichtig ist und du nicht komplett auf native Alternativen umsteigen willst, hier ein paar Tipps, wie man kommerzielle Plugins unter Linux zuverlässiger nutzen kann:
|
||||||
|
|
||||||
|
- **Wine + VST Bridge / yabridge**: Viele Nutzer berichten, dass Windows-VSTs mit yabridge in Reaper unter Linux ziemlich gut laufen. Manche hatten Probleme mit Soundlibrary-Pfaden etc., aber wenn man das richtig einrichtet (z. B. Wineprefix, korrekter Pfad zu den Samples), dann klappt’s oft sehr gut.
|
||||||
|
- **Reaper Native + Linux-VST Unterstützung**: Die Linux-Version von Reaper kann native Linux VSTs nutzen, und mit yabridge auch Windows VSTs; das heißt, du kannst beides kombinieren.
|
||||||
|
- **Sample Libraries exportieren / konvertieren**: Wenn du z. B. Libraries hast, die in einem Format sind, das EZ-Drummer verwendet, könnte man prüfen, ob man die Samples in ein universelles Format bringt (z.B. SFZ) und dann mit einem Sampler wie LinuxSampler oder DrumGizmo nutzen. Das erspart Abhängigkeiten.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Wenn du möchtest, kann ich ein paar **kommerziell verfügbare Drum-PlugIns** heraussuchen, die nachweislich unter Linux + Reaper stabil laufen, inkl. Preis & Klangbeispiele, damit du vergleichen kannst? Möchtest du das?
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
|
||||||
|
Ich bin auf der Suche nach einer guten Software für meine MP3 Musiksammlung in Linux, mit die Synchronisation mit meinem Android Handy gut funktioniert.
|
||||||
|
|
||||||
|
### Hintergrund
|
||||||
|
Bisher habe ich als Ex-Windows-Nutzer das Programm "Media-Monkey" in der Pro Version verwendet, d.h. auf dem PC und dem Handy mit der gleichnamigen App.
|
||||||
|
|
||||||
|
### Anfrage
|
||||||
|
Bitte zeige mir gute Alternativen, bestehend aus Linux Programm für PC und Android App für Handy.
|
||||||
|
|
||||||
|
### Anforderungen:
|
||||||
|
* Flexible Organisation der Library nach Benutzerdefinierten Kriterien (z.B. Album Artist, Genre, Album, etc.)
|
||||||
|
* Bearbeitungsmöglichkeiten aller Song Infos
|
||||||
|
* Bewertungssystem und Verschlagwortung
|
||||||
|
* Playlisten: statisch und dynamsisch (d.h. regelbasiert)
|
||||||
|
* Leichte Synchronisierbarkeit zwischen Rechner und Handy:
|
||||||
|
* Änderungen an Metadaten, insbes. "Last Played" werden in beide Richtungen übernommen
|
||||||
|
* Möglichkeit die Bitrate der MP3s beim Synchronisieren anzupassen (z.B. um Speicherplatz auf Handy zu sparen)
|
||||||
|
* Synchronisation kabelgebunden oder über WLAN
|
||||||
|
|
||||||
|
### Optionale Anforderungen
|
||||||
|
* Möglichkeit, fehlende Metadaten aus WWW zu ergänzen
|
||||||
|
* Erstellung von Benutzerdefinierten Metadaten Feldern, z.B. als Berechnung aus anderen Feldern
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
Super, danke für die präzise Beschreibung – das hilft sehr!
|
||||||
|
Ich fasse mal die Landschaft für dich zusammen: es gibt unter Linux kein exaktes 1:1-Pendant zu **MediaMonkey**, aber einige Kombinationen aus Desktop-Software + Android-App können sehr nahe herankommen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. **MusicBee (via Wine) + Gonemad / PowerAmp (Android)**
|
||||||
|
|
||||||
|
- **Linux (Wine):** MusicBee läuft recht stabil unter Wine. Viele Ex-MediaMonkey-User nutzen es als Ersatz, weil es die meisten Features (flexible Library, Tags, Bewertungen, Smart-Playlists, Metadaten aus dem Netz) abdeckt.
|
||||||
|
|
||||||
|
- **Android:** Keine eigene App, aber Sync mit **GoneMAD** oder **PowerAmp** möglich. Mit Tools wie `syncthing` oder `Resilio Sync` kannst du Library, Ratings & Playcounts abgleichen.
|
||||||
|
|
||||||
|
- **Pro:** Funktionsumfang fast wie MediaMonkey.
|
||||||
|
|
||||||
|
- **Contra:** Keine native Linux-App, Integration Handy↔PC muss manuell über Sync-Tools eingerichtet werden.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. **Clementine / Strawberry (Linux) + Android App Clementine Remote / DSub**
|
||||||
|
|
||||||
|
- **Linux:** [[Strawberry 1]] ist ein Fork von Clementine, moderner gepflegt.
|
||||||
|
|
||||||
|
- Bibliotheksorganisation nach vielen Kriterien.
|
||||||
|
|
||||||
|
- Metadatenbearbeitung, inkl. Coverdownload von Last.fm, MusicBrainz.
|
||||||
|
|
||||||
|
- Playlists: statisch + dynamisch.
|
||||||
|
|
||||||
|
- **Android:** Offizielle Clementine-Remote-App für Steuerung, oder Streaming via Subsonic-kompatibler Apps (z. B. [[DSub]], [[Ultrasonic]]).
|
||||||
|
- siehe auch [[IT-Know-How/Linux/Subsonic-API]]
|
||||||
|
|
||||||
|
- **Sync:**
|
||||||
|
|
||||||
|
- Metadaten (Playcount, Ratings) werden am PC gespeichert.
|
||||||
|
|
||||||
|
- Handy-Sync ist etwas frickelig, echte **bidirektionale Playcount-Synchronisation** gibt es nicht nativ.
|
||||||
|
|
||||||
|
- **Pro:** Native Linux-App, offene Formate.
|
||||||
|
|
||||||
|
- **Contra:** Sync mit Handy nicht so nahtlos wie MediaMonkey.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. **Amarok / Elisa (KDE) + Android (KDE Connect, VLC, PowerAmp)**
|
||||||
|
|
||||||
|
- **Linux:** Amarok war früher sehr stark, inzwischen etwas veraltet. Elisa ist der moderne KDE-Player, aber weniger mächtig in Smart-Playlists.
|
||||||
|
|
||||||
|
- **Android:** Mit **KDE Connect** kannst du Dateien kabellos synchronisieren, aber Metadaten-Sync (z. B. "Last Played") fehlt.
|
||||||
|
|
||||||
|
- **Pro:** Schön in KDE integriert.
|
||||||
|
|
||||||
|
- **Contra:** Nicht so mächtig wie MediaMonkey.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. **Rhythmbox + Android (Lollypop / VLC)**
|
||||||
|
|
||||||
|
- **Linux:** Rhythmbox (GNOME Standard) oder Lollypop (modernere Oberfläche).
|
||||||
|
|
||||||
|
- **Features:** Library, Metadaten, Bewertungen.
|
||||||
|
|
||||||
|
- **Sync:** Per Kabel (MTP) oder WLAN/Sync-Tools, aber kein sauberer Playcount-Abgleich.
|
||||||
|
|
||||||
|
- **Contra:** Sehr basic, keine regelbasierten Playlists wie MediaMonkey.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. **Self-Hosted Server + Android (Subsonic/Airsonic + DSub/Ampache)**
|
||||||
|
|
||||||
|
- **Linux:** Airsonic, [Navidrome] oder Koel als **Musikserver**.
|
||||||
|
|
||||||
|
- **Features:** Vollständige Weboberfläche, flexible Library, Tags, Playcounts, Bewertungen.
|
||||||
|
|
||||||
|
- **Android:** Mit Apps wie **DSub**, **Substreamer**, **Ultrasonic** Zugriff und **automatische Playcount-Sync**.
|
||||||
|
|
||||||
|
- **Pro:**
|
||||||
|
|
||||||
|
- Playcounts, Metadaten und Playlists sind _immer synchronisiert_.
|
||||||
|
|
||||||
|
- Zugriff auch von unterwegs.
|
||||||
|
|
||||||
|
- **Contra:** Kein klassischer "Desktop-Player", sondern Server-Setup. Eher für Power-User.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. **Syncthing / rsync als Backend für bestehende Player**
|
||||||
|
|
||||||
|
- Falls dir wichtig ist, die MP3s in voller Struktur 1:1 zwischen Rechner und Handy zu haben (inkl. Playcounts, Bitrate-Anpassung), kannst du auch einen reinen Player wie **Strawberry** am PC + **GoneMAD** oder **PowerAmp** am Handy nutzen, und den Abgleich über **Syncthing** erledigen.
|
||||||
|
|
||||||
|
- Bitraten-Transkodierung beim Sync ist tricky: am besten über ein Script oder mit Tools wie **FFmpeg** beim Kopieren lösen.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fazit (Empfehlungen)
|
||||||
|
|
||||||
|
- **"Am nächsten an MediaMonkey"** → **MusicBee unter Wine + GoneMAD/PowerAmp auf Android** (aber kein native Linux).
|
||||||
|
|
||||||
|
- **Native Linux-Lösung, solide & gepflegt** → **Strawberry auf Linux + GoneMAD auf Android**, Sync per Syncthing/rsync.
|
||||||
|
|
||||||
|
- **Wenn Playcount/Rating-Sync über Geräte _wirklich_ zentral ist** → **[[IT-Know-How/Linux/Navidrome]] (Server) + DSub/Ultrasonic auf Android**.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
👉 Frage an dich:
|
||||||
|
Ist dir wichtiger, dass das Ganze **nativ auf Linux läuft** (also Wine vermeiden), oder dass du **möglichst nahe an der MediaMonkey-Experience bleibst**, auch wenn’s Wine erfordert?
|
||||||
|
|
||||||
|
---
|
||||||
|
Ich ziehe es vor, wenn es nativ unter Linux läuft. Es **muss** nicht auch nicht Media Monkey nachahmen, es sollte vom Funktionsumfang nur ähnlich mächtig sein. Wenn für Synchronisation extra Tools benötigt werden ist das ok. Wichtig wäre mir, dass Bearbeitungen am PC (Hinzugefügte Songs, Playlisten statisch und dynamisch, Metadaten etc) möglichst 1 zu 1 auch auf dem Handy verfügbar sind.
|
||||||
|
|
||||||
|
---
|
||||||
|
Perfekt — danke für die Präzisierung. Du willst also **native Linux**-Werkzeuge, die in Summe ungefähr so mächtig sind wie MediaMonkey, und die Änderungen am PC (neue Songs, statische + dynamische Playlists, Metadaten usw.) sollen **möglichst 1:1 auf dem Android-Handy verfügbar** sein. Ich habe zwei praxiserprobte, native-unter-Linux-Workflows für genau dieses Ziel — einer ist _server-zentriert_ (am zuverlässigsten für Bidirektionalität von Playcounts/Playlists/Metadaten), der andere ist _Datei-Sync/Offline_-orientiert (besser für rein lokale Dateien/Offline-Nutzung, aber mit Einschränkungen bei Playcount/Ratings). Ich liste jeweils Voraussetzungen, wie es funktioniert, Vor-/Nachteile und konkrete Umsetzungspunkte.
|
||||||
|
|
||||||
|
# Empfehlung A — **(Meine Top-Wahl)** Lokaler Musik-Server ([[IT-Know-How/Linux/Navidrome]]/Airsonic) + native Player (Strawberry) auf PC + Subsonic-Client auf Android (z. B. DSub / Ultrasonic)
|
||||||
|
|
||||||
|
**Warum:** [[IT-Know-How/Linux/Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie **Strawberry** zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
Wie das zusammenwirkt — Kurzablauf:
|
||||||
|
|
||||||
|
1. Auf dem Linux-PC: music-folder (z. B. `~/Music`) → Strawberry zum Abspielen & Tag-Editing. Strawberry ist native, hat Smart/Dynamic-Playlists und Tag-Editoren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
2. Auf dem Linux-PC: [[IT-Know-How/Linux/Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[IT-Know-How/Linux/Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[IT-Know-How/Linux/Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||||
|
|
||||||
|
|
||||||
|
Wesentliche Vorteile:
|
||||||
|
|
||||||
|
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128–192 kbps laden, während der PC die Originals behält. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||||
|
|
||||||
|
- Desktop bleibt native (Strawberry), Server läuft nativ unter Linux. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
|
||||||
|
Nachteile / Dinge, die du beachten solltest:
|
||||||
|
|
||||||
|
- Es ist kein „klassischer“ Einzelprogramm-Desktop-Workflow mehr, sondern ein **Server + Clients**-Setup (läuft aber lokal auf deinem Rechner, keine Cloud nötig).
|
||||||
|
|
||||||
|
- Manche Subsonic-Clients handhaben Offline-Caching unterschiedlich (Ordnerstruktur, Caching-Verhalten). Testen lohnt sich. ([GitHub](https://github.com/airsonic-advanced/airsonic-advanced/issues/873?utm_source=chatgpt.com "DSub sync/cache with Airsonic 11 dumps all files into main ..."))
|
||||||
|
|
||||||
|
|
||||||
|
**Kurz-Setup-Hinweise:**
|
||||||
|
|
||||||
|
- Installiere [[IT-Know-How/Linux/Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||||
|
|
||||||
|
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[IT-Know-How/Linux/Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
- Auf Android: DSub/Ultrasonic konfigurieren (Server-URL mit deiner lokalen IP), in der App die Download/Transcode-Qualität setzen. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Empfehlung B — **Datei-Sync (offline) Workflow**: Strawberry (Linux) + Syncthing (oder rsync) + Android-Player (GoneMAD / Poweramp)
|
||||||
|
|
||||||
|
**Warum:** Wenn du viel offline hörst und tatsächliche Dateien auf dem Handy brauchst (z. B. Hi-Res oder bestimmte Ordnerstruktur), ist Syncthing eine sehr komfortable, native Lösung zum Spiegeln von Ordnern PC ↔ Handy. Strawberry bearbeitet Tags/Playlists auf dem PC und die Dateien werden 1:1 auf's Handy kopiert. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
Wie das zusammenwirkt — Kurzablauf:
|
||||||
|
|
||||||
|
1. Strawberry verwaltet die Dateien lokal und erzeugt Playlists (M3U).
|
||||||
|
|
||||||
|
2. Syncthing synchronisiert den Music-Ordner (und Playlist-Exports) automatisch auf das Handy. Syncthing läuft nativ unter Linux und Android. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
|
||||||
|
|
||||||
|
3. Auf Android: ein mächtiger Offline-Player wie **GoneMAD** oder **Poweramp** liest die Dateien/Playlists vom synchronisierten Ordner.
|
||||||
|
|
||||||
|
|
||||||
|
Vorteile:
|
||||||
|
|
||||||
|
- Volle Offline-Verfügbarkeit (keine Server-Software nötig).
|
||||||
|
|
||||||
|
- Absolute Dateiintegrität — exakt die gleichen MP3/FLAC liegen auf beiden Geräten.
|
||||||
|
|
||||||
|
|
||||||
|
Wesentliche Einschränkungen (sehr wichtig):
|
||||||
|
|
||||||
|
- **Playcounts / Ratings**: Viele Android-Player (z. B. Poweramp) speichern Playcounts/Rating in einer **internen App-Datenbank** und schreiben diese **nicht** zuverlässig zurück in die MP3-Tags (POPM/PCNT). Dadurch geht die echte bidirektionale Synchronisation von „Last played / playcount / rating“ verloren, bzw. sie ist nur mit zusätzlichen Tools/Workarounds möglich. Poweramp z.B. unterstützt POPM nicht als schreibbaren Standard-Rating-Export. GoneMAD hat einige Optionen, kann aber nicht immer sauber bidirektional zu jedem Desktop-Tool synchronisieren. ([Poweramp](https://forum.powerampapp.com/topic/21099-will-not-recognize-ratings-tags/?utm_source=chatgpt.com "Will not recognize ratings tags - Poweramp Feature Requests"))
|
||||||
|
|
||||||
|
- Android-Medienindexer kann neue Dateien verzögert erkennen; manchmal muss man den Index anstoßen oder die App neu starten, wenn Syncthing neue Musik ablegt. ([Syncthing Community Forum](https://forum.syncthing.net/t/music-synced-onto-phone-not-picked-up-by-android/22191?utm_source=chatgpt.com "Music Synced onto Phone Not Picked Up by Android"))
|
||||||
|
|
||||||
|
|
||||||
|
Workarounds:
|
||||||
|
|
||||||
|
- Verwende ID3-Frames, die als Standard existieren — z. B. **PCNT** (Play Counter) oder **POPM** (Popularimeter) — und scripte gelegentlich ein Update/Export/Import dieser Frames zwischen Player-DB und Dateien. Die PCNT-Frame ist Teil der ID3-Spec und kann playcount direkt in die Datei schreiben — das funktioniert aber nur, wenn der Android-Player diese Frames auch schreibt/liest. ([id3.org](https://id3.org/id3v2.3.0?utm_source=chatgpt.com "id3v2.3.0"))
|
||||||
|
|
||||||
|
- Manche Nutzer verwenden periodische Exporte (z. B. M3U/CSV) und ein kleines Script, das die DB-Werte abgleicht — ist aber Aufwand und fragile Lösung. (Wenn du experimentierfreudig bist, möglich.)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Vergleich & Entscheidungshilfe — kurz
|
||||||
|
|
||||||
|
- **Wenn du wirklich möchtest, dass Playcounts / LastPlayed / Ratings verlässlich zwischen PC ↔ Handy synchron sind → wähle den Server-Ansatz ([[IT-Know-How/Linux/Navidrome]] / Airsonic)**. Das ist die sauberste, wartungsarme Lösung für bidirektionale Nutzungsdaten; zusätzlich hast du komfortable Transcoding-Optionen für mobile Daten/Storage. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
- **Wenn du maximale Offline-Kontrolle über die Dateien willst (keine Serverstruktur) → wähle Syncthing + ein mächtiges Android-Player,** akzeptiere aber Einschränkungen bei Ratings/Playcounts bzw. plane zusätzliche Scripts/Workarounds ein. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Konkrete Vorschläge zum sofortigen Ausprobieren (in dieser Reihenfolge)
|
||||||
|
|
||||||
|
1. **Testlauf Server-Option (empfohlen):**
|
||||||
|
|
||||||
|
- Installiere [[IT-Know-How/Linux/Navidrome]] (Docker oder Paket) und zeige es auf `~/Music`. ([[IT-Know-How/Linux/Navidrome]] ist leicht, kann lokal laufen.) ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
- Installiere DSub (oder Ultrasonic) auf dem Handy, verbinde mit [[IT-Know-How/Linux/Navidrome]]. Teste Streaming + Offline-Download + setzte Download-Bitrate auf z. B. 160 kbps. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||||
|
|
||||||
|
- Auf dem PC: installiere **Strawberry**, bearbeite ein paar Tags & Playlists, lasse [[IT-Know-How/Linux/Navidrome]] neu scannen — prüfe die Änderungen im Android-Client. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
2. **Falls du stattdessen Offline-Dateien bevorzugst:**
|
||||||
|
|
||||||
|
- Installiere **Syncthing** auf PC + Android, sync einen kleinen Test-Musikordner. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
|
||||||
|
|
||||||
|
- Auf Android: teste **GoneMAD** (sehr anpassbar) oder **Poweramp** als Player, probiere, ob Ratings/Playcounts in deiner Kombination zuverlässig geschrieben/gezogen werden (Hinweis: Poweramp schreibt POPM nicht). ([Google Play](https://play.google.com/store/apps/details?hl=en_US&id=gonemad.gmmp&utm_source=chatgpt.com "GoneMAD Music Player - Apps on Google Play"))
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Quellen (wichtigste Belege)
|
||||||
|
|
||||||
|
- Strawberry — native Linux Player: Smart/dynamic playlists, Tag-Editor, MusicBrainz/cover lookup. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
- [[IT-Know-How/Linux/Navidrome]] — leichter Subsonic-kompatibler Server, lokal nutzbar; Optionen für AutoImportPlaylists / Transcoding/Download-Transcode. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
- Subsonic/DSub ecosystem — Android-Clients für Subsonic/[[IT-Know-How/Linux/Navidrome]] (Streaming, Offline Caching, Bitrate/Transcode Optionen). ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||||
|
|
||||||
|
- ID3-Frames (PCNT / POPM) — Playcount-Frame `PCNT` ist Teil der ID3v2-Spec (kann in Datei gespeichert werden). ([id3.org](https://id3.org/id3v2.3.0?utm_source=chatgpt.com "id3v2.3.0"))
|
||||||
|
|
||||||
|
- Poweramp & Rating/Tagging Limit: Poweramp schreibt/liest POPM/PCNT nicht standardmäßig; Ratings werden intern gespeichert — wichtige Einschränkung für Datei-Sync Workflows. ([Poweramp](https://forum.powerampapp.com/topic/21099-will-not-recognize-ratings-tags/?utm_source=chatgpt.com "Will not recognize ratings tags - Poweramp Feature Requests"))
|
||||||
|
|
||||||
|
- Syncthing für Datei-Sync Android ↔ PC — verbreitete Praxis, aber Android-Indexing / Rechte / folder ownership sind zu beachten. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Wenn du willst, mache ich sofort eines von beiden für dich praktisch:
|
||||||
|
|
||||||
|
- **Variante A:** Ich erstelle dir eine Schritt-für-Schritt-Anleitung (konkret für Debian/Ubuntu/Fedora) zum Installieren/Einrichten von [[IT-Know-How/Linux/Navidrome]] + Strawberry + DSub (inkl. Beispiel-Config für Transcoding/AutoImport).
|
||||||
|
|
||||||
|
- **Variante B:** Oder ich schreibe ein kurzes Syncthing-Setup-Tutorial + Hinweise, wie du Ratings/Playcounts am besten per ID3/Script synchronisierst (inkl. Beispielscript, das `PCNT`/`POPM` per `mutagen` oder `eyeD3` setzt).
|
||||||
|
|
||||||
|
|
||||||
|
Sag mir einfach welches Setup du zuerst ausprobieren willst — ich liefere die konkrete, sofort ausführbare Anleitung (inkl. Konfig-Snippets).
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Warum:** [[IT-Know-How/Linux/Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server, -> [[IT-Know-How/Linux/Subsonic-API]]) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie [[Strawberry 1]] zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
Wie das zusammenwirkt — Kurzablauf:
|
||||||
|
|
||||||
|
1. Auf dem Linux-PC: music-folder (z. B. `~/Music`) → Strawberry zum Abspielen & Tag-Editing. Strawberry ist native, hat Smart/Dynamic-Playlists und Tag-Editoren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
2. Auf dem Linux-PC: [[IT-Know-How/Linux/Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[IT-Know-How/Linux/Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[IT-Know-How/Linux/Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||||
|
|
||||||
|
|
||||||
|
Wesentliche Vorteile:
|
||||||
|
|
||||||
|
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||||
|
|
||||||
|
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128–192 kbps laden, während der PC die Originals behält. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||||
|
|
||||||
|
- Desktop bleibt native (Strawberry), Server läuft nativ unter Linux. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
|
||||||
|
Nachteile / Dinge, die du beachten solltest:
|
||||||
|
|
||||||
|
- Es ist kein „klassischer“ Einzelprogramm-Desktop-Workflow mehr, sondern ein **Server + Clients**-Setup (läuft aber lokal auf deinem Rechner, keine Cloud nötig).
|
||||||
|
|
||||||
|
- Manche Subsonic-Clients handhaben Offline-Caching unterschiedlich (Ordnerstruktur, Caching-Verhalten). Testen lohnt sich. ([GitHub](https://github.com/airsonic-advanced/airsonic-advanced/issues/873?utm_source=chatgpt.com "DSub sync/cache with Airsonic 11 dumps all files into main ..."))
|
||||||
|
|
||||||
|
|
||||||
|
**Kurz-Setup-Hinweise:**
|
||||||
|
|
||||||
|
- Installiere [[IT-Know-How/Linux/Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||||
|
|
||||||
|
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[IT-Know-How/Linux/Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||||
|
|
||||||
|
- Auf Android: DSub/Ultrasonic konfigurieren (Server-URL mit deiner lokalen IP), in der App die Download/Transcode-Qualität setzen. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. **Playcounts / Metadaten in Strawberry vs. Navidrome**
|
||||||
|
|
||||||
|
- **Wenn du Strawberry „lokal“ (eigene Library, also direkt auf den Musikdateien im Dateisystem) benutzt:**
|
||||||
|
|
||||||
|
- Playcounts und Ratings werden **nur in Strawberries interner Datenbank** gepflegt, nicht in Navidrome.
|
||||||
|
|
||||||
|
- Metadatenänderungen (Tags, Cover etc.), die du in den Dateien speicherst, **sieht Navidrome** beim nächsten Scan (manuell oder automatisch). → Cover/Tags sind also synchron, **aber Playcounts und Ratings nicht**.
|
||||||
|
|
||||||
|
- **Wenn du Strawberry „über Streaming“ mit Navidrome verbindest:**
|
||||||
|
|
||||||
|
- Playcounts und Ratings werden im **Navidrome-Server** gespeichert, d.h. Handy + PC greifen auf denselben Zähler/Rating zurück.
|
||||||
|
|
||||||
|
- Änderungen in der Datei selbst sind dann nachrangig (es sei denn, du editierst die Tags explizit im Dateisystem).
|
||||||
|
|
||||||
|
|
||||||
|
👉 Empfehlung:
|
||||||
|
|
||||||
|
- Für **Playcounts und Bewertungen**, immer über das Navidrome-Streaming-Backend hören.
|
||||||
|
|
||||||
|
- Für **Tag-Bearbeitung** (Album Artist, Genre, Cover etc.) kannst du ruhig Strawberry lokal verwenden → nach dem Speichern erkennt Navidrome die geänderten Tags.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. **Navidrome auf Synology NAS installieren – sinnvoll?**
|
||||||
|
|
||||||
|
- **Ja, absolut sinnvoll.** Vorteile:
|
||||||
|
|
||||||
|
- Deine Musik liegt vermutlich sowieso schon auf der NAS.
|
||||||
|
|
||||||
|
- Navidrome kann 24/7 laufen, unabhängig vom PC.
|
||||||
|
|
||||||
|
- Dein Handy kann direkt auf die NAS zugreifen (auch unterwegs, wenn du Portfreigabe oder VPN einrichtest).
|
||||||
|
|
||||||
|
- Installationsmöglichkeiten:
|
||||||
|
|
||||||
|
- **Docker-Container** (empfohlen, wenn du Docker auf der Synology nutzt). Das offizielle Image ist `deluan/navidrome`.
|
||||||
|
|
||||||
|
- Oder als native Binary in einer Synology-Chroot/Entwicklungsumgebung (Docker ist aber deutlich einfacher).
|
||||||
|
|
||||||
|
|
||||||
|
👉 Empfehlung: Wenn die NAS immer läuft → installiere Navidrome dort. Dann kannst du Strawberry am PC so konfigurieren, dass er sich nur noch als Client auf den NAS-Server verbindet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. **Navidrome beim Systemstart automatisch starten lassen**
|
||||||
|
|
||||||
|
Hängt davon ab, wie du es installiert hast:
|
||||||
|
|
||||||
|
- **Systemd-Service (klassisch, wenn du es auf deinem Linux-PC laufen lässt):**
|
||||||
|
|
||||||
|
1. Service-Datei erstellen:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# /etc/systemd/system/navidrome.service
|
||||||
|
[Unit]
|
||||||
|
Description=Navidrome Music Server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=deinuser
|
||||||
|
Group=deinuser
|
||||||
|
ExecStart=/usr/local/bin/navidrome --configfile /etc/navidrome.toml
|
||||||
|
Restart=on-failure
|
||||||
|
WorkingDirectory=/home/deinuser
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Aktivieren & starten:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable navidrome
|
||||||
|
sudo systemctl start navidrome
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Docker + Systemd:**
|
||||||
|
Wenn du Navidrome via Docker laufen lässt, kannst du entweder `docker run --restart=always ...` nutzen oder einen systemd-Service schreiben, der den Container startet.
|
||||||
|
|
||||||
|
- **Synology NAS (Docker):**
|
||||||
|
Die Synology Docker-Oberfläche bietet eine Einstellung **„Automatisch starten“** beim Container an. Einfach anhaken, dann startet Navidrome mit der NAS.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ **Kurz zusammengefasst:**
|
||||||
|
|
||||||
|
- **Playcounts/Ratings:** Nur über Navidrome-Streaming → sonst bleiben sie lokal in Strawberry.
|
||||||
|
|
||||||
|
- **Metadaten (Tags, Cover):** Bearbeitung in Strawberry → Navidrome liest sie beim nächsten Scan ein.
|
||||||
|
|
||||||
|
- **NAS:** Ideal für Dauerbetrieb, am besten per Docker.
|
||||||
|
|
||||||
|
- **Autostart:** systemd-Service (Linux) oder Autostart in Synology Docker aktivieren.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
👉 Soll ich dir eine konkrete Schritt-für-Schritt-Anleitung für **Navidrome auf Synology NAS (per Docker)** schreiben, inkl. `docker run`-Beispiel und Volume-Mounts (z. B. für `music/` und `data/`)? Dann kannst du deine PC-Instanz ablösen und alles zentralisieren.
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<https://www.navidrome.org/>
|
||||||
|
|
||||||
|
Hier eine ausführliche Vorstellung von **Navidrome**:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔎 Was ist Navidrome?
|
||||||
|
|
||||||
|
Navidrome ist ein **selbstgehosteter Musikserver** für \[\[Linux\]\] (und andere Plattformen). Er funktioniert ähnlich wie Spotify oder Apple Music – nur mit deiner eigenen Musikbibliothek. Du lädst deine Audiodateien (MP3, FLAC, OGG, AAC etc.) auf deinen Server, und Navidrome macht sie über ein Web-Interface oder kompatible Apps (\[\[Subsonic-API\]\]) überall verfügbar.
|
||||||
|
|
||||||
|
Kurz:
|
||||||
|
👉 Deine Musik, dein Server, jederzeit und überall streambar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎶 Was kann Navidrome?
|
||||||
|
|
||||||
|
- **Streaming im Browser** mit einem modernen, responsiven Webplayer.
|
||||||
|
- **Unterstützt viele Clients** über die Subsonic-API (z. B. \[\[DSub\]\], \[\[Ultrasonic\]\], \[\[Substreamer\]\], Symfonium, etc.).
|
||||||
|
- **Automatische Bibliotheksindizierung**: Scannt Ordner, liest Metadaten und baut deine Mediathek.
|
||||||
|
- **Benutzerverwaltung**: Mehrere Accounts mit eigenen Playlists, Favoriten und Rechten.
|
||||||
|
- **Playlists & Favoriten** (inkl. Smart-Playlists).
|
||||||
|
- **Transcoding on the fly**: Wandelt Dateien in kleinere Formate um, falls deine Verbindung langsam ist.
|
||||||
|
- **Leichtgewichtig & ressourcenschonend** (geschrieben in Go).
|
||||||
|
- **Cross-Plattform**: \[\[Linux\]\], Windows, macOS, ARM (z. B. Raspberry Pi).
|
||||||
|
- **Docker-Images verfügbar** für einfache Installation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Vorteile gegenüber anderen Lösungen
|
||||||
|
|
||||||
|
- **Leichtgewichtiger als Plex oder Jellyfin**, weil es sich auf Musik konzentriert.
|
||||||
|
- **Moderner und aktiver entwickelt als Airsonic, Subsonic & Co.**
|
||||||
|
- **Einfach zu installieren und zu warten** (ein Binary oder Docker-Container reicht).
|
||||||
|
- **Sehr niedrige Hardware-Anforderungen** – läuft problemlos auf kleinen VPS oder einem Raspberry Pi.
|
||||||
|
- **Sehr gute Client-Kompatibilität** durch \[\[Subsonic-API\]\].
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Installation unter Linux
|
||||||
|
|
||||||
|
### Variante 1: Per Binary (klassisch)
|
||||||
|
|
||||||
|
1. Lade die aktuelle Version herunter:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget https://github.com/navidrome/navidrome/releases/latest/download/navidrome_linux_amd64.tar.gz
|
||||||
|
tar xzf navidrome_linux_amd64.tar.gz
|
||||||
|
sudo mv navidrome /usr/local/bin/
|
||||||
|
```
|
||||||
|
2. Erstelle einen Benutzer für Navidrome:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo useradd -r -s /bin/false navidrome
|
||||||
|
```
|
||||||
|
3. Erstelle ein Konfigurationsverzeichnis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir /var/lib/navidrome
|
||||||
|
sudo chown navidrome:navidrome /var/lib/navidrome
|
||||||
|
```
|
||||||
|
4. Systemd-Service einrichten (optional).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Variante 2: \[\[Docker\]\] (empfohlen)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name=navidrome \
|
||||||
|
-p 4533:4533 \
|
||||||
|
-v /pfad/zu/deiner/musik:/music \
|
||||||
|
-v /pfad/zu/navidrome/data:/data \
|
||||||
|
deluan/navidrome:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Ersteinrichtung
|
||||||
|
|
||||||
|
- Navidrome läuft nun auf: <http://localhost:4533>
|
||||||
|
- Beim ersten Start wirst du aufgefordert, ein **Admin-Konto** anzulegen.
|
||||||
|
- Danach: Musikordner wird automatisch eingelesen (Metadaten, Cover, etc.).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 Dinge, die man beachten sollte
|
||||||
|
|
||||||
|
- **Firewall/Portfreigabe**: Wenn du von außen zugreifen willst, Port 4533 öffnen oder einen Reverse Proxy (nginx/traefik mit HTTPS) davor schalten.
|
||||||
|
- **Sicherung**: Datenbank & Konfigurationsordner `/data` regelmäßig sichern.
|
||||||
|
- **Rechte**: Musikordner muss für den Navidrome-Benutzer lesbar sein.
|
||||||
|
- **Transcoding**: Falls du FLAC → MP3 brauchst, sollte `ffmpeg` installiert sein.
|
||||||
|
- **Clients**: Nutze eine kompatible App für Smartphone-Streaming (z. B. Symfonium [Android], iSub [iOS]).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
\[\[Navidrome mit Strawberry 1\]\]
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
Strawberry ist ein **Musikplayer und -manager** für [[Linux]] (auch für Windows und macOS verfügbar), der sich auf **lokale Musiksammlungen** konzentriert. Er ist ein Fork von _Clementine_, das wiederum auf _Amarok_ basiert. Strawberry richtet sich vor allem an Nutzer, die eine **große Sammlung an Musikdateien (MP3, FLAC, OGG, etc.) lokal verwalten** möchten – im Gegensatz zu Playern, die stark auf Streaming setzen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Zweck von Strawberry
|
||||||
|
|
||||||
|
- **Abspielen von Musikdateien** in allen gängigen Formaten.
|
||||||
|
|
||||||
|
- **Bibliotheksverwaltung**: Organisieren großer Sammlungen anhand von Metadaten, Tags und Ordnerstrukturen.
|
||||||
|
|
||||||
|
- **Metadatenverwaltung**: Bearbeiten von Tags, Laden von Cover-Artworks, Abgleich mit Online-Datenbanken (z. B. MusicBrainz).
|
||||||
|
|
||||||
|
- **Wiedergabelisten**: Erstellen und Verwalten komplexer Playlists.
|
||||||
|
|
||||||
|
- **Audiowiedergabe in hoher Qualität** mit Unterstützung von Hi-Res-Formaten.
|
||||||
|
|
||||||
|
- **Externe Dienste**: Scrobbling zu Last.fm, Libre.fm oder ListenBrainz.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Funktionen
|
||||||
|
|
||||||
|
- Unterstützung für FLAC, MP3, OGG, WAV, WMA, AAC u. v. m.
|
||||||
|
|
||||||
|
- Wiedergabe mit **GStreamer** (gute Audioqualität, viele Codecs).
|
||||||
|
|
||||||
|
- **Tag-Editor** für ID3, Vorbis- und FLAC-Tags.
|
||||||
|
|
||||||
|
- Automatisches Laden von **Album-Covern**.
|
||||||
|
|
||||||
|
- **EQ und ReplayGain**-Unterstützung.
|
||||||
|
|
||||||
|
- **Wiedergabelisten** im M3U-, XSPF- und PLS-Format.
|
||||||
|
|
||||||
|
- **Gerätesynchronisation**: Musik auf mobile Player kopieren.
|
||||||
|
|
||||||
|
- **Streaming-Radio** (einfache Integration, aber nicht Hauptfokus).
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Vorteile
|
||||||
|
|
||||||
|
- **Fokus auf lokale Musik** – ideal für Sammler, die ihre eigene Bibliothek pflegen.
|
||||||
|
|
||||||
|
- **Schnell und ressourcenschonend** im Vergleich zu schwergewichtigeren Lösungen wie Amarok.
|
||||||
|
|
||||||
|
- **Moderne Code-Basis**: aktiver Fork von Clementine mit Bugfixes und Verbesserungen.
|
||||||
|
|
||||||
|
- **Hohe Audioqualität** mit vielen Formaten und Hi-Res-Support.
|
||||||
|
|
||||||
|
- **Cross-Platform**: Linux, Windows, macOS.
|
||||||
|
|
||||||
|
- **Keine Zwangs-Cloud-Anbindung** wie bei Spotify & Co.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❌ Nachteile
|
||||||
|
|
||||||
|
- **Kein nativer Streaming-Fokus** (nur begrenzte Unterstützung für Online-Dienste, keine direkte Spotify-/Apple-Music-Integration).
|
||||||
|
|
||||||
|
- **Eher klassische Oberfläche** – wirkt funktional, aber nicht besonders modern/minimalistisch.
|
||||||
|
|
||||||
|
- **Weniger Community als bei großen Projekten** (z. B. Rhythmbox oder VLC).
|
||||||
|
|
||||||
|
- **Kein eigener mobiler Client** – Synchronisation nur über Dateiübertragung.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💻 Installation
|
||||||
|
|
||||||
|
### Unter Ubuntu/Debian
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install strawberry
|
||||||
|
```
|
||||||
|
|
||||||
|
Falls nicht im Standard-Repo (bei älteren Versionen):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo add-apt-repository ppa:jonaski/strawberry
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install strawberry
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unter Fedora
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install strawberry
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unter Arch Linux / Manjaro
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo pacman -S strawberry
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternative: Flatpak (universell)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak install flathub org.strawberrymusicplayer.strawberry
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Einrichtung
|
||||||
|
|
||||||
|
1. **Musikordner hinzufügen**: Beim ersten Start fragt Strawberry nach Verzeichnissen, in denen Musik liegt.
|
||||||
|
|
||||||
|
2. **Bibliothek scannen**: Die Dateien werden eingelesen und nach Tags sortiert.
|
||||||
|
|
||||||
|
3. **Audioausgabe konfigurieren**: In den Einstellungen (z. B. ALSA, PulseAudio, PipeWire auswählen).
|
||||||
|
|
||||||
|
4. **Metadaten-Services aktivieren**: Verknüpfung mit MusicBrainz, Last.fm oder Libre.fm, wenn gewünscht.
|
||||||
|
|
||||||
|
5. **Wiedergabelisten und Cover laden**: Automatisches Suchen und Speichern aktivieren.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 Was man beachten sollte
|
||||||
|
|
||||||
|
- Strawberry ist für **Sammler und Audiophile** gedacht – wenn man hauptsächlich Spotify oder YouTube nutzt, ist es weniger passend.
|
||||||
|
|
||||||
|
- Gute Organisation der Musikordner und Tags erleichtert die Verwaltung erheblich.
|
||||||
|
|
||||||
|
- Bei **Hi-Res-Audio**: Prüfen, ob das Audiosystem (ALSA/PipeWire) korrekt konfiguriert ist.
|
||||||
|
|
||||||
|
- Für große Bibliotheken (>100.000 Tracks) sollte man auf genügend RAM und eine SSD achten, sonst wird die Suche langsam.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
👉 Soll ich dir eine Schritt-für-Schritt-Anleitung schreiben, wie du Strawberry nach der Installation optimal für eine große Musiksammlung einrichtest (inkl. Cover, Tags, Audio-Einstellungen)?
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
Perfekt – dann ist eine Subsonic-kompatible Library genau das, was du suchst 👍
|
||||||
|
|
||||||
|
Für [[Python]] gibt es z. B. [`py-sonic`](https://github.com/crustymonkey/py-sonic).
|
||||||
|
Die ist zwar nicht mehr super aktiv gepflegt, funktioniert aber mit [[IT-Know-How/Linux/Navidrome]] problemlos, weil Navidrome die [[IT-Know-How/Linux/Subsonic-API]] spricht.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install py-sonic
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Grund-Setup
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pysonic.connection import Connection
|
||||||
|
|
||||||
|
# Verbindung aufbauen
|
||||||
|
conn = Connection(
|
||||||
|
host="http://localhost:4533",
|
||||||
|
username="meinuser",
|
||||||
|
password="meinpass",
|
||||||
|
api_version="1.16.1",
|
||||||
|
client_name="pyclient"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Anwendungsfälle
|
||||||
|
|
||||||
|
### 1. Playlist erstellen oder öffnen
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Neue Playlist
|
||||||
|
playlist = conn.create_playlist("Importierte M3U Playlist")
|
||||||
|
|
||||||
|
# Alle Playlists abfragen
|
||||||
|
all_playlists = conn.get_playlists()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Tracks suchen (z. B. per Filename, Titel, Artist)
|
||||||
|
|
||||||
|
```python
|
||||||
|
search = conn.search2(query="Songtitel", songCount=5)
|
||||||
|
for song in search['song']:
|
||||||
|
print(song['id'], song['title'], song['artist'])
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Track zur Playlist hinzufügen
|
||||||
|
|
||||||
|
```python
|
||||||
|
conn.update_playlist(
|
||||||
|
playlist_id=playlist['id'],
|
||||||
|
song_id=["12345", "67890"] # mehrere IDs möglich
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Stern vergeben
|
||||||
|
|
||||||
|
```python
|
||||||
|
conn.star("12345") # Song-ID
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Bookmark setzen
|
||||||
|
|
||||||
|
```python
|
||||||
|
conn.create_bookmark("12345", position=60000, comment="Kapitel 1")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow: M3U importieren
|
||||||
|
|
||||||
|
Du kannst einfach durch deine `.m3u`-Datei iterieren, für jede Zeile versuchen, den Track im Navidrome zu finden, und dann Aktionen ausführen:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def import_m3u_to_navidrome(m3u_path, playlist_name):
|
||||||
|
# Playlist anlegen
|
||||||
|
playlist = conn.create_playlist(playlist_name)
|
||||||
|
playlist_id = playlist['id']
|
||||||
|
|
||||||
|
with open(m3u_path, encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith("#") or not line.strip():
|
||||||
|
continue
|
||||||
|
filename = line.strip().split("/")[-1] # nur Dateiname
|
||||||
|
|
||||||
|
# Suche im Server
|
||||||
|
search = conn.search2(query=filename, songCount=1)
|
||||||
|
if 'song' in search and search['song']:
|
||||||
|
song = search['song'][0]
|
||||||
|
song_id = song['id']
|
||||||
|
|
||||||
|
# Playlist hinzufügen
|
||||||
|
conn.update_playlist(playlist_id=playlist_id, song_id=[song_id])
|
||||||
|
|
||||||
|
# Stern setzen
|
||||||
|
conn.star(song_id)
|
||||||
|
|
||||||
|
# Bookmark bei 0 (Startpunkt)
|
||||||
|
conn.create_bookmark(song_id, position=0, comment="Importiert aus M3U")
|
||||||
|
|
||||||
|
print(f"→ {filename} gefunden und verarbeitet.")
|
||||||
|
else:
|
||||||
|
print(f"⚠ {filename} nicht gefunden.")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
👉 Damit hättest du ziemlich genau deinen beschriebenen Workflow:
|
||||||
|
M3U → Tracks auflösen → Playlist + Sterne + Bookmarks automatisch setzen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Soll ich dir ein **vollständiges Script** bauen, das direkt eine `.m3u` einliest, die passende Playlist erstellt und alle drei Aktionen (Playlist-Eintrag, Stern, Bookmark) in einem Durchlauf macht?
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
# Timeshift Kommandozeilen-Nutzung
|
||||||
|
|
||||||
|
## Überblick
|
||||||
|
Timeshift ist ein Backup-Tool für Linux-Systeme, das System-Snapshots erstellt. Es kann sowohl über eine grafische Oberfläche als auch über die Kommandozeile verwendet werden.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
```bash
|
||||||
|
# Ubuntu/Debian
|
||||||
|
sudo apt update && sudo apt install timeshift
|
||||||
|
|
||||||
|
# Arch Linux
|
||||||
|
sudo pacman -S timeshift
|
||||||
|
|
||||||
|
# Fedora/CentOS
|
||||||
|
sudo dnf install timeshift
|
||||||
|
```
|
||||||
|
|
||||||
|
## Grundlegende Konfiguration
|
||||||
|
|
||||||
|
### Initialisierung
|
||||||
|
```bash
|
||||||
|
# Timeshift einrichten (wählt automatisch RSYNC oder BTRFS)
|
||||||
|
sudo timeshift --check
|
||||||
|
|
||||||
|
# Konfiguration anzeigen
|
||||||
|
sudo timeshift --list-config
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup-Typ festlegen
|
||||||
|
```bash
|
||||||
|
# RSYNC-Modus (Standard für ext4)
|
||||||
|
sudo timeshift --rsync
|
||||||
|
|
||||||
|
# BTRFS-Modus (für BTRFS-Dateisysteme)
|
||||||
|
sudo timeshift --btrfs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Snapshots erstellen
|
||||||
|
|
||||||
|
### Manuellen Snapshot erstellen
|
||||||
|
```bash
|
||||||
|
# Einfacher Snapshot
|
||||||
|
sudo timeshift --create
|
||||||
|
|
||||||
|
# Snapshot mit Kommentar
|
||||||
|
sudo timeshift --create --comments "Vor System-Update"
|
||||||
|
|
||||||
|
# Snapshot mit spezifischem Namen
|
||||||
|
sudo timeshift --create --comments "Pre-Kernel-Update-$(date +%Y%m%d)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automatische Snapshots konfigurieren
|
||||||
|
```bash
|
||||||
|
# Tägliche Snapshots aktivieren
|
||||||
|
sudo timeshift --snapshot-device /dev/sda1 --schedule-daily
|
||||||
|
|
||||||
|
# Wöchentliche Snapshots
|
||||||
|
sudo timeshift --schedule-weekly
|
||||||
|
|
||||||
|
# Monatliche Snapshots
|
||||||
|
sudo timeshift --schedule-monthly
|
||||||
|
```
|
||||||
|
|
||||||
|
## Snapshots verwalten
|
||||||
|
|
||||||
|
### Snapshots auflisten
|
||||||
|
```bash
|
||||||
|
# Alle verfügbaren Snapshots anzeigen
|
||||||
|
sudo timeshift --list
|
||||||
|
|
||||||
|
# Detaillierte Liste
|
||||||
|
sudo timeshift --list --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
### Snapshot-Informationen anzeigen
|
||||||
|
```bash
|
||||||
|
# Informationen zu einem spezifischen Snapshot
|
||||||
|
sudo timeshift --list | grep "2024-01-15"
|
||||||
|
```
|
||||||
|
|
||||||
|
## System wiederherstellen
|
||||||
|
|
||||||
|
### Komplette Systemwiederherstellung
|
||||||
|
```bash
|
||||||
|
# Neuesten Snapshot wiederherstellen
|
||||||
|
sudo timeshift --restore
|
||||||
|
|
||||||
|
# Spezifischen Snapshot wiederherstellen
|
||||||
|
sudo timeshift --restore --snapshot "2024-01-15_18-30-45"
|
||||||
|
|
||||||
|
# Wiederherstellung mit Bestätigung
|
||||||
|
sudo timeshift --restore --snapshot "2024-01-15_18-30-45" --skip-grub
|
||||||
|
```
|
||||||
|
|
||||||
|
### Einzelne Dateien wiederherstellen
|
||||||
|
```bash
|
||||||
|
# Snapshot mounten (nur-lesen)
|
||||||
|
sudo timeshift --restore --snapshot "2024-01-15_18-30-45" --clone
|
||||||
|
|
||||||
|
# Dann Dateien manuell kopieren
|
||||||
|
cp /timeshift/snapshots/2024-01-15_18-30-45/localhost/path/to/file /original/path/
|
||||||
|
```
|
||||||
|
|
||||||
|
## TTY-Sitzung (Notfall-Wiederherstellung)
|
||||||
|
|
||||||
|
### Zugang zur TTY
|
||||||
|
```bash
|
||||||
|
# Wechsel zu TTY (Strg+Alt+F1 bis F6)
|
||||||
|
# Oder über SSH wenn verfügbar
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wiederherstellung in TTY
|
||||||
|
```bash
|
||||||
|
# 1. Als root anmelden
|
||||||
|
sudo su -
|
||||||
|
|
||||||
|
# 2. Snapshots auflisten
|
||||||
|
timeshift --list
|
||||||
|
|
||||||
|
# 3. System wiederherstellen
|
||||||
|
timeshift --restore --snapshot "SNAPSHOT_NAME"
|
||||||
|
|
||||||
|
# 4. System neustarten
|
||||||
|
reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notfall-Boot von Live-USB
|
||||||
|
```bash
|
||||||
|
# 1. Live-USB booten
|
||||||
|
# 2. Festplatte mounten
|
||||||
|
sudo mount /dev/sda1 /mnt
|
||||||
|
|
||||||
|
# 3. Timeshift auf Live-System installieren
|
||||||
|
sudo apt update && sudo apt install timeshift
|
||||||
|
|
||||||
|
# 4. Wiederherstellung auf gemountete Partition
|
||||||
|
sudo timeshift --restore --target-device /dev/sda1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nützliche Optionen
|
||||||
|
|
||||||
|
### Backup-Ausschlüsse konfigurieren
|
||||||
|
```bash
|
||||||
|
# Bestimmte Verzeichnisse ausschließen
|
||||||
|
sudo timeshift --exclude /home/user/Downloads
|
||||||
|
sudo timeshift --exclude /tmp
|
||||||
|
sudo timeshift --exclude /var/cache
|
||||||
|
```
|
||||||
|
|
||||||
|
### Aufbewahrungsrichtlinien
|
||||||
|
```bash
|
||||||
|
# Maximale Anzahl Snapshots begrenzen
|
||||||
|
sudo timeshift --max-snapshots 5
|
||||||
|
|
||||||
|
# Alte Snapshots automatisch löschen
|
||||||
|
sudo timeshift --delete-old
|
||||||
|
```
|
||||||
|
|
||||||
|
### Snapshot löschen
|
||||||
|
```bash
|
||||||
|
# Spezifischen Snapshot löschen
|
||||||
|
sudo timeshift --delete --snapshot "2024-01-15_18-30-45"
|
||||||
|
|
||||||
|
# Alle bis auf die letzten 3 löschen
|
||||||
|
sudo timeshift --delete-old --max-snapshots 3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatisierung mit Cron
|
||||||
|
|
||||||
|
### Tägliche Backups einrichten
|
||||||
|
```bash
|
||||||
|
# Crontab bearbeiten
|
||||||
|
sudo crontab -e
|
||||||
|
|
||||||
|
# Tägliches Backup um 2:00 Uhr
|
||||||
|
0 2 * * * /usr/bin/timeshift --create --comments "Daily-Auto-$(date +\%Y\%m\%d)" && /usr/bin/timeshift --delete-old --max-snapshots 7
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring und Logs
|
||||||
|
|
||||||
|
### Status überprüfen
|
||||||
|
```bash
|
||||||
|
# Timeshift-Status
|
||||||
|
sudo timeshift --check
|
||||||
|
|
||||||
|
# Logs anzeigen
|
||||||
|
sudo journalctl -u timeshift
|
||||||
|
tail -f /var/log/timeshift.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Speicherplatz überwachen
|
||||||
|
```bash
|
||||||
|
# Snapshot-Größen anzeigen
|
||||||
|
du -sh /timeshift/snapshots/*
|
||||||
|
|
||||||
|
# Verfügbaren Speicher prüfen
|
||||||
|
df -h /timeshift
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Häufige Probleme
|
||||||
|
```bash
|
||||||
|
# Berechtigungen reparieren
|
||||||
|
sudo timeshift --check
|
||||||
|
|
||||||
|
# Cache leeren
|
||||||
|
sudo rm -rf /tmp/timeshift*
|
||||||
|
|
||||||
|
# Snapshot-Index reparieren
|
||||||
|
sudo timeshift --delete-old --scripted
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recovery bei korrupten Snapshots
|
||||||
|
```bash
|
||||||
|
# Snapshot-Konsistenz prüfen
|
||||||
|
sudo timeshift --list --check-snapshots
|
||||||
|
|
||||||
|
# Defekte Snapshots entfernen
|
||||||
|
sudo timeshift --delete --snapshot "CORRUPT_SNAPSHOT"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Wichtige Hinweise:**
|
||||||
|
- Immer mit `sudo` ausführen
|
||||||
|
- Vor wichtigen Systemänderungen Snapshots erstellen
|
||||||
|
- Regelmäßig alte Snapshots löschen (Speicherplatz)
|
||||||
|
- Bei BTRFS-Systemen BTRFS-Modus verwenden
|
||||||
|
- Boot-Snapshots für kritische Updates erstellen
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
Kurz gesagt: **Nein – GNU Stow führt keine Skripte aus.**
|
||||||
|
Und das ist auch Absicht 🙂
|
||||||
|
|
||||||
|
GNU Stow macht **nur eine Sache**:
|
||||||
|
|
||||||
|
> Es erzeugt und entfernt Symlinks.
|
||||||
|
|
||||||
|
Keine Hooks.
|
||||||
|
Keine Post-Deploy-Skripte.
|
||||||
|
Keine Automatik.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🧠 Warum ist das so?
|
||||||
|
|
||||||
|
Stow ist bewusst:
|
||||||
|
|
||||||
|
* minimalistisch
|
||||||
|
* deterministisch
|
||||||
|
* side-effect-frei
|
||||||
|
|
||||||
|
Dadurch bleibt dein Setup transparent und reproduzierbar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ✅ Aber: Man kann es kombinieren
|
||||||
|
|
||||||
|
Wenn du beim „Deploy“ zusätzlich Dinge tun willst (z. B. Monitor-Symlink setzen, Pakete installieren, Cache leeren, etc.), gibt es saubere Lösungen:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 Lösung 1: Bootstrap-Script (empfohlen)
|
||||||
|
|
||||||
|
Du schreibst dir ein Script wie:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd ~/dotfiles
|
||||||
|
|
||||||
|
echo "→ Stowing configs"
|
||||||
|
stow hypr
|
||||||
|
stow waybar
|
||||||
|
stow zsh
|
||||||
|
|
||||||
|
echo "→ Setting monitor config"
|
||||||
|
ln -sf desktop.conf hypr/.config/hypr/monitors/current.conf
|
||||||
|
|
||||||
|
echo "→ Reloading Hyprland"
|
||||||
|
hyprctl reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann einfach:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
💡 Das ist die professionellste Lösung.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 Lösung 2: Hostname-basierte Logik im Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
HOST=$(hostname)
|
||||||
|
|
||||||
|
if [[ "$HOST" == "desktop" ]]; then
|
||||||
|
ln -sf desktop.conf hypr/.config/hypr/monitors/current.conf
|
||||||
|
elif [[ "$HOST" == "laptop" ]]; then
|
||||||
|
ln -sf laptop.conf hypr/.config/hypr/monitors/current.conf
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann musst du nichts manuell wählen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 Lösung 3: Makefile (sehr elegant)
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```make
|
||||||
|
install:
|
||||||
|
stow hypr
|
||||||
|
stow waybar
|
||||||
|
./scripts/select-monitor.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Sehr beliebt in Dotfile-Repos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 Lösung 4: „echte“ Dotfile-Manager
|
||||||
|
|
||||||
|
Wenn du wirklich Logik + Templates willst:
|
||||||
|
|
||||||
|
* chezmoi
|
||||||
|
* yadm
|
||||||
|
|
||||||
|
Diese können:
|
||||||
|
|
||||||
|
* Hostname erkennen
|
||||||
|
* Variablen verwenden
|
||||||
|
* Templates generieren
|
||||||
|
* Skripte ausführen
|
||||||
|
|
||||||
|
Aber sie sind komplexer als Stow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🎯 Empfehlung für dich (Hyprland + mehrere Systeme)
|
||||||
|
|
||||||
|
Da du:
|
||||||
|
|
||||||
|
* Monitor-Configs pro System brauchst
|
||||||
|
* wahrscheinlich Arch nutzt
|
||||||
|
* modular arbeiten willst
|
||||||
|
|
||||||
|
👉 **Stow + Bootstrap-Script** ist die perfekte Balance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 💬 Kurzantwort auf deine Frage
|
||||||
|
|
||||||
|
| Frage | Antwort |
|
||||||
|
| ------------------------ | ----------------- |
|
||||||
|
| Führt Stow Skripte aus? | ❌ Nein |
|
||||||
|
| Kann man es kombinieren? | ✅ Ja |
|
||||||
|
| Beste Praxis? | Stow + install.sh |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[[Linux Musikprogramme]]
|
||||||
|
[[Softlinks 1]]
|
||||||
|
[[Synchronisation & Backup 1]]
|
||||||
|
|
||||||
|
# Konsolen Know-How
|
||||||
|
[[Linux Konsole Zeichen löschen]]
|
||||||
|
[[Paketinstallation aus tar.gz]]
|
||||||
|
[[Disable KVM for VirtualBox]]
|
||||||
|
[[Linux Terminal Shortcut]]
|
||||||
|
[[Drives & Mounts 1]]
|
||||||
|
[[Computerkram/find]]
|
||||||
|
[[Link-Verknüpfung in Linux]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
Nutze ==`udisksctl`==
|
||||||
|
### Installation
|
||||||
|
Arch Linux
|
||||||
|
```bash
|
||||||
|
sudo pacman -S udisks2
|
||||||
|
```
|
||||||
|
### Geräte anzeigen
|
||||||
|
```bash
|
||||||
|
lsblsk
|
||||||
|
```
|
||||||
|
Wenn man möchte mit Option `-f`
|
||||||
|
USB Stick müsste dann z.B. `sda1` oder `sdb1` sein.
|
||||||
|
### Mount
|
||||||
|
```bash
|
||||||
|
udisksctl mount -b /dev/sdb1
|
||||||
|
```
|
||||||
|
Ausgabe zeigt an, wo gemountet wurde
|
||||||
|
### Unmount
|
||||||
|
```bash
|
||||||
|
udisksctl unmount -b /dev/sdb1
|
||||||
|
```
|
||||||
|
|
||||||
@@ -0,0 +1,458 @@
|
|||||||
|
Hier ist ein kompaktes, aber vollständiges **VIM Cheat Sheet** 📝
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Modi in VIM
|
||||||
|
|
||||||
|
|Modus|Bedeutung|Wechsel|
|
||||||
|
|---|---|---|
|
||||||
|
|**Normal Mode**|Navigation & Befehle|`Esc`|
|
||||||
|
|**Insert Mode**|Texteingabe|`i`, `a`, `o`, etc.|
|
||||||
|
|**Visual Mode**|Text markieren|`v`, `V`, `Ctrl+v`|
|
||||||
|
|**Command Mode**|Speichern, Beenden, etc.|`:`|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Insert Mode Befehle
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`i`|Vor Cursor einfügen|
|
||||||
|
|`a`|Nach Cursor einfügen|
|
||||||
|
|`I`|Am Zeilenanfang einfügen|
|
||||||
|
|`A`|Am Zeilenende einfügen|
|
||||||
|
|`o`|Neue Zeile unterhalb|
|
||||||
|
|`O`|Neue Zeile oberhalb|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Navigation (Normal Mode)
|
||||||
|
|
||||||
|
### Zeichenweise
|
||||||
|
|
||||||
|
```
|
||||||
|
h ← j ↓ k ↑ l →
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wortweise
|
||||||
|
|
||||||
|
```
|
||||||
|
w nächstes Wort
|
||||||
|
b vorheriges Wort
|
||||||
|
e Wortende
|
||||||
|
```
|
||||||
|
|
||||||
|
### Zeilenweise
|
||||||
|
|
||||||
|
```
|
||||||
|
0 Zeilenanfang
|
||||||
|
^ Erstes Nicht-Leerzeichen
|
||||||
|
$ Zeilenende
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datei
|
||||||
|
|
||||||
|
```
|
||||||
|
gg Anfang der Datei
|
||||||
|
G Ende der Datei
|
||||||
|
:n Gehe zu Zeile n
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Löschen
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`x`|Zeichen löschen|
|
||||||
|
|`dd`|Zeile löschen|
|
||||||
|
|`dw`|Wort löschen|
|
||||||
|
|`d$`|Bis Zeilenende löschen|
|
||||||
|
|`d0`|Bis Zeilenanfang löschen|
|
||||||
|
|
||||||
|
💡 Kombination: `d` + Bewegung funktioniert immer
|
||||||
|
(z.B. `d3w` = 3 Wörter löschen)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Kopieren & Einfügen
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`yy`|Zeile kopieren|
|
||||||
|
|`yw`|Wort kopieren|
|
||||||
|
|`p`|Nach Cursor einfügen|
|
||||||
|
|`P`|Vor Cursor einfügen|
|
||||||
|
|
||||||
|
#### Register
|
||||||
|
Vor alle Kopieren oder Einfügen Befehle kann ein `"3` gestellt werden, um ins 3. Register zu schreiben bzw. daraus heraus zu lesen. Z.b. kopiert `"7yw` das Wort ins 7. Register und `"4p` fügt das 4. Register nach dem Curser ein.
|
||||||
|
💡 Das spezielle Register `+`/`*` ist das System-Clipboard, sehr Praktisch zum Austausch von Text mit anderen Programmen
|
||||||
|
Alle Register ansehen: `:reg`
|
||||||
|
💡 Das spezielle Register `%` enthält den aktuellen Dateipfad -> aktuelle Dateipfad in System-Clipboard: `:let @+=@%`.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Undo / Redo
|
||||||
|
|
||||||
|
```
|
||||||
|
u Undo
|
||||||
|
Ctrl+r Redo
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Visual Mode
|
||||||
|
|
||||||
|
|Befehl|Wirkung|
|
||||||
|
|---|---|
|
||||||
|
|`v`|Zeichenweise markieren|
|
||||||
|
|`V`|Ganze Zeile markieren|
|
||||||
|
|`Ctrl+v`|Block markieren|
|
||||||
|
|
||||||
|
Nach Markierung:
|
||||||
|
|
||||||
|
```
|
||||||
|
d löschen
|
||||||
|
y kopieren
|
||||||
|
> einrücken
|
||||||
|
< ausrücken
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Suchen & Ersetzen
|
||||||
|
|
||||||
|
```
|
||||||
|
/text Vorwärts suchen
|
||||||
|
?text Rückwärts suchen
|
||||||
|
n Nächstes Ergebnis
|
||||||
|
N Vorheriges Ergebnis
|
||||||
|
```
|
||||||
|
|
||||||
|
Ersetzen:
|
||||||
|
|
||||||
|
```
|
||||||
|
:%s/alt/neu/g Ganze Datei
|
||||||
|
:s/alt/neu/g Aktuelle Zeile
|
||||||
|
:%s/alt/neu/gc Mit Bestätigung
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Speichern & Beenden
|
||||||
|
|
||||||
|
```
|
||||||
|
:w Speichern
|
||||||
|
:q Beenden
|
||||||
|
:wq Speichern & Beenden
|
||||||
|
:x Speichern & Beenden
|
||||||
|
:q! Ohne Speichern beenden
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Fenster & Tabs
|
||||||
|
|
||||||
|
```
|
||||||
|
:split Horizontal teilen
|
||||||
|
:vsplit Vertikal teilen
|
||||||
|
Ctrl+w w Zwischen Fenstern wechseln
|
||||||
|
:tabnew Neuer Tab
|
||||||
|
gt Nächster Tab
|
||||||
|
gT Vorheriger Tab
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Nützliche Shortcuts
|
||||||
|
|
||||||
|
```
|
||||||
|
. Letzte Aktion wiederholen
|
||||||
|
>> Zeile einrücken
|
||||||
|
<< Zeile ausrücken
|
||||||
|
ciw Wort ändern
|
||||||
|
cc Zeile ändern
|
||||||
|
J Zeilen zusammenführen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Makros
|
||||||
|
|
||||||
|
```
|
||||||
|
qa Aufnahme in Register a starten
|
||||||
|
q Aufnahme stoppen
|
||||||
|
@a Makro a ausführen
|
||||||
|
@@ Letztes Makro wiederholen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Zahlen-Präfixe (Sehr wichtig!)
|
||||||
|
|
||||||
|
Viele Befehle lassen sich multiplizieren:
|
||||||
|
|
||||||
|
```
|
||||||
|
3dd 3 Zeilen löschen
|
||||||
|
5w 5 Wörter vor
|
||||||
|
2yy 2 Zeilen kopieren
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
# Zeilennummern aus- und anschalten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Absolute Zeilennummern
|
||||||
|
|
||||||
|
### Einschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set number
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ausschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set nonumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Toggle:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set number!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Relative Zeilennummern
|
||||||
|
|
||||||
|
### Einschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set relativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ausschalten:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set norelativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
### Toggle:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set relativenumber!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Absolute + Relative kombinieren (Sehr beliebt 🔥)
|
||||||
|
|
||||||
|
Viele nutzen diese Kombination:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:set number relativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
👉 Ergebnis:
|
||||||
|
|
||||||
|
* Aktuelle Zeile = **absolute Nummer**
|
||||||
|
* Alle anderen Zeilen = **relative Nummern**
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```
|
||||||
|
8
|
||||||
|
2
|
||||||
|
1
|
||||||
|
10 ← aktuelle Zeile
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
Das ist perfekt für Bewegungen wie:
|
||||||
|
|
||||||
|
```
|
||||||
|
5j
|
||||||
|
3k
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Dauerhaft aktivieren (.vimrc)
|
||||||
|
|
||||||
|
In deiner `~/.vimrc`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
set number
|
||||||
|
set relativenumber
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Smart Toggle Mapping (Optional ⭐)
|
||||||
|
|
||||||
|
Viele nutzen ein Keybinding:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
nnoremap <leader>n :set number! relativenumber!<CR>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann kannst du mit:
|
||||||
|
|
||||||
|
```
|
||||||
|
\ n
|
||||||
|
```
|
||||||
|
|
||||||
|
(beim Standard-`leader`) beide gleichzeitig toggeln.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Block Aus- und Einkommentieren
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 1️⃣ Rein mit Vim (ohne Plugin)
|
||||||
|
|
||||||
|
## ✅ Ganze Zeilen im Visual Mode kommentieren
|
||||||
|
|
||||||
|
### Schritt 1: Block markieren
|
||||||
|
|
||||||
|
* `V` → Zeilenweise markieren
|
||||||
|
* `j / k` → Bereich wählen
|
||||||
|
|
||||||
|
### Schritt 2: Kommentarzeichen einfügen
|
||||||
|
|
||||||
|
Beispiel für `#`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:s/^/# /
|
||||||
|
```
|
||||||
|
|
||||||
|
Im Visual Mode einfach:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:'<,'>s/^/# /
|
||||||
|
```
|
||||||
|
|
||||||
|
👉 Fügt `# ` am Anfang jeder markierten Zeile ein.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Auskommentieren
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:'<,'>s/^# //
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Noch schneller (ohne `:` tippen)
|
||||||
|
|
||||||
|
Markieren mit `V`, dann:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:s/^/# /
|
||||||
|
```
|
||||||
|
|
||||||
|
Vim setzt `'<,'>` automatisch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 2️⃣ Noch effizienter: Visual Block Mode (Sehr elegant ⚡)
|
||||||
|
|
||||||
|
Perfekt für feste Kommentarzeichen wie `#`, `//`, `--`.
|
||||||
|
|
||||||
|
### Schritt 1
|
||||||
|
|
||||||
|
```
|
||||||
|
Ctrl + v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schritt 2
|
||||||
|
|
||||||
|
Mit `j/k` mehrere Zeilen markieren (nur Spalte 0)
|
||||||
|
|
||||||
|
### Schritt 3
|
||||||
|
|
||||||
|
```
|
||||||
|
Shift + i
|
||||||
|
#
|
||||||
|
Esc
|
||||||
|
```
|
||||||
|
|
||||||
|
💥 Vim fügt das in alle markierten Zeilen ein.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔹 Entfernen mit Block Mode
|
||||||
|
|
||||||
|
1. `Ctrl + v`
|
||||||
|
2. Erste 2 Zeichen (`# `) markieren
|
||||||
|
3. `d`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 3️⃣ Beste Lösung: Plugin (Empfohlen 🔥)
|
||||||
|
|
||||||
|
Wenn du regelmäßig kommentierst → nimm ein Plugin.
|
||||||
|
|
||||||
|
Sehr beliebt:
|
||||||
|
|
||||||
|
* vim-commentary von Tim Pope
|
||||||
|
|
||||||
|
### Installation (mit vim-plug):
|
||||||
|
|
||||||
|
```vim
|
||||||
|
Plug 'tpope/vim-commentary'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nutzung:
|
||||||
|
|
||||||
|
* `gcc` → aktuelle Zeile toggeln
|
||||||
|
* `gc` (im Visual Mode) → Block toggeln
|
||||||
|
|
||||||
|
💎 Vorteil:
|
||||||
|
|
||||||
|
* erkennt automatisch Kommentarzeichen je nach Dateityp
|
||||||
|
* funktioniert mit `//`, `#`, `--`, `/* */`, etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔹 4️⃣ Absolute Power-User Lösung (Ohne Plugin, aber smart)
|
||||||
|
|
||||||
|
In `.vimrc`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
vnoremap <leader>c :s/^/# /<CR>
|
||||||
|
vnoremap <leader>u :s/^# //<CR>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann:
|
||||||
|
|
||||||
|
```
|
||||||
|
\c → kommentieren
|
||||||
|
\u → auskommentieren
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔥 Meine Empfehlung
|
||||||
|
|
||||||
|
| Wenn du... | Lösung |
|
||||||
|
| ----------------------------- | ----------------- |
|
||||||
|
| Nur selten kommentierst | Visual Block Mode |
|
||||||
|
| Viel programmierst | vim-commentary |
|
||||||
|
| Minimalistisch bleiben willst | eigenes Mapping |
|
||||||
|
|
||||||
|
---
|
||||||
|
# Verschiedenes
|
||||||
|
- `%`: zur nächsten Klammer
|
||||||
|
- `TOhtml`: HTML Export
|
||||||
|
- `:ls`: Buffer anzeigen -> `:b 3` den 3. Buffer öffnen
|
||||||
|
- `.` : letzte Aktion wiederholen
|
||||||
|
- `:e path/to/file` öffnet Datei, nur `:e` aktualisiert die geöffnete Datei, `:e!` verwirft dabei alle Änderungen
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# `fmt` – Textabsätze umbrechen
|
||||||
|
|
||||||
|
`fmt` formatiert einfachen Text neu, indem es Zeilen innerhalb eines Absatzes zusammenführt und passend zur gewünschten Breite wieder umbrechen lässt. Es gehört bei GNU/Linux üblicherweise zu **GNU coreutils**.
|
||||||
|
|
||||||
|
`fmt` ist für Fließtext gedacht, nicht für Programmcode oder Dokumente mit komplexer Formatierung.
|
||||||
|
|
||||||
|
## Grundlegende Verwendung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fmt notizen.txt # Ausgabe auf stdout, Standardbreite: 75 Zeichen
|
||||||
|
fmt -w 80 notizen.txt # auf höchstens 80 Zeichen umbrechen
|
||||||
|
fmt -w 72 # Text aus stdin formatieren
|
||||||
|
```
|
||||||
|
|
||||||
|
Datei bearbeiten und das Ergebnis in eine neue Datei schreiben:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fmt -w 80 notizen.txt > notizen-neu.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
> Nicht direkt mit `fmt notizen.txt > notizen.txt` überschreiben: Die Shell leert die Zieldatei bereits, bevor `fmt` sie einliest.
|
||||||
|
|
||||||
|
## Nützliche Optionen
|
||||||
|
|
||||||
|
| Option | Bedeutung |
|
||||||
|
|---|---|
|
||||||
|
| `-w 80` | Maximale Zeilenbreite festlegen (Standard: 75) |
|
||||||
|
| `-s` | Nur zu lange Zeilen umbrechen, kurze Zeilen nicht mit Nachbarzeilen zusammenführen |
|
||||||
|
| `-u` | Einheitliche Abstände zwischen Wörtern und Sätzen erzeugen |
|
||||||
|
| `-c` | Einrückung der ersten beiden Zeilen eines Absatzes als „crown margin“ behandeln |
|
||||||
|
|
||||||
|
Beispiel für eine Mail oder einen Text, dessen vorhandene Zeilenumbrüche weitgehend erhalten bleiben sollen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fmt -s -w 72 mail.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wie `fmt` Absätze erkennt
|
||||||
|
|
||||||
|
- Ein Absatz besteht grundsätzlich aus zusammenhängenden Textzeilen.
|
||||||
|
- Leerzeilen trennen Absätze und bleiben erhalten.
|
||||||
|
- `fmt` verbindet kurze Zeilen innerhalb eines Absatzes und verteilt den Text neu.
|
||||||
|
- Lange Wörter werden normalerweise nicht automatisch getrennt.
|
||||||
|
|
||||||
|
## Typische Anwendungsfälle
|
||||||
|
|
||||||
|
- Lange oder uneinheitlich umbrochene Textdateien lesbar machen.
|
||||||
|
- Text aus einer Pipe auf eine feste Breite bringen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat entwurf.txt | fmt -w 72
|
||||||
|
```
|
||||||
|
|
||||||
|
- Einen Absatz für ein Terminal, eine E-Mail oder einen Plain-Text-Editor umbrechen.
|
||||||
|
|
||||||
|
## Grenzen und Stolperfallen
|
||||||
|
|
||||||
|
- `fmt` versteht keine Markdown-Struktur: Listen, Tabellen, Überschriften und Codeblöcke können beim Umbruch beschädigt werden.
|
||||||
|
- Für Quellcode ist es ungeeignet; dafür den passenden Formatter der jeweiligen Sprache verwenden.
|
||||||
|
- Die Eingabedatei wird nicht verändert. `fmt` schreibt das Ergebnis standardmäßig auf die Standardausgabe.
|
||||||
|
|
||||||
|
## Siehe auch
|
||||||
|
|
||||||
|
- [[IT-Know-How/Linux/BASH Basics/find|find]] – Dateien suchen
|
||||||
|
- [[IT-Know-How/Linux/Linux|Linux]]
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# `locate` – Dateien schnell anhand des Namens finden
|
||||||
|
|
||||||
|
`locate` sucht Dateipfade in einer vorberechneten Datenbank. Dadurch ist die Suche meist sehr schnell – anders als `find` muss `locate` dafür nicht bei jeder Suche das Dateisystem durchlaufen.
|
||||||
|
|
||||||
|
Auf aktuellen Linux-Systemen wird häufig **plocate** verwendet; andere Distributionen können eine andere `locate`-Implementierung bereitstellen. Verfügbare Optionen und der Aktualisierungsdienst können sich deshalb leicht unterscheiden.
|
||||||
|
|
||||||
|
## Grundlegende Verwendung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
locate ssh_config # Pfade finden, deren Name zum Muster passt
|
||||||
|
locate -i readme.md # Groß-/Kleinschreibung ignorieren
|
||||||
|
locate -b bashrc # nur Dateinamen statt des gesamten Pfads durchsuchen
|
||||||
|
```
|
||||||
|
|
||||||
|
Anführungszeichen sind sinnvoll, wenn ein Suchmuster Leerzeichen oder Shell-Sonderzeichen enthält:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
locate 'project notes'
|
||||||
|
locate '*.service'
|
||||||
|
```
|
||||||
|
|
||||||
|
Viele Implementierungen behandeln ein Muster ohne Platzhalter wie eine Teilzeichenfolge. Details zum Musterformat stehen in `man locate`.
|
||||||
|
|
||||||
|
## Suchdatenbank aktualisieren
|
||||||
|
|
||||||
|
`locate` findet nur Einträge, die in seiner Datenbank stehen. Diese wird üblicherweise automatisch regelmäßig aktualisiert. Nach dem Erstellen oder Verschieben einer Datei kann die Datenbank daher zunächst veraltet sein.
|
||||||
|
|
||||||
|
Manuell aktualisieren (Befehl und Berechtigungen hängen von der Installation ab):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo updatedb
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach die Suche erneut ausführen. Auf manchen Systemen heißt das Aktualisierungswerkzeug anders oder wird über einen systemd-Timer verwaltet.
|
||||||
|
|
||||||
|
## Wann `locate` sinnvoll ist
|
||||||
|
|
||||||
|
- Wenn schnell ein wahrscheinlich vorhandener Pfad gesucht werden soll.
|
||||||
|
- Wenn der genaue Ordner unbekannt ist, der Dateiname aber ungefähr bekannt ist.
|
||||||
|
- Für eine erste Orientierung, bevor eine gezieltere Suche gestartet wird.
|
||||||
|
|
||||||
|
## Grenzen und Stolperfallen
|
||||||
|
|
||||||
|
- `locate` durchsucht **Dateinamen und Pfade**, nicht den Inhalt der Dateien.
|
||||||
|
- Neue, verschobene oder gelöschte Dateien sind eventuell noch nicht in der Datenbank berücksichtigt.
|
||||||
|
- Es eignet sich nicht gut für Bedingungen wie Dateigröße, Änderungsdatum oder Dateityp innerhalb eines bestimmten Verzeichnisses.
|
||||||
|
- Ein gefundener Pfad garantiert nicht, dass du die Datei lesen oder öffnen darfst.
|
||||||
|
- Die Zugänglichkeit der Datenbank und ausgeschlossene Verzeichnisse hängen von der jeweiligen Konfiguration ab.
|
||||||
|
|
||||||
|
Für eine aktuelle Suche mit Filtern ist `find` besser geeignet, zum Beispiel:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find ~/Downloads -type f -iname '*bericht*.pdf'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Siehe auch
|
||||||
|
|
||||||
|
- [[IT-Know-How/Linux/BASH Basics/find|find]] – aktuelle Suche mit Filtern
|
||||||
|
- [[IT-Know-How/Linux/Linux|Linux]]
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# GNU Stow – Dateien mit Symlinks verwalten
|
||||||
|
|
||||||
|
**GNU Stow** verwaltet Verzeichnisbäume, indem es symbolische Links (Symlinks) zu deren Dateien und Unterverzeichnissen anlegt oder entfernt. Ein häufiger Anwendungsfall ist die zentrale Verwaltung von **Dotfiles** und Konfigurationsdateien.
|
||||||
|
|
||||||
|
Stow führt dabei keine Installationsskripte aus und erzeugt keine Konfigurationsdateien aus Vorlagen: Seine Aufgabe ist die Verwaltung der Symlinks.
|
||||||
|
|
||||||
|
## Grundidee: Paketstruktur spiegelt das Ziel
|
||||||
|
|
||||||
|
Jede Unterstruktur unterhalb des Stow-Verzeichnisses ist ein „Paket“. Die Verzeichnisse und Dateien darin entsprechen den Pfaden, die im Zielverzeichnis entstehen sollen.
|
||||||
|
|
||||||
|
```text
|
||||||
|
~/dotfiles/
|
||||||
|
├── zsh/
|
||||||
|
│ ├── .zshrc
|
||||||
|
│ └── .config/
|
||||||
|
│ └── zsh/
|
||||||
|
│ └── aliases
|
||||||
|
└── git/
|
||||||
|
└── .gitconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Beim Stowen von `zsh` mit `~` als Ziel werden zum Beispiel `~/.zshrc` und `~/.config/zsh/aliases` verlinkt.
|
||||||
|
|
||||||
|
## Pakete verknüpfen und entfernen
|
||||||
|
|
||||||
|
Mit explizitem Stow- und Zielverzeichnis sind die Befehle unabhängig vom aktuellen Arbeitsverzeichnis verständlich:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Erst gefahrlos prüfen, was Stow tun würde
|
||||||
|
stow --simulate --verbose --dir="$HOME/dotfiles" --target="$HOME" zsh
|
||||||
|
|
||||||
|
# Symlinks anlegen
|
||||||
|
stow --dir="$HOME/dotfiles" --target="$HOME" zsh
|
||||||
|
|
||||||
|
# Symlinks dieses Pakets wieder entfernen
|
||||||
|
stow --delete --dir="$HOME/dotfiles" --target="$HOME" zsh
|
||||||
|
|
||||||
|
# Paket entfernen und anschließend erneut verknüpfen
|
||||||
|
stow --restow --dir="$HOME/dotfiles" --target="$HOME" zsh
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Kurzformen für häufige Optionen sind `-n` (simulieren), `-v` (Ausgabe), `-d` (Stow-Verzeichnis), `-t` (Zielverzeichnis), `-D` (entfernen) und `-R` (erneut anwenden).
|
||||||
|
|
||||||
|
## Typischer Dotfiles-Workflow
|
||||||
|
|
||||||
|
1. Konfigurationen in einem versionierten Verzeichnis wie `~/dotfiles` organisieren.
|
||||||
|
2. Pro Gruppe oder Programm ein Paketverzeichnis anlegen, zum Beispiel `zsh`, `git` oder `hypr`.
|
||||||
|
3. Die Paketstruktur so aufbauen, dass sie die gewünschten Pfade relativ zum Home-Verzeichnis abbildet.
|
||||||
|
4. Mit `stow -n -v ...` zunächst prüfen, welche Links entstehen würden.
|
||||||
|
5. Das Paket mit Stow verknüpfen und die Links bei Bedarf mit `stow -D ...` wieder entfernen.
|
||||||
|
|
||||||
|
## Konflikte und wichtige Hinweise
|
||||||
|
|
||||||
|
- Stow überschreibt vorhandene, nicht von Stow verwaltete Dateien nicht einfach. Bei Konflikten bricht es ab und meldet das Problem.
|
||||||
|
- Vorhandene Konfigurationen erst sichern oder bewusst in das Paket übernehmen, bevor Stow sie verwalten soll.
|
||||||
|
- Die Option `--adopt` kann vorhandene Dateien aus dem Ziel in das Paket verschieben. Sie kann Dateien verändern; nur nach Prüfung und mit Backup verwenden.
|
||||||
|
- Symlinks können auf dasselbe Dateisystem oder über verschiedene Datenträger hinweg zeigen, solange Ziel und Link erreichbar sind.
|
||||||
|
- Stow ist kein Paketmanager und installiert keine Programme. Für hostabhängige Logik, Templates oder zusätzliche Aktionen sind Skripte oder andere Dotfile-Manager nötig.
|
||||||
|
|
||||||
|
## Siehe auch
|
||||||
|
|
||||||
|
- [[IT-Know-How/Linux/Hyprland/Stow mit Logik|Stow mit Logik]] – GNU Stow mit Skripten kombinieren
|
||||||
|
- [[IT-Know-How/Linux/Linux|Linux]]
|
||||||
+207
@@ -0,0 +1,207 @@
|
|||||||
|
|
||||||
|
|
||||||
|
**Open WebUI is an [extensible](https://docs.openwebui.com/features/plugin/), feature-rich, and user-friendly self-hosted AI platform designed to operate entirely offline.** It supports various LLM runners like **Ollama** and **OpenAI-compatible APIs**, with **built-in inference engine** for RAG, making it a **powerful AI deployment solution**.
|
||||||
|
|
||||||
|
Passionate about open-source AI? [Join our team →](https://careers.openwebui.com/)
|
||||||
|
|
||||||
|
       [](https://discord.gg/5rJgQTnV4s) [](https://github.com/sponsors/tjbck)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
tip
|
||||||
|
|
||||||
|
**Looking for an [Enterprise Plan](https://docs.openwebui.com/enterprise)?** — **[Speak with Our Sales Team Today!](mailto:sales@openwebui.com)**
|
||||||
|
|
||||||
|
Get **enhanced capabilities**, including **custom theming and branding**, **Service Level Agreement (SLA) support**, **Long-Term Support (LTS) versions**, and **more!**
|
||||||
|
|
||||||
|
## Quick Start with [[Docker]] 🐳
|
||||||
|
|
||||||
|
info
|
||||||
|
|
||||||
|
**WebSocket** support is required for Open WebUI to function correctly. Ensure that your network configuration allows WebSocket connections.
|
||||||
|
|
||||||
|
**If Ollama is on your computer**, use this command:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||||
|
```
|
||||||
|
|
||||||
|
**To run Open WebUI with Nvidia GPU support**, use this command:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 --gpus all --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:cuda
|
||||||
|
```
|
||||||
|
|
||||||
|
For environments with limited storage or bandwidth, Open WebUI offers slim image variants that exclude pre-bundled models. These images are significantly smaller but download required models on first use:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main-slim
|
||||||
|
```
|
||||||
|
|
||||||
|
### Open WebUI Bundled with Ollama
|
||||||
|
|
||||||
|
This installation method uses a single container image that bundles Open WebUI with Ollama, allowing for a streamlined setup via a single command. Choose the appropriate command based on your hardware setup:
|
||||||
|
|
||||||
|
- **With GPU Support**: Utilize GPU resources by running the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- **For CPU Only**: If you're not using a GPU, use this command instead:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Both commands facilitate a built-in, hassle-free installation of both Open WebUI and Ollama, ensuring that you can get everything up and running swiftly.
|
||||||
|
|
||||||
|
After installation, you can access Open WebUI at [http://localhost:3000](http://localhost:3000). Enjoy! 😄
|
||||||
|
|
||||||
|
### Using the Dev Branch 🌙
|
||||||
|
|
||||||
|
warning
|
||||||
|
|
||||||
|
The `:dev` branch contains the latest unstable features and changes. Use it at your own risk as it may have bugs or incomplete features.
|
||||||
|
|
||||||
|
If you want to try out the latest bleeding-edge features and are okay with occasional instability, you can use the `:dev` tag like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
For the slim variant of the dev branch:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:dev-slim
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating Open WebUI
|
||||||
|
|
||||||
|
To update Open WebUI container easily, follow these steps:
|
||||||
|
|
||||||
|
#### Manual Update
|
||||||
|
|
||||||
|
Use [Watchtower](https://containrrr.dev/watchtower) to update your Docker container manually:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once open-webui
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Automatic Updates
|
||||||
|
|
||||||
|
Keep your container updated automatically every 5 minutes:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -d --name watchtower --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --interval 300 open-webui
|
||||||
|
```
|
||||||
|
|
||||||
|
🔧 **Note**: Replace `open-webui` with your container name if it's different.
|
||||||
|
|
||||||
|
## Manual Installation
|
||||||
|
|
||||||
|
info
|
||||||
|
|
||||||
|
### Platform Compatibility
|
||||||
|
|
||||||
|
Open WebUI works on macOS, [[Linux]] (x86_64 and ARM64, including Raspberry Pi and other ARM boards), and Windows.
|
||||||
|
|
||||||
|
There are two main ways to install and run Open WebUI: using the `uv` runtime manager or Python's `pip`. While both methods are effective, **we strongly recommend using `uv`** as it simplifies environment management and minimizes potential conflicts.
|
||||||
|
|
||||||
|
### Installation with `uv` (Recommended)
|
||||||
|
|
||||||
|
The `uv` runtime manager ensures seamless Python environment management for applications like Open WebUI. Follow these steps to get started:
|
||||||
|
|
||||||
|
#### 1. Install `uv`
|
||||||
|
|
||||||
|
Pick the appropriate installation command for your operating system:
|
||||||
|
|
||||||
|
- **macOS/Linux**:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- **Windows**:
|
||||||
|
|
||||||
|
```
|
||||||
|
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 2. Run Open WebUI
|
||||||
|
|
||||||
|
Once `uv` is installed, running Open WebUI is a breeze. Use the command below, ensuring to set the `DATA_DIR` environment variable to avoid data loss. Example paths are provided for each platform:
|
||||||
|
|
||||||
|
- **macOS/Linux**:
|
||||||
|
|
||||||
|
```
|
||||||
|
DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- **Windows**:
|
||||||
|
|
||||||
|
```
|
||||||
|
$env:DATA_DIR="C:\open-webui\data"; uvx --python 3.11 open-webui@latest serve
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
|
||||||
|
**For PostgreSQL Support:**
|
||||||
|
|
||||||
|
The default installation now uses a slimmed-down package. If you need **PostgreSQL support**, install with all optional dependencies:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install open-webui[all]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installation with `pip`
|
||||||
|
|
||||||
|
For users installing Open WebUI with [[Python]]'s package manager `pip`, **it is strongly recommended to use Python runtime managers like `uv` or `conda`**. These tools help manage Python environments effectively and avoid conflicts.
|
||||||
|
|
||||||
|
Python 3.11 is the development environment. Python 3.12 seems to work but has not been thoroughly tested. Python 3.13 is entirely untested and some dependencies do not work with Python 3.13 yet—**use at your own risk**.
|
||||||
|
|
||||||
|
1. **Install Open WebUI**:
|
||||||
|
|
||||||
|
Open your terminal and run the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install open-webui
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
- **Start Open WebUI**:
|
||||||
|
|
||||||
|
Once installed, start the server using:
|
||||||
|
|
||||||
|
```
|
||||||
|
open-webui serve
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Updating Open WebUI
|
||||||
|
|
||||||
|
To update to the latest version, simply run:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install --upgrade open-webui
|
||||||
|
```
|
||||||
|
|
||||||
|
This method installs all necessary dependencies and starts Open WebUI, allowing for a simple and efficient setup. After installation, you can access Open WebUI at [http://localhost:8080](http://localhost:8080). Enjoy! 😄
|
||||||
|
|
||||||
|
## Other Installation Methods
|
||||||
|
|
||||||
|
We offer various installation alternatives, including non-Docker native installation methods, Docker Compose, Kustomize, and Helm. Visit our [Open WebUI Documentation](https://docs.openwebui.com/getting-started/) or join our [Discord community](https://discord.gg/5rJgQTnV4s) for comprehensive guidance.
|
||||||
|
|
||||||
|
Continue with the full [getting started guide](https://docs.openwebui.com/getting-started).
|
||||||
|
|
||||||
|
### Desktop App
|
||||||
|
|
||||||
|
We also have an **experimental** desktop app, which is actively a **work in progress (WIP)**. While it offers a convenient way to run Open WebUI natively on your system without Docker or manual setup, it is **not yet stable**.
|
||||||
|
|
||||||
|
👉 For stability and production use, we strongly recommend installing via **Docker** or **Python (`uv` or `pip`)**.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
```md
|
|
||||||
---
|
---
|
||||||
title: "Rust Tutorial (für Python-Erfahrene)"
|
title: "Rust Tutorial (für Python-Erfahrene)"
|
||||||
tags: [rust, tutorial, programming]
|
tags: [rust, tutorial, programming]
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
## Modi
|
||||||
|
```text
|
||||||
|
i In den Insert-Modus (vor Cursor)
|
||||||
|
I Insert am Zeilenanfang
|
||||||
|
a Insert nach Cursor
|
||||||
|
A Insert am Zeilenende
|
||||||
|
o Neue Zeile unterhalb + Insert
|
||||||
|
O Neue Zeile oberhalb + Insert
|
||||||
|
|
||||||
|
<Esc> Zurück in Normalmodus
|
||||||
|
|
||||||
|
v Visueller Modus (Zeichenweise)
|
||||||
|
V Visueller Modus (Zeilenweise)
|
||||||
|
<C-v> Visueller Blockmodus
|
||||||
|
```
|
||||||
|
## Navigation (Normalmodus)
|
||||||
|
```text
|
||||||
|
h j k l Links / runter / hoch / rechts
|
||||||
|
|
||||||
|
0 Zeilenanfang
|
||||||
|
^ Erstes nicht-leer Zeichen
|
||||||
|
$ Zeilenende
|
||||||
|
|
||||||
|
w Zum nächsten Wortanfang
|
||||||
|
b Zum vorherigen Wortanfang
|
||||||
|
e Zum Wortende
|
||||||
|
W B E Wie oben, aber Worte durch Leerzeichen getrennt
|
||||||
|
|
||||||
|
gg Erste Zeile
|
||||||
|
G Letzte Zeile
|
||||||
|
ngg / nG Zu Zeile n
|
||||||
|
|
||||||
|
H Oberer Bildschirmrand
|
||||||
|
M Mittlerer Bildschirmrand
|
||||||
|
L Unterer Bildschirmrand
|
||||||
|
|
||||||
|
Ctrl-u Halbe Seite hoch
|
||||||
|
Ctrl-d Halbe Seite runter
|
||||||
|
Ctrl-b Seite hoch
|
||||||
|
Ctrl-f Seite runter
|
||||||
|
```
|
||||||
|
## Basis-Bearbeitung
|
||||||
|
```text
|
||||||
|
x Zeichen unter Cursor löschen
|
||||||
|
X Zeichen links vom Cursor löschen
|
||||||
|
r<char> Zeichen ersetzen
|
||||||
|
|
||||||
|
dd Zeile löschen (cut)
|
||||||
|
D Bis zum Zeilenende löschen
|
||||||
|
cc Zeile ändern (delete + insert)
|
||||||
|
C Bis zum Zeilenende ändern
|
||||||
|
|
||||||
|
yy Zeile kopieren
|
||||||
|
Y Alias für yy
|
||||||
|
p Einfügen NACH Cursor/Zeile
|
||||||
|
P Einfügen VOR Cursor/Zeile
|
||||||
|
|
||||||
|
u Undo
|
||||||
|
Ctrl-r Redo
|
||||||
|
|
||||||
|
J Nächste Zeile an aktuelle anhängen
|
||||||
|
>> Zeile einrücken (indent)
|
||||||
|
<< Zeile ausrücken (unindent)
|
||||||
|
```
|
||||||
|
## Mit Counts & Bewegungen
|
||||||
|
Viele Befehle funktionieren mit einer Anzahl (count) und einer Bewegung:
|
||||||
|
```text
|
||||||
|
3w 3 Wörter vor
|
||||||
|
5j 5 Zeilen runter
|
||||||
|
|
||||||
|
d3w 3 Wörter löschen
|
||||||
|
c$ Bis Zeilenende ändern
|
||||||
|
y0 Bis Zeilenanfang kopieren
|
||||||
|
```
|
||||||
|
## Textobjekte (im Normal- / Visuellen Modus)
|
||||||
|
```text
|
||||||
|
aw A word (inkl. Leerzeichen)
|
||||||
|
iw Inner word
|
||||||
|
as A sentence
|
||||||
|
is Inner sentence
|
||||||
|
ap A paragraph
|
||||||
|
ip Inner paragraph
|
||||||
|
|
||||||
|
a" / i" Text in Anführungszeichen
|
||||||
|
a' / i' Text in einfachen Quotes
|
||||||
|
a) / i) Text in Klammern (usw. für {}, [], <>)
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
ci" Inhalt von "..." ändern
|
||||||
|
da( Klammerausdruck inklusive Klammern löschen
|
||||||
|
viw Wort unter Cursor markieren
|
||||||
|
```
|
||||||
|
## Suchen & Ersetzen
|
||||||
|
```text
|
||||||
|
/word Vorwärts nach „word“ suchen
|
||||||
|
?word Rückwärts suchen
|
||||||
|
n Nächster Treffer
|
||||||
|
N Vorheriger Treffer
|
||||||
|
|
||||||
|
* Wort unter Cursor vorwärts suchen
|
||||||
|
# Wort unter Cursor rückwärts suchen
|
||||||
|
|
||||||
|
:%s/alt/neu/g In gesamter Datei ersetzen
|
||||||
|
:%s/alt/neu/gc Mit Bestätigung
|
||||||
|
:.,$s/alt/neu/g Von aktueller Zeile bis Ende
|
||||||
|
:10,20s/alt/neu/g In Zeilen 10–20
|
||||||
|
```
|
||||||
|
## Dateien, Buffers, Splits & Tabs
|
||||||
|
```text
|
||||||
|
:e datei Datei öffnen
|
||||||
|
:w Speichern
|
||||||
|
:w name Unter anderem Namen speichern
|
||||||
|
:q Beenden
|
||||||
|
:q! Beenden ohne Speichern
|
||||||
|
:wq / :x Speichern und beenden
|
||||||
|
:qa Alle Fenster schließen
|
||||||
|
:qa! Alle schließen ohne Speichern
|
||||||
|
|
||||||
|
" Buffer (Dateien im Speicher)
|
||||||
|
:ls Buffer-Liste
|
||||||
|
:buffer n Buffer n öffnen
|
||||||
|
:bnext / :bn Nächster Buffer
|
||||||
|
:bprev / :bp Vorheriger Buffer
|
||||||
|
:bdelete Buffer schließen
|
||||||
|
|
||||||
|
" Splits
|
||||||
|
:split datei Horizontaler Split
|
||||||
|
:vsplit datei Vertikaler Split
|
||||||
|
Ctrl-w s Split horizontal
|
||||||
|
Ctrl-w v Split vertikal
|
||||||
|
Ctrl-w w Zum nächsten Split
|
||||||
|
Ctrl-w h/j/k/l Split wechseln
|
||||||
|
Ctrl-w q Split schließen
|
||||||
|
|
||||||
|
" Tabs
|
||||||
|
:tabnew Neuer Tab
|
||||||
|
:tabclose Tab schließen
|
||||||
|
:tabnext / :tn Nächster Tab
|
||||||
|
:tabprev / :tp Vorheriger Tab
|
||||||
|
```
|
||||||
|
## Visual Mode Aktionen
|
||||||
|
```text
|
||||||
|
v / V / Ctrl-v Auswahl starten
|
||||||
|
y Auswahl kopieren
|
||||||
|
d Auswahl löschen
|
||||||
|
c Auswahl ändern
|
||||||
|
|
||||||
|
> Einrücken
|
||||||
|
< Ausrücken
|
||||||
|
= Auto-Indent (z.B. für Code)
|
||||||
|
|
||||||
|
: Befehl auf Auswahl anwenden
|
||||||
|
(Bereich wird automatisch eingetragen)
|
||||||
|
```
|
||||||
|
## Makros & Wiederholung
|
||||||
|
```text
|
||||||
|
. Letzte Änderung wiederholen
|
||||||
|
|
||||||
|
q<a> Macro in Register a aufzeichnen
|
||||||
|
(z.B. qa)
|
||||||
|
... Aktionen ausführen
|
||||||
|
q Aufzeichnung beenden
|
||||||
|
|
||||||
|
@a Macro a ausführen
|
||||||
|
3@a Macro 3x ausführen
|
||||||
|
@@ Letztes Macro wiederholen
|
||||||
|
```
|
||||||
|
## Register
|
||||||
|
```text
|
||||||
|
"0 Zuletzt kopiertes (y) ohne delete
|
||||||
|
"1–"9 Verlaufsregister
|
||||||
|
"" Default-Register
|
||||||
|
|
||||||
|
"+ System-Clipboard (kopieren/einfügen mit OS)
|
||||||
|
"* Auswahl-Clipboard (unter Linux/X11)
|
||||||
|
|
||||||
|
Beispiele:
|
||||||
|
"ayw Wort in Register a kopieren
|
||||||
|
"ap Inhalt von Register a einfügen
|
||||||
|
"+y In System-Clipboard kopieren
|
||||||
|
"+p Aus System-Clipboard einfügen
|
||||||
|
```
|
||||||
|
## Kommandomodus (Ex-Befehle)
|
||||||
|
```text
|
||||||
|
:!cmd Externen Befehl ausführen
|
||||||
|
:r !cmd Ausgabe von cmd einfügen
|
||||||
|
:r datei Datei unter Cursor-Zeile einfügen
|
||||||
|
|
||||||
|
:set nu Zeilennummern an
|
||||||
|
:set nonu Zeilennummern aus
|
||||||
|
:set relativenumber Relative Nummern
|
||||||
|
:set tabstop=4 shiftwidth=4 expandtab
|
||||||
|
```
|
||||||
|
## Einfache .vimrc-Beispiele
|
||||||
|
```vim
|
||||||
|
" Zeilennummern
|
||||||
|
set number
|
||||||
|
set relativenumber
|
||||||
|
|
||||||
|
" Einrückung
|
||||||
|
set tabstop=4
|
||||||
|
set shiftwidth=4
|
||||||
|
set expandtab
|
||||||
|
set smartindent
|
||||||
|
|
||||||
|
" Suche
|
||||||
|
set ignorecase
|
||||||
|
set smartcase
|
||||||
|
set hlsearch
|
||||||
|
set incsearch
|
||||||
|
|
||||||
|
" Maus
|
||||||
|
set mouse=a
|
||||||
|
```
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
[[Navidrome]]
|
||||||
|
## 🧩 **Option 1: Über die Web-Oberfläche**
|
||||||
|
|
||||||
|
Wenn du nur die Bibliothek neu scannen willst:
|
||||||
|
|
||||||
|
1. Melde dich als **Admin** in der Weboberfläche an.
|
||||||
|
|
||||||
|
2. Gehe zu **Settings → Admin → Rescan Library** (oder „Bibliothek neu scannen“).
|
||||||
|
|
||||||
|
3. Wähle **„Full Rescan“** (Vollständiger Scan) aus.
|
||||||
|
|
||||||
|
|
||||||
|
Das ist der einfachste Weg — aber wenn du den Vorgang **per Shell oder Skript** auslösen willst, siehe Option 2 oder 3.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐳 **Option 2: Über die Docker Shell**
|
||||||
|
|
||||||
|
Wenn du direkten Zugriff auf den Container hast:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it <container_name> navidrome rescan --force
|
||||||
|
```
|
||||||
|
|
||||||
|
🔹 `<container_name>` ersetzt du durch den tatsächlichen Namen deines Containers, z. B. `navidrome`.
|
||||||
|
🔹 Der Parameter `--force` erzwingt eine vollständige Neuindizierung (nicht nur eine inkrementelle).
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it navidrome navidrome rescan --force
|
||||||
|
```
|
||||||
|
|
||||||
|
Falls `navidrome` nicht im `PATH` ist (z. B. je nach Image):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it navidrome /app/navidrome rescan --force
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ **Option 3: Durch Neustart mit Umgebungsvariable**
|
||||||
|
|
||||||
|
Wenn du den Container neu startest und gleich beim Start eine Neuindizierung erzwingen willst, kannst du temporär folgende Umgebungsvariable setzen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
-e ND_SCAN_ON_STARTUP=true \
|
||||||
|
-e ND_SCAN_FORCED=true \
|
||||||
|
...
|
||||||
|
--name navidrome \
|
||||||
|
deluan/navidrome:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Oder, wenn du `docker-compose` nutzt:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- ND_SCAN_ON_STARTUP=true
|
||||||
|
- ND_SCAN_FORCED=true
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann einmal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose restart navidrome
|
||||||
|
```
|
||||||
|
|
||||||
|
Das löst bei jedem Start eine **vollständige Neuindizierung** aus.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 **Zusatzinfos**
|
||||||
|
|
||||||
|
- `navidrome rescan` akzeptiert auch `--quiet` (ohne Logausgabe).
|
||||||
|
|
||||||
|
- Der Fortschritt erscheint in den Logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs -f navidrome
|
||||||
|
```
|
||||||
|
|
||||||
|
- Die Indizierung kann bei großen Bibliotheken einige Zeit dauern.
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
```bash
|
||||||
|
# /etc/fstab: static file system information.
|
||||||
|
#
|
||||||
|
# Use 'blkid' to print the universally unique identifier for a
|
||||||
|
# device; this may be used with UUID= as a more robust way to name devices
|
||||||
|
# that works even if disks are added and removed. See fstab(5).
|
||||||
|
#
|
||||||
|
# <file system> <mount point> <type> <options> <dump> <pass>
|
||||||
|
# / was on /dev/nvme0n1p2 during installation
|
||||||
|
UUID=4d4554dc-e3fc-499c-991c-074655585d11 / ext4 errors=remount-ro 0 1
|
||||||
|
# /boot/efi was on /dev/nvme0n1p1 during installation
|
||||||
|
UUID=FCBD-00BE /boot/efi vfat umask=0077 0 1
|
||||||
|
/swapfile none swap sw 0 0
|
||||||
|
UUID=04F6962EF6961FCA /media/mathias/Anbau2 ntfs-3g defaults,umask=000,uid=1000,gid=1000 0 0
|
||||||
|
UUID=A8F0EC77F0EC4D5E /media/mathias/Bilder ntfs-3g defaults,umask=000,uid=1000,gid=1000 0 0
|
||||||
|
UUID=a642b8a8-2cdd-4635-a094-e408073a236d /media/mathieu/vault ext4 defaults 0 2
|
||||||
|
```
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
# Git-Historie durchsuchen
|
||||||
|
|
||||||
|
## Kurzfassung
|
||||||
|
|
||||||
|
`rg` durchsucht normalerweise den aktuellen Dateistand. Auch mit
|
||||||
|
`--hidden --no-ignore` wird die eigentliche Git-Historie nicht zuverlässig
|
||||||
|
durchsucht: Die historischen Objekte liegen unter `.git/objects` komprimiert
|
||||||
|
und über ihre Hashes organisiert.
|
||||||
|
|
||||||
|
Für die Git-Historie verwendet man je nach Fragestellung `git log`, `git grep`
|
||||||
|
und `git rev-list`.
|
||||||
|
|
||||||
|
## Änderungen mit `git log` finden
|
||||||
|
|
||||||
|
### Exakte Zeichenfolge: `-S`
|
||||||
|
|
||||||
|
Mit `-S` findet man Commits, in denen sich die Anzahl einer exakten
|
||||||
|
Zeichenfolge geändert hat — also typischerweise, wenn eine Zeichenfolge
|
||||||
|
hinzugefügt oder entfernt wurde:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all -S'example_endpoint' --oneline
|
||||||
|
```
|
||||||
|
|
||||||
|
Die zugehörigen Änderungen anzeigen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all -S'example_endpoint' -p
|
||||||
|
```
|
||||||
|
|
||||||
|
### Regulärer Ausdruck: `-G`
|
||||||
|
|
||||||
|
Mit `-G` sucht Git in hinzugefügten und entfernten Zeilen nach einem regulären
|
||||||
|
Ausdruck:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all -G'example[_-]endpoint' --oneline
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit Patch-Ausgabe:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all -G'example[_-]endpoint' -p
|
||||||
|
```
|
||||||
|
|
||||||
|
`--all` bezieht alle Commits ein, die von lokalen Branches, Remote-Tracking-
|
||||||
|
Branches und Tags erreichbar sind.
|
||||||
|
|
||||||
|
## Vollständige historische Dateistände durchsuchen
|
||||||
|
|
||||||
|
`git log -S` und `git log -G` suchen nach Änderungen. Wenn stattdessen jeder
|
||||||
|
vollständige Dateistand durchsucht werden soll, kann man `git grep` mit
|
||||||
|
`git rev-list` kombinieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git rev-list --all |
|
||||||
|
while read commit; do
|
||||||
|
git grep -n -E 'example[_-]endpoint' "$commit" -- &&
|
||||||
|
echo "Found in $commit"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Ausgabe enthält die Commit-ID, die betroffene Datei und die Zeilennummer.
|
||||||
|
Einen einzelnen historischen Dateistand kann man direkt durchsuchen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git grep -n -E 'example[_-]endpoint' <COMMIT>
|
||||||
|
```
|
||||||
|
|
||||||
|
Ein Commit kann beispielsweise ein vollständiger Hash, ein Branch-Name oder
|
||||||
|
ein Tag sein:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git grep -n -E 'example[_-]endpoint' HEAD~10
|
||||||
|
git grep -n -E 'example[_-]endpoint' v1.2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reflog und nicht mehr erreichbare Commits
|
||||||
|
|
||||||
|
`--all` findet nur Commits, die noch über Referenzen erreichbar sind. Kürzlich
|
||||||
|
gelöschte Branches können zusätzlich über die Reflogs gefunden werden:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all --reflog -G'example[_-]endpoint' --oneline
|
||||||
|
```
|
||||||
|
|
||||||
|
Falls ein Commit weder über Branches, Tags noch Reflogs erreichbar ist, kann
|
||||||
|
Git ihn eventuell noch als unerreichbares Objekt kennen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git fsck --full --no-reflogs --unreachable
|
||||||
|
```
|
||||||
|
|
||||||
|
Nur unerreichbare Commits durchsuchen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git fsck --full --no-reflogs --unreachable |
|
||||||
|
awk '$2 == "commit" { print $3 }' |
|
||||||
|
while read commit; do
|
||||||
|
git grep -n -E 'example[_-]endpoint' "$commit" -- &&
|
||||||
|
echo "Found in $commit"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
Das funktioniert nur, solange die Objekte noch nicht durch Garbage Collection
|
||||||
|
entfernt wurden. Bei einem Shallow Clone kann außerdem die ältere Historie
|
||||||
|
lokal fehlen.
|
||||||
|
|
||||||
|
## `rg` und `.git`
|
||||||
|
|
||||||
|
Der Befehl:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rg --hidden --no-ignore '/example[\_\-]endpoint'
|
||||||
|
```
|
||||||
|
|
||||||
|
durchsucht den aktuellen Dateibaum einschließlich normalerweise versteckter
|
||||||
|
Dateien. Er durchsucht jedoch nicht sinnvoll die komprimierten historischen
|
||||||
|
Git-Objekte unter `.git/objects`.
|
||||||
|
|
||||||
|
Für den regulären Ausdruck genügt normalerweise:
|
||||||
|
|
||||||
|
```text
|
||||||
|
example[_-]endpoint
|
||||||
|
```
|
||||||
|
|
||||||
|
Der führende `/` ist ein wörtliches Zeichen und sollte nur verwendet werden,
|
||||||
|
wenn tatsächlich ein Slash vor `example` gesucht werden soll. Die Backslashes
|
||||||
|
vor `_` und `-` sind hier ebenfalls nicht erforderlich.
|
||||||
|
|
||||||
|
Für die Suche im aktuellen Dateistand siehe [[Linux/ripgrep_guide]]. Für
|
||||||
|
Informationen darüber, warum alte Historie fehlen oder umgeschrieben worden
|
||||||
|
kann, siehe [[Git-History-Truncation]].
|
||||||
+1247
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,262 @@
|
|||||||
|
# Python-Paket auf Gitea veröffentlichen
|
||||||
|
|
||||||
|
Gitea kann als private oder öffentliche PyPI-Registry verwendet werden. Damit lassen sich eigene Python-Pakete bauen, versionieren und in anderen Projekten mit `pip` oder `uv` installieren.
|
||||||
|
|
||||||
|
Diese Anleitung verwendet `utils` als Beispielpaket und den Gitea-Server `gitea.schneiderserver.site`.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- ein Python-Projekt mit `pyproject.toml`
|
||||||
|
- ein Gitea-Repository
|
||||||
|
- `uv` für Environment, Tests und Build
|
||||||
|
- `twine` für das Veröffentlichen
|
||||||
|
- ein privater Gitea Personal Access Token
|
||||||
|
|
||||||
|
Verwandt: [[uv]] und [[pytest]].
|
||||||
|
|
||||||
|
## Paket lokal bauen
|
||||||
|
|
||||||
|
Im Projektverzeichnis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv sync
|
||||||
|
uv run pytest
|
||||||
|
uv build
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach liegen normalerweise zwei Dateien in `dist/`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dist/utils-0.1.0.tar.gz
|
||||||
|
dist/utils-0.1.0-py3-none-any.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
Vor einem erneuten Build kann `dist/` entfernt werden:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf dist
|
||||||
|
uv build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gitea-Endpunkte
|
||||||
|
|
||||||
|
Der Owner ist der Gitea-Benutzer oder die Organisation, unter der das Paket veröffentlicht wird. Er ist nicht zwingend der Repository-Name.
|
||||||
|
|
||||||
|
Publish-Endpunkt:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://<gitea-host>/api/packages/<owner>/pypi
|
||||||
|
```
|
||||||
|
|
||||||
|
Installations-Endpunkt:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://<gitea-host>/api/packages/<owner>/pypi/simple
|
||||||
|
```
|
||||||
|
|
||||||
|
Für den eigenen Server und den Benutzer `mathias` lautet das beispielsweise:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://gitea.schneiderserver.site/api/packages/mathias/pypi
|
||||||
|
https://gitea.schneiderserver.site/api/packages/mathias/pypi/simple
|
||||||
|
```
|
||||||
|
|
||||||
|
## Token
|
||||||
|
|
||||||
|
`YOUR_GITEA_TOKEN` steht für einen **privaten Personal Access Token** aus Gitea. Es handelt sich nicht um einen öffentlichen Token.
|
||||||
|
|
||||||
|
Für das Veröffentlichen wird mindestens eine Berechtigung zum Schreiben von Packages benötigt, typischerweise `write:package`. Für die Installation privater Packages wird `read:package` benötigt. Die genauen Namen können je nach Gitea-Version leicht abweichen.
|
||||||
|
|
||||||
|
Den Token niemals:
|
||||||
|
|
||||||
|
- in Git committen
|
||||||
|
- in eine README schreiben
|
||||||
|
- im Chat oder in Logs veröffentlichen
|
||||||
|
- dauerhaft direkt in die Shell-History schreiben
|
||||||
|
|
||||||
|
Für CI/CD sollte der Token als Gitea-Action-Secret hinterlegt werden, zum Beispiel als `GITEA_TOKEN`.
|
||||||
|
|
||||||
|
## Manuell mit Twine veröffentlichen
|
||||||
|
|
||||||
|
Twine installieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv tool install twine
|
||||||
|
```
|
||||||
|
|
||||||
|
`~/.pypirc` anlegen oder ergänzen:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[distutils]
|
||||||
|
index-servers =
|
||||||
|
gitea
|
||||||
|
|
||||||
|
[gitea]
|
||||||
|
repository = https://gitea.schneiderserver.site/api/packages/mathias/pypi
|
||||||
|
username = mathias
|
||||||
|
password = YOUR_PRIVATE_GITEA_TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
Anschließend veröffentlichen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m twine upload --repository gitea dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
Gitea akzeptiert denselben Paketnamen mit derselben Versionsnummer nicht zweimal. Für eine neue Veröffentlichung muss daher zuerst die Version in `pyproject.toml` erhöht werden:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
version = "0.1.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach erneut bauen und veröffentlichen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf dist
|
||||||
|
uv build
|
||||||
|
python -m twine upload --repository gitea dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
## In einem anderen Projekt installieren
|
||||||
|
|
||||||
|
### Öffentliches Paket
|
||||||
|
|
||||||
|
Wenn das Package und die Registry anonym lesbar sind:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install \
|
||||||
|
--index-url https://gitea.schneiderserver.site/api/packages/mathias/pypi/simple \
|
||||||
|
utils
|
||||||
|
```
|
||||||
|
|
||||||
|
### Privates Paket
|
||||||
|
|
||||||
|
Für ein privates Package ist ein Token mit `read:package` erforderlich:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install \
|
||||||
|
--index-url https://<username>:<read-token>@gitea.schneiderserver.site/api/packages/mathias/pypi/simple \
|
||||||
|
utils
|
||||||
|
```
|
||||||
|
|
||||||
|
Dasselbe funktioniert mit `uv`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv pip install \
|
||||||
|
--index-url https://<username>:<read-token>@gitea.schneiderserver.site/api/packages/mathias/pypi/simple \
|
||||||
|
utils
|
||||||
|
```
|
||||||
|
|
||||||
|
Tokens besser nicht direkt in Befehle schreiben, weil sie in der Shell-History oder Prozessliste sichtbar werden können. Für lokale Nutzung besser einen Credential-Helper oder eine geschützte Konfigurationsdatei verwenden; in CI ausschließlich Secrets verwenden.
|
||||||
|
|
||||||
|
## `--index-url` und `--extra-index-url`
|
||||||
|
|
||||||
|
Für private interne Packages ist `--index-url` vorzuziehen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install --index-url <gitea-pypi-simple-url> utils
|
||||||
|
```
|
||||||
|
|
||||||
|
`--extra-index-url` kann zu Dependency-Confusion-Problemen führen, weil ein gleichnamiges öffentliches Paket von PyPI aufgelöst werden könnte. Falls zusätzlich öffentliche PyPI-Abhängigkeiten gebraucht werden, sollte die Paketquellen-Konfiguration bewusst und projektbezogen eingerichtet werden.
|
||||||
|
|
||||||
|
## Git-Tags und Releases
|
||||||
|
|
||||||
|
Git-Tag und Paketversion sollten übereinstimmen:
|
||||||
|
|
||||||
|
```text
|
||||||
|
pyproject.toml: version = "0.1.0"
|
||||||
|
Git-Tag: v0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add pyproject.toml
|
||||||
|
git commit -m "Release version 0.1.0"
|
||||||
|
git tag v0.1.0
|
||||||
|
git push origin main
|
||||||
|
git push origin v0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Tagging ist nicht zwingend für den manuellen Upload, macht Releases aber nachvollziehbar und kann später als Auslöser für Gitea Actions dienen.
|
||||||
|
|
||||||
|
## Automatisierung mit Gitea Actions
|
||||||
|
|
||||||
|
Ein Workflow kann bei jedem `v*`-Tag automatisch testen, bauen und veröffentlichen. Die Zugangsdaten gehören als Repository-Secrets in Gitea und nicht in die Workflow-Datei.
|
||||||
|
|
||||||
|
Beispiel für `.gitea/workflows/publish.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Publish package
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.14"
|
||||||
|
|
||||||
|
- name: Install uv
|
||||||
|
run: pip install uv
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: uv sync
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: uv run pytest
|
||||||
|
|
||||||
|
- name: Build package
|
||||||
|
run: uv build
|
||||||
|
|
||||||
|
- name: Publish to Gitea
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: ${{ secrets.GITEA_USERNAME }}
|
||||||
|
TWINE_PASSWORD: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
TWINE_REPOSITORY_URL: https://gitea.schneiderserver.site/api/packages/mathias/pypi
|
||||||
|
run: uv run --with twine twine upload dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
Dazu in Gitea die Secrets `GITEA_USERNAME` und `GITEA_TOKEN` konfigurieren.
|
||||||
|
|
||||||
|
## Fehlersuche: `404 Not Found`
|
||||||
|
|
||||||
|
Bei einem Fehler wie:
|
||||||
|
|
||||||
|
```text
|
||||||
|
HTTPError: 404 Not Found from https://gitea.schneiderserver.site/api/packages/mathias/pypi
|
||||||
|
```
|
||||||
|
|
||||||
|
ist der Token wahrscheinlich nicht das Hauptproblem. Ungültige Zugangsdaten führen meistens zu `401 Unauthorized` oder `403 Forbidden`.
|
||||||
|
|
||||||
|
Folgende Punkte prüfen:
|
||||||
|
|
||||||
|
1. Ist `mathias` exakt der Gitea-Benutzername oder Organisationsname?
|
||||||
|
2. Wird der Repository-Owner statt des Repository-Namens verwendet?
|
||||||
|
3. Ist die Package Registry in der Gitea-Instanz aktiviert?
|
||||||
|
4. Wird der Gitea-Server über einen Reverse Proxy mit einem URL-Präfix betrieben?
|
||||||
|
5. Wird der Publish-Endpunkt ohne `/simple` verwendet?
|
||||||
|
6. Ist der Token noch gültig und besitzt er `write:package`?
|
||||||
|
|
||||||
|
Der Gitea-API-Endpunkt kann unabhängig davon erreichbar sein:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://gitea.schneiderserver.site/api/v1/version
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Publish-Endpunkt antwortet auf einen normalen `GET`-Aufruf möglicherweise mit `405 Method Not Allowed`, weil er nur Upload-Anfragen akzeptiert. Das ist ein Hinweis darauf, dass der Endpunkt existiert; ein `404` deutet eher auf einen falschen Owner, einen falschen Pfad oder eine deaktivierte Registry hin.
|
||||||
|
|
||||||
|
## Offizielle Dokumentation
|
||||||
|
|
||||||
|
- [Gitea PyPI Package Registry](https://docs.gitea.com/usage/packages/pypi/)
|
||||||
|
- [Gitea Package Registry Übersicht](https://docs.gitea.com/usage/packages/overview/)
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
Pydantic ist ein zentrales Werkzeug im heutigen Python-Ökosystem, vor allem im Umfeld von APIs (z.B. [[FastAPI]]), Konfiguration und Datenvalidierung.
|
hPydantic ist ein zentrales Werkzeug im heutigen Python-Ökosystem, vor allem im Umfeld von APIs (z.B. [[FastAPI]]), Konfiguration und Datenvalidierung.
|
||||||
Im Folgenden bekommst du eine systematische Einführung mit praxisnahen Beispielen.
|
Im Folgenden bekommst du eine systematische Einführung mit praxisnahen Beispielen.
|
||||||
|
|
||||||
**Hinweis:** Die Beispiele orientieren sich an **Pydantic v2** (aktuelle Hauptversion). In v1 ist die Syntax ähnlich, aber es gibt einige Unterschiede (z.B. `@validator` vs. `@field_validator`).
|
**Hinweis:** Die Beispiele orientieren sich an **Pydantic v2** (aktuelle Hauptversion). In v1 ist die Syntax ähnlich, aber es gibt einige Unterschiede (z.B. `@validator` vs. `@field_validator`).
|
||||||
|
|||||||
+1
-1
@@ -94,7 +94,7 @@ Fixtures sind einer der größten Vorteile von `pytest` im Vergleich zu `unittes
|
|||||||
|
|
||||||
**Beispiel: einfache Fixture**
|
**Beispiel: einfache Fixture**
|
||||||
|
|
||||||
```python
|
```python1
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user