patch
This commit is contained in:
parent
4e2171fcda
commit
449dfa0ec7
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
8
.idea/Animecli.iml
generated
Normal file
8
.idea/Animecli.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
12
.idea/material_theme_project_new.xml
generated
Normal file
12
.idea/material_theme_project_new.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MaterialThemeProjectNewConfig">
|
||||
<option name="metadata">
|
||||
<MTProjectMetadataState>
|
||||
<option name="migrated" value="true" />
|
||||
<option name="pristineConfig" value="false" />
|
||||
<option name="userId" value="6cf94393:1970244d378:-7ffa" />
|
||||
</MTProjectMetadataState>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Animecli.iml" filepath="$PROJECT_DIR$/.idea/Animecli.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
77
animecli.py
77
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 = [
|
||||
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
requests~=2.32.3
|
||||
yt-dlp~=2025.6.3.233020.dev0
|
||||
beautifulsoup4~=4.13.4
|
Loading…
x
Reference in New Issue
Block a user