From c366504868e3c2517adcd651962110858fc46b87 Mon Sep 17 00:00:00 2001 From: jcfp Date: Wed, 10 Feb 2021 14:12:06 +0100 Subject: [PATCH] add resolution pattern key to sorting (#1794) --- interfaces/Config/templates/config_sorting.tmpl | 15 ++++++++ sabnzbd/constants.py | 2 ++ sabnzbd/sorting.py | 33 +++++++++++++++++- tests/test_sorting.py | 46 +++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 tests/test_sorting.py diff --git a/interfaces/Config/templates/config_sorting.tmpl b/interfaces/Config/templates/config_sorting.tmpl index 2fdd0ca..322a0a1 100644 --- a/interfaces/Config/templates/config_sorting.tmpl +++ b/interfaces/Config/templates/config_sorting.tmpl @@ -131,6 +131,11 @@ $T('ep-us-name') + $T('Resolution'): + %r + 1080p + + $T('fileExt'): %ext avi @@ -246,6 +251,11 @@ 2009 + $T('Resolution'): + %r + 1080p + + $T('extension'): %ext avi @@ -408,6 +418,11 @@ 2000 + $T('Resolution'): + %r + 1080p + + $T('orgFilename'): %fn $T('sort-File') diff --git a/sabnzbd/constants.py b/sabnzbd/constants.py index eab736a..0eb2c80 100644 --- a/sabnzbd/constants.py +++ b/sabnzbd/constants.py @@ -141,6 +141,8 @@ year_match = r"[\W]([1|2]\d{3})([^\w]|$)" # Something '(YYYY)' or '.YYYY.' or ' sample_match = r"((^|[\W_])(sample|proof))" # something-sample or something-proof +resolution_match = r"(^|[\W_])((240|360|480|540|576|720|900|1080|1440|2160|4320)[piP])([\W_]|$)" # 576i, 720p, 1080P + class Status: COMPLETED = "Completed" # PP: Job is finished diff --git a/sabnzbd/sorting.py b/sabnzbd/sorting.py index 908fb05..294bf0f 100644 --- a/sabnzbd/sorting.py +++ b/sabnzbd/sorting.py @@ -38,7 +38,7 @@ from sabnzbd.filesystem import ( sanitize_foldername, clip_path, ) -from sabnzbd.constants import series_match, date_match, year_match, sample_match +from sabnzbd.constants import series_match, date_match, year_match, sample_match, resolution_match import sabnzbd.cfg as cfg from sabnzbd.nzbstuff import NzbObject @@ -359,6 +359,9 @@ class SeriesSorter: self.nzo, self.match_obj, self.original_job_name ) + def get_show_resolution(self): + self.show_info["resolution"] = get_resolution(self.original_job_name) + def get_values(self): """ Collect and construct all the values needed for path replacement """ try: @@ -374,6 +377,9 @@ class SeriesSorter: # - Episode Name self.get_showdescriptions() + # - Resolution + self.get_show_resolution() + return True except: @@ -422,6 +428,9 @@ class SeriesSorter: mapping.append(("%e", self.show_info["episode_num"])) mapping.append(("%0e", self.show_info["episode_num_alt"])) + # Replace resolution + mapping.append(("%r", self.show_info["resolution"])) + # Make sure unsupported %desc is removed mapping.append(("%desc", "")) @@ -635,6 +644,9 @@ class MovieSorter: year = "" self.movie_info["year"] = year + # Get resolution + self.movie_info["resolution"] = get_resolution(self.original_job_name) + # - Get Decades self.movie_info["decade"], self.movie_info["decade_two"] = get_decades(year) @@ -680,6 +692,9 @@ class MovieSorter: # Replace year mapping.append(("%y", self.movie_info["year"])) + # Replace resolution + mapping.append(("%r", self.movie_info["resolution"])) + # Replace decades mapping.append(("%decade", self.movie_info["decade"])) mapping.append(("%0decade", self.movie_info["decade_two"])) @@ -854,6 +869,9 @@ class DateSorter: # - Get Decades self.date_info["decade"], self.date_info["decade_two"] = get_decades(self.date_info["year"]) + # - Get resolution + self.date_info["resolution"] = get_resolution(self.original_job_name) + # - Get Title self.date_info["ttitle"], self.date_info["ttitle_two"], self.date_info["ttitle_three"] = get_titles( self.nzo, self.match_obj, self.original_job_name, True @@ -899,6 +917,9 @@ class DateSorter: mapping.append(("%year", self.date_info["year"])) mapping.append(("%y", self.date_info["year"])) + # Replace resolution + mapping.append(("%r", self.date_info["resolution"])) + if self.date_info["ep_name"]: mapping.append(("%desc", self.date_info["ep_name"])) mapping.append(("%.desc", self.date_info["ep_name_two"])) @@ -1129,6 +1150,16 @@ def get_decades(year): return decade, decade2 +def get_resolution(job_name): + try: + RE_RESOLUTION = re.compile(resolution_match) + # Use the last match, lowercased + resolution = RE_RESOLUTION.findall(job_name)[-1][1].lower() + except Exception: + resolution = "" + return resolution + + def check_for_folder(path): """ Return True if any folder is found in the tree at 'path' """ for _root, dirs, _files in os.walk(path): diff --git a/tests/test_sorting.py b/tests/test_sorting.py new file mode 100644 index 0000000..a5086c9 --- /dev/null +++ b/tests/test_sorting.py @@ -0,0 +1,46 @@ +#!/usr/bin/python3 -OO +# Copyright 2007-2021 The SABnzbd-Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +""" +tests.test_sorting - Testing functions in sorting.py +""" + +from sabnzbd import sorting +from tests.testhelper import * + + +class TestSorting: + @pytest.mark.parametrize( + "job_name, result", + [ + ("Ubuntu.optimized.for.1080p.Screens-Canonical", "1080p"), + ("Debian_for_240i_Scientific_Calculators-FTPMasters", "240i"), + ("OpenBSD Streaming Edition 4320P", "4320p"), # Lower-case result + ("Surely.1080p.is.better.than.720p", "720p"), # Last hit wins + ("2160p.Campaign.Video", "2160p"), # Resolution at the start + ("Some.Linux.Iso.1234p", ""), # Non-standard resolution + ("No.Resolution.Anywhere", ""), + ("not.keeping.its1080p.distance", ""), # No separation + ("not_keeping_1440idistance_either", ""), + ("240 is a semiperfect and highly composite number", ""), # Number only + (480, ""), + (None, ""), + ("", ""), + ], + ) + def test_get_resolution(self, job_name, result): + assert sorting.get_resolution(job_name) == result