anime-sama-cli 1.1__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/PKG-INFO +57 -14
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/README.md +56 -13
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/pyproject.toml +1 -1
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/catalogue.py +29 -10
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/constants.py +1 -1
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/flows.py +2 -2
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/fzf_utils.py +19 -13
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/top_level.py +108 -34
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/uv.lock +1 -1
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/.github/workflows/pypi.yml +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/.gitignore +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/.python-version +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/LICENSE +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/anisama-cli +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/examples/new_episodes_rss.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/scripts/debug_vidmoly.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/__init__.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/assets/ascii_art +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/__main__.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/config.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/config.toml +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/downloader.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/episode_extra_info.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/episode_tree.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/error_handeling.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/internal_player.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/play_menu.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/utils.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli_standalone.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/episode.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/langs.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/season.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/__init__.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/anilist.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/api_helpers.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/catalogue_tui.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/completions.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/config.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/download_utils.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/history.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/menus.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/planning.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/planning_tui.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/playback.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/runner.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/system_deps.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/terminal.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/utils.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/__init__.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/data/catalogue_data.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/data/episode_data.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/data/season_data.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_catalogue.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_cli_utils.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_download.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_seasons.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_top_level.py +0 -0
- {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anime-sama-cli
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: Regarder ou télécharger des animés en VF/VOSTFR depuis le terminal (anime-sama.to)
|
|
5
5
|
Project-URL: Repository, https://github.com/CheikhNaro/anime-sama-cli/
|
|
6
6
|
Project-URL: Documentation, https://github.com/CheikhNaro/anime-sama-cli#readme
|
|
@@ -35,7 +35,11 @@ https://github.com/user-attachments/assets/d04bddbd-4b20-4d63-a650-5b4a6add65da
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
## Dépendances
|
|
38
|
+
## Dépendances
|
|
39
|
+
|
|
40
|
+
Le projet a besoin des éléments suivants pour fonctionner.
|
|
41
|
+
|
|
42
|
+
### Dépendances système
|
|
39
43
|
|
|
40
44
|
| Dépendance | Rôle | Version minimale |
|
|
41
45
|
|------------|------|------------------|
|
|
@@ -46,16 +50,18 @@ https://github.com/user-attachments/assets/d04bddbd-4b20-4d63-a650-5b4a6add65da
|
|
|
46
50
|
| **ffmpeg** | Requis par yt-dlp pour fusionner flux audio/vidéo | — |
|
|
47
51
|
| **chafa** | Affichage des covers (jaquettes) dans le panneau de prévisualisation fzf (sixel/ASCII) | — |
|
|
48
52
|
|
|
49
|
-
**Terminal pour les covers :**
|
|
53
|
+
**Terminal pour les covers :** pour que les jaquettes s’affichent correctement, utilisez un terminal qui supporte l’affichage d’images ou le protocole sixel (p. ex. **Kitty**, **iTerm2**, **WezTerm**, **foot**). Avec **chafa**, un aperçu en caractères est possible même dans les terminaux qui ne gèrent pas les images nativement.
|
|
50
54
|
|
|
51
55
|
### Dépendances Python (gérées à l’installation)
|
|
52
56
|
|
|
53
|
-
Elles sont installées automatiquement : `httpx`, `platformdirs`, `rich`, `textual`, `tomli` (si Python < 3.11), `yt-dlp`.
|
|
57
|
+
Elles sont installées automatiquement avec le projet : `httpx`, `platformdirs`, `rich`, `textual`, `tomli` (si Python < 3.11), `yt-dlp`.
|
|
54
58
|
|
|
55
59
|
---
|
|
56
60
|
|
|
57
61
|
## Fonctionnalités
|
|
58
62
|
|
|
63
|
+
<details><summary><b>Voir les fonctionnalités</b></summary>
|
|
64
|
+
|
|
59
65
|
- **Regarder** : parcourir le catalogue, choisir un animé et un épisode, lecture dans MPV ou VLC.
|
|
60
66
|
- **Télécharger** : sélection d’épisodes ou de saisons pour téléchargement (via yt-dlp).
|
|
61
67
|
- **Planning** : affichage du planning des sorties de la semaine et lecture depuis le planning.
|
|
@@ -63,13 +69,15 @@ Elles sont installées automatiquement : `httpx`, `platformdirs`, `rich`, `textu
|
|
|
63
69
|
- **Historique local** : consultation de l’historique de visionnage local.
|
|
64
70
|
- **Recherche** : recherche dans le catalogue et dans l’historique.
|
|
65
71
|
|
|
72
|
+
</details>
|
|
73
|
+
|
|
66
74
|
---
|
|
67
75
|
|
|
68
76
|
## Installation des dépendances système
|
|
69
77
|
|
|
70
78
|
Installez d’abord les paquets système selon votre distribution, puis installez le projet (voir section suivante).
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
<details><summary><b>Debian / Ubuntu (et dérivés)</b></summary>
|
|
73
81
|
|
|
74
82
|
Sur les distributions basées sur Debian (Ubuntu, Linux Mint, etc.), utilisez `apt` :
|
|
75
83
|
|
|
@@ -93,7 +101,9 @@ Sur les distributions basées sur Debian (Ubuntu, Linux Mint, etc.), utilisez `a
|
|
|
93
101
|
|
|
94
102
|
**Note :** La version de `yt-dlp` dans les dépôts peut être en retard. Pour une version à jour, vous pouvez utiliser pipx : `pipx install yt-dlp`.
|
|
95
103
|
|
|
96
|
-
|
|
104
|
+
</details>
|
|
105
|
+
|
|
106
|
+
<details><summary><b>Arch Linux (et dérivés)</b></summary>
|
|
97
107
|
|
|
98
108
|
Sur Arch (et dérivés comme Manjaro), utilisez `pacman` :
|
|
99
109
|
|
|
@@ -105,9 +115,12 @@ Sur Arch (et dérivés comme Manjaro), utilisez `pacman` :
|
|
|
105
115
|
```bash
|
|
106
116
|
sudo pacman -S vlc
|
|
107
117
|
```
|
|
118
|
+
|
|
108
119
|
Sous Arch, les paquets sont en général à jour ; `yt-dlp` et `fzf` sont maintenus dans les dépôts officiels.
|
|
109
120
|
|
|
110
|
-
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
<details><summary><b>Fedora / RHEL (et dérivés)</b></summary>
|
|
111
124
|
|
|
112
125
|
Sur Fedora, RHEL, CentOS Stream, Rocky, Alma, etc., utilisez `dnf` :
|
|
113
126
|
|
|
@@ -119,21 +132,24 @@ Sur Fedora, RHEL, CentOS Stream, Rocky, Alma, etc., utilisez `dnf` :
|
|
|
119
132
|
```bash
|
|
120
133
|
sudo dnf install mpv
|
|
121
134
|
```
|
|
122
|
-
Si vous préférez VLC :
|
|
135
|
+
Si mpv n’est pas disponible, ou si vous préférez VLC :
|
|
123
136
|
```bash
|
|
124
137
|
sudo dnf install vlc
|
|
125
138
|
```
|
|
139
|
+
|
|
126
140
|
Sur RHEL/CentOS, si `yt-dlp` ou `fzf` ne sont pas dans les dépôts par défaut, vous pouvez les installer via pip pour `yt-dlp` (`pip install -U yt-dlp`) et suivre les instructions officielles pour `fzf` si besoin.
|
|
127
141
|
|
|
142
|
+
</details>
|
|
143
|
+
|
|
128
144
|
---
|
|
129
145
|
|
|
130
146
|
## Installation
|
|
131
147
|
|
|
132
148
|
Une fois les dépendances système installées :
|
|
133
149
|
|
|
134
|
-
|
|
150
|
+
<details><summary><b>Debian / Ubuntu (et dérivés)</b></summary>
|
|
135
151
|
|
|
136
|
-
Sur les systèmes basés sur Debian (Python géré par le système, PEP 668), **n’utilisez pas** `pip install
|
|
152
|
+
Sur les systèmes basés sur Debian (Python géré par le système, PEP 668), **n’utilisez pas** `pip install`. Utilisez **pipx** pour installer l’application dans un environnement virtuel dédié.
|
|
137
153
|
|
|
138
154
|
**Depuis PyPI :**
|
|
139
155
|
```bash
|
|
@@ -152,7 +168,9 @@ export PATH="$HOME/.local/bin:$PATH"
|
|
|
152
168
|
```
|
|
153
169
|
Et exécutez `pipx ensurepath` si ce n’est pas déjà fait.
|
|
154
170
|
|
|
155
|
-
|
|
171
|
+
</details>
|
|
172
|
+
|
|
173
|
+
<details><summary><b>Autres distributions (Arch, Fedora, ...)</b></summary>
|
|
156
174
|
|
|
157
175
|
```bash
|
|
158
176
|
pip install anime-sama-cli
|
|
@@ -165,13 +183,38 @@ git clone https://github.com/CheikhNaro/anime-sama-cli.git && cd anime-sama-cli
|
|
|
165
183
|
|
|
166
184
|
Si nécessaire, ajoutez `~/.local/bin` à votre `PATH`.
|
|
167
185
|
|
|
186
|
+
</details>
|
|
187
|
+
|
|
188
|
+
### Désinstaller l’outil
|
|
189
|
+
|
|
190
|
+
**Désinstallation du programme :**
|
|
191
|
+
|
|
192
|
+
- Si vous avez installé avec **pipx** (recommandé) :
|
|
193
|
+
```bash
|
|
194
|
+
pipx uninstall anime-sama-cli
|
|
195
|
+
```
|
|
196
|
+
- Si vous avez installé avec **pip** :
|
|
197
|
+
```bash
|
|
198
|
+
pip uninstall anime-sama-cli
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Cela retire le paquet et les commandes `anime-sama` / `anime-sama-cli`. **Les dossiers de configuration et de cache ne sont pas supprimés.**
|
|
202
|
+
|
|
203
|
+
**Supprimer aussi la config et le cache (optionnel) :**
|
|
204
|
+
|
|
205
|
+
Pour tout effacer (préférences, historique, cache des covers) :
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
rm -rf ~/.config/anime-sama_api ~/.config/anime-sama-cli ~/.cache/anime-sama-cli
|
|
209
|
+
```
|
|
210
|
+
|
|
168
211
|
---
|
|
169
212
|
|
|
170
213
|
Vous pouvez aussi lancer sans installer : `./anisama-cli` depuis la racine du dépôt (avec les dépendances Python déjà installées dans un venv).
|
|
171
214
|
|
|
172
215
|
---
|
|
173
216
|
|
|
174
|
-
|
|
217
|
+
##<details><summary><b>Utilisation</b></summary>
|
|
175
218
|
|
|
176
219
|
### Lancer l’outil (menu principal)
|
|
177
220
|
|
|
@@ -199,8 +242,6 @@ Pour modifier la langue d’affichage des épisodes :
|
|
|
199
242
|
anime-sama --set-lang
|
|
200
243
|
```
|
|
201
244
|
|
|
202
|
-
**Comportement avec VLC :** à chaque épisode, une nouvelle fenêtre VLC s’ouvre. Quand vous la fermez, VLC se ferme totalement (pas de minimisation en arrière-plan ni dans la zone de notification). Le script affiche alors le menu « Que faire maintenant ? » ; si vous choisissez un autre épisode, VLC s’ouvre à nouveau pour le lire.
|
|
203
|
-
|
|
204
245
|
### Se connecter à AniList et importer son historique
|
|
205
246
|
|
|
206
247
|
Pour lier un compte AniList et importer les listes « déjà vus » et « à regarder » :
|
|
@@ -217,6 +258,8 @@ Après connexion, l’historique AniList est disponible dans le menu (Historique
|
|
|
217
258
|
anime-sama --help
|
|
218
259
|
```
|
|
219
260
|
|
|
261
|
+
</details>
|
|
262
|
+
|
|
220
263
|
---
|
|
221
264
|
|
|
222
265
|
Merci à [@Sky-NiniKo](https://github.com/Sky-NiniKo/anime-sama_api) pour avoir rendu ce projet possible
|
|
@@ -6,7 +6,11 @@ https://github.com/user-attachments/assets/d04bddbd-4b20-4d63-a650-5b4a6add65da
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## Dépendances
|
|
9
|
+
## Dépendances
|
|
10
|
+
|
|
11
|
+
Le projet a besoin des éléments suivants pour fonctionner.
|
|
12
|
+
|
|
13
|
+
### Dépendances système
|
|
10
14
|
|
|
11
15
|
| Dépendance | Rôle | Version minimale |
|
|
12
16
|
|------------|------|------------------|
|
|
@@ -17,16 +21,18 @@ https://github.com/user-attachments/assets/d04bddbd-4b20-4d63-a650-5b4a6add65da
|
|
|
17
21
|
| **ffmpeg** | Requis par yt-dlp pour fusionner flux audio/vidéo | — |
|
|
18
22
|
| **chafa** | Affichage des covers (jaquettes) dans le panneau de prévisualisation fzf (sixel/ASCII) | — |
|
|
19
23
|
|
|
20
|
-
**Terminal pour les covers :**
|
|
24
|
+
**Terminal pour les covers :** pour que les jaquettes s’affichent correctement, utilisez un terminal qui supporte l’affichage d’images ou le protocole sixel (p. ex. **Kitty**, **iTerm2**, **WezTerm**, **foot**). Avec **chafa**, un aperçu en caractères est possible même dans les terminaux qui ne gèrent pas les images nativement.
|
|
21
25
|
|
|
22
26
|
### Dépendances Python (gérées à l’installation)
|
|
23
27
|
|
|
24
|
-
Elles sont installées automatiquement : `httpx`, `platformdirs`, `rich`, `textual`, `tomli` (si Python < 3.11), `yt-dlp`.
|
|
28
|
+
Elles sont installées automatiquement avec le projet : `httpx`, `platformdirs`, `rich`, `textual`, `tomli` (si Python < 3.11), `yt-dlp`.
|
|
25
29
|
|
|
26
30
|
---
|
|
27
31
|
|
|
28
32
|
## Fonctionnalités
|
|
29
33
|
|
|
34
|
+
<details><summary><b>Voir les fonctionnalités</b></summary>
|
|
35
|
+
|
|
30
36
|
- **Regarder** : parcourir le catalogue, choisir un animé et un épisode, lecture dans MPV ou VLC.
|
|
31
37
|
- **Télécharger** : sélection d’épisodes ou de saisons pour téléchargement (via yt-dlp).
|
|
32
38
|
- **Planning** : affichage du planning des sorties de la semaine et lecture depuis le planning.
|
|
@@ -34,13 +40,15 @@ Elles sont installées automatiquement : `httpx`, `platformdirs`, `rich`, `textu
|
|
|
34
40
|
- **Historique local** : consultation de l’historique de visionnage local.
|
|
35
41
|
- **Recherche** : recherche dans le catalogue et dans l’historique.
|
|
36
42
|
|
|
43
|
+
</details>
|
|
44
|
+
|
|
37
45
|
---
|
|
38
46
|
|
|
39
47
|
## Installation des dépendances système
|
|
40
48
|
|
|
41
49
|
Installez d’abord les paquets système selon votre distribution, puis installez le projet (voir section suivante).
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
<details><summary><b>Debian / Ubuntu (et dérivés)</b></summary>
|
|
44
52
|
|
|
45
53
|
Sur les distributions basées sur Debian (Ubuntu, Linux Mint, etc.), utilisez `apt` :
|
|
46
54
|
|
|
@@ -64,7 +72,9 @@ Sur les distributions basées sur Debian (Ubuntu, Linux Mint, etc.), utilisez `a
|
|
|
64
72
|
|
|
65
73
|
**Note :** La version de `yt-dlp` dans les dépôts peut être en retard. Pour une version à jour, vous pouvez utiliser pipx : `pipx install yt-dlp`.
|
|
66
74
|
|
|
67
|
-
|
|
75
|
+
</details>
|
|
76
|
+
|
|
77
|
+
<details><summary><b>Arch Linux (et dérivés)</b></summary>
|
|
68
78
|
|
|
69
79
|
Sur Arch (et dérivés comme Manjaro), utilisez `pacman` :
|
|
70
80
|
|
|
@@ -76,9 +86,12 @@ Sur Arch (et dérivés comme Manjaro), utilisez `pacman` :
|
|
|
76
86
|
```bash
|
|
77
87
|
sudo pacman -S vlc
|
|
78
88
|
```
|
|
89
|
+
|
|
79
90
|
Sous Arch, les paquets sont en général à jour ; `yt-dlp` et `fzf` sont maintenus dans les dépôts officiels.
|
|
80
91
|
|
|
81
|
-
|
|
92
|
+
</details>
|
|
93
|
+
|
|
94
|
+
<details><summary><b>Fedora / RHEL (et dérivés)</b></summary>
|
|
82
95
|
|
|
83
96
|
Sur Fedora, RHEL, CentOS Stream, Rocky, Alma, etc., utilisez `dnf` :
|
|
84
97
|
|
|
@@ -90,21 +103,24 @@ Sur Fedora, RHEL, CentOS Stream, Rocky, Alma, etc., utilisez `dnf` :
|
|
|
90
103
|
```bash
|
|
91
104
|
sudo dnf install mpv
|
|
92
105
|
```
|
|
93
|
-
Si vous préférez VLC :
|
|
106
|
+
Si mpv n’est pas disponible, ou si vous préférez VLC :
|
|
94
107
|
```bash
|
|
95
108
|
sudo dnf install vlc
|
|
96
109
|
```
|
|
110
|
+
|
|
97
111
|
Sur RHEL/CentOS, si `yt-dlp` ou `fzf` ne sont pas dans les dépôts par défaut, vous pouvez les installer via pip pour `yt-dlp` (`pip install -U yt-dlp`) et suivre les instructions officielles pour `fzf` si besoin.
|
|
98
112
|
|
|
113
|
+
</details>
|
|
114
|
+
|
|
99
115
|
---
|
|
100
116
|
|
|
101
117
|
## Installation
|
|
102
118
|
|
|
103
119
|
Une fois les dépendances système installées :
|
|
104
120
|
|
|
105
|
-
|
|
121
|
+
<details><summary><b>Debian / Ubuntu (et dérivés)</b></summary>
|
|
106
122
|
|
|
107
|
-
Sur les systèmes basés sur Debian (Python géré par le système, PEP 668), **n’utilisez pas** `pip install
|
|
123
|
+
Sur les systèmes basés sur Debian (Python géré par le système, PEP 668), **n’utilisez pas** `pip install`. Utilisez **pipx** pour installer l’application dans un environnement virtuel dédié.
|
|
108
124
|
|
|
109
125
|
**Depuis PyPI :**
|
|
110
126
|
```bash
|
|
@@ -123,7 +139,9 @@ export PATH="$HOME/.local/bin:$PATH"
|
|
|
123
139
|
```
|
|
124
140
|
Et exécutez `pipx ensurepath` si ce n’est pas déjà fait.
|
|
125
141
|
|
|
126
|
-
|
|
142
|
+
</details>
|
|
143
|
+
|
|
144
|
+
<details><summary><b>Autres distributions (Arch, Fedora, ...)</b></summary>
|
|
127
145
|
|
|
128
146
|
```bash
|
|
129
147
|
pip install anime-sama-cli
|
|
@@ -136,13 +154,38 @@ git clone https://github.com/CheikhNaro/anime-sama-cli.git && cd anime-sama-cli
|
|
|
136
154
|
|
|
137
155
|
Si nécessaire, ajoutez `~/.local/bin` à votre `PATH`.
|
|
138
156
|
|
|
157
|
+
</details>
|
|
158
|
+
|
|
159
|
+
### Désinstaller l’outil
|
|
160
|
+
|
|
161
|
+
**Désinstallation du programme :**
|
|
162
|
+
|
|
163
|
+
- Si vous avez installé avec **pipx** (recommandé) :
|
|
164
|
+
```bash
|
|
165
|
+
pipx uninstall anime-sama-cli
|
|
166
|
+
```
|
|
167
|
+
- Si vous avez installé avec **pip** :
|
|
168
|
+
```bash
|
|
169
|
+
pip uninstall anime-sama-cli
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Cela retire le paquet et les commandes `anime-sama` / `anime-sama-cli`. **Les dossiers de configuration et de cache ne sont pas supprimés.**
|
|
173
|
+
|
|
174
|
+
**Supprimer aussi la config et le cache (optionnel) :**
|
|
175
|
+
|
|
176
|
+
Pour tout effacer (préférences, historique, cache des covers) :
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
rm -rf ~/.config/anime-sama_api ~/.config/anime-sama-cli ~/.cache/anime-sama-cli
|
|
180
|
+
```
|
|
181
|
+
|
|
139
182
|
---
|
|
140
183
|
|
|
141
184
|
Vous pouvez aussi lancer sans installer : `./anisama-cli` depuis la racine du dépôt (avec les dépendances Python déjà installées dans un venv).
|
|
142
185
|
|
|
143
186
|
---
|
|
144
187
|
|
|
145
|
-
|
|
188
|
+
##<details><summary><b>Utilisation</b></summary>
|
|
146
189
|
|
|
147
190
|
### Lancer l’outil (menu principal)
|
|
148
191
|
|
|
@@ -170,8 +213,6 @@ Pour modifier la langue d’affichage des épisodes :
|
|
|
170
213
|
anime-sama --set-lang
|
|
171
214
|
```
|
|
172
215
|
|
|
173
|
-
**Comportement avec VLC :** à chaque épisode, une nouvelle fenêtre VLC s’ouvre. Quand vous la fermez, VLC se ferme totalement (pas de minimisation en arrière-plan ni dans la zone de notification). Le script affiche alors le menu « Que faire maintenant ? » ; si vous choisissez un autre épisode, VLC s’ouvre à nouveau pour le lire.
|
|
174
|
-
|
|
175
216
|
### Se connecter à AniList et importer son historique
|
|
176
217
|
|
|
177
218
|
Pour lier un compte AniList et importer les listes « déjà vus » et « à regarder » :
|
|
@@ -188,6 +229,8 @@ Après connexion, l’historique AniList est disponible dans le menu (Historique
|
|
|
188
229
|
anime-sama --help
|
|
189
230
|
```
|
|
190
231
|
|
|
232
|
+
</details>
|
|
233
|
+
|
|
191
234
|
---
|
|
192
235
|
|
|
193
236
|
Merci à [@Sky-NiniKo](https://github.com/Sky-NiniKo/anime-sama_api) pour avoir rendu ce projet possible
|
|
@@ -7,7 +7,7 @@ packages = ["src/anime_sama_api"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "anime-sama-cli"
|
|
10
|
-
version = "
|
|
10
|
+
version = "2.0.1"
|
|
11
11
|
description = "Regarder ou télécharger des animés en VF/VOSTFR depuis le terminal (anime-sama.to)"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
license = "GPL-3.0-or-later"
|
|
@@ -85,32 +85,51 @@ class Catalogue:
|
|
|
85
85
|
return seasons
|
|
86
86
|
|
|
87
87
|
async def advancement(self) -> str:
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
page = await self.page()
|
|
89
|
+
search = cast(
|
|
90
|
+
list[str],
|
|
91
|
+
re.findall(r"Actualité[\s\S]*?info-val[^>]*>([^<]+)", page),
|
|
92
|
+
)
|
|
93
|
+
if not search:
|
|
94
|
+
search = cast(
|
|
95
|
+
list[str], re.findall(r"Actualité.+?>(.+?)<", page)
|
|
96
|
+
)
|
|
90
97
|
if not search:
|
|
91
98
|
return ""
|
|
92
|
-
|
|
93
99
|
return search[0]
|
|
94
100
|
|
|
95
101
|
async def correspondence(self) -> str:
|
|
102
|
+
page = await self.page()
|
|
96
103
|
search = cast(
|
|
97
|
-
list[str],
|
|
104
|
+
list[str],
|
|
105
|
+
re.findall(r"Correspondance[\s\S]*?info-val[^>]*>([^<]+)", page),
|
|
98
106
|
)
|
|
99
|
-
|
|
107
|
+
if not search:
|
|
108
|
+
search = cast(
|
|
109
|
+
list[str], re.findall(r"Correspondance.+?>(.+?)<", page)
|
|
110
|
+
)
|
|
100
111
|
if not search:
|
|
101
112
|
return ""
|
|
102
|
-
|
|
103
113
|
return search[0]
|
|
104
114
|
|
|
105
115
|
async def synopsis(self) -> str:
|
|
116
|
+
page = await self.page()
|
|
106
117
|
search = cast(
|
|
107
|
-
list[str],
|
|
118
|
+
list[str],
|
|
119
|
+
re.findall(
|
|
120
|
+
r'<h2[^>]*>Synopsis</h2>[\s\S]*?<p[^>]*id="synopsisText"[^>]*>(.+?)</p>',
|
|
121
|
+
page,
|
|
122
|
+
re.IGNORECASE,
|
|
123
|
+
),
|
|
108
124
|
)
|
|
109
|
-
|
|
125
|
+
if not search:
|
|
126
|
+
search = cast(
|
|
127
|
+
list[str], re.findall(r"Synopsis[\W\w]+?>(.+)<", page)
|
|
128
|
+
)
|
|
110
129
|
if not search:
|
|
111
130
|
return ""
|
|
112
|
-
|
|
113
|
-
return search[0]
|
|
131
|
+
from html import unescape as html_unescape
|
|
132
|
+
return html_unescape(search[0].strip())
|
|
114
133
|
|
|
115
134
|
async def is_mature(self) -> bool:
|
|
116
135
|
"""Return True if the catalogue contain a warning about adult content"""
|
|
@@ -32,7 +32,7 @@ ANIME_SAMA_API_CONFIG_DIR = Path(
|
|
|
32
32
|
) / "anime-sama_api"
|
|
33
33
|
ANIME_SAMA_API_CONFIG_FILE = ANIME_SAMA_API_CONFIG_DIR / "config.toml"
|
|
34
34
|
DOWNLOADS_DIR_NAME = "Téléchargements"
|
|
35
|
-
__version__ = "2.0.
|
|
35
|
+
__version__ = "2.0.1"
|
|
36
36
|
|
|
37
37
|
FZF_MIN_VERSION = (0, 53, 0)
|
|
38
38
|
COVER_CACHE_DIR = Path(
|
|
@@ -185,7 +185,7 @@ async def run_watch_flow(cfg: dict[str, str]) -> bool:
|
|
|
185
185
|
proc.wait()
|
|
186
186
|
else:
|
|
187
187
|
print(constants.RED + "Impossible de lancer l'épisode suivant." + constants.RESET)
|
|
188
|
-
|
|
188
|
+
continue
|
|
189
189
|
elif after == "précédent":
|
|
190
190
|
idx_ep -= 1
|
|
191
191
|
selected_episode = episodes[idx_ep]
|
|
@@ -202,7 +202,7 @@ async def run_watch_flow(cfg: dict[str, str]) -> bool:
|
|
|
202
202
|
proc.wait()
|
|
203
203
|
else:
|
|
204
204
|
print(constants.RED + "Impossible de lancer l'épisode précédent." + constants.RESET)
|
|
205
|
-
|
|
205
|
+
continue
|
|
206
206
|
elif after == "saison_suivante":
|
|
207
207
|
if not has_next_season:
|
|
208
208
|
break
|
|
@@ -78,21 +78,27 @@ def _fetch_page_info(page_url: str) -> dict[str, str]:
|
|
|
78
78
|
html = resp.read().decode("utf-8", errors="replace")
|
|
79
79
|
except Exception:
|
|
80
80
|
return result
|
|
81
|
-
|
|
81
|
+
synopsis_m = re.search(
|
|
82
|
+
r'<h2[^>]*>Synopsis</h2>[\s\S]*?<p[^>]*id="synopsisText"[^>]*>(.+?)</p>',
|
|
83
|
+
html,
|
|
84
|
+
re.IGNORECASE,
|
|
85
|
+
)
|
|
86
|
+
if synopsis_m:
|
|
82
87
|
raw = html_module.unescape(synopsis_m.group(1).strip())
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
result["synopsis"] = raw
|
|
89
|
+
genre_m = re.search(
|
|
90
|
+
r'<h2[^>]*>Genres</h2>\s*<div[^>]*class="genres-wrap"[^>]*>([\s\S]+?)</div>',
|
|
91
|
+
html,
|
|
92
|
+
re.IGNORECASE,
|
|
93
|
+
)
|
|
94
|
+
if genre_m:
|
|
95
|
+
genres = re.findall(r'genre-pill[^>]*>([^<]+)', genre_m.group(1))
|
|
96
|
+
result["genre"] = ", ".join(
|
|
97
|
+
html_module.unescape(g.strip()) for g in genres if g.strip()
|
|
98
|
+
)
|
|
99
|
+
type_m = re.search(r'<h2[^>]*>(Anime|Scans|Manga|Film)</h2>', html, re.IGNORECASE)
|
|
94
100
|
if type_m:
|
|
95
|
-
result["type"] =
|
|
101
|
+
result["type"] = type_m.group(1)
|
|
96
102
|
return result
|
|
97
103
|
|
|
98
104
|
|
|
@@ -11,7 +11,6 @@ from httpx import AsyncClient
|
|
|
11
11
|
from .catalogue import Catalogue, Category
|
|
12
12
|
from .episode import Episode
|
|
13
13
|
from .langs import Lang, flags
|
|
14
|
-
from .season import Season
|
|
15
14
|
from .utils import filter_literal, is_Literal
|
|
16
15
|
|
|
17
16
|
logger = logging.getLogger(__name__)
|
|
@@ -105,31 +104,81 @@ class AnimeSama:
|
|
|
105
104
|
|
|
106
105
|
def _yield_catalogues_from(self, html: str) -> Generator[Catalogue]:
|
|
107
106
|
text_without_script = re.sub(r"<script[\W\w]+?</script>", "", html)
|
|
108
|
-
for
|
|
109
|
-
|
|
107
|
+
for card_match in re.finditer(
|
|
108
|
+
r'<div[^>]*class="[^"]*catalog-card[^"]*"[^>]*>[\s\S]*?</a>\s*</div>',
|
|
110
109
|
text_without_script,
|
|
110
|
+
re.IGNORECASE,
|
|
111
111
|
):
|
|
112
|
-
(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
112
|
+
card_html = card_match.group()
|
|
113
|
+
|
|
114
|
+
url_m = re.search(r'href="([^"]+)"', card_html)
|
|
115
|
+
if not url_m:
|
|
116
|
+
continue
|
|
117
|
+
url = unescape(url_m.group(1))
|
|
118
|
+
|
|
119
|
+
image_m = re.search(r'src="([^"]+)"', card_html)
|
|
120
|
+
image_url = unescape(image_m.group(1)) if image_m else ""
|
|
121
121
|
|
|
122
|
+
name_m = re.search(r'card-title[^>]*>(.*?)</h2>', card_html, re.IGNORECASE)
|
|
123
|
+
name = unescape(name_m.group(1).strip()) if name_m else ""
|
|
124
|
+
|
|
125
|
+
alt_m = re.search(
|
|
126
|
+
r'alternate-titles[^>]*>(.*?)</p>', card_html, re.IGNORECASE
|
|
127
|
+
)
|
|
128
|
+
alt_names_raw = unescape(alt_m.group(1)) if alt_m else ""
|
|
122
129
|
alternative_names = (
|
|
123
|
-
|
|
130
|
+
[a.strip() for a in alt_names_raw.split(",") if a.strip()]
|
|
131
|
+
if alt_names_raw
|
|
132
|
+
else []
|
|
124
133
|
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
|
|
135
|
+
genres: list[str] = []
|
|
136
|
+
genre_rows = re.findall(
|
|
137
|
+
r'<div class="info-row">[\s\S]*?</div>\s*</div>', card_html
|
|
138
|
+
)
|
|
139
|
+
for row in genre_rows:
|
|
140
|
+
label_m = re.search(
|
|
141
|
+
r'info-label[^>]*>[\s\S]*?Genres[\s\S]*?</span>', row, re.IGNORECASE
|
|
142
|
+
)
|
|
143
|
+
if label_m:
|
|
144
|
+
genres = [
|
|
145
|
+
unescape(t.strip())
|
|
146
|
+
for t in re.findall(
|
|
147
|
+
r'genre-tag[^>]*>([^<]+)', row
|
|
148
|
+
)
|
|
149
|
+
if t.strip()
|
|
150
|
+
]
|
|
151
|
+
break
|
|
152
|
+
|
|
153
|
+
categories: list[str] = []
|
|
154
|
+
for row in genre_rows:
|
|
155
|
+
label_m = re.search(
|
|
156
|
+
r'info-label[^>]*>[\s\S]*?Types?[\s\S]*?</span>',
|
|
157
|
+
row,
|
|
158
|
+
re.IGNORECASE,
|
|
159
|
+
)
|
|
160
|
+
if label_m:
|
|
161
|
+
type_vals = re.findall(r'info-value[^>]*>([^<]+)', row)
|
|
162
|
+
for val in type_vals:
|
|
163
|
+
parts = [v.strip() for v in val.split(",") if v.strip()]
|
|
164
|
+
categories.extend(parts)
|
|
165
|
+
break
|
|
166
|
+
|
|
167
|
+
languages: list[str] = []
|
|
168
|
+
for row in genre_rows:
|
|
169
|
+
label_m = re.search(
|
|
170
|
+
r'info-label[^>]*>[\s\S]*?Langues[\s\S]*?</span>',
|
|
171
|
+
row,
|
|
172
|
+
re.IGNORECASE,
|
|
173
|
+
)
|
|
174
|
+
if label_m:
|
|
175
|
+
flag_titles = re.findall(r'lang-flag[^>]*title="([^"]+)"', row)
|
|
176
|
+
for title in flag_titles:
|
|
177
|
+
lang = self._flag_title_to_lang(title)
|
|
178
|
+
if lang:
|
|
179
|
+
languages.append(lang)
|
|
180
|
+
break
|
|
181
|
+
|
|
133
182
|
_category_fix = {"Autre": "Autres", "Animes": "Anime", "Films": "Film"}
|
|
134
183
|
categories = [_category_fix.get(c.strip(), c.strip()) for c in categories if c.strip()]
|
|
135
184
|
|
|
@@ -141,7 +190,6 @@ class AnimeSama:
|
|
|
141
190
|
categories_checked = cast(
|
|
142
191
|
set[Category], set(filter_literal(categories, Category, not_in_literal))
|
|
143
192
|
)
|
|
144
|
-
# Ne pas logger pour les langues : le site peut mettre "Scans" dans les langues (ex. Watamote)
|
|
145
193
|
languages_checked = cast(
|
|
146
194
|
set[Lang], set(filter_literal(languages, Lang, lambda _: None))
|
|
147
195
|
)
|
|
@@ -157,23 +205,49 @@ class AnimeSama:
|
|
|
157
205
|
client=self.client,
|
|
158
206
|
)
|
|
159
207
|
|
|
208
|
+
@staticmethod
|
|
209
|
+
def _flag_title_to_lang(title: str) -> str | None:
|
|
210
|
+
from .langs import flagid2lang
|
|
211
|
+
return flagid2lang.get(title.strip().lower())
|
|
212
|
+
|
|
160
213
|
def _yield_release_episodes_from(self, html: str) -> Generator[EpisodeRelease]:
|
|
161
|
-
for
|
|
162
|
-
|
|
214
|
+
for card_match in re.finditer(
|
|
215
|
+
r'<div[^>]*class="[^"]*anime-card-premium[^"]*"[^>]*>[\s\S]*?</a>\s*</div>',
|
|
163
216
|
html,
|
|
217
|
+
re.IGNORECASE,
|
|
164
218
|
):
|
|
165
|
-
(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
219
|
+
card_html = card_match.group()
|
|
220
|
+
url_m = re.search(r'href="([^"]+)"', card_html)
|
|
221
|
+
if not url_m:
|
|
222
|
+
continue
|
|
223
|
+
season_url = unescape(url_m.group(1))
|
|
224
|
+
|
|
225
|
+
image_m = re.search(r'src="([^"]+)"', card_html)
|
|
226
|
+
image_url = unescape(image_m.group(1)) if image_m else ""
|
|
227
|
+
|
|
228
|
+
alt_m = re.search(r'alt="([^"]*)"', card_html)
|
|
229
|
+
serie_name = unescape(alt_m.group(1).strip()) if alt_m else ""
|
|
230
|
+
|
|
231
|
+
badge_m = re.search(
|
|
232
|
+
r'badge-text[^>]*>([^<]+)', card_html, re.IGNORECASE
|
|
233
|
+
)
|
|
234
|
+
category_raw = unescape(badge_m.group(1).strip()) if badge_m else "Anime"
|
|
235
|
+
|
|
236
|
+
lang_m = re.search(
|
|
237
|
+
r'language-badge-top[\s\S]*?badge-text[^>]*>([^<]+)',
|
|
238
|
+
card_html,
|
|
239
|
+
re.IGNORECASE,
|
|
240
|
+
)
|
|
241
|
+
language = unescape(lang_m.group(1).strip()) if lang_m else "VOSTFR"
|
|
242
|
+
|
|
243
|
+
info_m = re.search(
|
|
244
|
+
r'info-text[^>]*>([^<]+)', card_html, re.IGNORECASE
|
|
245
|
+
)
|
|
246
|
+
descriptive = unescape(info_m.group(1).strip()) if info_m else ""
|
|
247
|
+
|
|
248
|
+
categories = [category_raw]
|
|
174
249
|
_category_fix = {"Autre": "Autres", "Animes": "Anime", "Films": "Film"}
|
|
175
250
|
categories = [_category_fix.get(c.strip(), c.strip()) for c in categories if c.strip()]
|
|
176
|
-
language = language.strip() if language else "VOSTFR"
|
|
177
251
|
|
|
178
252
|
def not_in_literal(value: Any) -> None:
|
|
179
253
|
logger.warning(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|