Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88743c101d |
8 changed files with 100 additions and 31 deletions
10
stream_fusion/utils/cache/cache.py
vendored
10
stream_fusion/utils/cache/cache.py
vendored
|
|
@ -19,7 +19,15 @@ def search_public(media):
|
||||||
cache_search["language"] = cache_search["languages"][0]
|
cache_search["language"] = cache_search["languages"][0]
|
||||||
# Wtf, why do we need to use __dict__ here? And also, why is it stuck when we use media directly?
|
# Wtf, why do we need to use __dict__ here? And also, why is it stuck when we use media directly?
|
||||||
response = requests.get(url, json=cache_search)
|
response = requests.get(url, json=cache_search)
|
||||||
return response.json()
|
try:
|
||||||
|
response.raise_for_status() # Lève une exception pour les codes d'état HTTP d'erreur (4xx ou 5xx)
|
||||||
|
return response.json()
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logger.error(f"Search: Erreur lors de la récupération des résultats du cache public: {e}")
|
||||||
|
return None
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
logger.error(f"Search: Erreur de décodage JSON pour le cache public: {e}. Contenu de la réponse: {response.text[:200]}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def cache_public(torrents: List[TorrentItem], media):
|
def cache_public(torrents: List[TorrentItem], media):
|
||||||
|
|
|
||||||
|
|
@ -105,18 +105,26 @@ class Torbox(BaseDebrid):
|
||||||
|
|
||||||
if existing_torrent:
|
if existing_torrent:
|
||||||
logger.info(f"Torbox: Found existing torrent with ID: {existing_torrent['id']}")
|
logger.info(f"Torbox: Found existing torrent with ID: {existing_torrent['id']}")
|
||||||
torrent_info = existing_torrent
|
torrent_id = existing_torrent["id"]
|
||||||
if not torrent_info or "id" not in torrent_info:
|
# Get full torrent info with files
|
||||||
logger.error("Torbox: Failed to add or find torrent.")
|
torrent_response = self.get_torrent_info(torrent_id)
|
||||||
|
if not torrent_response or "data" not in torrent_response:
|
||||||
|
logger.error("Torbox: Failed to get torrent info.")
|
||||||
return None
|
return None
|
||||||
torrent_id = torrent_info["id"]
|
torrent_info = torrent_response["data"]
|
||||||
else:
|
else:
|
||||||
# Add the magnet or torrent file
|
# Add the magnet or torrent file
|
||||||
torrent_info = self.add_magnet_or_torrent(magnet, torrent_download)
|
add_response = self.add_magnet_or_torrent(magnet, torrent_download)
|
||||||
if not torrent_info or "torrent_id" not in torrent_info:
|
if not add_response or "torrent_id" not in add_response:
|
||||||
logger.error("Torbox: Failed to add or find torrent.")
|
logger.error("Torbox: Failed to add or find torrent.")
|
||||||
return None
|
return None
|
||||||
torrent_id = torrent_info["torrent_id"]
|
torrent_id = add_response["torrent_id"]
|
||||||
|
# Get full torrent info with files
|
||||||
|
torrent_response = self.get_torrent_info(torrent_id)
|
||||||
|
if not torrent_response or "data" not in torrent_response:
|
||||||
|
logger.error("Torbox: Failed to get torrent info.")
|
||||||
|
return None
|
||||||
|
torrent_info = torrent_response["data"]
|
||||||
|
|
||||||
logger.info(f"Torbox: Working with torrent ID: {torrent_id}")
|
logger.info(f"Torbox: Working with torrent ID: {torrent_id}")
|
||||||
|
|
||||||
|
|
@ -237,14 +245,27 @@ class Torbox(BaseDebrid):
|
||||||
logger.error(f"Torbox: Invalid season/episode format: {season}/{episode}")
|
logger.error(f"Torbox: Invalid season/episode format: {season}/{episode}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
matching_files = [
|
logger.info(f"Torbox: DEBUG - Traitement de {len(files)} fichiers au total")
|
||||||
file for file in files
|
for i, file in enumerate(files):
|
||||||
if season_episode_in_filename(file["short_name"], numeric_season, numeric_episode) and is_video_file(file["short_name"])
|
logger.info(f"Torbox: DEBUG - Fichier {i+1}: {file['short_name']} (taille: {file['size']}, is_video: {is_video_file(file['short_name'])})")
|
||||||
]
|
|
||||||
|
matching_files = []
|
||||||
|
for file in files:
|
||||||
|
if is_video_file(file["short_name"]):
|
||||||
|
logger.info(f"Torbox: Vérification fichier vidéo: {file['short_name']}")
|
||||||
|
if season_episode_in_filename(file["short_name"], numeric_season, numeric_episode):
|
||||||
|
logger.info(f"Torbox: ✓ Match RTN pour {file['short_name']}")
|
||||||
|
matching_files.append(file)
|
||||||
|
else:
|
||||||
|
logger.info(f"Torbox: ✗ Pas de match RTN pour {file['short_name']}")
|
||||||
|
else:
|
||||||
|
logger.info(f"Torbox: Fichier ignoré (pas vidéo): {file['short_name']}")
|
||||||
|
|
||||||
|
logger.info(f"Torbox: {len(matching_files)} fichiers trouvés avec RTN pour S{numeric_season:02d}E{numeric_episode:02d}")
|
||||||
|
|
||||||
if matching_files:
|
if matching_files:
|
||||||
largest_matching_file = max(matching_files, key=lambda x: x["size"])
|
largest_matching_file = max(matching_files, key=lambda x: x["size"])
|
||||||
logger.info(f"Torbox: Selected largest matching file (ID: {largest_matching_file['id']}, Name: {largest_matching_file['name']}, Size: {largest_matching_file['size']}) for series")
|
logger.info(f"Torbox: Selected largest matching file (ID: {largest_matching_file['id']}, Name: {largest_matching_file['short_name']}, Size: {largest_matching_file['size']}) for series")
|
||||||
return largest_matching_file["id"]
|
return largest_matching_file["id"]
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Torbox: No matching files found for S{numeric_season:02d}E{numeric_episode:02d}, trying smart fallback")
|
logger.warning(f"Torbox: No matching files found for S{numeric_season:02d}E{numeric_episode:02d}, trying smart fallback")
|
||||||
|
|
@ -259,10 +280,27 @@ class Torbox(BaseDebrid):
|
||||||
for file in files if is_video_file(file["short_name"])
|
for file in files if is_video_file(file["short_name"])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
logger.info(f"Torbox: Appel du smart fallback avec {len(fallback_files)} fichiers")
|
||||||
|
for f in fallback_files:
|
||||||
|
logger.info(f"Torbox: Fichier fallback: {f.get('name')} (taille: {f.get('size')}, ID: {f.get('index')})")
|
||||||
|
|
||||||
fallback_file = smart_episode_fallback(fallback_files, numeric_season, numeric_episode)
|
fallback_file = smart_episode_fallback(fallback_files, numeric_season, numeric_episode)
|
||||||
if fallback_file:
|
if fallback_file:
|
||||||
logger.info(f"Torbox: Smart fallback selected file: {fallback_file.get('name')} (ID: {fallback_file.get('index')})")
|
logger.info(f"Torbox: Smart fallback a sélectionné: {fallback_file.get('name')} (ID: {fallback_file.get('index')})")
|
||||||
return fallback_file.get('index')
|
return fallback_file.get('index')
|
||||||
else:
|
else:
|
||||||
logger.error(f"Torbox: Smart fallback also failed for S{numeric_season:02d}E{numeric_episode:02d}")
|
logger.info("Torbox: Smart fallback n'a rien trouvé, essai du fallback final pour fichier unique")
|
||||||
return None
|
# Final fallback: for single-file torrents, just take the only video file
|
||||||
|
video_files = [f for f in files if is_video_file(f["short_name"])]
|
||||||
|
logger.info(f"Torbox: DEBUG - Trouvé {len(video_files)} fichiers vidéo dans le fallback final")
|
||||||
|
for vf in video_files:
|
||||||
|
logger.info(f"Torbox: DEBUG - Fichier vidéo: {vf['short_name']} (ID: {vf['id']})")
|
||||||
|
|
||||||
|
if len(video_files) == 1:
|
||||||
|
single_file = video_files[0]
|
||||||
|
logger.info(f"Torbox: Fichier vidéo unique détecté, utilisation: {single_file['short_name']} (ID: {single_file['id']})")
|
||||||
|
return single_file["id"]
|
||||||
|
else:
|
||||||
|
logger.error(f"Torbox: Le fallback intelligent a aussi échoué pour S{numeric_season:02d}E{numeric_episode:02d}")
|
||||||
|
logger.error(f"Torbox: Trouvé {len(video_files)} fichiers vidéo, attendu exactement 1 pour le fallback fichier unique")
|
||||||
|
return None
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,16 @@ class TMDB(MetadataProvider):
|
||||||
languages=self.config['languages']
|
languages=self.config['languages']
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
tmdb_id = data["tv_results"][0]["id"]
|
||||||
|
season_num = int(full_id[1])
|
||||||
|
episode_num = int(full_id[2])
|
||||||
|
|
||||||
result = Series(
|
result = Series(
|
||||||
id=id,
|
id=id,
|
||||||
tmdb_id = data["tv_results"][0]["id"],
|
tmdb_id=tmdb_id,
|
||||||
titles=[self.replace_weird_characters(data["tv_results"][0]["name"])],
|
titles=[self.replace_weird_characters(data["tv_results"][0]["name"])],
|
||||||
season="S{:02d}".format(int(full_id[1])),
|
season="S{:02d}".format(season_num),
|
||||||
episode="E{:02d}".format(int(full_id[2])),
|
episode="E{:02d}".format(episode_num),
|
||||||
languages=self.config['languages']
|
languages=self.config['languages']
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,15 @@ class Series(Media):
|
||||||
self.season = season
|
self.season = season
|
||||||
self.episode = episode
|
self.episode = episode
|
||||||
self.seasonfile = None
|
self.seasonfile = None
|
||||||
|
|
||||||
|
def get_season_number(self) -> int:
|
||||||
|
"""Extract season number from season string (e.g., 'S02' -> 2)"""
|
||||||
|
if self.season and self.season.startswith('S'):
|
||||||
|
return int(self.season[1:])
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_episode_number(self) -> int:
|
||||||
|
"""Extract episode number from episode string (e.g., 'E05' -> 5)"""
|
||||||
|
if self.episode and self.episode.startswith('E'):
|
||||||
|
return int(self.episode[1:])
|
||||||
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,7 @@ class TorrentService:
|
||||||
|
|
||||||
if season[0] in parsed_file.seasons and episode[0] in parsed_file.episodes:
|
if season[0] in parsed_file.seasons and episode[0] in parsed_file.episodes:
|
||||||
episode_files.append({
|
episode_files.append({
|
||||||
"file_index": file_index,
|
"file_index": None, # Let debrid service handle file selection
|
||||||
"title": file,
|
"title": file,
|
||||||
"size": files["length"]
|
"size": files["length"]
|
||||||
})
|
})
|
||||||
|
|
@ -266,7 +266,9 @@ class TorrentService:
|
||||||
# Doesn't that need to be indented?
|
# Doesn't that need to be indented?
|
||||||
file_index += 1
|
file_index += 1
|
||||||
|
|
||||||
return max(episode_files, key=lambda file: file["size"])
|
if episode_files:
|
||||||
|
return max(episode_files, key=lambda file: file["size"])
|
||||||
|
return None
|
||||||
|
|
||||||
def __find_full_index(self, file_structure):
|
def __find_full_index(self, file_structure):
|
||||||
self.logger.debug("Starting to build full index of video files")
|
self.logger.debug("Starting to build full index of video files")
|
||||||
|
|
|
||||||
|
|
@ -544,7 +544,9 @@ class TorrentSmartContainer:
|
||||||
return
|
return
|
||||||
file = max(files, key=lambda file: file["size"])
|
file = max(files, key=lambda file: file["size"])
|
||||||
torrent_item.availability = debrid
|
torrent_item.availability = debrid
|
||||||
torrent_item.file_index = file["file_index"]
|
# Only update file_index if it wasn't set to None for intelligent selection
|
||||||
|
if torrent_item.file_index is not None:
|
||||||
|
torrent_item.file_index = file["file_index"]
|
||||||
torrent_item.file_name = file["title"]
|
torrent_item.file_name = file["title"]
|
||||||
torrent_item.size = file["size"]
|
torrent_item.size = file["size"]
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ class YggflixAPI:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
pool_connections=10,
|
pool_connections=10,
|
||||||
pool_maxsize=10,
|
pool_maxsize=50,
|
||||||
max_retries=3,
|
max_retries=0,
|
||||||
timeout=10,
|
timeout=8,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Initialize the YggflixAPI class.
|
Initialize the YggflixAPI class.
|
||||||
|
|
|
||||||
|
|
@ -474,13 +474,16 @@ async def get_results(
|
||||||
|
|
||||||
if len(filtered_results) < min_results:
|
if len(filtered_results) < min_results:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Search: Insufficient filtered results ({len(filtered_results)}). Performing new search."
|
f"Search: Insufficient filtered results ({len(filtered_results)}). Searching for new torrents to add."
|
||||||
)
|
)
|
||||||
await redis_cache.delete(cache_key)
|
# Ne pas supprimer le cache, chercher de nouveaux torrents
|
||||||
unfiltered_results = await get_search_results(media, config)
|
new_results = await get_search_results(media, config)
|
||||||
unfiltered_results_dict = [item.to_dict() for item in unfiltered_results]
|
# Fusionner anciens + nouveaux (merge_items déduplique automatiquement)
|
||||||
await redis_cache.set(cache_key, unfiltered_results_dict, expiration=settings.redis_expiration)
|
all_results = merge_items(unfiltered_results, new_results)
|
||||||
filtered_results = filter_items(unfiltered_results, media, config=config)
|
# Mettre à jour le cache avec tous les résultats
|
||||||
|
await redis_cache.set(cache_key, [item.to_dict() for item in all_results], expiration=settings.redis_expiration)
|
||||||
|
# Refiltrer avec tous les résultats
|
||||||
|
filtered_results = filter_items(all_results, media, config=config)
|
||||||
|
|
||||||
logger.success(
|
logger.success(
|
||||||
f"Search: Final number of filtered results: {len(filtered_results)}"
|
f"Search: Final number of filtered results: {len(filtered_results)}"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue