示例#1
0
    def test_rich_comparison_and_len(self):
        """
        Test rich comparison and length
        """
        # dicts for testing
        dict_0 = {}  # Empty dictionary
        dict_1 = {1: 'Elephant'}  # Single numeric key
        dict_2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys

        # Construct NumDicts from dicts
        num_dict = NumDict()
        num_dict_0 = NumDict(dict_0)
        num_dict_1 = NumDict(dict_1)
        num_dict_2 = NumDict(dict_2)

        # Construct NumDicts from NumDicts
        num_dict_from_num_dict = NumDict(num_dict)
        num_dict_from_num_dict_0 = NumDict(num_dict_0)
        num_dict_from_num_dict_1 = NumDict(num_dict_1)
        num_dict_from_num_dict_2 = NumDict(num_dict_2)

        all_dicts = [
            dict_0, dict_1, dict_2, num_dict, num_dict_0, num_dict_1,
            num_dict_2, num_dict_from_num_dict, num_dict_from_num_dict_0,
            num_dict_from_num_dict_1, num_dict_from_num_dict_2
        ]
        for val_a in all_dicts:
            for val_b in all_dicts:
                self.assertEqual(val_a == val_b, len(val_a) == len(val_b))
示例#2
0
class Overview(object):  # pylint: disable=too-few-public-methods
    UNAIRED = UNAIRED  # 1
    SNATCHED = SNATCHED  # 2
    WANTED = WANTED  # 3
    GOOD = DOWNLOADED  # 4
    SKIPPED = SKIPPED  # 5
    SNATCHED_PROPER = SNATCHED_PROPER  # 9
    SNATCHED_BEST = SNATCHED_BEST  # 1
    SNATCHED_FRENCH = SNATCHED_FRENCH  # 13

    # Should suffice!
    QUAL = 50

    overviewStrings = NumDict({
        SKIPPED: "skipped",
        WANTED: "wanted",
        QUAL: "qual",
        GOOD: "good",
        UNAIRED: "unaired",
        SNATCHED: "snatched",
        # we can give these a different class later, otherwise
        # breaks checkboxes in displayShow for showing different statuses
        SNATCHED_BEST: "snatched",
        SNATCHED_PROPER: "snatched",
        SNATCHED_FRENCH: "snatched"
    })
示例#3
0
    def test_rich_comparison_and_len(self):
        # dicts for testing
        d0 = {}  # Empty dictionary
        d1 = {1: 'Elephant'}  # Single numeric key
        d2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys

        # Construct NumDicts from dicts
        n = NumDict()
        n0 = NumDict(d0)
        n1 = NumDict(d1)
        n2 = NumDict(d2)

        # Construct NumDicts from NumDicts
        nn = NumDict(n)
        nn0 = NumDict(n0)
        nn1 = NumDict(n1)
        nn2 = NumDict(n2)

        all_dicts = [d0, d1, d2, n, n0, n1, n2, nn, nn0, nn1, nn2]
        for a in all_dicts:
            for b in all_dicts:
                self.assertEqual(a == b, len(a) == len(b))
示例#4
0
    def test_dict_access_and_mod(self):
        """
        Test num dict access and modification
        """
        # dicts for testing
        dict_0 = {}  # Empty dictionary
        dict_1 = {1: 'Elephant'}  # Single numeric key
        dict_2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys

        #  Construct NumDicts from dicts
        num_dict_0 = NumDict()
        num_dict_1 = NumDict(dict_1)
        num_dict_2 = NumDict(dict_2)

        # test __getitem__
        self.assertEqual(num_dict_2[1], 'Elephant')
        with self.assertRaises(KeyError):
            _ = num_dict_1['Mouse']  # key is not numeric
        with self.assertRaises(KeyError):
            _ = num_dict_1.__getitem__('Mouse')  # key is not numeric
        with self.assertRaises(KeyError):
            _ = num_dict_1[None]  # key does not exist
        with self.assertRaises(KeyError):
            _ = num_dict_1.__getitem__(None)  # key does not exist

        # Test __setitem__
        num_dict_3 = NumDict(num_dict_2)
        self.assertEqual(num_dict_2, num_dict_3)

        num_dict_3[2] = 'Frog'
        self.assertNotEqual(num_dict_2, num_dict_3)

        # Check None keys and numeric key conversion
        num_dict_3['3'] = 'Armadillo'
        num_dict_3[None] = 'Cockroach'

        # Check long ints
        num_dict_3[12390809518259081208909880312] = 'Squid'
        num_dict_3['12390809518259081208909880312'] = 'Octopus'
        self.assertEqual(num_dict_3[12390809518259081208909880312], 'Octopus')

        with self.assertRaises(TypeError):
            num_dict_3.__setitem__('Gorilla', 1)  # key is not numeric
        with self.assertRaises(TypeError):
            num_dict_3['Chimpanzee'] = 1  # key is not numeric
        with self.assertRaises(TypeError):
            num_dict_3[(4, 1)] = 1  # key is not numeric
        with self.assertRaises(TypeError):
            num_dict_3[[1, 3, 4]] = 1  # key is not numeric and is not hashable

        # Test __delitem__
        del num_dict_3[3]
        del num_dict_3[None]
        with self.assertRaises(KeyError):
            del num_dict_3[3]  # already deleted
        with self.assertRaises(KeyError):
            num_dict_3.__delitem__(3)  # already deleted
        with self.assertRaises(KeyError):
            del num_dict_3[
                'Mouse']  # key would not exist, since it is not numeric

        # Test clear
        num_dict_3.clear()
        self.assertEqual(num_dict_3, {})

        # Test copy()
        num_dict_2a = dict_2.copy()
        self.assertEqual(num_dict_2, num_dict_2a)
        num_dict_2b = num_dict_2.copy()
        self.assertEqual(num_dict_2b, num_dict_2)
        num_dict_2c = UserDict({1: 'Elephant', 2: 'Mouse'})
        num_dict_2d = num_dict_2c.copy(
        )  # making a copy of a UserDict is special cased
        self.assertEqual(num_dict_2c, num_dict_2d)

        class MyNumDict(NumDict):
            """
            subclass Numdict for testing
            """
            def display(self):
                """
                add a method to subclass to differentiate from superclass
                """
                print('MyNumDict:', self)

        my_num_dict = MyNumDict(num_dict_2)
        my_num_dict_a = my_num_dict.copy()
        self.assertEqual(my_num_dict_a, my_num_dict)

        my_num_dict[1] = 'Frog'
        self.assertNotEqual(my_num_dict_a, my_num_dict)

        # Test keys, items, values
        self.assertEqual(sorted(six.iterkeys(num_dict_2)),
                         sorted(six.iterkeys(dict_2)))
        self.assertEqual(sorted(six.iteritems(num_dict_2)),
                         sorted(six.iteritems(dict_2)))
        self.assertEqual(sorted(six.itervalues(num_dict_2)),
                         sorted(six.itervalues(dict_2)))

        # Test "in".
        for i in num_dict_2:
            self.assertIn(i, num_dict_2)
            self.assertEqual(i in num_dict_1, i in dict_1)
            self.assertEqual(i in num_dict_0, i in dict_0)

        self.assertFalse(None in num_dict_2)
        self.assertEqual(None in num_dict_2, None in dict_2)

        dict_2[None] = 'Cow'
        num_dict_2[None] = dict_2[None]
        self.assertTrue(None in num_dict_2)
        self.assertEqual(None in num_dict_2, None in dict_2)

        self.assertFalse('Penguin' in num_dict_2)

        # Test update
        test = NumDict()
        test.update(dict_2)
        self.assertEqual(test, num_dict_2)

        # Test get
        for i in num_dict_2:
            self.assertEqual(num_dict_2.get(i), num_dict_2[i])
            self.assertEqual(num_dict_1.get(i), dict_1.get(i))
            self.assertEqual(num_dict_0.get(i), dict_0.get(i))

        for i in ['purple', None, 12312301924091284, 23]:
            self.assertEqual(num_dict_2.get(i), dict_2.get(i), i)

        with self.assertRaises(AssertionError):
            i = '1'
            self.assertEqual(
                num_dict_2.get(i), dict_2.get(i),
                i)  # dict_2 expects string key which does not exist

        # Test "in" iteration.
        num_dict_2b = num_dict_2
        for i in range(20):
            num_dict_2[i] = six.text_type(i)
            num_dict_2b[six.text_type(i)] = six.text_type(i)
        self.assertEqual(num_dict_2, num_dict_2b)

        ikeys = []
        for k in num_dict_2:
            ikeys.append(k)
        self.assertEqual(set(ikeys), set(num_dict_2.keys()))

        # Test setdefault
        val = 1
        test = NumDict()
        self.assertEqual(test.setdefault(val, 42), 42)
        self.assertEqual(test.setdefault(val, '42'), 42)
        self.assertNotEqual(test.setdefault(val, 42), '42')
        self.assertNotEqual(test.setdefault(val, '42'), '42')
        self.assertIn(val, test)

        self.assertEqual(test.setdefault(val, 23), 42)
        self.assertEqual(test.setdefault(val, '23'), 42)
        self.assertNotEqual(test.setdefault(val, 23), '42')
        self.assertNotEqual(test.setdefault(val, '23'), '42')
        self.assertIn(val, test)

        # Test pop
        val = 1
        test = NumDict({val: 42})
        self.assertEqual(test.pop(val), 42)
        self.assertRaises(KeyError, test.pop, val)
        self.assertEqual(test.pop(val, 1), 1)
        test[val] = 42
        self.assertEqual(test.pop(val, 1), 42)

        # Test popitem
        val = 1
        test = NumDict({val: 42})
        self.assertEqual(test.popitem(), (val, 42))
        self.assertRaises(KeyError, test.popitem)
