mirror of
https://github.com/Benexl/FastAnime.git
synced 2026-01-01 15:35:55 -08:00
chore: correct package issues
This commit is contained in:
134
viu_cli/cli/utils/parser.py
Normal file
134
viu_cli/cli/utils/parser.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""Episode range parsing utilities for Viu CLI commands."""
|
||||
|
||||
from typing import Iterator
|
||||
|
||||
|
||||
def parse_episode_range(
|
||||
episode_range_str: str | None, available_episodes: list[str]
|
||||
) -> Iterator[str]:
|
||||
"""
|
||||
Parse an episode range string and return an iterator of episode numbers.
|
||||
|
||||
This function handles various episode range formats:
|
||||
- Single episode: "5" -> episodes from index 5 onwards
|
||||
- Range with start and end: "5:10" -> episodes from index 5 to 10 (exclusive)
|
||||
- Range with step: "5:10:2" -> episodes from index 5 to 10 with step 2
|
||||
- Start only: "5:" -> episodes from index 5 onwards
|
||||
- End only: ":10" -> episodes from beginning to index 10
|
||||
- All episodes: ":" -> all episodes
|
||||
|
||||
Args:
|
||||
episode_range_str: The episode range string to parse (e.g., "5:10", "5:", ":10", "5")
|
||||
available_episodes: List of available episode numbers/identifiers
|
||||
|
||||
Returns:
|
||||
Iterator over the selected episode numbers
|
||||
|
||||
Raises:
|
||||
ValueError: If the episode range format is invalid
|
||||
IndexError: If the specified indices are out of range
|
||||
|
||||
Examples:
|
||||
>>> episodes = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
|
||||
>>> list(parse_episode_range("2:5", episodes))
|
||||
['3', '4', '5']
|
||||
>>> list(parse_episode_range("5:", episodes))
|
||||
['6', '7', '8', '9', '10']
|
||||
>>> list(parse_episode_range(":3", episodes))
|
||||
['1', '2', '3']
|
||||
>>> list(parse_episode_range("2:8:2", episodes))
|
||||
['3', '5', '7']
|
||||
"""
|
||||
if not episode_range_str:
|
||||
# No range specified, return all episodes
|
||||
return iter(available_episodes)
|
||||
|
||||
# Sort episodes numerically for consistent ordering
|
||||
episodes = sorted(available_episodes, key=float)
|
||||
|
||||
if ":" in episode_range_str:
|
||||
# Handle colon-separated ranges
|
||||
parts = episode_range_str.split(":")
|
||||
|
||||
if len(parts) == 3:
|
||||
# Format: start:end:step
|
||||
start_str, end_str, step_str = parts
|
||||
if not all([start_str, end_str, step_str]):
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"When using 3 parts (start:end:step), all parts must be non-empty."
|
||||
)
|
||||
|
||||
try:
|
||||
start_idx = int(start_str)
|
||||
end_idx = int(end_str)
|
||||
step = int(step_str)
|
||||
|
||||
if step <= 0:
|
||||
raise ValueError("Step value must be positive")
|
||||
|
||||
return iter(episodes[start_idx:end_idx:step])
|
||||
except ValueError as e:
|
||||
if "invalid literal" in str(e):
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"All parts must be valid integers."
|
||||
) from e
|
||||
raise
|
||||
|
||||
elif len(parts) == 2:
|
||||
# Format: start:end or start: or :end
|
||||
start_str, end_str = parts
|
||||
|
||||
if start_str and end_str:
|
||||
# Both start and end specified: start:end
|
||||
try:
|
||||
start_idx = int(start_str)
|
||||
end_idx = int(end_str)
|
||||
return iter(episodes[start_idx:end_idx])
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"Start and end must be valid integers."
|
||||
) from e
|
||||
|
||||
elif start_str and not end_str:
|
||||
# Only start specified: start:
|
||||
try:
|
||||
start_idx = int(start_str)
|
||||
return iter(episodes[start_idx:])
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"Start must be a valid integer."
|
||||
) from e
|
||||
|
||||
elif not start_str and end_str:
|
||||
# Only end specified: :end
|
||||
try:
|
||||
end_idx = int(end_str)
|
||||
return iter(episodes[:end_idx])
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"End must be a valid integer."
|
||||
) from e
|
||||
|
||||
else:
|
||||
# Both empty: ":"
|
||||
return iter(episodes)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"Too many colon separators."
|
||||
)
|
||||
else:
|
||||
# Single number: start from that index onwards
|
||||
try:
|
||||
start_idx = int(episode_range_str)
|
||||
return iter(episodes[start_idx:])
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
f"Invalid episode range format: '{episode_range_str}'. "
|
||||
"Must be a valid integer."
|
||||
) from e
|
||||
Reference in New Issue
Block a user