Compare commits

...

3 Commits

Author SHA1 Message Date
Safihre
d8ab19087d Update text files for 3.4.2 2021-10-15 08:19:00 +02:00
Safihre
ec8a79eedd Revert to using regex based sample detection
Closes #1964
2021-10-13 18:24:48 +02:00
Safihre
f1e2a8e9d8 Prevent double guessit parsing 2021-10-12 09:02:03 +02:00
7 changed files with 58 additions and 67 deletions

View File

@@ -1,7 +1,7 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 3.4.2RC3
Summary: SABnzbd-3.4.2RC3
Version: 3.4.2
Summary: SABnzbd-3.4.2
Home-page: https://sabnzbd.org
Author: The SABnzbd Team
Author-email: team@sabnzbd.org

View File

@@ -1,4 +1,4 @@
Release Notes - SABnzbd 3.4.2 Release Candidate 2
Release Notes - SABnzbd 3.4.2
=========================================================
## Bugfixes since 3.4.1
@@ -6,6 +6,7 @@ Release Notes - SABnzbd 3.4.2 Release Candidate 2
Warning will be shown if no category is selected.
- Sorting would fail if `%ext` or `%fn` was not used.
- Job failure due to Sorting-problems was not shown in the History.
- `Ignore Samples` did not remove all sample files.
- Crash when `.par2` files were missing during download.
- Prevent scanning the whole file to identify the correct extension.
- `.rXX`, `.cbz` and `.cbr` extensions were wrongly renamed.

View File

@@ -43,6 +43,7 @@ from sabnzbd.filesystem import userxbit
TAB_UNITS = ("", "K", "M", "G", "T", "P")
RE_UNITS = re.compile(r"(\d+\.*\d*)\s*([KMGTP]?)", re.I)
RE_VERSION = re.compile(r"(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)")
RE_SAMPLE = re.compile(r"((^|[\W_])(sample|proof))", re.I) # something-sample or something-proof
RE_IP4 = re.compile(r"inet\s+(addr:\s*)?(\d+\.\d+\.\d+\.\d+)")
RE_IP6 = re.compile(r"inet6\s+(addr:\s*)?([0-9a-f:]+)", re.I)
@@ -808,6 +809,11 @@ def get_all_passwords(nzo) -> List[str]:
return unique_passwords
def is_sample(filename: str) -> bool:
"""Try to determine if filename is (most likely) a sample"""
return bool(re.search(RE_SAMPLE, filename))
def find_on_path(targets):
"""Search the PATH for a program and return full path"""
if sabnzbd.WIN32:

View File