示例#5
0
    def test_constructors(self):
        """
        Test NumDict constructors
        """
        # dicts for testing
        dict_0 = {}  # Empty dictionary
        dict_1 = {1: 'Elephant'}  # Single numeric key
        dict_2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys
        dict_3 = {'3': 'Aardvark'}  # Numeric string key
        dict_4 = {'3': 'Aardvark', '4': 'Ant'}  # Multiple numeric string keys
        dict_5 = {
            5: 'Cat',
            '6': 'Dog'
        }  # Mixed numeric and numeric string keys
        dict_6 = {1: None, '2': None}  # None as values
        dict_7 = {None: 'Empty'}  # None as key

        # Construct NumDicts from dicts
        num_dict = NumDict()
        num_dict_0 = NumDict(dict_0)
        num_dict_1 = NumDict(dict_1)
        num_dict_2 = NumDict(dict_2)
        num_dict_3 = NumDict(dict_3)
        num_dict_4 = NumDict(dict_4)
        num_dict_5 = NumDict(dict_5)
        num_dict_6 = NumDict(dict_6)
        num_dict_7 = NumDict(dict_7)

        # Most NumDicts from dicts should compare equal...
        self.assertEqual(num_dict, {})
        self.assertEqual(num_dict_0, dict_0)
        self.assertEqual(num_dict_1, dict_1)
        self.assertEqual(num_dict_2, dict_2)

        # ...however, numeric keys are not equal to numeric string keys...
        self.assertNotEqual(num_dict_3, dict_3)
        self.assertNotEqual(num_dict_4, dict_4)
        self.assertNotEqual(num_dict_5, dict_5)
        self.assertNotEqual(num_dict_6, dict_6)

        # ...but None keys work just fine
        self.assertEqual(num_dict_7, dict_7)

        # Construct dicts from NumDicts
        dict_from_num_dict = dict(num_dict)
        dict_from_num_dict_1 = dict(num_dict_1)
        dict_from_num_dict_2 = dict(num_dict_2)
        dict_from_num_dict_3 = dict(num_dict_3)
        dict_from_num_dict_4 = dict(num_dict_4)
        dict_from_num_dict_5 = dict(num_dict_5)
        dict_from_num_dict_6 = dict(num_dict_6)
        dict_from_num_dict_7 = dict(num_dict_7)

        # All dicts from NumDicts should compare equal
        self.assertEqual(num_dict, dict_from_num_dict)
        self.assertEqual(num_dict_1, dict_from_num_dict_1)
        self.assertEqual(num_dict_2, dict_from_num_dict_2)
        self.assertEqual(num_dict_3, dict_from_num_dict_3)
        self.assertEqual(num_dict_4, dict_from_num_dict_4)
        self.assertEqual(num_dict_5, dict_from_num_dict_5)
        self.assertEqual(num_dict_6, dict_from_num_dict_6)
        self.assertEqual(num_dict_7, dict_from_num_dict_7)

        # Construct NumDicts from NumDicts
        num_dict_from_num_dict = NumDict(num_dict)
        num_dict_from_num_dict_0 = NumDict(num_dict_0)
        num_dict_from_num_dict_1 = NumDict(num_dict_1)
        num_dict_from_num_dict_2 = NumDict(num_dict_2)
        num_dict_from_num_dict_3 = NumDict(num_dict_3)
        num_dict_from_num_dict_4 = NumDict(num_dict_4)
        num_dict_from_num_dict_5 = NumDict(num_dict_5)
        num_dict_from_num_dict_6 = NumDict(num_dict_6)
        num_dict_from_num_dict_7 = NumDict(num_dict_7)

        # All NumDicts from NumDicts should compare equal
        self.assertEqual(num_dict, num_dict_from_num_dict)
        self.assertEqual(num_dict_0, num_dict_from_num_dict_0)
        self.assertEqual(num_dict_1, num_dict_from_num_dict_1)
        self.assertEqual(num_dict_2, num_dict_from_num_dict_2)
        self.assertEqual(num_dict_3, num_dict_from_num_dict_3)
        self.assertEqual(num_dict_4, num_dict_from_num_dict_4)
        self.assertEqual(num_dict_5, num_dict_from_num_dict_5)
        self.assertEqual(num_dict_6, num_dict_from_num_dict_6)
        self.assertEqual(num_dict_7, num_dict_from_num_dict_7)

        # keyword arg constructor should fail
        with self.assertRaises(TypeError):
            NumDict(
                one=1,
                two=2)  # Raise TypeError since we can't have numeric keywords

        # item sequence constructors work fine...
        self.assertEqual(NumDict([(1, 'Elephant'), (2, 'Mouse')]),
                         dict_from_num_dict_2)
        self.assertEqual(NumDict(dict=[(1, 'Elephant'), (2, 'Mouse')]),
                         dict_from_num_dict_2)
        self.assertEqual(NumDict([(1, 'Elephant'), ('2', 'Mouse')]),
                         dict_from_num_dict_2)
        self.assertEqual(NumDict(dict=[('1', 'Elephant'), (2, 'Mouse')]),
                         dict_from_num_dict_2)

        # ...unless you have a non-numeric key
        with self.assertRaises(TypeError):
            NumDict([('Rat', 11), ('Snake', 12)])
        with self.assertRaises(TypeError):
            NumDict(dict=[('Rat', 11), ('Snake', 12)])

        # combining item sequence constructors with keyword args does not work
        with self.assertRaises(
                TypeError
        ):  # Raise TypeError since we can't have numeric keywords
            NumDict([(1, 'one'), (2, 'two')], two=3, five=4)

        # alternate constructors
        dict_8 = {1: 'Echo', 2: 'Echo'}

        self.assertEqual(NumDict.fromkeys('1 2'.split()), dict_from_num_dict_6)
        self.assertEqual(NumDict().fromkeys('1 2'.split()),
                         dict_from_num_dict_6)
        self.assertEqual(NumDict.fromkeys('1 2'.split(), 'Echo'), dict_8)
        self.assertEqual(NumDict().fromkeys('1 2'.split(), 'Echo'), dict_8)
        self.assertTrue(num_dict_1.fromkeys('1 2'.split()) is not num_dict_1)
        self.assertIsInstance(num_dict_1.fromkeys('1 2'.split()), NumDict)
        self.assertIsInstance(num_dict_2.fromkeys('1 2'.split()), NumDict)
        self.assertIsInstance(num_dict_3.fromkeys('1 2'.split()), NumDict)
        self.assertIsInstance(num_dict_4.fromkeys('1 2'.split()), NumDict)
示例#6
0
    def test_repr(self):
        """
        Test representation of NumDicts
        """
        # dicts for testing
        dict_0 = {}  # Empty dictionary
        dict_1 = {1: 'Elephant'}  # Single numeric key
        dict_2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys
        dict_3 = {'3': 'Aardvark'}  # Numeric string key
        dict_4 = {'3': 'Aardvark', '4': 'Ant'}  # Multiple numeric string keys
        dict_5 = {
            5: 'Cat',
            '6': 'Dog'
        }  # Mixed numeric and numeric string keys
        dict_6 = {1: None, '2': None}  # None as values
        dict_7 = {None: 'Empty'}  # None as key

        #  Construct NumDicts from dicts
        num_dict = NumDict()
        num_dict_0 = NumDict(dict_0)
        num_dict_1 = NumDict(dict_1)
        num_dict_2 = NumDict(dict_2)
        num_dict_3 = NumDict(dict_3)
        num_dict_4 = NumDict(dict_4)
        num_dict_5 = NumDict(dict_5)
        num_dict_6 = NumDict(dict_6)
        num_dict_7 = NumDict(dict_7)

        reps = (
            "{}",
            "{1: u'Elephant'}",
            "{1: u'Elephant', 2: u'Mouse'}",
            "'3': u'Aardvark'",
            "{'3': u'Aardvark', '4': u'Ant'}",
            "{5: u'Cat', '6': u'Dog'}",
            "{1: None, '2': None}",
            "{None: u'Empty'}",
        )

        # Most representations of NumDicts should compare equal to dicts...
        self.assertEqual(six.text_type(num_dict), six.text_type({}))
        self.assertEqual(repr(num_dict), repr({}))
        self.assertIn(repr(num_dict), reps)

        self.assertEqual(six.text_type(num_dict_0), six.text_type(dict_0))
        self.assertEqual(repr(num_dict_0), repr(dict_0))
        self.assertIn(repr(num_dict_0), reps)

        self.assertEqual(six.text_type(num_dict_1), six.text_type(dict_1))
        self.assertEqual(repr(num_dict_1), repr(dict_1))
        self.assertIn(repr(num_dict_1), reps)

        self.assertEqual(six.text_type(num_dict_2), six.text_type(dict_2))
        self.assertEqual(repr(num_dict_2), repr(dict_2))
        self.assertIn(repr(num_dict_2), reps)

        # ...however, numeric keys are not equal to numeric string keys...
        # ...so the string representations for those are different...
        self.assertNotEqual(six.text_type(num_dict_3), six.text_type(dict_3))
        self.assertNotEqual(repr(num_dict_3), repr(dict_3))
        self.assertNotIn(repr(num_dict_3), reps)

        self.assertNotEqual(six.text_type(num_dict_4), six.text_type(dict_4))
        self.assertNotEqual(repr(num_dict_4), repr(dict_4))
        self.assertNotIn(repr(num_dict_4), reps)

        self.assertNotEqual(six.text_type(num_dict_5), six.text_type(dict_5))
        self.assertNotEqual(repr(num_dict_5), repr(dict_5))
        self.assertNotIn(repr(num_dict_5), reps)

        self.assertNotEqual(six.text_type(num_dict_6), six.text_type(dict_6))
        self.assertNotEqual(repr(num_dict_6), repr(dict_6))
        self.assertNotIn(repr(num_dict_6), reps)

        # ...but None keys work just fine
        self.assertEqual(six.text_type(num_dict_7), six.text_type(dict_7))
        self.assertEqual(repr(num_dict_7), repr(dict_7))
        self.assertIn(repr(num_dict_7), reps)
