diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..d34719a
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/Animecli.iml b/.idea/Animecli.iml
new file mode 100644
index 0000000..d8b3f6c
--- /dev/null
+++ b/.idea/Animecli.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml
new file mode 100644
index 0000000..bc106ba
--- /dev/null
+++ b/.idea/material_theme_project_new.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..1d3ce46
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..d1ff3f0
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/animecli.py b/animecli.py
index 5deb072..c730196 100644
--- a/animecli.py
+++ b/animecli.py
@@ -129,9 +129,15 @@ def extract_episode_sources(url_page):
return [(sources, None) for sources in episode_sources]
def format_dernier(dernier_url, saison):
- m = re.search(r'[Ee](\d{1,3})', dernier_url or "")
- ep = m.group(1) if m else "?"
- return f"Saison {saison}, épisode {ep}, {dernier_url or 'aucun'}"
+ if not dernier_url or dernier_url == "?":
+ return f"Saison {saison}, épisode ?, aucun"
+ m = re.search(r'[Ee](\d{1,3})', dernier_url)
+ if m:
+ ep = m.group(1)
+ else:
+ m2 = re.search(r'(\d{1,3})(?!.*\d)', dernier_url)
+ ep = m2.group(1) if m2 else "?"
+ return f"Saison {saison}, épisode {ep}, {dernier_url}"
def telecharger_episode(url, saison_folder, filename, qualite):
ydl_opts = {
@@ -195,27 +201,67 @@ def handle_multi_download(stdscr, conn):
return
selected = [False] * len(episode_data)
- cursor = 0
+ cursor = 0 # 0 = "Tout sélectionner", 1...N = épisodes
+ scroll_offset = 0
+
while True:
stdscr.clear()
+ max_y, max_x = stdscr.getmaxyx()
+ visible_lines = max_y - 3 # 1 ligne titre + 2 marges
+ total_lines = len(episode_data) + 1 # +1 pour "Tout sélectionner"
+
+ # Gestion du scroll
+ if cursor < scroll_offset:
+ scroll_offset = cursor
+ elif cursor >= scroll_offset + visible_lines:
+ scroll_offset = cursor - visible_lines + 1
+
stdscr.addstr(0, 0, "Sélectionnez les épisodes à télécharger (Espace pour cocher, Entrée pour valider) :")
- for idx, (sources, _) in enumerate(episode_data):
- mark = "[X]" if selected[idx] else "[ ]"
- line = f"{mark} Épisode {idx+1}"
- if idx == cursor:
+
+ # Affichage de la case "Tout sélectionner"
+ tout_sel = all(selected) and len(selected) > 0
+ mark = "[X]" if tout_sel else "[ ]"
+ y = 2
+ if scroll_offset == 0:
+ if cursor == 0:
stdscr.attron(curses.color_pair(1))
- safe_addstr(stdscr, 2 + idx, 2, line)
+ safe_addstr(stdscr, y, 2, f"{mark} Tout sélectionner")
stdscr.attroff(curses.color_pair(1))
else:
- safe_addstr(stdscr, 2 + idx, 2, line)
+ safe_addstr(stdscr, y, 2, f"{mark} Tout sélectionner")
+ y += 1
+
+ # Affichage des épisodes visibles
+ for idx in range(len(episode_data)):
+ line_idx = idx + 1 # +1 à cause de "Tout sélectionner"
+ if line_idx < scroll_offset:
+ continue
+ if y - 2 >= visible_lines:
+ break
+ mark = "[X]" if selected[idx] else "[ ]"
+ line = f"{mark} Épisode {idx+1}"
+ if cursor == line_idx:
+ stdscr.attron(curses.color_pair(1))
+ safe_addstr(stdscr, y, 2, line)
+ stdscr.attroff(curses.color_pair(1))
+ else:
+ safe_addstr(stdscr, y, 2, line)
+ y += 1
+
stdscr.refresh()
k = stdscr.getch()
if k == curses.KEY_UP and cursor > 0:
cursor -= 1
- elif k == curses.KEY_DOWN and cursor < len(episode_data) - 1:
+ elif k == curses.KEY_DOWN and cursor < total_lines - 1:
cursor += 1
elif k == ord(' '):
- selected[cursor] = not selected[cursor]
+ if cursor == 0:
+ # (Dé)sélectionner tout
+ new_val = not all(selected)
+ for i in range(len(selected)):
+ selected[i] = new_val
+ else:
+ selected[cursor - 1] = not selected[cursor - 1]
elif k in [curses.KEY_ENTER, 10, 13]:
break
@@ -260,6 +306,13 @@ def handle_multi_download(stdscr, conn):
else:
print(f"Echec téléchargement: {url}")
+ # Mise à jour du dernier épisode téléchargé
+ if to_download:
+ dernier_url = download_queue[-1][0]
+ c = conn.cursor()
+ c.execute("UPDATE animes SET dernier_episode = ? WHERE id = ?", (dernier_url, anime_id))
+ conn.commit()
+
def curses_menu(stdscr, conn):
curses.curs_set(0)
menu = [
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..a810877
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+requests~=2.32.3
+yt-dlp~=2025.6.3.233020.dev0
+beautifulsoup4~=4.13.4
\ No newline at end of file