Merge pull request #2577 from fuzeman/tv_searcher
[TV] Season pack matching, better show search triggering
This commit is contained in:
@@ -94,6 +94,8 @@ class ShowBase(MediaBase):
|
|||||||
season_params = {'season_identifier': season_id}
|
season_params = {'season_identifier': season_id}
|
||||||
# Calling all info providers; merge your info now for individual season
|
# Calling all info providers; merge your info now for individual season
|
||||||
single_season = fireEvent('season.info', merge = True, identifier = identifier, params = season_params)
|
single_season = fireEvent('season.info', merge = True, identifier = identifier, params = season_params)
|
||||||
|
single_season['category_id'] = params.get('category_id')
|
||||||
|
single_season['profile_id'] = params.get('profile_id')
|
||||||
single_season['title'] = single_season.get('original_title', None)
|
single_season['title'] = single_season.get('original_title', None)
|
||||||
single_season['identifier'] = season_id
|
single_season['identifier'] = season_id
|
||||||
single_season['parent_identifier'] = identifier
|
single_season['parent_identifier'] = identifier
|
||||||
@@ -125,6 +127,8 @@ class ShowBase(MediaBase):
|
|||||||
episode_params['absolute'] = absolute_number
|
episode_params['absolute'] = absolute_number
|
||||||
# Calling all info providers; merge your info now for individual episode
|
# Calling all info providers; merge your info now for individual episode
|
||||||
single_episode = fireEvent('episode.info', merge = True, identifier = identifier, params = episode_params)
|
single_episode = fireEvent('episode.info', merge = True, identifier = identifier, params = episode_params)
|
||||||
|
single_episode['category_id'] = params.get('category_id')
|
||||||
|
single_episode['profile_id'] = params.get('profile_id')
|
||||||
single_episode['title'] = single_episode.get('original_title', None)
|
single_episode['title'] = single_episode.get('original_title', None)
|
||||||
single_episode['identifier'] = episode_id
|
single_episode['identifier'] = episode_id
|
||||||
single_episode['parent_identifier'] = single_season['identifier']
|
single_episode['parent_identifier'] = single_season['identifier']
|
||||||
@@ -134,9 +138,14 @@ class ShowBase(MediaBase):
|
|||||||
single_episode.get('original_title', '')))
|
single_episode.get('original_title', '')))
|
||||||
e = self.addToDatabase(params = single_episode, type = "episode")
|
e = self.addToDatabase(params = single_episode, type = "episode")
|
||||||
|
|
||||||
|
# Start searching now that all the media has been added
|
||||||
|
if search_after:
|
||||||
|
onComplete = self.createOnComplete(parent['id'])
|
||||||
|
onComplete()
|
||||||
|
|
||||||
return parent
|
return parent
|
||||||
|
|
||||||
def addToDatabase(self, params = {}, type = "show", force_readd = True, search_after = True, update_library = False, status_id = None):
|
def addToDatabase(self, params = {}, type = "show", force_readd = True, search_after = False, update_library = False, status_id = None):
|
||||||
log.debug("show.addToDatabase")
|
log.debug("show.addToDatabase")
|
||||||
|
|
||||||
if not params.get('identifier'):
|
if not params.get('identifier'):
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from couchpotato import Env, get_session
|
from couchpotato import Env, get_session
|
||||||
from couchpotato.core.event import addEvent, fireEvent
|
from couchpotato.core.event import addEvent, fireEvent
|
||||||
from couchpotato.core.helpers.variable import getTitle, tryInt, toIterable
|
from couchpotato.core.helpers.variable import getTitle, toIterable
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
from couchpotato.core.media._base.searcher.main import SearchSetupError
|
from couchpotato.core.media._base.searcher.main import SearchSetupError
|
||||||
|
from couchpotato.core.media.show._base import ShowBase
|
||||||
from couchpotato.core.plugins.base import Plugin
|
from couchpotato.core.plugins.base import Plugin
|
||||||
from couchpotato.core.settings.model import Media
|
from couchpotato.core.settings.model import Media
|
||||||
from qcond import QueryCondenser
|
from qcond import QueryCondenser
|
||||||
@@ -17,10 +18,20 @@ class ShowSearcher(Plugin):
|
|||||||
|
|
||||||
in_progress = False
|
in_progress = False
|
||||||
|
|
||||||
# TODO come back to this later, think this could be handled better
|
# TODO come back to this later, think this could be handled better, this is starting to get out of hand....
|
||||||
quality_map = {
|
quality_map = {
|
||||||
|
'bluray_1080p': {'resolution': ['1080p'], 'source': ['bluray']},
|
||||||
|
'bluray_720p': {'resolution': ['720p'], 'source': ['bluray']},
|
||||||
|
|
||||||
|
'bdrip_1080p': {'resolution': ['1080p'], 'source': ['BDRip']},
|
||||||
|
'bdrip_720p': {'resolution': ['720p'], 'source': ['BDRip']},
|
||||||
|
|
||||||
|
'brrip_1080p': {'resolution': ['1080p'], 'source': ['BRRip']},
|
||||||
|
'brrip_720p': {'resolution': ['720p'], 'source': ['BRRip']},
|
||||||
|
|
||||||
'webdl_1080p': {'resolution': ['1080p'], 'source': ['webdl', ['web', 'dl']]},
|
'webdl_1080p': {'resolution': ['1080p'], 'source': ['webdl', ['web', 'dl']]},
|
||||||
'webdl_720p': {'resolution': ['720p'], 'source': ['webdl', ['web', 'dl']]},
|
'webdl_720p': {'resolution': ['720p'], 'source': ['webdl', ['web', 'dl']]},
|
||||||
|
'webdl_480p': {'resolution': ['480p'], 'source': ['webdl', ['web', 'dl']]},
|
||||||
|
|
||||||
'hdtv_720p': {'resolution': ['720p'], 'source': ['hdtv']},
|
'hdtv_720p': {'resolution': ['720p'], 'source': ['hdtv']},
|
||||||
'hdtv_sd': {'resolution': ['480p', None], 'source': ['hdtv']},
|
'hdtv_sd': {'resolution': ['480p', None], 'source': ['hdtv']},
|
||||||
@@ -42,8 +53,15 @@ class ShowSearcher(Plugin):
|
|||||||
def single(self, media, search_protocols = None, manual = False):
|
def single(self, media, search_protocols = None, manual = False):
|
||||||
show, season, episode = self.getLibraries(media['library'])
|
show, season, episode = self.getLibraries(media['library'])
|
||||||
|
|
||||||
|
db = get_session()
|
||||||
|
|
||||||
if media['type'] == 'show':
|
if media['type'] == 'show':
|
||||||
# TODO handle show searches (scan all seasons)
|
for library in season:
|
||||||
|
# TODO ideally we shouldn't need to fetch the media for each season library here
|
||||||
|
m = db.query(Media).filter_by(library_id = library['library_id']).first()
|
||||||
|
|
||||||
|
fireEvent('season.searcher.single', m.to_dict(ShowBase.search_dict))
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Find out search type
|
# Find out search type
|
||||||
@@ -59,8 +77,6 @@ class ShowSearcher(Plugin):
|
|||||||
log.debug('Episode doesn\'t have a profile or already done, assuming in manage tab.')
|
log.debug('Episode doesn\'t have a profile or already done, assuming in manage tab.')
|
||||||
return
|
return
|
||||||
|
|
||||||
db = get_session()
|
|
||||||
|
|
||||||
#pre_releases = fireEvent('quality.pre_releases', single = True)
|
#pre_releases = fireEvent('quality.pre_releases', single = True)
|
||||||
|
|
||||||
found_releases = []
|
found_releases = []
|
||||||
@@ -95,7 +111,12 @@ class ShowSearcher(Plugin):
|
|||||||
# Don't search for quality lower then already available.
|
# Don't search for quality lower then already available.
|
||||||
if has_better_quality is 0:
|
if has_better_quality is 0:
|
||||||
|
|
||||||
log.info('Search for %s S%02d%s in %s', (getTitle(show), season['season_number'], "E%02d" % episode['episode_number'] if episode else "", quality_type['quality']['label']))
|
log.info('Search for %s S%02d%s in %s', (
|
||||||
|
getTitle(show),
|
||||||
|
season['season_number'],
|
||||||
|
"E%02d" % episode['episode_number'] if episode and len(episode) == 1 else "",
|
||||||
|
quality_type['quality']['label'])
|
||||||
|
)
|
||||||
quality = fireEvent('quality.single', identifier = quality_type['quality']['identifier'], single = True)
|
quality = fireEvent('quality.single', identifier = quality_type['quality']['identifier'], single = True)
|
||||||
|
|
||||||
results = fireEvent('searcher.search', search_protocols, media, quality, single = True)
|
results = fireEvent('searcher.search', search_protocols, media, quality, single = True)
|
||||||
@@ -119,7 +140,7 @@ class ShowSearcher(Plugin):
|
|||||||
fireEvent('release.delete', release.get('id'), single = True)
|
fireEvent('release.delete', release.get('id'), single = True)
|
||||||
else:
|
else:
|
||||||
log.info('Better quality (%s) already available or snatched for %s', (quality_type['quality']['label'], default_title))
|
log.info('Better quality (%s) already available or snatched for %s', (quality_type['quality']['label'], default_title))
|
||||||
fireEvent('movie.restatus', media['id'])
|
fireEvent('media.restatus', media['id'])
|
||||||
break
|
break
|
||||||
|
|
||||||
# Break if CP wants to shut down
|
# Break if CP wants to shut down
|
||||||
@@ -128,6 +149,16 @@ class ShowSearcher(Plugin):
|
|||||||
|
|
||||||
if len(too_early_to_search) > 0:
|
if len(too_early_to_search) > 0:
|
||||||
log.info2('Too early to search for %s, %s', (too_early_to_search, default_title))
|
log.info2('Too early to search for %s, %s', (too_early_to_search, default_title))
|
||||||
|
elif media['type'] == 'season' and not ret:
|
||||||
|
# If nothing was found, start searching for episodes individually
|
||||||
|
log.info('No season pack found, starting individual episode search')
|
||||||
|
|
||||||
|
for library in episode:
|
||||||
|
# TODO ideally we shouldn't need to fetch the media for each episode library here
|
||||||
|
m = db.query(Media).filter_by(library_id = library['library_id']).first()
|
||||||
|
|
||||||
|
fireEvent('episode.searcher.single', m.to_dict(ShowBase.search_dict))
|
||||||
|
|
||||||
|
|
||||||
fireEvent('notify.frontend', type = 'show.searcher.ended.%s' % media['id'], data = True)
|
fireEvent('notify.frontend', type = 'show.searcher.ended.%s' % media['id'], data = True)
|
||||||
|
|
||||||
@@ -234,17 +265,18 @@ class ShowSearcher(Plugin):
|
|||||||
|
|
||||||
libraries = library['related_libraries']
|
libraries = library['related_libraries']
|
||||||
|
|
||||||
# Get libraries and return lists only if there is multiple items
|
# Show always collapses as there can never be any multiples
|
||||||
show = libraries.get('show', [])
|
show = libraries.get('show', [])
|
||||||
if len(show) <= 1:
|
show = show[0] if len(show) else None
|
||||||
show = show[0] if len(show) else None
|
|
||||||
|
|
||||||
|
# Season collapses if the subject is a season or episode
|
||||||
season = libraries.get('season', [])
|
season = libraries.get('season', [])
|
||||||
if len(season) <= 1:
|
if library['type'] in ['season', 'episode']:
|
||||||
season = season[0] if len(season) else None
|
season = season[0] if len(season) else None
|
||||||
|
|
||||||
|
# Episode collapses if the subject is a episode
|
||||||
episode = libraries.get('episode', [])
|
episode = libraries.get('episode', [])
|
||||||
if len(episode) <= 1:
|
if library['type'] == 'episode':
|
||||||
episode = episode[0] if len(episode) else None
|
episode = episode[0] if len(episode) else None
|
||||||
|
|
||||||
return show, season, episode
|
return show, season, episode
|
||||||
|
|||||||
@@ -35,29 +35,46 @@ class Matcher(Plugin):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def flattenInfo(self, info):
|
||||||
|
flat_info = {}
|
||||||
|
|
||||||
|
for match in info:
|
||||||
|
for key, value in match.items():
|
||||||
|
if key not in flat_info:
|
||||||
|
flat_info[key] = []
|
||||||
|
|
||||||
|
flat_info[key].append(value)
|
||||||
|
|
||||||
|
return flat_info
|
||||||
|
|
||||||
|
def simplifyValue(self, value):
|
||||||
|
if not value:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
return simplifyString(value)
|
||||||
|
|
||||||
|
if isinstance(value, list):
|
||||||
|
return [self.simplifyValue(x) for x in value]
|
||||||
|
|
||||||
|
raise ValueError("Unsupported value type")
|
||||||
|
|
||||||
def chainMatch(self, chain, group, tags):
|
def chainMatch(self, chain, group, tags):
|
||||||
|
info = self.flattenInfo(chain.info[group])
|
||||||
|
|
||||||
found_tags = []
|
found_tags = []
|
||||||
|
for tag, accepted in tags.items():
|
||||||
|
values = [self.simplifyValue(x) for x in info.get(tag, [None])]
|
||||||
|
|
||||||
for match in chain.info[group]:
|
if any([val in accepted for val in values]):
|
||||||
for ck, cv in match.items():
|
found_tags.append(tag)
|
||||||
if ck not in tags:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(cv, basestring) and simplifyString(cv) in tags[ck]:
|
|
||||||
found_tags.append(ck)
|
|
||||||
|
|
||||||
elif isinstance(cv, list):
|
|
||||||
simple_list = [simplifyString(x) for x in cv]
|
|
||||||
|
|
||||||
if simple_list in tags[ck]:
|
|
||||||
found_tags.append(ck)
|
|
||||||
|
|
||||||
log.debug('tags found: %s, required: %s' % (found_tags, tags.keys()))
|
log.debug('tags found: %s, required: %s' % (found_tags, tags.keys()))
|
||||||
|
|
||||||
if set(tags.keys()) == set(found_tags):
|
if set(tags.keys()) == set(found_tags):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return set([key for key, value in tags.items() if None not in value]) == set(found_tags)
|
return all([key in found_tags for key, value in tags.items()])
|
||||||
|
|
||||||
def correctIdentifier(self, chain, media):
|
def correctIdentifier(self, chain, media):
|
||||||
required_id = fireEvent('library.identifier', media['library'], single = True)
|
required_id = fireEvent('library.identifier', media['library'], single = True)
|
||||||
@@ -76,6 +93,14 @@ class Matcher(Plugin):
|
|||||||
for k, v in identifier.items():
|
for k, v in identifier.items():
|
||||||
identifier[k] = tryInt(v, None)
|
identifier[k] = tryInt(v, None)
|
||||||
|
|
||||||
|
if any([x in identifier for x in ['episode_from', 'episode_to']]):
|
||||||
|
log.info2('Wrong: releases with identifier ranges are not supported yet')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 'episode' is required in identifier for subset matching
|
||||||
|
if 'episode' not in identifier:
|
||||||
|
identifier['episode'] = None
|
||||||
|
|
||||||
if not dictIsSubset(required_id, identifier):
|
if not dictIsSubset(required_id, identifier):
|
||||||
log.info2('Wrong: required identifier %s does not match release identifier %s', (str(required_id), str(identifier)))
|
log.info2('Wrong: required identifier %s does not match release identifier %s', (str(required_id), str(identifier)))
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -28,10 +28,20 @@ class QualityPlugin(Plugin):
|
|||||||
{'identifier': 'ts', 'size': (600, 1000), 'label': 'TeleSync', 'alternative': ['telesync', 'hdts'], 'allow': [], 'ext':[]},
|
{'identifier': 'ts', 'size': (600, 1000), 'label': 'TeleSync', 'alternative': ['telesync', 'hdts'], 'allow': [], 'ext':[]},
|
||||||
{'identifier': 'cam', 'size': (600, 1000), 'label': 'Cam', 'alternative': ['camrip', 'hdcam'], 'allow': [], 'ext':[]},
|
{'identifier': 'cam', 'size': (600, 1000), 'label': 'Cam', 'alternative': ['camrip', 'hdcam'], 'allow': [], 'ext':[]},
|
||||||
|
|
||||||
# TODO come back to this later, think this could be handled better
|
# TODO come back to this later, think this could be handled better, this is starting to get out of hand....
|
||||||
|
# BluRay
|
||||||
|
{'identifier': 'bluray_1080p', 'hd': True, 'size': (800, 5000), 'label': 'BluRay - 1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
|
{'identifier': 'bluray_720p', 'hd': True, 'size': (800, 5000), 'label': 'BluRay - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
|
# BDRip
|
||||||
|
{'identifier': 'bdrip_1080p', 'hd': True, 'size': (800, 5000), 'label': 'BDRip - 1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
|
{'identifier': 'bdrip_720p', 'hd': True, 'size': (800, 5000), 'label': 'BDRip - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
|
# BRRip
|
||||||
|
{'identifier': 'brrip_1080p', 'hd': True, 'size': (800, 5000), 'label': 'BRRip - 1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
|
{'identifier': 'brrip_720p', 'hd': True, 'size': (800, 5000), 'label': 'BRRip - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
# WEB-DL
|
# WEB-DL
|
||||||
{'identifier': 'webdl_1080p', 'hd': True, 'size': (800, 5000), 'label': 'WEB-DL - 1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
{'identifier': 'webdl_1080p', 'hd': True, 'size': (800, 5000), 'label': 'WEB-DL - 1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
{'identifier': 'webdl_720p', 'hd': True, 'size': (800, 5000), 'label': 'WEB-DL - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
{'identifier': 'webdl_720p', 'hd': True, 'size': (800, 5000), 'label': 'WEB-DL - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
|
{'identifier': 'webdl_480p', 'hd': True, 'size': (100, 5000), 'label': 'WEB-DL - 480p', 'width': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
# HDTV
|
# HDTV
|
||||||
{'identifier': 'hdtv_720p', 'hd': True, 'size': (800, 5000), 'label': 'HDTV - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
{'identifier': 'hdtv_720p', 'hd': True, 'size': (800, 5000), 'label': 'HDTV - 720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv']},
|
||||||
{'identifier': 'hdtv_sd', 'hd': False, 'size': (100, 1000), 'label': 'HDTV - SD', 'width': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'mp4', 'avi']},
|
{'identifier': 'hdtv_sd', 'hd': False, 'size': (100, 1000), 'label': 'HDTV - SD', 'width': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'mp4', 'avi']},
|
||||||
|
|||||||
@@ -138,13 +138,21 @@ class Movie(MovieProvider, Base):
|
|||||||
|
|
||||||
class Season(SeasonProvider, Base):
|
class Season(SeasonProvider, Base):
|
||||||
|
|
||||||
|
# TODO come back to this later, a better quality system needs to be created
|
||||||
cat_ids = [
|
cat_ids = [
|
||||||
([65], ['hdtv_sd', 'hdtv_720p', 'webdl_720p', 'webdl_1080p']),
|
([65], [
|
||||||
|
'bluray_1080p', 'bluray_720p',
|
||||||
|
'bdrip_1080p', 'bdrip_720p',
|
||||||
|
'brrip_1080p', 'brrip_720p',
|
||||||
|
'webdl_1080p', 'webdl_720p', 'webdl_480p',
|
||||||
|
'hdtv_720p', 'hdtv_sd'
|
||||||
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Episode(EpisodeProvider, Base):
|
class Episode(EpisodeProvider, Base):
|
||||||
|
|
||||||
|
# TODO come back to this later, a better quality system needs to be created
|
||||||
cat_ids = [
|
cat_ids = [
|
||||||
([5], ['hdtv_720p', 'webdl_720p', 'webdl_1080p']),
|
([5], ['hdtv_720p', 'webdl_720p', 'webdl_1080p']),
|
||||||
([4, 78, 79], ['hdtv_sd'])
|
([4, 78, 79], ['hdtv_sd'])
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from caper.parsers.anime import AnimeParser
|
|||||||
from caper.parsers.scene import SceneParser
|
from caper.parsers.scene import SceneParser
|
||||||
|
|
||||||
|
|
||||||
__version_info__ = ('0', '2', '5')
|
__version_info__ = ('0', '2', '6')
|
||||||
__version_branch__ = 'master'
|
__version_branch__ = 'master'
|
||||||
|
|
||||||
__version__ = "%s%s" % (
|
__version__ = "%s%s" % (
|
||||||
|
|||||||
@@ -53,11 +53,8 @@ class CaptureConstraint(object):
|
|||||||
elif hasattr(fragment, name):
|
elif hasattr(fragment, name):
|
||||||
match = self.capture_group.parser.matcher.value_match(getattr(fragment, name), arg, single=True)
|
match = self.capture_group.parser.matcher.value_match(getattr(fragment, name), arg, single=True)
|
||||||
return 1.0, match is not None
|
return 1.0, match is not None
|
||||||
|
|
||||||
if not hasattr(fragment, name):
|
|
||||||
raise ValueError("Unable to find fragment with name '%s'" % name)
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unexpected argument type")
|
raise ValueError("Unable to find attribute with name '%s'" % name)
|
||||||
|
|
||||||
def execute(self, fragment):
|
def execute(self, fragment):
|
||||||
results = []
|
results = []
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ PATTERN_GROUPS = [
|
|||||||
(1.0, [
|
(1.0, [
|
||||||
# S01E01-E02
|
# S01E01-E02
|
||||||
('^S(?P<season>\d+)E(?P<episode_from>\d+)$', '^E(?P<episode_to>\d+)$'),
|
('^S(?P<season>\d+)E(?P<episode_from>\d+)$', '^E(?P<episode_to>\d+)$'),
|
||||||
|
# S03 E01 to E08
|
||||||
|
('^S(?P<season>\d+)$', '^E(?P<episode_from>\d+)$', '^to$', '^E(?P<episode_to>\d+)$'),
|
||||||
|
|
||||||
|
# S01-S03
|
||||||
|
('^S(?P<season_from>\d+)$', '^S(?P<season_to>\d+)$'),
|
||||||
|
|
||||||
# S02E13
|
# S02E13
|
||||||
r'^S(?P<season>\d+)E(?P<episode>\d+)$',
|
r'^S(?P<season>\d+)E(?P<episode>\d+)$',
|
||||||
# S01 E13
|
# S01 E13
|
||||||
@@ -72,25 +78,62 @@ PATTERN_GROUPS = [
|
|||||||
'1080p'
|
'1080p'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
#
|
||||||
|
# Source
|
||||||
|
#
|
||||||
|
|
||||||
(r'(?P<source>%s)', [
|
(r'(?P<source>%s)', [
|
||||||
|
'DVDRiP',
|
||||||
|
# HDTV
|
||||||
'HDTV',
|
'HDTV',
|
||||||
'PDTV',
|
'PDTV',
|
||||||
'DSR',
|
'DSR',
|
||||||
'DVDRiP',
|
# WEB
|
||||||
'WEBDL'
|
'WEBRip',
|
||||||
|
'WEBDL',
|
||||||
|
# BluRay
|
||||||
|
'BluRay',
|
||||||
|
'B(D|R)Rip',
|
||||||
|
# DVD
|
||||||
|
'DVDR',
|
||||||
|
'DVD9',
|
||||||
|
'DVD5'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
# For 'WEB-DL', 'WEB DL', etc...
|
# For multi-fragment 'WEB-DL', 'WEB-Rip', etc... matches
|
||||||
('(?P<source>WEB)', '(?P<source>DL)'),
|
('(?P<source>WEB)', '(?P<source>DL|Rip)'),
|
||||||
|
|
||||||
|
#
|
||||||
|
# Codec
|
||||||
|
#
|
||||||
|
|
||||||
(r'(?P<codec>%s)', [
|
(r'(?P<codec>%s)', [
|
||||||
'x264',
|
'x264',
|
||||||
'XViD',
|
'XViD',
|
||||||
'H264'
|
'H264',
|
||||||
|
'AVC'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
# For 'H 264' tags
|
# For multi-fragment 'H 264' tags
|
||||||
('(?P<codec>H)', '(?P<codec>264)'),
|
('(?P<codec>H)', '(?P<codec>264)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('dvd', [
|
||||||
|
r'D(ISC)?(?P<disc>\d+)',
|
||||||
|
|
||||||
|
r'R(?P<region>[0-8])',
|
||||||
|
|
||||||
|
(r'(?P<encoding>%s)', [
|
||||||
|
'PAL',
|
||||||
|
'NTSC'
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('audio', [
|
||||||
|
(r'(?P<codec>%s)', [
|
||||||
|
'AC3',
|
||||||
|
'TrueHD'
|
||||||
|
]),
|
||||||
|
|
||||||
(r'(?P<language>%s)', [
|
(r'(?P<language>%s)', [
|
||||||
'GERMAN',
|
'GERMAN',
|
||||||
@@ -100,6 +143,10 @@ PATTERN_GROUPS = [
|
|||||||
'DANiSH',
|
'DANiSH',
|
||||||
'iTALiAN'
|
'iTALiAN'
|
||||||
]),
|
]),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('scene', [
|
||||||
|
r'(?P<proper>PROPER|REAL)',
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -123,11 +170,17 @@ class SceneParser(Parser):
|
|||||||
|
|
||||||
self.capture_fragment('show_name', single=False)\
|
self.capture_fragment('show_name', single=False)\
|
||||||
.until(fragment__re='identifier')\
|
.until(fragment__re='identifier')\
|
||||||
.until(fragment__re='video')\
|
.until(fragment__re='video') \
|
||||||
|
.until(fragment__re='dvd') \
|
||||||
|
.until(fragment__re='audio') \
|
||||||
|
.until(fragment__re='scene') \
|
||||||
.execute()
|
.execute()
|
||||||
|
|
||||||
self.capture_fragment('identifier', regex='identifier', single=False)\
|
self.capture_fragment('identifier', regex='identifier', single=False)\
|
||||||
.capture_fragment('video', regex='video', single=False)\
|
.capture_fragment('video', regex='video', single=False) \
|
||||||
|
.capture_fragment('dvd', regex='dvd', single=False) \
|
||||||
|
.capture_fragment('audio', regex='audio', single=False) \
|
||||||
|
.capture_fragment('scene', regex='scene', single=False) \
|
||||||
.until(left_sep__eq='-', right__eq=None)\
|
.until(left_sep__eq='-', right__eq=None)\
|
||||||
.execute()
|
.execute()
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class CaperResult(object):
|
|||||||
self.chains.append(chain)
|
self.chains.append(chain)
|
||||||
|
|
||||||
for chain in self.chains:
|
for chain in self.chains:
|
||||||
chain.weights.append(chain.num_matched / float(max_matched or chain.num_matched))
|
chain.weights.append(chain.num_matched / float(max_matched or chain.num_matched or 1))
|
||||||
chain.finish()
|
chain.finish()
|
||||||
|
|
||||||
self.chains.sort(key=lambda chain: chain.weight, reverse=True)
|
self.chains.sort(key=lambda chain: chain.weight, reverse=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user