示例#7
0
class Quality(object):
    """
    Determine quality and set status codes
    """
    NONE = 0  # 0
    SDTV = 1  # 1
    SDDVD = 1 << 1  # 2
    HDTV = 1 << 2  # 4
    RAWHDTV = 1 << 3  # 8  -- 720p/1080i mpeg2 (trollhd releases)
    FULLHDTV = 1 << 4  # 16 -- 1080p HDTV (QCF releases)
    HDWEBDL = 1 << 5  # 32
    FULLHDWEBDL = 1 << 6  # 64 -- 1080p web-dl
    HDBLURAY = 1 << 7  # 128
    FULLHDBLURAY = 1 << 8  # 256
    UHD_4K_TV = 1 << 9  # 512 -- 2160p aka 4K UHD aka UHD-1
    UHD_4K_WEBDL = 1 << 10  # 1024
    UHD_4K_BLURAY = 1 << 11  # 2048
    UHD_8K_TV = 1 << 12  # 4096 -- 4320p aka 8K UHD aka UHD-2
    UHD_8K_WEBDL = 1 << 13  # 8192
    UHD_8K_BLURAY = 1 << 14  # 16384
    ANYHDTV = HDTV | FULLHDTV  # 20
    ANYWEBDL = HDWEBDL | FULLHDWEBDL  # 96
    ANYBLURAY = HDBLURAY | FULLHDBLURAY  # 384

    # put these bits at the other end of the spectrum, far enough out that they shouldn't interfere
    UNKNOWN = 1 << 15  # 32768

    qualityStrings = NumDict({
        None: "None",
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "SDTV",
        SDDVD: "SD DVD",
        HDTV: "720p HDTV",
        RAWHDTV: "RawHD",
        FULLHDTV: "1080p HDTV",
        HDWEBDL: "720p WEB-DL",
        FULLHDWEBDL: "1080p WEB-DL",
        HDBLURAY: "720p BluRay",
        FULLHDBLURAY: "1080p BluRay",
        UHD_4K_TV: "4K UHD TV",
        UHD_8K_TV: "8K UHD TV",
        UHD_4K_WEBDL: "4K UHD WEB-DL",
        UHD_8K_WEBDL: "8K UHD WEB-DL",
        UHD_4K_BLURAY: "4K UHD BluRay",
        UHD_8K_BLURAY: "8K UHD BluRay",
    })

    sceneQualityStrings = NumDict({
        None: "None",
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "HDTV",
        SDDVD: "",
        HDTV: "720p HDTV",
        RAWHDTV: "1080i HDTV",
        FULLHDTV: "1080p HDTV",
        HDWEBDL: "720p WEB-DL",
        FULLHDWEBDL: "1080p WEB-DL",
        HDBLURAY: "720p BluRay",
        FULLHDBLURAY: "1080p BluRay",
        UHD_4K_TV: "4K UHD TV",
        UHD_8K_TV: "8K UHD TV",
        UHD_4K_WEBDL: "4K UHD WEB-DL",
        UHD_8K_WEBDL: "8K UHD WEB-DL",
        UHD_4K_BLURAY: "4K UHD BluRay",
        UHD_8K_BLURAY: "8K UHD BluRay",
    })

    combinedQualityStrings = NumDict({
        ANYHDTV: "HDTV",
        ANYWEBDL: "WEB-DL",
        ANYBLURAY: "BluRay"
    })

    cssClassStrings = NumDict({
        None: "None",
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "SDTV",
        SDDVD: "SDDVD",
        HDTV: "HD720p",
        RAWHDTV: "RawHD",
        FULLHDTV: "HD1080p",
        HDWEBDL: "HD720p",
        FULLHDWEBDL: "HD1080p",
        HDBLURAY: "HD720p",
        FULLHDBLURAY: "HD1080p",
        UHD_4K_TV: "UHD-4K",
        UHD_8K_TV: "UHD-8K",
        UHD_4K_WEBDL: "UHD-4K",
        UHD_8K_WEBDL: "UHD-8K",
        UHD_4K_BLURAY: "UHD-4K",
        UHD_8K_BLURAY: "UHD-8K",
        ANYHDTV: "any-hd",
        ANYWEBDL: "any-hd",
        ANYBLURAY: "any-hd"
    })

    statusPrefixes = NumDict({
        DOWNLOADED: _("Downloaded"),
        SNATCHED: _("Snatched"),
        SNATCHED_PROPER: _("Snatched (Proper)"),
        FAILED: _("Failed"),
        SNATCHED_BEST: _("Snatched (Best)"),
        ARCHIVED: _("Archived")
    })

    @staticmethod
    def _getStatusStrings(status):
        """
        Returns string values associated with Status prefix

        :param status: Status prefix to resolve
        :return: Human readable status value
        """
        to_return = {}
        for quality in Quality.qualityStrings:
            if quality is not None:
                stat = Quality.statusPrefixes[status]
                qual = Quality.qualityStrings[quality]
                comp = Quality.compositeStatus(status, quality)
                to_return[comp] = '{0} ({1})'.format(stat, qual)
        return to_return

    @staticmethod
    def combineQualities(allowed_qualities, preferred_qualities):
        any_quality = 0
        best_quality = 0
        if allowed_qualities:
            any_quality = reduce(operator.or_, allowed_qualities)
        if preferred_qualities:
            best_quality = reduce(operator.or_, preferred_qualities)
        return any_quality | (best_quality << 16)

    @staticmethod
    def splitQuality(quality):
        if quality is None:
            quality = Quality.NONE
        allowed_qualities = []
        preferred_qualities = []
        for cur_qual in Quality.qualityStrings:
            if cur_qual is None:
                cur_qual = Quality.NONE
            if cur_qual & quality:
                allowed_qualities.append(cur_qual)
            if cur_qual << 16 & quality:
                preferred_qualities.append(cur_qual)

        return sorted(allowed_qualities), sorted(preferred_qualities)

    @staticmethod
    def nameQuality(name, anime=False):
        """
        Return The quality from an episode File renamed by SickRage
        If no quality is achieved it will try scene_quality regex

        :param name: to parse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality prefix
        """

        # Try Scene names first
        quality = Quality.scene_quality(name, anime)
        if quality != Quality.UNKNOWN:
            return quality

        quality = Quality.qualityFromFileMeta(name)
        if quality != Quality.UNKNOWN:
            return quality

        if name.lower().endswith(".ts"):
            return Quality.RAWHDTV
        else:
            return Quality.UNKNOWN

    @staticmethod
    def scene_quality(name, anime=False):  # pylint: disable=too-many-branches, too-many-statements
        """
        Return The quality from the scene episode File

        :param name: Episode filename to analyse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality
        """

        if not name:
            return Quality.UNKNOWN

        name = ek(path.basename, name)

        result = None
        ep = EpisodeTags(name)

        if anime:
            sd_options = tags.anime_sd.search(name)
            hd_options = tags.anime_hd.search(name)
            full_hd = tags.anime_fullhd.search(name)
            ep.rex[b'bluray'] = tags.anime_bluray

            # BluRay
            if ep.bluray and (full_hd or hd_options):
                result = Quality.FULLHDBLURAY if full_hd else Quality.HDBLURAY
            # HD TV
            elif not ep.bluray and (full_hd or hd_options):
                result = Quality.FULLHDTV if full_hd else Quality.HDTV
            # SD DVD
            elif ep.dvd:
                result = Quality.SDDVD
            # SD TV
            elif sd_options:
                result = Quality.SDTV

            return Quality.UNKNOWN if result is None else result

        # Is it UHD?
        if ep.vres in [2160, 4320] and ep.scan == 'p':
            # BluRay
            full_res = (ep.vres == 4320)
            if ep.avc and ep.bluray:
                result = Quality.UHD_4K_BLURAY if not full_res else Quality.UHD_8K_BLURAY
            # WEB-DL
            elif (ep.avc and ep.itunes) or ep.web:
                result = Quality.UHD_4K_WEBDL if not full_res else Quality.UHD_8K_WEBDL
            # HDTV
            elif ep.avc and ep.tv == 'hd':
                result = Quality.UHD_4K_TV if not full_res else Quality.UHD_8K_TV

        # Is it HD?
        elif ep.vres in [1080, 720]:
            if ep.scan == 'p':
                # BluRay
                full_res = (ep.vres == 1080)
                if ep.avc and (ep.bluray or ep.hddvd):
                    result = Quality.FULLHDBLURAY if full_res else Quality.HDBLURAY
                # WEB-DL
                elif (ep.avc and ep.itunes) or ep.web:
                    result = Quality.FULLHDWEBDL if full_res else Quality.HDWEBDL
                # HDTV
                elif ep.avc and ep.tv == 'hd':
                    result = Quality.FULLHDTV if full_res else Quality.HDTV  #1080 HDTV h264
                # MPEG2 encoded
                elif all([ep.vres == 1080, ep.tv == 'hd', ep.mpeg]):
                    result = Quality.RAWHDTV
                elif all([ep.vres == 720, ep.tv == 'hd', ep.mpeg]):
                    result = Quality.RAWHDTV
            elif (ep.res == '1080i') and ep.tv == 'hd' and (
                    ep.mpeg or (ep.raw and ep.avc_non_free)):
                result = Quality.RAWHDTV
        elif ep.hrws:
            result = Quality.HDTV

        # Is it SD?
        elif ep.xvid or ep.avc:
            # SD DVD
            if ep.dvd or ep.bluray:
                result = Quality.SDDVD
            # SDTV
            elif ep.res == '480p' or any([ep.tv, ep.sat, ep.web]):
                result = Quality.SDTV
        elif ep.dvd:
            # SD DVD
            result = Quality.SDDVD
        elif ep.tv:
            # SD TV/HD TV
            result = Quality.SDTV

        return Quality.UNKNOWN if result is None else result

    @staticmethod
    def qualityFromFileMeta(filename):  # pylint: disable=too-many-branches
        """
        Get quality file file metadata

        :param filename: Filename to analyse
        :return: Quality prefix
        """

        height = video_screen_size(filename)[1]
        if not height:
            return Quality.UNKNOWN

        base_filename = ek(path.basename, filename)
        bluray = re.search(r"blue?-?ray|hddvd|b[rd](rip|mux)", base_filename,
                           re.I) is not None
        webdl = re.search(r"web.?dl|web(rip|mux|hd)", base_filename,
                          re.I) is not None

        ret = Quality.UNKNOWN
        if 3240 < height:
            ret = ((Quality.UHD_8K_TV, Quality.UHD_8K_BLURAY)[bluray],
                   Quality.UHD_8K_WEBDL)[webdl]
        if 1620 < height <= 3240:
            ret = ((Quality.UHD_4K_TV, Quality.UHD_4K_BLURAY)[bluray],
                   Quality.UHD_4K_WEBDL)[webdl]
        elif 800 < height <= 1620:
            ret = ((Quality.FULLHDTV, Quality.FULLHDBLURAY)[bluray],
                   Quality.FULLHDWEBDL)[webdl]
        elif 680 < height <= 800:
            ret = ((Quality.HDTV, Quality.HDBLURAY)[bluray],
                   Quality.HDWEBDL)[webdl]
        elif height <= 680:
            ret = (Quality.SDTV, Quality.SDDVD)[re.search(
                r'dvd|b[rd]rip|blue?-?ray', base_filename, re.I) is not None]

        return ret

    @staticmethod
    def compositeStatus(status, quality):
        if quality is None:
            quality = Quality.NONE
        return status + 100 * quality

    @staticmethod
    def qualityDownloaded(status):
        return (status - DOWNLOADED) / 100

    @staticmethod
    def splitCompositeStatus(status):
        """
        Split a composite status code into a status and quality.

        :param status: to split
        :returns: a tuple containing (status, quality)
        """
        status = long(status)
        if status == UNKNOWN:
            return UNKNOWN, Quality.UNKNOWN

        for q in sorted(Quality.qualityStrings.keys(), reverse=True):
            if status > q * 100:
                return status - q * 100, q

        return status, Quality.NONE

    @staticmethod
    def sceneQualityFromName(name, quality):  # pylint: disable=too-many-branches
        """
        Get scene naming parameters from filename and quality

        :param name: Filename to check
        :param quality: int of quality to make sure we get the right rip type
        :return: encoder type for scene quality naming
        """
        codec_list = ['xvid', 'divx']
        x264_list = ['x264', 'x 264', 'x.264']
        h264_list = ['h264', 'h 264', 'h.264', 'avc']
        x265_list = ['x265', 'x 265', 'x.265']
        h265_list = ['h265', 'h 265', 'h.265', 'hevc']
        codec_list += x264_list + h264_list + x265_list + h265_list

        found_codecs = {}
        found_codec = None

        for codec in codec_list:
            if codec in name.lower():
                found_codecs[name.lower().rfind(codec)] = codec

        if found_codecs:
            sorted_codecs = sorted(found_codecs, reverse=True)
            found_codec = found_codecs[list(sorted_codecs)[0]]

        # 2 corresponds to SDDVD quality
        if quality == 2:
            if re.search(r"b(r|d|rd)?(-| |\.)?(rip|mux)", name.lower()):
                rip_type = " BDRip"
            elif re.search(r"(dvd)(-| |\.)?(rip|mux)?", name.lower()):
                rip_type = " DVDRip"
            else:
                rip_type = ""

        if found_codec:
            if codec_list[0] in found_codec:
                found_codec = 'XviD'
            elif codec_list[1] in found_codec:
                found_codec = 'DivX'
            elif found_codec in x264_list:
                found_codec = x264_list[0]
            elif found_codec in h264_list:
                found_codec = h264_list[0]
            elif found_codec in x265_list:
                found_codec = x265_list[0]
            elif found_codec in h265_list:
                found_codec = h265_list[0]

            if quality == 2:
                return rip_type + " " + found_codec
            else:
                return " " + found_codec
        elif quality == 2:
            return rip_type
        else:
            return ""

    @staticmethod
    def statusFromName(name, anime=False):
        """
        Get a status object from filename

        :param name: Filename to check
        :param anime: boolean to enable anime parsing
        :return: Composite status/quality object
        """
        return Quality.compositeStatus(DOWNLOADED,
                                       Quality.nameQuality(name, anime))

    DOWNLOADED = None
    SNATCHED = None
    SNATCHED_PROPER = None
    FAILED = None
    SNATCHED_BEST = None
    ARCHIVED = None
