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