/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())
|