示例#8
0
NOTIFY_DOWNLOAD = 2
NOTIFY_SUBTITLE_DOWNLOAD = 3
NOTIFY_GIT_UPDATE = 4
NOTIFY_GIT_UPDATE_TEXT = 5
NOTIFY_LOGIN = 6
NOTIFY_LOGIN_TEXT = 7

notifyStrings = NumDict({
    # pylint: disable=undefined-variable
    NOTIFY_SNATCH:
    _("Started Download"),
    NOTIFY_DOWNLOAD:
    _("Download Finished"),
    NOTIFY_SUBTITLE_DOWNLOAD:
    _("Subtitle Download Finished"),
    NOTIFY_GIT_UPDATE:
    _("SickRage Updated"),
    NOTIFY_GIT_UPDATE_TEXT:
    _("SickRage Updated To Commit#: "),
    NOTIFY_LOGIN:
    _("SickRage new login"),
    NOTIFY_LOGIN_TEXT:
    _("New login from IP: {0}. http://geomaplookup.net/?ip={0}")
})

# Episode statuses
UNKNOWN = -1  # should never happen
UNAIRED = 1  # episodes that haven't aired yet
SNATCHED = 2  # qualified with quality
WANTED = 3  # episodes we don't have but want to get
DOWNLOADED = 4  # qualified with quality
示例#9
0
class Quality(object):
    """
    Determine quality and set status codes
    """
    NONE = 0  # 0
    SDTV = 1  # 1
    SDDVD = 1 << 1  # 2
    HDTV = 1 << 2  # 4
    RAWHDTV = 1 << 3  # 8  -- 720p/1080i mpeg2 (trollhd releases)
    FULLHDTV = 1 << 4  # 16 -- 1080p HDTV (QCF releases)
    HDWEBDL = 1 << 5  # 32
    FULLHDWEBDL = 1 << 6  # 64 -- 1080p web-dl
    HDBLURAY = 1 << 7  # 128
    FULLHDBLURAY = 1 << 8  # 256
    UHD_4K_TV = 1 << 9  # 512 -- 2160p aka 4K UHD aka UHD-1
    UHD_4K_WEBDL = 1 << 10  # 1024
    UHD_4K_BLURAY = 1 << 11  # 2048
    UHD_8K_TV = 1 << 12  # 4096 -- 4320p aka 8K UHD aka UHD-2
    UHD_8K_WEBDL = 1 << 13  # 8192
    UHD_8K_BLURAY = 1 << 14  # 16384
    ANYHDTV = HDTV | FULLHDTV  # 20
    ANYWEBDL = HDWEBDL | FULLHDWEBDL  # 96
    ANYBLURAY = HDBLURAY | FULLHDBLURAY  # 384

    # put these bits at the other end of the spectrum, far enough out that they shouldn't interfere
    UNKNOWN = 1 << 15  # 32768

    qualityStrings = NumDict({
        None: "None",
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "SDTV",
        SDDVD: "SD DVD",
        HDTV: "720p HDTV",
        RAWHDTV: "RawHD",
        FULLHDTV: "1080p HDTV",
        HDWEBDL: "720p WEB-DL",
        FULLHDWEBDL: "1080p WEB-DL",
        HDBLURAY: "720p BluRay",
        FULLHDBLURAY: "1080p BluRay",
        UHD_4K_TV: "4K UHD TV",
        UHD_8K_TV: "8K UHD TV",
        UHD_4K_WEBDL: "4K UHD WEB-DL",
        UHD_8K_WEBDL: "8K UHD WEB-DL",
        UHD_4K_BLURAY: "4K UHD BluRay",
        UHD_8K_BLURAY: "8K UHD BluRay",
    })

    sceneQualityStrings = NumDict({
        None: "None",
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "HDTV",
        SDDVD: "",
        HDTV: "720p HDTV",
        RAWHDTV: "1080i HDTV",
        FULLHDTV: "1080p HDTV",
        HDWEBDL: "720p WEB-DL",
        FULLHDWEBDL: "1080p WEB-DL",
        HDBLURAY: "720p BluRay",
        FULLHDBLURAY: "1080p BluRay",
        UHD_4K_TV: "4K UHD TV",
        UHD_8K_TV: "8K UHD TV",
        UHD_4K_WEBDL: "4K UHD WEB-DL",
        UHD_8K_WEBDL: "8K UHD WEB-DL",
        UHD_4K_BLURAY: "4K UHD BluRay",
        UHD_8K_BLURAY: "8K UHD BluRay",
    })

    combinedQualityStrings = NumDict({
        ANYHDTV: "HDTV",
        ANYWEBDL: "WEB-DL",
        ANYBLURAY: "BluRay"
    })

    cssClassStrings = NumDict({
        None: "None",
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "SDTV",
        SDDVD: "SDDVD",
        HDTV: "HD720p",
        RAWHDTV: "RawHD",
        FULLHDTV: "HD1080p",
        HDWEBDL: "HD720p",
        FULLHDWEBDL: "HD1080p",
        HDBLURAY: "HD720p",
        FULLHDBLURAY: "HD1080p",
        UHD_4K_TV: "UHD-4K",
        UHD_8K_TV: "UHD-8K",
        UHD_4K_WEBDL: "UHD-4K",
        UHD_8K_WEBDL: "UHD-8K",
        UHD_4K_BLURAY: "UHD-4K",
        UHD_8K_BLURAY: "UHD-8K",
        ANYHDTV: "any-hd",
        ANYWEBDL: "any-hd",
        ANYBLURAY: "any-hd"
    })

    statusPrefixes = NumDict({
        DOWNLOADED: "Downloaded",
        SNATCHED: "Snatched",
        SNATCHED_PROPER: "Snatched (Proper)",
        FAILED: "Failed",
        SNATCHED_BEST: "Snatched (Best)",
        ARCHIVED: "Archived"
    })

    @staticmethod
    def _getStatusStrings(status):
        """
        Returns string values associated with Status prefix

        :param status: Status prefix to resolve
        :return: Human readable status value
        """
        to_return = {}
        for quality in Quality.qualityStrings:
            if quality is not None:
                stat = Quality.statusPrefixes[status]
                qual = Quality.qualityStrings[quality]
                comp = Quality.compositeStatus(status, quality)
                to_return[comp] = '%s (%s)' % (stat, qual)
        return to_return

    @staticmethod
    def combineQualities(allowed_qualities, preferred_qualities):
        any_quality = 0
        best_quality = 0
        if allowed_qualities:
            any_quality = reduce(operator.or_, allowed_qualities)
        if preferred_qualities:
            best_quality = reduce(operator.or_, preferred_qualities)
        return any_quality | (best_quality << 16)

    @staticmethod
    def splitQuality(quality):
        if quality is None:
            quality = Quality.NONE
        allowed_qualities = []
        preferred_qualities = []
        for cur_qual in Quality.qualityStrings:
            if cur_qual is None:
                cur_qual = Quality.NONE
            if cur_qual & quality:
                allowed_qualities.append(cur_qual)
            if cur_qual << 16 & quality:
                preferred_qualities.append(cur_qual)

        return sorted(allowed_qualities), sorted(preferred_qualities)

    @staticmethod
    def nameQuality(name, anime=False):
        """
        Return The quality from an episode File renamed by SickRage
        If no quality is achieved it will try sceneQuality regex

        :param name: to parse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality prefix
        """

        # Try Scene names first
        quality = Quality.sceneQuality(name, anime)
        if quality != Quality.UNKNOWN:
            return quality

        quality = Quality.assumeQuality(name)
        if quality != Quality.UNKNOWN:
            return quality

        return Quality.UNKNOWN

    @staticmethod
    # TODO: Remove this method and sceneQuality after the new scene_quality has been validated.
    def old_scene_quality(name, anime=False):  # pylint: disable=too-many-branches
        """
        Return The quality from the scene episode File

        :param name: Episode filename to analyse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality prefix
        """

        ret = Quality.UNKNOWN
        if not name:
            return ret

        name = ek(path.basename, name)

        check_name = lambda regex_list, func: func(
            [re.search(regex, name, re.I) for regex in regex_list])

        if anime:
            dvd_options = check_name([r"dvd", r"dvdrip"], any)
            bluray_options = check_name([r"BD", r"blue?-?ray"], any)
            sd_options = check_name([r"360p", r"480p", r"848x480", r"XviD"],
                                    any)
            hd_options = check_name([r"720p", r"1280x720", r"960x720"], any)
            full_hd = check_name([r"1080p", r"1920x1080"], any)

            if sd_options and not bluray_options and not dvd_options:
                ret = Quality.SDTV
            elif dvd_options:
                ret = Quality.SDDVD
            elif hd_options and not bluray_options and not full_hd:
                ret = Quality.HDTV
            elif full_hd and not bluray_options and not hd_options:
                ret = Quality.FULLHDTV
            elif hd_options and not bluray_options and not full_hd:
                ret = Quality.HDWEBDL
            elif bluray_options and hd_options and not full_hd:
                ret = Quality.HDBLURAY
            elif bluray_options and full_hd and not hd_options:
                ret = Quality.FULLHDBLURAY

            return ret

        if check_name([
                r"480p|web.?dl|web(rip|mux|hd)|[sph]d.?tv|dsr|tv(rip|mux)|satrip",
                r"xvid|divx|[xh].?26[45]"
        ], all) and not check_name(
            [r"(720|1080)[pi]"], all) and not check_name([
                r"hr.ws.pdtv.[xh].?26[45]",
                r"dvd(rip|mux)|b[rd](rip|mux)|blue?-?ray"
            ], any):
            ret = Quality.SDTV
        elif check_name([
                r"dvd(rip|mux)|b[rd](rip|mux)|blue?-?ray",
                r"xvid|divx|[xh].?26[45]"
        ], all) and not check_name([r"(720|1080)[pi]"],
                                   all) and not check_name(
                                       [r"hr.ws.pdtv.[xh].?26[45]"], any):
            ret = Quality.SDDVD
        elif check_name(
            [r"720p", r"hd.?tv", r"[xh].?26[45]"],
                all) or check_name([r"hr.ws.pdtv.[xh].?26[45]"],
                                   any) and not check_name([r"1080[pi]"], all):
            ret = Quality.HDTV
        elif check_name([r"720p|1080i", r"hd.?tv", r"mpeg-?2"],
                        all) or check_name([r"1080[pi].hdtv", r"h.?26[45]"],
                                           all):
            ret = Quality.RAWHDTV
        elif check_name([r"1080p", r"hd.?tv", r"[xh].?26[45]"], all):
            ret = Quality.FULLHDTV
        elif check_name([r"720p", r"web.?dl|web(rip|mux|hd)"],
                        all) or check_name(
                            [r"720p", r"itunes", r"[xh].?26[45]"], all):
            ret = Quality.HDWEBDL
        elif check_name([r"1080p", r"web.?dl|web(rip|mux|hd)"],
                        all) or check_name(
                            [r"1080p", r"itunes", r"[xh].?26[45]"], all):
            ret = Quality.FULLHDWEBDL
        elif check_name(
            [r"720p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"],
                all):
            ret = Quality.HDBLURAY
        elif check_name(
            [r"1080p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"],
                all):
            ret = Quality.FULLHDBLURAY

        return ret

    @staticmethod
    def scene_quality(name, anime=False):  # pylint: disable=too-many-branches
        """
        Return The quality from the scene episode File

        :param name: Episode filename to analyse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality
        """

        if not name:
            return Quality.UNKNOWN
        else:
            name = ek(path.basename, name)

        result = None
        ep = EpisodeTags(name)

        if anime:
            sd_options = tags.anime_sd.search(name)
            hd_options = tags.anime_hd.search(name)
            full_hd = tags.anime_fullhd.search(name)
            ep.rex[u'bluray'] = tags.anime_bluray

            # BluRay
            if ep.bluray and (full_hd or hd_options):
                result = Quality.FULLHDBLURAY if full_hd else Quality.HDBLURAY
            # HD TV
            elif not ep.bluray and (full_hd or hd_options):
                result = Quality.FULLHDTV if full_hd else Quality.HDTV
            # SD DVD
            elif ep.dvd:
                result = Quality.SDDVD
            # SD TV
            elif sd_options:
                result = Quality.SDTV

            return Quality.UNKNOWN if result is None else result

        # Is it UHD?
        if ep.vres in [2160, 4320] and ep.scan == u'p':
            # BluRay
            full_res = (ep.vres == 4320)
            if ep.avc and ep.bluray:
                result = Quality.UHD_4K_BLURAY if not full_res else Quality.UHD_8K_BLURAY
            # WEB-DL
            elif (ep.avc and ep.itunes) or ep.web:
                result = Quality.UHD_4K_WEBDL if not full_res else Quality.UHD_8K_WEBDL
            # HDTV
            elif ep.avc and ep.tv == u'hd':
                result = Quality.UHD_4K_TV if not full_res else Quality.UHD_8K_TV

        # Is it HD?
        elif ep.vres in [1080, 720]:
            if ep.scan == u'p':
                # BluRay
                full_res = (ep.vres == 1080)
                if ep.avc and (ep.bluray or ep.hddvd):
                    result = Quality.FULLHDBLURAY if full_res else Quality.HDBLURAY
                # WEB-DL
                elif (ep.avc and ep.itunes) or ep.web:
                    result = Quality.FULLHDWEBDL if full_res else Quality.HDWEBDL
                # HDTV
                elif ep.avc and ep.tv == u'hd':
                    if not all([ep.vres == 1080, ep.raw, ep.avc_non_free]):
                        result = Quality.FULLHDTV if full_res else Quality.HDTV
                    else:
                        result = Quality.RAWHDTV
                elif all([ep.vres == 720, ep.tv == u'hd', ep.mpeg]):
                    result = Quality.RAWHDTV
            elif (ep.res == u'1080i') and ep.tv == u'hd':
                if ep.mpeg or (ep.raw and ep.avc_non_free):
                    result = Quality.RAWHDTV
        elif ep.hrws:
            result = Quality.HDTV

        # Is it SD?
        elif ep.xvid or ep.avc:
            # SD DVD
            if ep.dvd or ep.bluray:
                result = Quality.SDDVD
            # SDTV
            elif ep.res == u'480p' or any([ep.tv, ep.sat, ep.web]):
                result = Quality.SDTV

        return Quality.UNKNOWN if result is None else result

    def scene_french(name, anime=False):  # pylint: disable=too-many-branches
        """
        Return The quality from the scene episode File

        :param name: Episode filename to analyse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality
        """

        if not name:
            return ""
        else:
            name = ek(path.basename, name)

        result = None
        ep = Episode_fr(name)

        return ep

    @staticmethod
    # TODO: Remove this method and old_scene_quality after the new scene_quality has been validated.
    def sceneQuality(name, anime=False):
        """
        Validation for new scene_quality.

        :param name: Episode filename to analyse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality
        """
        # use the new scene_quality to determine quality
        result = Quality.scene_quality(name, anime)

        # if its a quality known by old_scene_quality assert they match
        if result <= Quality.FULLHDBLURAY or result == Quality.UNKNOWN:
            old = Quality.old_scene_quality(name, anime)
            assert old == result, 'Old quality does not match new: %s != %s : %s' % (
                Quality.qualityStrings[old], Quality.qualityStrings[result],
                name)

        return result

    @staticmethod
    def assumeQuality(name):
        """
        Assume a quality from file extension if we cannot resolve it otherwise

        :param name: File name of episode to analyse
        :return: Quality prefix
        """
        quality = Quality.qualityFromFileMeta(name)
        if quality != Quality.UNKNOWN:
            return quality

        if name.lower().endswith(".ts"):
            return Quality.RAWHDTV
        else:
            return Quality.UNKNOWN

    @staticmethod
    def qualityFromFileMeta(filename):  # pylint: disable=too-many-branches
        """
        Get quality file file metadata

        :param filename: Filename to analyse
        :return: Quality prefix
        """

        log.use_print = False

        try:
            parser = createParser(filename)
        except Exception:  # pylint: disable=broad-except
            parser = None

        if not parser:
            return Quality.UNKNOWN

        try:
            metadata = extractMetadata(parser)
        except Exception:  # pylint: disable=broad-except
            metadata = None

        try:
            parser.stream._input.close()  # pylint: disable=protected-access
        except Exception:  # pylint: disable=broad-except
            pass

        if not metadata:
            return Quality.UNKNOWN

        height = 0
        if metadata.has('height'):
            height = int(metadata.get('height') or 0)
        else:
            test = getattr(metadata, "iterGroups", None)
            if callable(test):
                for metagroup in metadata.iterGroups():
                    if metagroup.has('height'):
                        height = int(metagroup.get('height') or 0)

        if not height:
            return Quality.UNKNOWN

        base_filename = ek(path.basename, filename)
        bluray = re.search(r"blue?-?ray|hddvd|b[rd](rip|mux)", base_filename,
                           re.I) is not None
        webdl = re.search(r"web.?dl|web(rip|mux|hd)", base_filename,
                          re.I) is not None

        ret = Quality.UNKNOWN
        if 3240 < height:
            ret = ((Quality.UHD_8K_TV, Quality.UHD_8K_BLURAY)[bluray],
                   Quality.UHD_8K_WEBDL)[webdl]
        if 1620 < height <= 3240:
            ret = ((Quality.UHD_4K_TV, Quality.UHD_4K_BLURAY)[bluray],
                   Quality.UHD_4K_WEBDL)[webdl]
        elif 800 < height <= 1620:
            ret = ((Quality.FULLHDTV, Quality.FULLHDBLURAY)[bluray],
                   Quality.FULLHDWEBDL)[webdl]
        elif 680 < height <= 800:
            ret = ((Quality.HDTV, Quality.HDBLURAY)[bluray],
                   Quality.HDWEBDL)[webdl]
        elif height <= 680:
            ret = (Quality.SDTV, Quality.SDDVD)[re.search(
                r'dvd|b[rd]rip|blue?-?ray', base_filename, re.I) is not None]

        return ret

    @staticmethod
    def compositeStatus(status, quality):
        if quality is None:
            quality = Quality.NONE
        return status + 100 * quality

    @staticmethod
    def qualityDownloaded(status):
        return (status - DOWNLOADED) / 100

    @staticmethod
    def splitCompositeStatus(status):
        """
        Split a composite status code into a status and quality.

        :param status: to split
        :returns: a tuple containing (status, quality)
        """
        status = long(status)
        if status == UNKNOWN:
            return UNKNOWN, Quality.UNKNOWN

        for q in sorted(Quality.qualityStrings.keys(), reverse=True):
            if status > q * 100:
                return status - q * 100, q

        return status, Quality.NONE

    @staticmethod
    def sceneQualityFromName(name, quality):  # pylint: disable=too-many-branches
        """
        Get scene naming parameters from filename and quality

        :param name: Filename to check
        :param quality: int of quality to make sure we get the right rip type
        :return: encoder type for scene quality naming
        """
        codec_list = ['xvid', 'divx']
        x264_list = ['x264', 'x 264', 'x.264']
        h264_list = ['h264', 'h 264', 'h.264', 'avc']
        x265_list = ['x265', 'x 265', 'x.265']
        h265_list = ['h265', 'h 265', 'h.265', 'hevc']
        codec_list += x264_list + h264_list + x265_list + h265_list

        found_codecs = {}
        found_codec = None

        for codec in codec_list:
            if codec in name.lower():
                found_codecs[name.lower().rfind(codec)] = codec

        if found_codecs:
            sorted_codecs = sorted(found_codecs, reverse=True)
            found_codec = found_codecs[list(sorted_codecs)[0]]

        # 2 corresponds to SDDVD quality
        if quality == 2:
            if re.search(r"b(r|d|rd)?(-| |\.)?(rip|mux)", name.lower()):
                rip_type = " BDRip"
            elif re.search(r"(dvd)(-| |\.)?(rip|mux)?", name.lower()):
                rip_type = " DVDRip"
            else:
                rip_type = ""

        if found_codec:
            if codec_list[0] in found_codec:
                found_codec = 'XviD'
            elif codec_list[1] in found_codec:
                found_codec = 'DivX'
            elif found_codec in x264_list:
                found_codec = x264_list[0]
            elif found_codec in h264_list:
                found_codec = h264_list[0]
            elif found_codec in x265_list:
                found_codec = x265_list[0]
            elif found_codec in h265_list:
                found_codec = h265_list[0]

            if quality == 2:
                return rip_type + " " + found_codec
            else:
                return " " + found_codec
        elif quality == 2:
            return rip_type
        else:
            return ""

    @staticmethod
    def statusFromName(name, assume=True, anime=False):
        """
        Get a status object from filename

        :param name: Filename to check
        :param assume: boolean to assume quality by extension if we can't figure it out
        :param anime: boolean to enable anime parsing
        :return: Composite status/quality object
        """
        quality = Quality.nameQuality(name, anime)
        if assume and quality == Quality.UNKNOWN:
            quality = Quality.assumeQuality(name)
        return Quality.compositeStatus(DOWNLOADED, quality)

    DOWNLOADED = None
    SNATCHED = None
    SNATCHED_PROPER = None
    FAILED = None
    SNATCHED_BEST = None
    ARCHIVED = None
    SNATCHED_FRENCH = None