@@ -39,7 +39,7 @@ from sabnzbd.newsunpack import (
is_sfv_file,
)
from threading import Thread
from sabnzbd.misc import on_cleanup_list
from sabnzbd.misc import on_cleanup_list, is_sample
from sabnzbd.filesystem import (
real_path,
get_unique_path,
@@ -65,7 +65,7 @@ from sabnzbd.filesystem import (
get_filename,
)
from sabnzbd.nzbstuff import NzbObject
from sabnzbd.sorting import Sorter, is_sample
from sabnzbd.sorting import Sorter
from sabnzbd.constants import (
REPAIR_PRIORITY,
FORCE_PRIORITY,

View File

@@ -39,6 +39,7 @@ from sabnzbd.filesystem import (
)
import sabnzbd.cfg as cfg
from sabnzbd.constants import EXCLUDED_GUESSIT_PROPERTIES, IGNORED_MOVIE_FOLDERS
from sabnzbd.misc import is_sample
from sabnzbd.nzbstuff import NzbObject, scan_password
# Do not rename .vob files as they are usually DVD's
@@ -357,7 +358,8 @@ class SeriesSorter(BaseSorter):
def match(self):
"""Try to guess series info if config and category sort out or force is set"""
if self.force or (cfg.enable_tv_sorting() and cfg.tv_sort_string() and self.cat.lower() in self.cats):
self.guess = guess_what(self.original_job_name, sort_type="episode")
if not self.guess:
self.guess = guess_what(self.original_job_name, sort_type="episode")
if self.guess.get("type") == "episode" and "date" not in self.guess:
logging.debug("Using tv sorter for %s", self.original_job_name)
self.matched = True
@@ -424,7 +426,8 @@ class MovieSorter(BaseSorter):
def match(self):
"""Try to guess movie info if config and category sort out or force is set"""
if self.force or (cfg.enable_movie_sorting() and self.sort_string and self.cat.lower() in self.cats):
self.guess = guess_what(self.original_job_name, sort_type="movie")
if not self.guess:
self.guess = guess_what(self.original_job_name, sort_type="movie")
if self.guess.get("type") == "movie":
logging.debug("Using movie sorter for %s", self.original_job_name)
self.matched = True
@@ -509,7 +512,8 @@ class DateSorter(BaseSorter):
def match(self):
"""Checks the category for a match, if so set self.matched to true"""
if self.force or (cfg.enable_date_sorting() and self.sort_string and self.cat.lower() in self.cats):
self.guess = guess_what(self.original_job_name, sort_type="episode")
if not self.guess:
self.guess = guess_what(self.original_job_name, sort_type="episode")
if self.guess.get("type") == "episode" and "date" in self.guess:
logging.debug("Using date sorter for %s", self.original_job_name)
self.matched = True
@@ -627,40 +631,9 @@ def guess_what(name: str, sort_type: Optional[str] = None) -> MatchesDict:
):
guess["type"] = "unknown"
# Remove sample indicators from groupnames, e.g. 'sample-groupname' or 'groupname-proof'
group = guess.get("release_group", "")
if group.lower().startswith(("sample-", "proof-")) or group.lower().endswith(("-sample", "-proof")):
# Set clean groupname
guess["release_group"] = re.sub("^(sample|proof)-|-(sample|proof)$", "", group, re.I)
# Add 'Sample' property to the guess
other = guess.get("other")
if not other:
guess.setdefault("other", "Sample")
else:
if "Sample" not in guess["other"]:
# Pre-existing 'other' may be a string or a list
try:
guess["other"].append("Sample")
except AttributeError:
guess["other"] = [other, "Sample"]
return guess
def is_sample(filename: str) -> bool:
"""Try to determine if filename belongs to a sample"""
if os.path.splitext(filename)[0].lower().strip() in ("sample", "proof"):
# The entire filename is just 'sample.ext' or similar
return True
# If that didn't work, start guessing
guess = guess_what(filename).get("other", "")
if isinstance(guess, list):
return any(item in ("Sample", "Proof") for item in guess)
else:
return guess in ("Sample", "Proof")
def path_subst(path: str, mapping: List[Tuple[str, str]]) -> str:
"""Replace the sort string elements in the path with the real values provided by the mapping;
non-elements are copied verbatim."""

View File

@@ -214,6 +214,44 @@ class TestMisc:
os.unlink("test.cert")
os.unlink("test.key")
@pytest.mark.parametrize(
"name, result",
[
("Free.Open.Source.Movie.2001.1080p.WEB-DL.DD5.1.H264-FOSS", False), # Not samples
("Setup.exe", False),
("23.123.hdtv-rofl", False),
("Something.1080p.WEB-DL.DD5.1.H264-EMRG-sample", True), # Samples
("Something.1080p.WEB-DL.DD5.1.H264-EMRG-sample.ogg", True),
("Sumtin_Else_1080p_WEB-DL_DD5.1_H264_proof-EMRG", True),
("Wot.Eva.540i.WEB-DL.aac.H264-Groupie sample.mp4", True),
("file-sample.mkv", True),
("PROOF.JPG", True),
("Bla.s01e02.title.1080p.aac-sample proof.mkv", True),
("Bla.s01e02.title.1080p.aac-proof.mkv", True),
("Bla.s01e02.title.1080p.aac sample proof.mkv", True),
("Bla.s01e02.title.1080p.aac proof.mkv", True),
("Lwtn.s08e26.1080p.web.h264-glhf-sample.par2", True),
("Lwtn.s08e26.1080p.web.h264-glhf-sample.vol001-002.par2", True),
("Look at That 2011 540i WEB-DL.H265-NoSample", False),
],
)
def test_is_sample(self, name, result):
assert misc.is_sample(name) == result
@pytest.mark.parametrize(
"name, result",
[
("Not Death Proof (2022) 1080p x264 (DD5.1) BE Subs", False), # Try to trigger some false positives
("Proof.of.Everything.(2042).4320p.x266-4U", False),
("Crime_Scene_S01E13_Free_Sample_For_Sale_480p-OhDear", False),
("Sample That 2011 480p WEB-DL.H265-aMiGo", False),
("NOT A SAMPLE.JPG", False),
],
)
def test_is_sample_known_false_positives(self, name, result):
"""We know these fail, but don't have a better solution for them at the moment."""
assert misc.is_sample(name) != result
@pytest.mark.parametrize(
"test_input, expected_output",
[

View File

@@ -66,7 +66,7 @@ class TestSortingFunctions:
"country": "US",
},
),
("Test Movie 720p HDTV AAC x265 sample-MYgroup", {"release_group": "MYgroup", "other": "Sample"}),
("Test Movie 720p HDTV AAC x265 MYgroup-Sample", {"release_group": "MYgroup", "other": "Sample"}),
(None, None), # Jobname missing
("", None),
],
@@ -86,33 +86,6 @@ class TestSortingFunctions:
else:
assert guess[key] == value
@pytest.mark.parametrize(
"name, result",
[
("Free.Open.Source.Movie.2001.1080p.WEB-DL.DD5.1.H264-FOSS", False), # Not samples
("Setup.exe", False),
("23.123.hdtv-rofl", False),
("Something.1080p.WEB-DL.DD5.1.H264-EMRG-sample", True), # Samples
("Something.1080p.WEB-DL.DD5.1.H264-EMRG-sample.ogg", True),
("Sumtin_Else_1080p_WEB-DL_DD5.1_H264_proof-EMRG", True),
("Wot.Eva.540i.WEB-DL.aac.H264-Groupie sample.mp4", True),
("file-sample.mkv", True),
("PROOF.JPG", True),
("Bla.s01e02.title.1080p.aac-sample proof.mkv", True),
("Bla.s01e02.title.1080p.aac-proof.mkv", True),
("Bla.s01e02.title.1080p.aac sample proof.mkv", True),
("Bla.s01e02.title.1080p.aac proof.mkv", True),
("Not Death Proof (2022) 1080p x264 (DD5.1) BE Subs", False), # Try to trigger some false positives
("Proof.of.Everything.(2042).4320p.x266-4U", False),
("Crime_Scene_S01E13_Free_Sample_For_Sale_480p-OhDear", False),
("Sample That 2011 480p WEB-DL.H265-aMiGo", False),
("Look at That 2011 540i WEB-DL.H265-NoSample", False),
("NOT A SAMPLE.JPG", False),
],
)
def test_is_sample(self, name, result):
assert sorting.is_sample(name) == result
@pytest.mark.parametrize("platform", ["linux", "darwin", "win32"])
@pytest.mark.parametrize(
"path, result_unix, result_win",