This file is indexed.

/usr/lib/python3/dist-packages/guessit/transfo/guess_release_group.py is in python3-guessit 0.11.0-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# GuessIt - A library for guessing information from filenames
# Copyright (c) 2013 Nicolas Wack <wackou@gmail.com>
#
# GuessIt is free software; you can redistribute it and/or modify it under
# the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# GuessIt 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
# Lesser GNU General Public License for more details.
#
# You should have received a copy of the Lesser GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function, unicode_literals

import re

from guessit.plugins.transformers import Transformer
from guessit.matcher import GuessFinder, build_guess
from guessit.containers import PropertiesContainer
from guessit.patterns import sep
from guessit.guess import Guess
from guessit.textutils import strip_brackets


class GuessReleaseGroup(Transformer):
    def __init__(self):
        Transformer.__init__(self, -190)

        self.container = PropertiesContainer(canonical_from_pattern=False)
        self._allowed_groupname_pattern = '[\w@#€£$&!\?]'
        self._forbidden_groupname_lambda = [lambda elt: elt in ['rip', 'by', 'for', 'par', 'pour', 'bonus'],
                                            lambda elt: self._is_number(elt)]
        # If the previous property in this list, the match will be considered as safe
        # and group name can contain a separator.
        self.previous_safe_properties = ['videoCodec', 'format', 'videoApi', 'audioCodec', 'audioProfile', 'videoProfile', 'audioChannels', 'screenSize', 'other']
        self.previous_safe_values = {'other': ['Complete']}
        self.next_safe_properties = ['extension', 'website']
        self.next_safe_values = {'format': ['Telesync']}
        self.next_unsafe_properties = list(self.previous_safe_properties)
        self.next_unsafe_properties.extend(['episodeNumber', 'season'])
        self.container.sep_replace_char = '-'
        self.container.canonical_from_pattern = False
        self.container.enhance = True
        self.container.register_property('releaseGroup', self._allowed_groupname_pattern + '+')
        self.container.register_property('releaseGroup', self._allowed_groupname_pattern + '+-' + self._allowed_groupname_pattern + '+')
        self.re_sep = re.compile('(' + sep + ')')

    def register_arguments(self, opts, naming_opts, output_opts, information_opts, webservice_opts, other_options):
        naming_opts.add_argument('-G', '--expected-group', action='append', dest='expected_group',
                               help='Expected release group (can be used multiple times)')

    def supported_properties(self):
        return self.container.get_supported_properties()

    @staticmethod
    def _is_number(s):
        try:
            int(s)
            return True
        except ValueError:
            return False

    def validate_group_name(self, guess):
        val = guess['releaseGroup']
        if len(val) > 1:
            checked_val = ""
            forbidden = False
            for elt in self.re_sep.split(val): # separators are in the list because of capturing group
                if forbidden:
                    # Previous was forbidden, don't had separator
                    forbidden = False
                    continue
                for forbidden_lambda in self._forbidden_groupname_lambda:
                    forbidden = forbidden_lambda(elt.lower())
                    if forbidden:
                        if checked_val:
                            # Removing previous separator
                            checked_val = checked_val[0:len(checked_val) - 1]
                        break
                if not forbidden:
                    checked_val += elt

            val = checked_val
            if not val:
                return False
            if self.re_sep.match(val[-1]):
                val = val[:len(val)-1]
            if not val:
                return False
            if self.re_sep.match(val[0]):
                val = val[1:]
            if not val:
                return False
            guess['releaseGroup'] = val
            forbidden = False
            for forbidden_lambda in self._forbidden_groupname_lambda:
                forbidden = forbidden_lambda(val.lower())
                if forbidden:
                    break
            if not forbidden:
                return True
        return False

    @staticmethod
    def is_leaf_previous(leaf, node):
        if leaf.span[1] <= node.span[0]:
            for idx in range(leaf.span[1], node.span[0]):
                if leaf.root.value[idx] not in sep:
                    return False
            return True
        return False

    def validate_next_leaves(self, node):
        if 'series' in node.root.info or 'title' in node.root.info:
            # --expected-series or --expected-title is used.
            return True

        next_leaf = node.root.next_leaf(node)
        node_idx = node.node_last_idx
        while next_leaf and next_leaf.node_last_idx >= node_idx:
            node_idx = next_leaf.node_last_idx
            # Check next properties in the same group are not in unsafe properties list
            for next_unsafe_property in self.next_unsafe_properties:
                if next_unsafe_property in next_leaf.info:
                    return False
            next_leaf = next_leaf.root.next_leaf(next_leaf)

        # Make sure to avoid collision with 'series' or 'title' guessed later. Should be more precise.
        leaves = node.root.unidentified_leaves()
        return len(list(leaves)) > 1

    def validate_node(self, leaf, node, safe=False):
        if not self.is_leaf_previous(leaf, node):
            return False
        if not self.validate_next_leaves(node):
            return False
        if safe:
            for k, v in leaf.guess.items():
                if k in self.previous_safe_values and v not in self.previous_safe_values[k]:
                    return False
        return True

    def guess_release_group(self, string, node=None, options=None):
        if options and options.get('expected_group'):
            expected_container = PropertiesContainer(enhance=True, canonical_from_pattern=False)
            for expected_group in options.get('expected_group'):
                if expected_group.startswith('re:'):
                    expected_group = expected_group[3:]
                    expected_group = expected_group.replace(' ', '-')
                    expected_container.register_property('releaseGroup', expected_group, enhance=True)
                else:
                    expected_group = re.escape(expected_group)
                    expected_container.register_property('releaseGroup', expected_group, enhance=False)

            found = expected_container.find_properties(string, node, options, 'releaseGroup')
            guess = expected_container.as_guess(found, string, self.validate_group_name)
            if guess:
                return guess

        found = self.container.find_properties(string, node, options, 'releaseGroup')
        guess = self.container.as_guess(found, string, self.validate_group_name)
        validated_guess = None
        if guess:
            group_node = node.group_node()
            if group_node:
                for leaf in group_node.leaves_containing(self.previous_safe_properties):
                    if self.validate_node(leaf, node, True):
                        if leaf.root.value[leaf.span[1]] == '-':
                            guess.metadata().confidence = 1
                        else:
                            guess.metadata().confidence = 0.7
                        validated_guess = guess

            if not validated_guess:
                # If previous group last leaf is identified as a safe property,
                # consider the raw value as a releaseGroup
                previous_group_node = node.previous_group_node()
                if previous_group_node:
                    for leaf in previous_group_node.leaves_containing(self.previous_safe_properties):
                        if self.validate_node(leaf, node, False):
                            guess = Guess({'releaseGroup': node.value}, confidence=1, input=node.value, span=(0, len(node.value)))
                            if self.validate_group_name(guess):
                                node.guess = guess
                                validated_guess = guess

            if validated_guess:
                # If following group nodes have only one unidentified leaf, it belongs to the release group
                next_group_node = node

                while True:
                    next_group_node = next_group_node.next_group_node()
                    if next_group_node:
                        leaves = list(next_group_node.leaves())
                        if len(leaves) == 1 and not leaves[0].guess:
                            validated_guess['releaseGroup'] = validated_guess['releaseGroup'] + leaves[0].value
                            leaves[0].guess = validated_guess
                        else:
                            break
                    else:
                        break

            if not validated_guess and node.is_explicit() and node.node_last_idx == 0: # first node from group
                validated_guess = build_guess(node, 'releaseGroup', value=node.value[1:len(node.value)-1])
                validated_guess.metadata().confidence = 0.4
                validated_guess.metadata().span = 1, len(node.value)
                node.guess = validated_guess

        if validated_guess:
            # Strip brackets
            validated_guess['releaseGroup'] = strip_brackets(validated_guess['releaseGroup'])

        return validated_guess

    def process(self, mtree, options=None):
        GuessFinder(self.guess_release_group, None, self.log, options).process_nodes(mtree.unidentified_leaves())