示例#10
0
NOTIFY_SNATCH = 1
NOTIFY_DOWNLOAD = 2
NOTIFY_SUBTITLE_DOWNLOAD = 3
NOTIFY_GIT_UPDATE = 4
NOTIFY_GIT_UPDATE_TEXT = 5
NOTIFY_LOGIN = 6
NOTIFY_LOGIN_TEXT = 7

notifyStrings = NumDict({
    NOTIFY_SNATCH:
    "Started Download",
    NOTIFY_DOWNLOAD:
    "Download Finished",
    NOTIFY_SUBTITLE_DOWNLOAD:
    "Subtitle Download Finished",
    NOTIFY_GIT_UPDATE:
    "SickRage Updated",
    NOTIFY_GIT_UPDATE_TEXT:
    "SickRage Updated To Commit#: ",
    NOTIFY_LOGIN:
    "******",
    NOTIFY_LOGIN_TEXT:
    "New login from IP: {0}. http://geomaplookup.net/?ip={0}"
})

# Episode statuses
UNKNOWN = -1  # should never happen
UNAIRED = 1  # episodes that haven't aired yet
SNATCHED = 2  # qualified with quality
WANTED = 3  # episodes we don't have but want to get
DOWNLOADED = 4  # qualified with quality
SKIPPED = 5  # episodes we don't want
示例#11
0
    def test_constructors(self):
        """
        Test NumDict constructors
        """
        # dicts for testing
        d0 = {}  # Empty dictionary
        d1 = {1: 'Elephant'}  # Single numeric key
        d2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys
        d3 = {'3': 'Aardvark'}  # Numeric string key
        d4 = {'3': 'Aardvark', '4': 'Ant'}  # Multiple numeric string keys
        d5 = {5: 'Cat', '6': 'Dog'}  # Mixed numeric and numeric string keys
        d6 = {1: None, '2': None}  # None as values
        d7 = {None: 'Empty'}  # None as key

        # Construct NumDicts from dicts
        n = NumDict()
        n0 = NumDict(d0)
        n1 = NumDict(d1)
        n2 = NumDict(d2)
        n3 = NumDict(d3)
        n4 = NumDict(d4)
        n5 = NumDict(d5)
        n6 = NumDict(d6)
        n7 = NumDict(d7)

        # Most NumDicts from dicts should compare equal...
        self.assertEqual(n, {})
        self.assertEqual(n0, d0)
        self.assertEqual(n1, d1)
        self.assertEqual(n2, d2)

        # ...however, numeric keys are not equal to numeric string keys...
        self.assertNotEqual(n3, d3)
        self.assertNotEqual(n4, d4)
        self.assertNotEqual(n5, d5)
        self.assertNotEqual(n6, d6)

        # ...but None keys work just fine
        self.assertEqual(n7, d7)

        # Construct dicts from NumDicts
        dn = dict(n)
        dn1 = dict(n1)
        dn2 = dict(n2)
        dn3 = dict(n3)
        dn4 = dict(n4)
        dn5 = dict(n5)
        dn6 = dict(n6)
        dn7 = dict(n7)

        # All dicts from NumDicts should compare equal
        self.assertEqual(n, dn)
        self.assertEqual(n1, dn1)
        self.assertEqual(n2, dn2)
        self.assertEqual(n3, dn3)
        self.assertEqual(n4, dn4)
        self.assertEqual(n5, dn5)
        self.assertEqual(n6, dn6)
        self.assertEqual(n7, dn7)

        # Construct NumDicts from NumDicts
        nn = NumDict(n)
        nn0 = NumDict(n0)
        nn1 = NumDict(n1)
        nn2 = NumDict(n2)
        nn3 = NumDict(n3)
        nn4 = NumDict(n4)
        nn5 = NumDict(n5)
        nn6 = NumDict(n6)
        nn7 = NumDict(n7)

        # All NumDicts from NumDicts should compare equal
        self.assertEqual(n, nn)
        self.assertEqual(n0, nn0)
        self.assertEqual(n1, nn1)
        self.assertEqual(n2, nn2)
        self.assertEqual(n3, nn3)
        self.assertEqual(n4, nn4)
        self.assertEqual(n5, nn5)
        self.assertEqual(n6, nn6)
        self.assertEqual(n7, nn7)

        # keyword arg constructor should fail
        with self.assertRaises(TypeError):
            NumDict(
                one=1,
                two=2)  # Raise TypeError since we can't have numeric keywords

        # item sequence constructors work fine...
        self.assertEqual(NumDict([(1, 'Elephant'), (2, 'Mouse')]), dn2)
        self.assertEqual(NumDict(dict=[(1, 'Elephant'), (2, 'Mouse')]), dn2)
        self.assertEqual(NumDict([(1, 'Elephant'), ('2', 'Mouse')]), dn2)
        self.assertEqual(NumDict(dict=[('1', 'Elephant'), (2, 'Mouse')]), dn2)

        # ...unless you have a non-numeric key
        with self.assertRaises(TypeError):
            NumDict([('Rat', 11), ('Snake', 12)])
        with self.assertRaises(TypeError):
            NumDict(dict=[('Rat', 11), ('Snake', 12)])

        # combining item sequence constructors with keyword args does not work
        with self.assertRaises(
                TypeError
        ):  # Raise TypeError since we can't have numeric keywords
            NumDict([(1, 'one'), (2, 'two')], two=3, five=4)

        # alternate constructors
        d8 = {1: 'Echo', 2: 'Echo'}

        self.assertEqual(NumDict.fromkeys('1 2'.split()), dn6)
        self.assertEqual(NumDict().fromkeys('1 2'.split()), dn6)
        self.assertEqual(NumDict.fromkeys('1 2'.split(), 'Echo'), d8)
        self.assertEqual(NumDict().fromkeys('1 2'.split(), 'Echo'), d8)
        self.assertTrue(n1.fromkeys('1 2'.split()) is not n1)
        self.assertIsInstance(n1.fromkeys('1 2'.split()), NumDict)
        self.assertIsInstance(n2.fromkeys('1 2'.split()), NumDict)
        self.assertIsInstance(n3.fromkeys('1 2'.split()), NumDict)
        self.assertIsInstance(n4.fromkeys('1 2'.split()), NumDict)
