From bbc5ce75487ed87a989253b444f53c71d757f7db Mon Sep 17 00:00:00 2001 From: Dreu LaVelle Date: Sun, 1 Sep 2024 02:18:26 -0500 Subject: [PATCH] feat: update RTN to latest --- poetry.lock | 36 ++---- pyproject.toml | 2 +- src/program/downloaders/alldebrid.py | 56 +++++----- src/program/downloaders/realdebrid.py | 6 +- src/program/downloaders/shared.py | 14 ++- src/program/downloaders/torbox.py | 67 +++++------- src/program/media/item.py | 2 +- src/program/media/stream.py | 6 +- src/program/media/subtitle.py | 4 + src/program/scrapers/__init__.py | 2 +- src/program/scrapers/shared.py | 47 ++++---- src/program/settings/models.py | 46 ++------ src/program/settings/versions.py | 151 ++------------------------ src/tests/test_settings_migration.py | 10 +- 14 files changed, 137 insertions(+), 312 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2da71495..71a09c78 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1419,27 +1419,15 @@ files = [ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] -[[package]] -name = "parse-torrent-title" -version = "2.8.1" -description = "Extract media information from torrent-like filename" -optional = false -python-versions = "*" -files = [ - {file = "parse-torrent-title-2.8.1.tar.gz", hash = "sha256:939647c4bfacd2b3b878503a7bf79fcdbb11e74a895a4550eb84406d62742457"}, - {file = "parse_torrent_title-2.8.1-py2-none-any.whl", hash = "sha256:0467809b5004065e29c60dfe120499f44832c0be49dc0e7583a1325dd81bbc88"}, - {file = "parse_torrent_title-2.8.1-py3-none-any.whl", hash = "sha256:b96ee593b25fbf07150066d9d8de488b17c15c92b8b05745f984ff47db7f9fcb"}, -] - [[package]] name = "parsett" -version = "0.2.4" +version = "1.2.3" description = "PTT" optional = false python-versions = "<4.0,>=3.11" files = [ - {file = "parsett-0.2.4-py3-none-any.whl", hash = "sha256:2a47634f2616fffe6e0fc574439692c3d938442daaea51320ecabe002e995aae"}, - {file = "parsett-0.2.4.tar.gz", hash = "sha256:aa609f253841fd8586414428965c4fcaae436a3ca655c0a572359f921b56f108"}, + {file = "parsett-1.2.3-py3-none-any.whl", hash = "sha256:22cba9f02bcda2e89269012248f3e60831cf34c090be34bdc6eea5e0c4c3ed8a"}, + {file = "parsett-1.2.3.tar.gz", hash = "sha256:7ed3e00ca4f4e2a5f471efbfef21955872b31b7882164c17834c75ed3ec67e4b"}, ] [package.dependencies] @@ -1969,19 +1957,18 @@ files = [ [[package]] name = "rank-torrent-name" -version = "0.2.23" +version = "1.0.2" description = "Parse Torrents using PTN and Rank them according to your preferences!" optional = false python-versions = "<4.0,>=3.11" files = [ - {file = "rank_torrent_name-0.2.23-py3-none-any.whl", hash = "sha256:61b96db32e6d37dec4101c86654d266bde04628c3ac983fe71b99c4614b4d9eb"}, - {file = "rank_torrent_name-0.2.23.tar.gz", hash = "sha256:50a66c789ef74c9d0f7bdb84a3921e9bcf6b3d2f5ae3ffcce44d3dfac2590c00"}, + {file = "rank_torrent_name-1.0.2-py3-none-any.whl", hash = "sha256:60c975afb796c86d3bce7a8af2380a16d6f24fe0d4c1dad94a7d0e0198de9595"}, + {file = "rank_torrent_name-1.0.2.tar.gz", hash = "sha256:c9a53d38b7f1d20e089ef61db9777f300a1c17cb5a8d33542db5957bd8bd7a90"}, ] [package.dependencies] levenshtein = ">=0.25.0,<0.26.0" -parse-torrent-title = ">=2.8.1,<3.0.0" -parsett = ">=0.2.4,<0.3.0" +parsett = ">=1.2.3,<2.0.0" pydantic = ">=2.6.3,<3.0.0" regex = ">=2023.12.25,<2024.0.0" @@ -2580,17 +2567,18 @@ weaviate = ["weaviate-client (>=4.5.4,<5.0.0)"] [[package]] name = "textual" -version = "0.78.0" +version = "0.79.1" description = "Modern Text User Interface framework" optional = false python-versions = "<4.0.0,>=3.8.1" files = [ - {file = "textual-0.78.0-py3-none-any.whl", hash = "sha256:c9d3c7dc467c37ee2e54a0283ac2c85dac35e4fc949518ed054a65b8e3e9b822"}, - {file = "textual-0.78.0.tar.gz", hash = "sha256:421f508b0d41ea0b8ecf273bf83f0d19376667eb0a87f70575252395d90ab315"}, + {file = "textual-0.79.1-py3-none-any.whl", hash = "sha256:75f26c0a8829560a1a8cc739f758c2c1c684246e27166acb3f4ad40110200692"}, + {file = "textual-0.79.1.tar.gz", hash = "sha256:2aaa9778beac5e56957794ee492bd8d281d39516ccb0e507e726484a1327d8b2"}, ] [package.dependencies] markdown-it-py = {version = ">=2.1.0", extras = ["linkify", "plugins"]} +platformdirs = ">=4.2.2,<5.0.0" rich = ">=13.3.3" typing-extensions = ">=4.4.0,<5.0.0" @@ -3074,4 +3062,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "e668457d12d7221e673db6829dfaa03ff7b13eb23b5c66c9498eb02e7383e3ca" +content-hash = "da0c08520f7c877a0926c8b9e838c8ad3234d20836b2721c6fe9d63b1760b557" diff --git a/pyproject.toml b/pyproject.toml index ee322900..d98d09f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ uvicorn = {extras = ["standard"], version = "^0.30.6"} apscheduler = "^3.10.4" regex = "^2023.12.25" coverage = "^7.5.4" -rank-torrent-name = "0.2.23" cachetools = "^5.3.3" loguru = "^0.7.2" rich = "^13.7.1" @@ -34,6 +33,7 @@ alembic = "^1.13.2" psycopg2-binary = "^2.9.9" apprise = "^1.8.1" subliminal = "^2.2.1" +rank-torrent-name = "^1.0.2" [tool.poetry.group.dev.dependencies] pyright = "^1.1.352" diff --git a/src/program/downloaders/alldebrid.py b/src/program/downloaders/alldebrid.py index ed21434e..ec247163 100644 --- a/src/program/downloaders/alldebrid.py +++ b/src/program/downloaders/alldebrid.py @@ -17,7 +17,7 @@ from requests import ConnectTimeout from RTN.exceptions import GarbageTorrent from RTN.parser import parse -from RTN.patterns import extract_episodes +from RTN.extras import extract_episodes from utils.logger import logger from utils.ratelimiter import RateLimiter from utils.request import get, ping, post @@ -266,13 +266,12 @@ def _is_wanted_movie(self, file: dict, item: Movie) -> bool: if not isinstance(file, dict) or file.get("s", 0) < min_size or file.get("s", 0) > max_size or splitext(file.get("n", "").lower())[1] not in WANTED_FORMATS: return False - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["n"], remove_trash=True) - if parsed_file and parsed_file.type == "movie": - item.set("folder", item.active_stream.get("name")) - item.set("alternative_folder", item.active_stream.get("alternative_name", None)) - item.set("file", file["n"]) - return True + parsed_file = parse(file["n"]) + if parsed_file and parsed_file.type == "movie": + item.set("folder", item.active_stream.get("name")) + item.set("alternative_folder", item.active_stream.get("alternative_name", None)) + item.set("file", file["n"]) + return True return False def _is_wanted_episode(self, file: dict, item: Episode) -> bool: @@ -289,13 +288,12 @@ def _is_wanted_episode(self, file: dict, item: Episode) -> bool: one_season = len(item.parent.parent.seasons) == 1 - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["n"], remove_trash=True) - if parsed_file and item.number in parsed_file.episode and (item.parent.number in parsed_file.season or one_season): - item.set("folder", item.active_stream.get("name")) - item.set("alternative_folder", item.active_stream.get("alternative_name")) - item.set("file", file["n"]) - return True + parsed_file = parse(file["n"]) + if parsed_file and item.number in parsed_file.episodes and (item.parent.number in parsed_file.seasons or one_season): + item.set("folder", item.active_stream.get("name")) + item.set("alternative_folder", item.active_stream.get("alternative_name")) + item.set("file", file["n"]) + return True return False def _is_wanted_season(self, files: list, item: Season) -> bool: @@ -324,12 +322,11 @@ def _is_wanted_season(self, files: list, item: Season) -> bool: season_num = item.number for file in filenames: - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["n"], remove_trash=True) - if parsed_file and (season_num in parsed_file.season or one_season): - for ep_num in parsed_file.episode: - if ep_num in needed_episodes: - matched_files[ep_num] = file["n"] + parsed_file = parse(file["n"]) + if parsed_file and (season_num in parsed_file.seasons or one_season): + for ep_num in parsed_file.episodes: + if ep_num in needed_episodes: + matched_files[ep_num] = file["n"] if not matched_files: return False @@ -375,15 +372,14 @@ def _is_wanted_show(self, files: list, item: Show) -> bool: matched_files = {} for file in filenames: - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["n"], remove_trash=True) - if parsed_file: - for season_number, episodes in needed_episodes.items(): - if season_number in parsed_file.season: - for episode_number in list(episodes): - if episode_number in parsed_file.episode: - matched_files[(season_number, episode_number)] = file - episodes.remove(episode_number) + parsed_file = parse(file["n"]) + if parsed_file: + for season_number, episodes in needed_episodes.items(): + if season_number in parsed_file.seasons: + for episode_number in list(episodes): + if episode_number in parsed_file.episodes: + matched_files[(season_number, episode_number)] = file + episodes.remove(episode_number) if not matched_files: return False diff --git a/src/program/downloaders/realdebrid.py b/src/program/downloaders/realdebrid.py index b38001e4..93930368 100644 --- a/src/program/downloaders/realdebrid.py +++ b/src/program/downloaders/realdebrid.py @@ -2,15 +2,13 @@ from requests import ConnectTimeout from program.media.item import MediaItem from utils.ratelimiter import RateLimiter -from .shared import FileFinder +from .shared import FileFinder, VIDEO_EXTENSIONS import utils.request as request from loguru import logger from program.settings.manager import settings_manager as settings BASE_URL = "https://api.real-debrid.com/rest/1.0" -VIDEO_EXTENSIONS = [ - 'mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'm4v', 'webm', 'mpg', 'mpeg', 'm2ts', 'ts' -] + torrent_limiter = RateLimiter(1, 1) overall_limiter = RateLimiter(60, 60) diff --git a/src/program/downloaders/shared.py b/src/program/downloaders/shared.py index 7bbae3ce..422950ff 100644 --- a/src/program/downloaders/shared.py +++ b/src/program/downloaders/shared.py @@ -2,8 +2,18 @@ from program.media.item import MediaItem from program.media.state import States +from program.settings.manager import settings_manager + + +DEFAULT_VIDEO_EXTENSIONS = ["mp4", "mkv", "avi"] +ALLOWED_VIDEO_EXTENSIONS = ["mp4", "mkv", "avi", "mov", "wmv", "flv", "m4v", "webm", "mpg", "mpeg", "m2ts", "ts"] + +VIDEO_EXTENSIONS = settings_manager.settings.downloaders.video_extensions or DEFAULT_VIDEO_EXTENSIONS +VIDEO_EXTENSIONS = [ext for ext in VIDEO_EXTENSIONS if ext in ALLOWED_VIDEO_EXTENSIONS] + +if not VIDEO_EXTENSIONS: + VIDEO_EXTENSIONS = DEFAULT_VIDEO_EXTENSIONS -WANTED_FORMATS = {".mkv", ".mp4", ".avi"} class FileFinder: """ @@ -26,7 +36,7 @@ def get_cached_container(self, needed_media: dict[int, list[int]], break_pointer def filename_matches_show(self, filename): try: parsed_data = parse(filename) - return parsed_data.season[0], parsed_data.episode + return parsed_data.seasons[0], parsed_data.episodes except Exception: return None, None diff --git a/src/program/downloaders/torbox.py b/src/program/downloaders/torbox.py index 1420c2d2..a4d24f00 100644 --- a/src/program/downloaders/torbox.py +++ b/src/program/downloaders/torbox.py @@ -146,12 +146,12 @@ def find_required_files(self, item, container): and splitext(file["name"].lower())[1] in WANTED_FORMATS ] + parsed_file = parse(file["name"]) + if item.type == "movie": for file in files: - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["name"], remove_trash=True) - if parsed_file.type == "movie": - return [file] + if parsed_file.type == "movie": + return [file] if item.type == "show": # Create a dictionary to map seasons and episodes needed needed_episodes = {} @@ -179,22 +179,17 @@ def find_required_files(self, item, container): # the season and episode within the show matched_files = [] for file in files: - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["name"], remove_trash=True) - if ( - not parsed_file - or not parsed_file.parsed_title - or 0 in parsed_file.season - ): - continue - # Check each season and episode to find a match - for season_number, episodes in needed_episodes.items(): - if season_number in parsed_file.season: - for episode_number in list(episodes): - if episode_number in parsed_file.episode: - # Store the matched file for this episode - matched_files.append(file) - episodes.remove(episode_number) + if not parsed_file.seasons or parsed_file.seasons == [0]: + continue + + # Check each season and episode to find a match + for season_number, episodes in needed_episodes.items(): + if season_number in parsed_file.season: + for episode_number in list(episodes): + if episode_number in parsed_file.episode: + # Store the matched file for this episode + matched_files.append(file) + episodes.remove(episode_number) if not matched_files: return False @@ -217,19 +212,13 @@ def find_required_files(self, item, container): for file in files: if not file or not file.get("name"): continue - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["name"], remove_trash=True) - if ( - not parsed_file - or not parsed_file.episode - or 0 in parsed_file.season - ): - continue - # Check if the file's season matches the item's season or if there's only one season - if season_num in parsed_file.season or one_season: - for ep_num in parsed_file.episode: - if ep_num in needed_episodes: - matched_files.append(file) + if not parsed_file.seasons or parsed_file.seasons == [0]: # skip specials + continue + # Check if the file's season matches the item's season or if there's only one season + if season_num in parsed_file.seasons or one_season: + for ep_num in parsed_file.episodes: + if ep_num in needed_episodes: + matched_files.append(file) if not matched_files: return False @@ -240,13 +229,11 @@ def find_required_files(self, item, container): for file in files: if not file or not file.get("name"): continue - with contextlib.suppress(GarbageTorrent, TypeError): - parsed_file = parse(file["name"], remove_trash=True) - if ( - item.number in parsed_file.episode - and item.parent.number in parsed_file.season - ): - return [file] + if ( + item.number in parsed_file.episodes + and item.parent.number in parsed_file.seasons + ): + return [file] return [] diff --git a/src/program/media/item.py b/src/program/media/item.py index a65cb43a..cc522dad 100644 --- a/src/program/media/item.py +++ b/src/program/media/item.py @@ -650,7 +650,7 @@ def get_file_episodes(self) -> List[int]: if not self.file or not isinstance(self.file, str): raise ValueError("The file attribute must be a non-empty string.") # return list of episodes - return parse(self.file).episode + return parse(self.file).episodes @property def log_string(self): diff --git a/src/program/media/stream.py b/src/program/media/stream.py index b241b328..e6f07065 100644 --- a/src/program/media/stream.py +++ b/src/program/media/stream.py @@ -1,10 +1,14 @@ +from typing import TYPE_CHECKING from RTN import Torrent from sqlalchemy import Index from program.db.db import db import sqlalchemy from sqlalchemy.orm import Mapped, mapped_column, relationship -from loguru import logger + +if TYPE_CHECKING: + from program.media.item import MediaItem + class StreamRelation(db.Model): __tablename__ = "StreamRelation" diff --git a/src/program/media/subtitle.py b/src/program/media/subtitle.py index 1238fba1..e0d38665 100644 --- a/src/program/media/subtitle.py +++ b/src/program/media/subtitle.py @@ -2,6 +2,10 @@ from program.db.db import db from sqlalchemy import Integer, String, ForeignKey, Index from sqlalchemy.orm import Mapped, mapped_column, relationship +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from program.media.item import MediaItem class Subtitle(db.Model): diff --git a/src/program/scrapers/__init__.py b/src/program/scrapers/__init__.py index 0e36cec4..d58f5ed8 100644 --- a/src/program/scrapers/__init__.py +++ b/src/program/scrapers/__init__.py @@ -114,7 +114,7 @@ def run_service(service, item,): if sorted_streams and (log and settings_manager.settings.debug): item_type = item.type.title() - top_results = sorted(sorted_streams.values(), key=lambda x: x.rank, reverse=True)[:10] + top_results = list(sorted_streams.values())[:10] for sorted_tor in top_results: if isinstance(item, (Movie, Show)): logger.debug(f"[{item_type}] Parsed '{sorted_tor.parsed_title}' with rank {sorted_tor.rank} and ratio {sorted_tor.lev_ratio:.2f}: '{sorted_tor.raw_title}'") diff --git a/src/program/scrapers/shared.py b/src/program/scrapers/shared.py index 0e2185c1..bdd02fa4 100644 --- a/src/program/scrapers/shared.py +++ b/src/program/scrapers/shared.py @@ -14,7 +14,7 @@ settings_model = settings_manager.settings.ranking ranking_model = models.get(settings_model.profile) -rtn = RTN(settings_model, ranking_model, 0.821) +rtn = RTN(settings_model, ranking_model) def _get_stremio_identifier(item: MediaItem) -> str: @@ -53,55 +53,56 @@ def _parse_results(item: MediaItem, results: Dict[str, str]) -> Dict[str, Stream raw_title=raw_title, infohash=infohash, correct_title=correct_title, - remove_trash=True + remove_trash=settings_manager.settings.ranking.options["remove_all_trash"] ) if not torrent or not torrent.fetch: continue if isinstance(item, Movie): - if hasattr(item, "aired_at"): - # If the item has an aired_at date and it's not in the future, we can check the year - if item.aired_at <= datetime.now() and item.aired_at.year == torrent.data.year: - torrents.add(torrent) - else: - # This is a questionable move. - torrents.add(torrent) + if not torrent.data.year or not hasattr(item, "aired_at") or not item.aired_at or item.aired_at > datetime.now(): + continue + + year_range = [item.aired_at.year - 1, item.aired_at.year, item.aired_at.year + 1] + if torrent.data.year not in year_range: + continue + + torrents.add(torrent) elif isinstance(item, Show): if not needed_seasons: logger.error(f"No seasons found for {item.log_string}") break if ( - hasattr(torrent.data, "season") - and len(torrent.data.season) >= (len(needed_seasons) - 1) + hasattr(torrent.data, "seasons") + and len(torrent.data.seasons) >= (len(needed_seasons) - 1) and ( - not hasattr(torrent.data, "episode") - or len(torrent.data.episode) == 0 + not hasattr(torrent.data, "episodes") + or len(torrent.data.episodes) == 0 ) - or torrent.data.is_complete + or torrent.data.complete ): torrents.add(torrent) elif isinstance(item, Season): if ( - len(getattr(torrent.data, "season", [])) == 1 - and item.number in torrent.data.season + len(getattr(torrent.data, "seasons", [])) == 1 + and item.number in torrent.data.seasons and ( - not hasattr(torrent.data, "episode") - or len(torrent.data.episode) == 0 + not hasattr(torrent.data, "episodes") + or len(torrent.data.episodes) == 0 ) - or torrent.data.is_complete + or torrent.data.complete ): torrents.add(torrent) elif isinstance(item, Episode) and ( - item.number in torrent.data.episode + item.number in torrent.data.episodes and ( - not hasattr(torrent.data, "season") - or item.parent.number in torrent.data.season + not hasattr(torrent.data, "seasons") + or item.parent.number in torrent.data.seasons ) - or torrent.data.is_complete + or torrent.data.complete ): torrents.add(torrent) diff --git a/src/program/settings/models.py b/src/program/settings/models.py index b61a7b29..6f63b7a1 100644 --- a/src/program/settings/models.py +++ b/src/program/settings/models.py @@ -1,11 +1,11 @@ """Riven settings models""" from pathlib import Path import re -from typing import Any, Callable, Dict, List +from typing import Any, Callable, List from program.settings.migratable import MigratableBaseModel from pydantic import BaseModel, field_validator -from RTN.models import CustomRank, SettingsModel +from RTN.models import SettingsModel from utils import root_dir @@ -59,10 +59,11 @@ class TorboxModel(Observable): class DownloadersModel(Observable): - movie_filesize_min: int = 200 # MB - movie_filesize_max: int = -1 # MB (-1 is no limit) - episode_filesize_min: int = 40 # MB - episode_filesize_max: int = -1 # MB (-1 is no limit) + video_extensions: List[str] = ["mp4", "mkv", "avi"] + # movie_filesize_min: int = 200 # MB + # movie_filesize_max: int = -1 # MB (-1 is no limit) + # episode_filesize_min: int = 40 # MB + # episode_filesize_max: int = -1 # MB (-1 is no limit) real_debrid: RealDebridModel = RealDebridModel() all_debrid: AllDebridModel = AllDebridModel() torbox: TorboxModel = TorboxModel() @@ -279,39 +280,6 @@ class ScraperModel(Observable): class RTNSettingsModel(SettingsModel, Observable): profile: str = "default" - custom_ranks: Dict[str, CustomRank] = { - "uhd": CustomRank(fetch=False, rank=120), - "fhd": CustomRank(fetch=True, rank=100), - "hd": CustomRank(fetch=True, rank=80), - "sd": CustomRank(fetch=False, rank=-120), - "bluray": CustomRank(fetch=True, rank=80), - "hdr": CustomRank(fetch=False, rank=80), - "hdr10": CustomRank(fetch=False, rank=90), - "dolby_video": CustomRank(fetch=False, rank=-100), - "dts_x": CustomRank(fetch=False, rank=0), - "dts_hd": CustomRank(fetch=False, rank=0), - "dts_hd_ma": CustomRank(fetch=False, rank=0), - "atmos": CustomRank(fetch=False, rank=0), - "truehd": CustomRank(fetch=False, rank=0), - "ddplus": CustomRank(fetch=False, rank=0), - "aac": CustomRank(fetch=True, rank=70), - "ac3": CustomRank(fetch=True, rank=50), - "remux": CustomRank(fetch=False, rank=-1000), - "webdl": CustomRank(fetch=True, rank=90), - "repack": CustomRank(fetch=True, rank=5), - "proper": CustomRank(fetch=True, rank=4), - "dubbed": CustomRank(fetch=True, rank=3), - "subbed": CustomRank(fetch=True, rank=3), - "av1": CustomRank(fetch=False, rank=0), - "h264": CustomRank(fetch=True, rank=0), - "h265": CustomRank(fetch=True, rank=0), - "hevc": CustomRank(fetch=True, rank=0), - "avc": CustomRank(fetch=True, rank=0), - "dvdrip": CustomRank(fetch=True, rank=-100), - "bdrip": CustomRank(fetch=True, rank=5), - "brrip": CustomRank(fetch=True, rank=0), - "hdtv": CustomRank(fetch=True, rank=-100), - } # Application Settings diff --git a/src/program/settings/versions.py b/src/program/settings/versions.py index 6b35d8ce..cf54e9a2 100644 --- a/src/program/settings/versions.py +++ b/src/program/settings/versions.py @@ -1,158 +1,27 @@ -from RTN.models import BaseRankingModel +from RTN.models import BaseRankingModel, DefaultRanking, BestRanking from utils.logger import logger -class DefaultRanking(BaseRankingModel): - uhd: int = -1000 - fhd: int = 100 - hd: int = 50 - sd: int = -100 - dolby_video: int = -100 - aac: int = 70 - ac3: int = 50 - remux: int = -1000 - webdl: int = 90 - bluray: int = 80 - dvdrip: int = -100 - hdtv: int = -100 - - -class BestRemuxRanking(BaseRankingModel): - uhd: int = 100 - fhd: int = 60 - hd: int = 40 - sd: int = 20 - dolby_video: int = 100 - hdr: int = 80 - hdr10: int = 90 - dts_x: int = 100 - dts_hd: int = 80 - dts_hd_ma: int = 90 - atmos: int = 90 - truehd: int = 60 - aac: int = 30 - ac3: int = 20 - remux: int = 150 - webdl: int = -1000 - - -class BestWebRanking(BaseRankingModel): - uhd: int = 100 - fhd: int = 90 - hd: int = 80 - sd: int = 20 - dolby_video: int = 100 - hdr: int = 80 - hdr10: int = 90 - aac: int = 50 - ac3: int = 40 - remux: int = -1000 - webdl: int = 100 - - -class BestResolutionRanking(BaseRankingModel): - uhd: int = 100 - fhd: int = 90 - hd: int = 80 - sd: int = 70 - dolby_video: int = 100 - hdr: int = 80 - hdr10: int = 90 - dts_x: int = 100 - dts_hd: int = 80 - dts_hd_ma: int = 90 - atmos: int = 90 - truehd: int = 60 - ddplus: int = 90 - aac: int = 30 - ac3: int = 20 - remux: int = 150 - bluray: int = 120 - webdl: int = -1000 - - -class BestOverallRanking(BaseRankingModel): - uhd: int = 100 - fhd: int = 90 - hd: int = 80 - sd: int = 70 - dolby_video: int = 100 - hdr: int = 80 - hdr10: int = 90 - dts_x: int = 100 - dts_hd: int = 80 - dts_hd_ma: int = 90 - atmos: int = 90 - truehd: int = 60 - ddplus: int = 40 - aac: int = 30 - ac3: int = 20 - remux: int = 150 - bluray: int = 120 - webdl: int = 90 - - -class AnimeRanking(BaseRankingModel): - uhd: int = -1000 - fhd: int = 90 - hd: int = 80 - sd: int = 20 - aac: int = 70 - ac3: int = 50 - remux: int = -1000 - webdl: int = 90 - bluray: int = 50 - dubbed: int = 100 - subbed: int = 100 - - -class AllRanking(BaseRankingModel): - uhd: int = 1 - fhd: int = 1 - hd: int = 1 - sd: int = 1 - dolby_video: int = 1 - hdr: int = 1 - dts_x: int = 1 - dts_hd: int = 1 - dts_hd_ma: int = 1 - atmos: int = 1 - truehd: int = 1 - ddplus: int = 1 - aac: int = 2 - ac3: int = 1 - remux: int = 1 - webdl: int = 1 - bluray: int = 1 - - class RankModels: """ The `RankModels` class represents a collection of ranking models for different categories. Each ranking model is a subclass of the `BaseRankingModel` class. Attributes: - `default` (DefaultRanking): The default ranking model. - `remux` (BestRemuxRanking): The ranking model for the best remux. - `web` (BestWebRanking): The ranking model for the best web release. - `resolution` (BestResolutionRanking): The ranking model for the best resolution. - `overall` (BestOverallRanking): The ranking model for the best overall quality. - `anime` (AnimeRanking): The ranking model for anime releases. - `all` (AllRanking): The ranking model for all releases. + `default` (DefaultRanking): The default ranking model for getting best results for non-transcoded releases. + `custom` (BaseRankingModel): Uses a base ranking model for all categories with all ranks set to 0. + `best` (BestRanking): The best ranking model for getting the highest quality releases. Methods: `get(name: str)` -> `BaseRankingModel`: Returns a ranking model based on the given name. - If the name is not found, the default ranking model is returned. + + Note: + If the name is not found, use the `custom` model which uses a base ranking model for all categories with all ranks set to 0. """ - default: DefaultRanking = DefaultRanking() - custom: BaseRankingModel = BaseRankingModel() - remux: BestRemuxRanking = BestRemuxRanking() - web: BestWebRanking = BestWebRanking() - resolution: BestResolutionRanking = BestResolutionRanking() - overall: BestOverallRanking = BestOverallRanking() - anime: AnimeRanking = AnimeRanking() - all: AllRanking = AllRanking() + custom: BaseRankingModel = BaseRankingModel() # All ranks set to 0 by default + default: DefaultRanking = DefaultRanking() # Good for 720p/1080p releases + best: BestRanking = BestRanking() # Good for 4K HDR REMUX releases @classmethod def get(cls, name: str) -> BaseRankingModel: diff --git a/src/tests/test_settings_migration.py b/src/tests/test_settings_migration.py index 3ed369f7..981d9ad1 100644 --- a/src/tests/test_settings_migration.py +++ b/src/tests/test_settings_migration.py @@ -16,10 +16,10 @@ "map_metadata": True, "tracemalloc": False, "downloaders": { - "movie_filesize_min": 200, - "movie_filesize_max": -1, - "episode_filesize_min": 40, - "episode_filesize_max": -1, + # "movie_filesize_min": 200, + # "movie_filesize_max": -1, + # "episode_filesize_min": 40, + # "episode_filesize_max": -1, "real_debrid": { "enabled": False, "api_key": "", @@ -58,7 +58,7 @@ def test_load_and_migrate_settings(): assert settings_manager.settings.force_refresh is False assert settings_manager.settings.map_metadata is True assert settings_manager.settings.tracemalloc is False - assert settings_manager.settings.downloaders.movie_filesize_min == 200 + # assert settings_manager.settings.downloaders.movie_filesize_min == 200 assert settings_manager.settings.downloaders.real_debrid.enabled is False assert settings_manager.settings.downloaders.all_debrid.enabled is True assert settings_manager.settings.downloaders.all_debrid.api_key == "12345678"