Skip to content

Commit

Permalink
feat: enhance filesize validation for movies and episodes, improve lo…
Browse files Browse the repository at this point in the history
…gging and delete invalid torrents
  • Loading branch information
davidemarcoli committed Nov 6, 2024
1 parent 95e0cba commit dfcd589
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 29 deletions.
6 changes: 6 additions & 0 deletions src/program/services/downloaders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ def update_item_attributes(self, item: MediaItem, info, container) -> bool:
item.active_stream = {"infohash": info["hash"], "id": info["id"]}
found = True
break
else:
logger.debug(f"Deleting {info['id']} because it doesn't match the item type or size")
self.delete_torrent(info["id"])
if item.type in ["show", "season", "episode"]:
show = item
if item.type == "season":
Expand All @@ -117,4 +120,7 @@ def update_item_attributes(self, item: MediaItem, info, container) -> bool:
# We have to make sure the episode is correct if item is an episode
if item.type != "episode" or (item.type == "episode" and episode.number == item.number):
found = True
else:
logger.debug(f"Deleting {info['id']} because it doesn't match the item type or size")
self.delete_torrent(info["id"])
return found
82 changes: 55 additions & 27 deletions src/program/services/downloaders/shared.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from abc import ABC, abstractmethod
from datetime import datetime
from typing import Tuple

from loguru import logger
from RTN import parse
Expand Down Expand Up @@ -124,41 +125,68 @@ def hash_from_uri(magnet_uri: str) -> str:
max_episode_filesize = settings_manager.settings.downloaders.episode_filesize_mb_max
are_filesizes_valid = False

def _validate_filesizes() -> bool:
if not isinstance(settings_manager.settings.downloaders.movie_filesize_mb_min, int) or settings_manager.settings.downloaders.movie_filesize_mb_min < -1:
logger.error("Movie filesize min is not set or invalid.")
return False
if not isinstance(settings_manager.settings.downloaders.movie_filesize_mb_max, int) or settings_manager.settings.downloaders.movie_filesize_mb_max < -1:
logger.error("Movie filesize max is not set or invalid.")
return False
if not isinstance(settings_manager.settings.downloaders.episode_filesize_mb_min, int) or settings_manager.settings.downloaders.episode_filesize_mb_min < -1:
logger.error("Episode filesize min is not set or invalid.")
return False
if not isinstance(settings_manager.settings.downloaders.episode_filesize_mb_max, int) or settings_manager.settings.downloaders.episode_filesize_mb_max < -1:
logger.error("Episode filesize max is not set or invalid.")
def _validate_filesize_setting(value: int, setting_name: str) -> bool:
"""Validate a single filesize setting."""
if not isinstance(value, int) or value < -1:
logger.error(f"{setting_name} is not valid. Got {value}, expected integer >= -1")
return False
return True

def _validate_filesizes() -> bool:
"""
Validate all filesize settings from configuration.
Returns True if all settings are valid integers >= -1, False otherwise.
"""
settings = settings_manager.settings.downloaders
return all([
_validate_filesize_setting(settings.movie_filesize_mb_min, "Movie filesize min"),
_validate_filesize_setting(settings.movie_filesize_mb_max, "Movie filesize max"),
_validate_filesize_setting(settings.episode_filesize_mb_min, "Episode filesize min"),
_validate_filesize_setting(settings.episode_filesize_mb_max, "Episode filesize max")
])

are_filesizes_valid = _validate_filesizes()

def filesize_is_acceptable_movie(filesize):
BYTES_PER_MB = 1_000_000

def _convert_to_bytes(size_mb: int) -> int:
"""Convert size from megabytes to bytes."""
return size_mb * BYTES_PER_MB

def _get_size_limits(media_type: str) -> Tuple[int, int]:
"""Get min and max size limits in MB for given media type."""
settings = settings_manager.settings.downloaders
if media_type == "movie":
return (settings.movie_filesize_mb_min, settings.movie_filesize_mb_max)
return (settings.episode_filesize_mb_min, settings.episode_filesize_mb_max)

def _validate_filesize(filesize: int, media_type: str) -> bool:
"""
Validate file size against configured limits.
Args:
filesize: Size in bytes to validate
media_type: Type of media being validated
Returns:
bool: True if size is within configured range
"""
if not are_filesizes_valid:
logger.error("Filesize settings are invalid, movie file sizes will not be checked.")
logger.error(f"Filesize settings are invalid, {media_type.name.lower()} file sizes will not be checked.")
return True
min_size = settings_manager.settings.downloaders.movie_filesize_mb_min * 1_000_000
max_size = settings_manager.settings.downloaders.movie_filesize_mb_max * 1_000_000 if settings_manager.settings.downloaders.movie_filesize_mb_max != -1 else float("inf")

min_mb, max_mb = _get_size_limits(media_type)
min_size = 0 if min_mb == -1 else _convert_to_bytes(min_mb)
max_size = float("inf") if max_mb == -1 else _convert_to_bytes(max_mb)

is_acceptable = min_size <= filesize <= max_size
if not is_acceptable:
logger.debug(f"Filesize {filesize} is not within acceptable range {min_size} - {max_size}")
logger.debug(f"{media_type} filesize {filesize} bytes is not within acceptable range {min_size} - {max_size} bytes")
return is_acceptable

def filesize_is_acceptable_show(filesize):
if not are_filesizes_valid:
logger.error("Filesize settings are invalid, episode file sizes will not be checked.")
return True
min_size = settings_manager.settings.downloaders.episode_filesize_mb_min * 1_000_000
max_size = settings_manager.settings.downloaders.episode_filesize_mb_max * 1_000_000 if settings_manager.settings.downloaders.episode_filesize_mb_max != -1 else float("inf")
is_acceptable = min_size <= filesize <= max_size
if not is_acceptable:
logger.debug(f"Filesize {filesize} is not within acceptable range {min_size} - {max_size}")
return is_acceptable

def filesize_is_acceptable_movie(filesize: int) -> bool:
return _validate_filesize(filesize, "movie")

def filesize_is_acceptable_show(filesize: int) -> bool:
return _validate_filesize(filesize, "show")
4 changes: 2 additions & 2 deletions src/program/settings/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ class TorboxModel(Observable):
class DownloadersModel(Observable):
video_extensions: List[str] = ["mp4", "mkv", "avi"]
prefer_speed_over_quality: bool = True
movie_filesize_mb_min: int = -1 # MB
movie_filesize_mb_min: int = 0 # MB
movie_filesize_mb_max: int = -1 # MB (-1 is no limit)
episode_filesize_mb_min: int = -1 # MB
episode_filesize_mb_min: int = 0 # MB
episode_filesize_mb_max: int = -1 # MB (-1 is no limit)
real_debrid: RealDebridModel = RealDebridModel()
all_debrid: AllDebridModel = AllDebridModel()
Expand Down

0 comments on commit dfcd589

Please sign in to comment.