示例#12
0
    def test_dict_access_and_modification(self):
        # dicts for testing
        d0 = {}  # Empty dictionary
        d1 = {1: 'Elephant'}  # Single numeric key
        d2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys

        #  Construct NumDicts from dicts
        n0 = NumDict()
        n1 = NumDict(d1)
        n2 = NumDict(d2)

        # test __getitem__
        self.assertEqual(n2[1], 'Elephant')
        with self.assertRaises(KeyError):
            n1['Mouse']  # key is not numeric
        with self.assertRaises(KeyError):
            n1.__getitem__('Mouse')  # key is not numeric
        with self.assertRaises(KeyError):
            n1[None]  # key does not exist
        with self.assertRaises(KeyError):
            n1.__getitem__(None)  # key does not exist

        # Test __setitem__
        n3 = NumDict(n2)
        self.assertEqual(n2, n3)

        n3[2] = 'Frog'
        self.assertNotEqual(n2, n3)

        # Check None keys and numeric key conversion
        n3['3'] = 'Armadillo'
        n3[None] = 'Cockroach'

        # Check long ints
        n3[12390809518259081208909880312] = 'Squid'
        n3['12390809518259081208909880312'] = 'Octopus'
        self.assertEqual(n3[12390809518259081208909880312], 'Octopus')

        with self.assertRaises(TypeError):
            n3.__setitem__('Gorilla', 1)  # key is not numeric
        with self.assertRaises(TypeError):
            n3['Chimpanzee'] = 1  # key is not numeric
        with self.assertRaises(TypeError):
            n3[(4, 1)] = 1  # key is not numeric
        with self.assertRaises(TypeError):
            n3[[1, 3, 4]] = 1  # key is not numeric and is not hashable

        # Test __delitem__
        del n3[3]
        del n3[None]
        with self.assertRaises(KeyError):
            del n3[3]  # already deleted
        with self.assertRaises(KeyError):
            n3.__delitem__(3)  # already deleted
        with self.assertRaises(KeyError):
            del n3['Mouse']  # key would not exist, since it is not numeric

        # Test clear
        n3.clear()
        self.assertEqual(n3, {})

        # Test copy()
        n2a = d2.copy()
        self.assertEqual(n2, n2a)
        n2b = n2.copy()
        self.assertEqual(n2b, n2)
        n2c = UserDict({1: 'Elephant', 2: 'Mouse'})
        n2d = n2c.copy()  # making a copy of a UserDict is special cased
        self.assertEqual(n2c, n2d)

        class MyNumDict(NumDict):
            """
            subclass Numdict for testing
            """
            def display(self):
                """
                add a method to subclass to differentiate from superclass
                """
                print('MyNumDict:', self)

        m2 = MyNumDict(n2)
        m2a = m2.copy()
        self.assertEqual(m2a, m2)

        m2[1] = 'Frog'
        self.assertNotEqual(m2a, m2)

        # Test keys, items, values
        self.assertEqual(sorted(n2.keys()), sorted(d2.keys()))
        self.assertEqual(sorted(n2.items()), sorted(d2.items()))
        self.assertEqual(sorted(n2.values()), sorted(d2.values()))

        # Test "in".
        for i in n2:
            self.assertIn(i, n2)
            self.assertEqual(i in n1, i in d1)
            self.assertEqual(i in n0, i in d0)

        self.assertFalse(None in n2)
        self.assertEqual(None in n2, None in d2)

        d2[None] = 'Cow'
        n2[None] = d2[None]
        self.assertTrue(None in n2)
        self.assertEqual(None in n2, None in d2)

        self.assertEqual(n2.has_key(None), None in d2)
        if not PY3:
            self.assertEqual(n2.has_key(None), d2.has_key(None))
        self.assertFalse('Penguin' in n2)

        # Test update
        t = NumDict()
        t.update(d2)
        self.assertEqual(t, n2)

        # Test get
        for i in n2:
            self.assertEqual(n2.get(i), n2[i])
            self.assertEqual(n1.get(i), d1.get(i))
            self.assertEqual(n0.get(i), d0.get(i))

        for i in ['purple', None, 12312301924091284, 23]:
            self.assertEqual(n2.get(i), d2.get(i), i)

        with self.assertRaises(AssertionError):
            i = '1'
            self.assertEqual(n2.get(i), d2.get(i),
                             i)  # d2 expects string key which does not exist

        # Test "in" iteration.
        n2b = n2
        for i in range(20):
            n2[i] = str(i)
            n2b[str(i)] = str(i)
        self.assertEqual(n2, n2b)

        ikeys = []
        for k in n2:
            ikeys.append(k)
        self.assertEqual(set(ikeys), set(n2.keys()))

        # Test setdefault
        x = 1
        t = NumDict()
        self.assertEqual(t.setdefault(x, 42), 42)
        self.assertEqual(t.setdefault(x, '42'), 42)
        self.assertNotEqual(t.setdefault(x, 42), '42')
        self.assertNotEqual(t.setdefault(x, '42'), '42')
        self.assertIn(x, t)

        self.assertEqual(t.setdefault(x, 23), 42)
        self.assertEqual(t.setdefault(x, '23'), 42)
        self.assertNotEqual(t.setdefault(x, 23), '42')
        self.assertNotEqual(t.setdefault(x, '23'), '42')
        self.assertIn(x, t)

        # Test pop
        x = 1
        t = NumDict({x: 42})
        self.assertEqual(t.pop(x), 42)
        self.assertRaises(KeyError, t.pop, x)
        self.assertEqual(t.pop(x, 1), 1)
        t[x] = 42
        self.assertEqual(t.pop(x, 1), 42)

        # Test popitem
        x = 1
        t = NumDict({x: 42})
        self.assertEqual(t.popitem(), (x, 42))
        self.assertRaises(KeyError, t.popitem)
