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.
Files changed (58) hide show
  1. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/PKG-INFO +57 -14
  2. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/README.md +56 -13
  3. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/pyproject.toml +1 -1
  4. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/catalogue.py +29 -10
  5. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/constants.py +1 -1
  6. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/flows.py +2 -2
  7. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/fzf_utils.py +19 -13
  8. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/top_level.py +108 -34
  9. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/uv.lock +1 -1
  10. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/.github/workflows/pypi.yml +0 -0
  11. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/.gitignore +0 -0
  12. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/.python-version +0 -0
  13. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/LICENSE +0 -0
  14. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/anisama-cli +0 -0
  15. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/examples/new_episodes_rss.py +0 -0
  16. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/scripts/debug_vidmoly.py +0 -0
  17. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/__init__.py +0 -0
  18. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/assets/ascii_art +0 -0
  19. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/__main__.py +0 -0
  20. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/config.py +0 -0
  21. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/config.toml +0 -0
  22. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/downloader.py +0 -0
  23. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/episode_extra_info.py +0 -0
  24. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/episode_tree.py +0 -0
  25. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/error_handeling.py +0 -0
  26. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/internal_player.py +0 -0
  27. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/play_menu.py +0 -0
  28. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli/utils.py +0 -0
  29. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/cli_standalone.py +0 -0
  30. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/episode.py +0 -0
  31. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/langs.py +0 -0
  32. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/season.py +0 -0
  33. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/__init__.py +0 -0
  34. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/anilist.py +0 -0
  35. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/api_helpers.py +0 -0
  36. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/catalogue_tui.py +0 -0
  37. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/completions.py +0 -0
  38. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/config.py +0 -0
  39. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/download_utils.py +0 -0
  40. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/history.py +0 -0
  41. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/menus.py +0 -0
  42. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/planning.py +0 -0
  43. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/planning_tui.py +0 -0
  44. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/playback.py +0 -0
  45. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/runner.py +0 -0
  46. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/system_deps.py +0 -0
  47. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/standalone/terminal.py +0 -0
  48. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/src/anime_sama_api/utils.py +0 -0
  49. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/__init__.py +0 -0
  50. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/data/catalogue_data.py +0 -0
  51. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/data/episode_data.py +0 -0
  52. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/data/season_data.py +0 -0
  53. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_catalogue.py +0 -0
  54. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_cli_utils.py +0 -0
  55. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_download.py +0 -0
  56. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_seasons.py +0 -0
  57. {anime_sama_cli-1.1 → anime_sama_cli-2.0.1}/tests/test_top_level.py +0 -0
  58. {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: 1.1
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 requises
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 :** Afin que les covers 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.
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
- ### Debian / Ubuntu (et dérivés)
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
- ### Arch Linux (et dérivés)
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
- ### Fedora / RHEL (et dérivés)
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
- ### Debian / Ubuntu (et dérivés) — utiliser pipx uniquement
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` : l’environnement est « externally managed » et cela provoquera une erreur. Utilisez **pipx** pour installer l’application dans un environnement virtuel dédié.
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
- ### Autres distributions (Arch, Fedora, etc.)
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
- ## Utilisation
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 requises
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 :** Afin que les covers 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.
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 &lt; 3.11), `yt-dlp`.
28
+ Elles sont installées automatiquement avec le projet : `httpx`, `platformdirs`, `rich`, `textual`, `tomli` (si Python &lt; 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
- ### Debian / Ubuntu (et dérivés)
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
- ### Arch Linux (et dérivés)
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
- ### Fedora / RHEL (et dérivés)
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
- ### Debian / Ubuntu (et dérivés) — utiliser pipx uniquement
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` : l’environnement est « externally managed » et cela provoquera une erreur. Utilisez **pipx** pour installer l’application dans un environnement virtuel dédié.
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
- ### Autres distributions (Arch, Fedora, etc.)
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
- ## Utilisation
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 = "1.1"
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
- search = cast(list[str], re.findall(r"Actualité.+?>(.+?)<", await self.page()))
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], re.findall(r"Correspondance.+?>(.+?)<", await self.page())
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], re.findall(r"Synopsis[\W\w]+?>(.+)<", await self.page())
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.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
- break
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
- break
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
- for synopsis_m in re.finditer(r"Synopsis[\W\w]+?>(.+?)<", html):
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
- if raw and raw != "Synopsis" and len(raw) > 15:
84
- result["synopsis"] = raw
85
- break
86
- if not result["synopsis"]:
87
- synopsis_after = re.search(r"Synopsis\s*</[^>]+>\s*<[^>]+>(.+?)</[^>]+>", html, re.DOTALL)
88
- if synopsis_after:
89
- result["synopsis"] = html_module.unescape(synopsis_after.group(1).strip())
90
- genres_m = re.search(r"Genres[\W\w]+?>(.+?)<", html)
91
- if genres_m:
92
- result["genre"] = html_module.unescape(genres_m.group(1).strip())
93
- type_m = re.search(r"Types?[\W\w]+?>(.+?)<", html, re.IGNORECASE)
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"] = html_module.unescape(type_m.group(1).strip())
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 match in re.finditer(
109
- rf"href=\"({self.site_url}catalogue/.+)\"[\W\w]+?src=\"(.+?)\"[\W\w]+?<h2.+?>(.*)\n?<[\W\w]+?<p.+?>(.*)\n?<[\W\w]+?<p.+?>(.*)\n?<[\W\w]+?<p.+?>(.*)\n?<[\W\w]+?<p.+?>(.*)\n?<",
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
- url,
114
- image_url,
115
- name,
116
- alternative_names_str,
117
- genres_str,
118
- categories_str,
119
- languages_str,
120
- ) = (unescape(item) for item in match.groups())
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
- alternative_names_str.split(", ") if alternative_names_str else []
130
+ [a.strip() for a in alt_names_raw.split(",") if a.strip()]
131
+ if alt_names_raw
132
+ else []
124
133
  )
125
- if " - " in genres_str:
126
- genres = genres_str.split(" - ")
127
- else:
128
- genres = genres_str.split(", ") if genres_str else []
129
- categories = categories_str.split(", ") if categories_str else []
130
- languages = languages_str.split(", ") if languages_str else []
131
-
132
- # Normaliser les variantes du site (anime-sama utilise parfois des libellés incorrects)
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 match in re.finditer(
162
- rf"href=\"({self.site_url}catalogue/.+)\"[\W\w]+?src=\"(.+?)\"[\W\w]+?>(.*)\n?<[\W\w]+?>(.*)\n?<[\W\w]+?>(.*)\n?<[\W\w]+?>(.*)\n?<",
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
- season_url,
167
- image_url,
168
- serie_name,
169
- categories,
170
- language,
171
- descriptive,
172
- ) = match.groups()
173
- categories = categories.split(", ") if categories else ["Anime"]
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(
@@ -4,7 +4,7 @@ requires-python = ">=3.10"
4
4
 
5
5
  [[package]]
6
6
  name = "anime-sama-cli"
7
- version = "2.0.0"
7
+ version = "1.0.1"
8
8
  source = { editable = "." }
9
9
  dependencies = [
10
10
  { name = "httpx" },
File without changes
File without changes
File without changes