示例#13
0
    def test_repr(self):
        # dicts for testing
        d0 = {}  # Empty dictionary
        d1 = {1: 'Elephant'}  # Single numeric key
        d2 = {1: 'Elephant', 2: 'Mouse'}  # Multiple numeric keys
        d3 = {'3': 'Aardvark'}  # Numeric string key
        d4 = {'3': 'Aardvark', '4': 'Ant'}  # Multiple numeric string keys
        d5 = {5: 'Cat', '6': 'Dog'}  # Mixed numeric and numeric string keys
        d6 = {1: None, '2': None}  # None as values
        d7 = {None: 'Empty'}  # None as key

        #  Construct NumDicts from dicts
        n = NumDict()
        n0 = NumDict(d0)
        n1 = NumDict(d1)
        n2 = NumDict(d2)
        n3 = NumDict(d3)
        n4 = NumDict(d4)
        n5 = NumDict(d5)
        n6 = NumDict(d6)
        n7 = NumDict(d7)

        reps = (
            "{}",
            "{1: 'Elephant'}",
            "{1: 'Elephant', 2: 'Mouse'}",
            "'3': 'Aardvark'",
            "{'3': 'Aardvark', '4': 'Ant'}",
            "{5: 'Cat', '6': 'Dog'}",
            "{1: None, '2': None}",
            "{None: 'Empty'}",
        )

        # Most representations of NumDicts should compare equal to dicts...
        self.assertEqual(str(n), str({}))
        self.assertEqual(repr(n), repr({}))
        self.assertIn(repr(n), reps)

        self.assertEqual(str(n0), str(d0))
        self.assertEqual(repr(n0), repr(d0))
        self.assertIn(repr(n0), reps)

        self.assertEqual(str(n1), str(d1))
        self.assertEqual(repr(n1), repr(d1))
        self.assertIn(repr(n1), reps)

        self.assertEqual(str(n2), str(d2))
        self.assertEqual(repr(n2), repr(d2))
        self.assertIn(repr(n2), reps)

        # ...however, numeric keys are not equal to numeric string keys...
        # ...so the string representations for those are different...
        self.assertNotEqual(str(n3), str(d3))
        self.assertNotEqual(repr(n3), repr(d3))
        self.assertNotIn(repr(n3), reps)

        self.assertNotEqual(str(n4), str(d4))
        self.assertNotEqual(repr(n4), repr(d4))
        self.assertNotIn(repr(n4), reps)

        self.assertNotEqual(str(n5), str(d5))
        self.assertNotEqual(repr(n5), repr(d5))
        self.assertNotIn(repr(n5), reps)

        self.assertNotEqual(str(n6), str(d6))
        self.assertNotEqual(repr(n6), repr(d6))
        self.assertNotIn(repr(n6), reps)

        # ...but None keys work just fine
        self.assertEqual(str(n7), str(d7))
        self.assertEqual(repr(n7), repr(d7))
        self.assertIn(repr(n7), reps)
示例#14
0
class Quality(object):
    """
    Determine quality and set status codes
    """
    NONE = 0  # 0
    SDTV = 1  # 1
    SDDVD = 1 << 1  # 2
    HDTV = 1 << 2  # 4
    RAWHDTV = 1 << 3  # 8  -- 720p/1080i mpeg2 (trollhd releases)
    FULLHDTV = 1 << 4  # 16 -- 1080p HDTV (QCF releases)
    HDWEBDL = 1 << 5  # 32
    FULLHDWEBDL = 1 << 6  # 64 -- 1080p web-dl
    HDBLURAY = 1 << 7  # 128
    FULLHDBLURAY = 1 << 8  # 256
    ANYHDTV = HDTV | FULLHDTV  # 20
    ANYWEBDL = HDWEBDL | FULLHDWEBDL  # 96
    ANYBLURAY = HDBLURAY | FULLHDBLURAY  # 384

    # put these bits at the other end of the spectrum, far enough out that they shouldn't interfere
    UNKNOWN = 1 << 15  # 32768

    qualityStrings = NumDict({
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "SDTV",
        SDDVD: "SD DVD",
        HDTV: "720p HDTV",
        RAWHDTV: "RawHD",
        FULLHDTV: "1080p HDTV",
        HDWEBDL: "720p WEB-DL",
        FULLHDWEBDL: "1080p WEB-DL",
        HDBLURAY: "720p BluRay",
        FULLHDBLURAY: "1080p BluRay"
    })

    sceneQualityStrings = NumDict({
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "HDTV",
        SDDVD: "",
        HDTV: "720p HDTV",
        RAWHDTV: "1080i HDTV",
        FULLHDTV: "1080p HDTV",
        HDWEBDL: "720p WEB-DL",
        FULLHDWEBDL: "1080p WEB-DL",
        HDBLURAY: "720p BluRay",
        FULLHDBLURAY: "1080p BluRay"
    })

    combinedQualityStrings = NumDict({
        ANYHDTV: "HDTV",
        ANYWEBDL: "WEB-DL",
        ANYBLURAY: "BluRay"
    })

    cssClassStrings = NumDict({
        NONE: "N/A",
        UNKNOWN: "Unknown",
        SDTV: "SDTV",
        SDDVD: "SDDVD",
        HDTV: "HD720p",
        RAWHDTV: "RawHD",
        FULLHDTV: "HD1080p",
        HDWEBDL: "HD720p",
        FULLHDWEBDL: "HD1080p",
        HDBLURAY: "HD720p",
        FULLHDBLURAY: "HD1080p",
        ANYHDTV: "any-hd",
        ANYWEBDL: "any-hd",
        ANYBLURAY: "any-hd"
    })

    statusPrefixes = NumDict({
        DOWNLOADED: "Downloaded",
        SNATCHED: "Snatched",
        SNATCHED_PROPER: "Snatched (Proper)",
        FAILED: "Failed",
        SNATCHED_BEST: "Snatched (Best)",
        ARCHIVED: "Archived"
    })

    @staticmethod
    def _getStatusStrings(status):
        """
        Returns string values associated with Status prefix

        :param status: Status prefix to resolve
        :return: Human readable status value
        """
        to_return = {}
        for quality in Quality.qualityStrings:
            to_return[Quality.compositeStatus(status, quality)] = Quality.statusPrefixes[status] + " (" + \
                                                           Quality.qualityStrings[quality] + ")"
        return to_return

    @staticmethod
    def combineQualities(any_qualities, best_qualities):
        any_quality = 0
        best_quality = 0
        if any_qualities:
            any_quality = reduce(operator.or_, any_qualities)
        if best_qualities:
            best_quality = reduce(operator.or_, best_qualities)
        return any_quality | (best_quality << 16)

    @staticmethod
    def splitQuality(quality):
        any_qualities = []
        best_qualities = []
        for cur_qual in Quality.qualityStrings:
            if cur_qual & quality:
                any_qualities.append(cur_qual)
            if cur_qual << 16 & quality:
                best_qualities.append(cur_qual)

        return sorted(any_qualities), sorted(best_qualities)

    @staticmethod
    def nameQuality(name, anime=False):
        """
        Return The quality from an episode File renamed by SickRage
        If no quality is achieved it will try sceneQuality regex

        :param name: to parse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality prefix
        """

        # Try Scene names first
        quality = Quality.sceneQuality(name, anime)
        if quality != Quality.UNKNOWN:
            return quality

        quality = Quality.assumeQuality(name)
        if quality != Quality.UNKNOWN:
            return quality

        return Quality.UNKNOWN

    @staticmethod
    def sceneQuality(name, anime=False):  # pylint: disable=too-many-branches
        """
        Return The quality from the scene episode File

        :param name: Episode filename to analyse
        :param anime: Boolean to indicate if the show we're resolving is Anime
        :return: Quality prefix
        """

        ret = Quality.UNKNOWN
        if not name:
            return ret

        name = ek(path.basename, name)

        check_name = lambda regex_list, func: func(
            [re.search(regex, name, re.I) for regex in regex_list])

        if anime:
            dvd_options = check_name([r"dvd", r"dvdrip"], any)
            bluray_options = check_name([r"BD", r"blue?-?ray"], any)
            sd_options = check_name([r"360p", r"480p", r"848x480", r"XviD"],
                                    any)
            hd_options = check_name([r"720p", r"1280x720", r"960x720"], any)
            full_hd = check_name([r"1080p", r"1920x1080"], any)

            if sd_options and not bluray_options and not dvd_options:
                ret = Quality.SDTV
            elif dvd_options:
                ret = Quality.SDDVD
            elif hd_options and not bluray_options and not full_hd:
                ret = Quality.HDTV
            elif full_hd and not bluray_options and not hd_options:
                ret = Quality.FULLHDTV
            elif hd_options and not bluray_options and not full_hd:
                ret = Quality.HDWEBDL
            elif bluray_options and hd_options and not full_hd:
                ret = Quality.HDBLURAY
            elif bluray_options and full_hd and not hd_options:
                ret = Quality.FULLHDBLURAY

            return ret

        if check_name([
                r"480p|web.?dl|web(rip|mux|hd)|[sph]d.?tv|dsr|tv(rip|mux)|satrip",
                r"xvid|divx|[xh].?26[45]"
        ], all) and not check_name([r"(720|1080)[pi]"],
                                   all) and not check_name(
                                       [r"hr.ws.pdtv.[xh].?26[45]"], any):
            ret = Quality.SDTV
        elif check_name([
                r"dvd(rip|mux)|b[rd](rip|mux)|blue?-?ray",
                r"xvid|divx|[xh].?26[45]"
        ], all) and not check_name([r"(720|1080)[pi]"],
                                   all) and not check_name(
                                       [r"hr.ws.pdtv.[xh].?26[45]"], any):
            ret = Quality.SDDVD
        elif check_name(
            [r"720p", r"hd.?tv", r"[xh].?26[45]"],
                all) or check_name([r"hr.ws.pdtv.[xh].?26[45]"],
                                   any) and not check_name([r"1080[pi]"], all):
            ret = Quality.HDTV
        elif check_name([r"720p|1080i", r"hd.?tv", r"mpeg-?2"],
                        all) or check_name([r"1080[pi].hdtv", r"h.?26[45]"],
                                           all):
            ret = Quality.RAWHDTV
        elif check_name([r"1080p", r"hd.?tv", r"[xh].?26[45]"], all):
            ret = Quality.FULLHDTV
        elif check_name([r"720p", r"web.?dl|web(rip|mux|hd)"],
                        all) or check_name(
                            [r"720p", r"itunes", r"[xh].?26[45]"], all):
            ret = Quality.HDWEBDL
        elif check_name([r"1080p", r"web.?dl|web(rip|mux|hd)"],
                        all) or check_name(
                            [r"1080p", r"itunes", r"[xh].?26[45]"], all):
            ret = Quality.FULLHDWEBDL
        elif check_name(
            [r"720p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"],
                all):
            ret = Quality.HDBLURAY
        elif check_name(
            [r"1080p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"],
                all):
            ret = Quality.FULLHDBLURAY

        return ret

    @staticmethod
    def assumeQuality(name):
        """
        Assume a quality from file extension if we cannot resolve it otherwise

        :param name: File name of episode to analyse
        :return: Quality prefix
        """
        quality = Quality.qualityFromFileMeta(name)
        if quality != Quality.UNKNOWN:
            return quality

        if name.lower().endswith(".ts"):
            return Quality.RAWHDTV
        else:
            return Quality.UNKNOWN

    @staticmethod
    def qualityFromFileMeta(filename):  # pylint: disable=too-many-branches
        """
        Get quality file file metadata

        :param filename: Filename to analyse
        :return: Quality prefix
        """

        log.use_print = False

        try:
            parser = createParser(filename)
        except Exception:  # pylint: disable=broad-except
            parser = None

        if not parser:
            return Quality.UNKNOWN

        try:
            metadata = extractMetadata(parser)
        except Exception:  # pylint: disable=broad-except
            metadata = None

        try:
            parser.stream._input.close()  # pylint: disable=protected-access
        except Exception:  # pylint: disable=broad-except
            pass

        if not metadata:
            return Quality.UNKNOWN

        height = 0
        if metadata.has('height'):
            height = int(metadata.get('height') or 0)
        else:
            test = getattr(metadata, "iterGroups", None)
            if callable(test):
                for metagroup in metadata.iterGroups():
                    if metagroup.has('height'):
                        height = int(metagroup.get('height') or 0)

        if not height:
            return Quality.UNKNOWN

        base_filename = ek(path.basename, filename)
        bluray = re.search(r"blue?-?ray|hddvd|b[rd](rip|mux)", base_filename,
                           re.I) is not None
        webdl = re.search(r"web.?dl|web(rip|mux|hd)", base_filename,
                          re.I) is not None

        ret = Quality.UNKNOWN
        if height > 1000:
            ret = ((Quality.FULLHDTV, Quality.FULLHDBLURAY)[bluray],
                   Quality.FULLHDWEBDL)[webdl]
        elif 680 < height < 800:
            ret = ((Quality.HDTV, Quality.HDBLURAY)[bluray],
                   Quality.HDWEBDL)[webdl]
        elif height < 680:
            ret = (Quality.SDTV, Quality.SDDVD)[re.search(
                r'dvd|b[rd]rip|blue?-?ray', base_filename, re.I) is not None]

        return ret

    @staticmethod
    def compositeStatus(status, quality):
        return status + 100 * quality

    @staticmethod
    def qualityDownloaded(status):
        return (status - DOWNLOADED) / 100

    @staticmethod
    def splitCompositeStatus(status):
        """
        Split a composite status code into a status and quality.

        :param status: to split
        :returns: a tuple containing (status, quality)
        """
        if status == UNKNOWN:
            return UNKNOWN, Quality.UNKNOWN

        for q in sorted(Quality.qualityStrings.keys(), reverse=True):
            if status > q * 100:
                return status - q * 100, q

        return status, Quality.NONE

    @staticmethod
    def sceneQualityFromName(name, quality):  # pylint: disable=too-many-branches
        """
        Get scene naming parameters from filename and quality

        :param name: Filename to check
        :param quality: int of quality to make sure we get the right rip type
        :return: encoder type for scene quality naming
        """
        codec_list = ['xvid', 'divx']
        x264_list = ['x264', 'x 264', 'x.264']
        h264_list = ['h264', 'h 264', 'h.264', 'avc']
        x265_list = ['x265', 'x 265', 'x.265']
        h265_list = ['h265', 'h 265', 'h.265', 'hevc']
        codec_list += x264_list + h264_list + x265_list + h265_list

        found_codecs = {}
        found_codec = None

        for codec in codec_list:
            if codec in name.lower():
                found_codecs[name.lower().rfind(codec)] = codec

        if found_codecs:
            sorted_codecs = sorted(found_codecs, reverse=True)
            found_codec = found_codecs[list(sorted_codecs)[0]]

        # 2 corresponds to SDDVD quality
        if quality == 2:
            if re.search(r"b(r|d|rd)?(-| |\.)?(rip|mux)", name.lower()):
                rip_type = " BDRip"
            elif re.search(r"(dvd)(-| |\.)?(rip|mux)?", name.lower()):
                rip_type = " DVDRip"
            else:
                rip_type = ""

        if found_codec:
            if codec_list[0] in found_codec:
                found_codec = 'XviD'
            elif codec_list[1] in found_codec:
                found_codec = 'DivX'
            elif found_codec in x264_list:
                found_codec = x264_list[0]
            elif found_codec in h264_list:
                found_codec = h264_list[0]
            elif found_codec in x265_list:
                found_codec = x265_list[0]
            elif found_codec in h265_list:
                found_codec = h265_list[0]

            if quality == 2:
                return rip_type + " " + found_codec
            else:
                return " " + found_codec
        elif quality == 2:
            return rip_type
        else:
            return ""

    @staticmethod
    def statusFromName(name, assume=True, anime=False):
        """
        Get a status object from filename

        :param name: Filename to check
        :param assume: boolean to assume quality by extension if we can't figure it out
        :param anime: boolean to enable anime parsing
        :return: Composite status/quality object
        """
        quality = Quality.nameQuality(name, anime)
        if assume and quality == Quality.UNKNOWN:
            quality = Quality.assumeQuality(name)
        return Quality.compositeStatus(DOWNLOADED, quality)

    DOWNLOADED = None
    SNATCHED = None
    SNATCHED_PROPER = None
    FAILED = None
    SNATCHED_BEST = None
    ARCHIVED = None