Merge branch 'tv_season_searcher' into tv
This commit is contained in:
@@ -55,7 +55,7 @@ class Library(LibraryBase):
|
||||
)
|
||||
|
||||
def related(self, media):
|
||||
result = {media['type']: media}
|
||||
result = {self.key(media['type']): media}
|
||||
|
||||
db = get_db()
|
||||
cur = media
|
||||
@@ -63,9 +63,17 @@ class Library(LibraryBase):
|
||||
while cur and cur.get('parent_id'):
|
||||
cur = db.get('id', cur['parent_id'])
|
||||
|
||||
parts = cur['type'].split('.')
|
||||
result[self.key(cur['type'])] = cur
|
||||
|
||||
result[parts[-1]] = cur
|
||||
children = db.get_many('media_children', media['_id'], with_doc = True)
|
||||
|
||||
for item in children:
|
||||
key = self.key(item['doc']['type']) + 's'
|
||||
|
||||
if key not in result:
|
||||
result[key] = []
|
||||
|
||||
result[key].append(item['doc'])
|
||||
|
||||
return result
|
||||
|
||||
@@ -94,8 +102,7 @@ class Library(LibraryBase):
|
||||
|
||||
# Build children arrays
|
||||
for item in items:
|
||||
parts = item['doc']['type'].split('.')
|
||||
key = parts[-1] + 's'
|
||||
key = self.key(item['doc']['type']) + 's'
|
||||
|
||||
if key not in result:
|
||||
result[key] = {}
|
||||
@@ -115,3 +122,7 @@ class Library(LibraryBase):
|
||||
result['releases'] = fireEvent('release.for_media', result['_id'], single = True)
|
||||
|
||||
return result
|
||||
|
||||
def key(self, media_type):
|
||||
parts = media_type.split('.')
|
||||
return parts[-1]
|
||||
|
||||
@@ -4,11 +4,9 @@ import traceback
|
||||
from couchpotato import get_db
|
||||
from couchpotato.api import addApiView
|
||||
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
|
||||
from couchpotato.core.helpers.encoding import simplifyString
|
||||
from couchpotato.core.helpers.variable import getTitle, find
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.media import MediaBase
|
||||
from qcond import QueryCondenser
|
||||
|
||||
|
||||
log = CPLog(__name__)
|
||||
@@ -110,7 +108,7 @@ class ShowBase(MediaBase):
|
||||
|
||||
new = False
|
||||
try:
|
||||
m = fireEvent('media.with_identifiers', params.get('identifiers'), with_doc = True, single = True)['doc']
|
||||
m = db.get('media', 'thetvdb-%s' % params.get('identifiers', {}).get('thetvdb'), with_doc = True)['doc']
|
||||
except:
|
||||
new = True
|
||||
m = db.insert(media)
|
||||
@@ -155,7 +153,7 @@ class ShowBase(MediaBase):
|
||||
# Trigger update info
|
||||
if added and update_after:
|
||||
# Do full update to get images etc
|
||||
fireEventAsync('show.update_extras', m, info, store = True, on_complete = onComplete)
|
||||
fireEventAsync('show.update_extras', m.copy(), info, store = True, on_complete = onComplete)
|
||||
|
||||
# Remove releases
|
||||
for rel in fireEvent('release.for_media', m['_id'], single = True):
|
||||
|
||||
@@ -2,7 +2,7 @@ var EpisodeAction = new Class({
|
||||
|
||||
Implements: [Options],
|
||||
|
||||
class_name: 'action icon2',
|
||||
class_name: 'item-action icon2',
|
||||
|
||||
initialize: function(episode, options){
|
||||
var self = this;
|
||||
|
||||
@@ -14,7 +14,7 @@ var Episode = new Class({
|
||||
|
||||
self.profile = self.show.profile;
|
||||
|
||||
self.el = new Element('div.item').adopt(
|
||||
self.el = new Element('div.item.episode').adopt(
|
||||
self.detail = new Element('div.item.data')
|
||||
);
|
||||
|
||||
@@ -34,14 +34,14 @@ var Episode = new Class({
|
||||
self.quality = new Element('span.quality', {
|
||||
'events': {
|
||||
'click': function(e){
|
||||
var releases = self.detail.getElement('.episode-actions .releases');
|
||||
var releases = self.detail.getElement('.item-actions .releases');
|
||||
|
||||
if(releases.isVisible())
|
||||
releases.fireEvent('click', [e])
|
||||
}
|
||||
}
|
||||
}),
|
||||
self.actions = new Element('div.episode-actions')
|
||||
self.actions = new Element('div.item-actions')
|
||||
);
|
||||
|
||||
// Add profile
|
||||
|
||||
127
couchpotato/core/media/show/_base/static/season.js
Executable file
127
couchpotato/core/media/show/_base/static/season.js
Executable file
@@ -0,0 +1,127 @@
|
||||
var Season = new Class({
|
||||
|
||||
Extends: BlockBase,
|
||||
|
||||
action: {},
|
||||
|
||||
initialize: function(show, options, data){
|
||||
var self = this;
|
||||
self.setOptions(options);
|
||||
|
||||
self.show = show;
|
||||
self.options = options;
|
||||
self.data = data;
|
||||
|
||||
self.profile = self.show.profile;
|
||||
|
||||
self.el = new Element('div.item.season').adopt(
|
||||
self.detail = new Element('div.item.data')
|
||||
);
|
||||
|
||||
self.create();
|
||||
},
|
||||
|
||||
create: function(){
|
||||
var self = this;
|
||||
|
||||
self.detail.set('id', 'season_'+self.data._id);
|
||||
|
||||
self.detail.adopt(
|
||||
new Element('span.name', {'text': self.getTitle()}),
|
||||
|
||||
self.quality = new Element('span.quality', {
|
||||
'events': {
|
||||
'click': function(e){
|
||||
var releases = self.detail.getElement('.item-actions .releases');
|
||||
|
||||
if(releases.isVisible())
|
||||
releases.fireEvent('click', [e])
|
||||
}
|
||||
}
|
||||
}),
|
||||
self.actions = new Element('div.item-actions')
|
||||
);
|
||||
|
||||
// Add profile
|
||||
if(self.profile.data) {
|
||||
self.profile.getTypes().each(function(type){
|
||||
var q = self.addQuality(type.get('quality'), type.get('3d'));
|
||||
|
||||
if((type.finish == true || type.get('finish')) && !q.hasClass('finish')){
|
||||
q.addClass('finish');
|
||||
q.set('title', q.get('title') + ' Will finish searching for this movie if this quality is found.')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add releases
|
||||
self.updateReleases();
|
||||
|
||||
Object.each(self.options.actions, function(action, key){
|
||||
self.action[key.toLowerCase()] = action = new self.options.actions[key](self);
|
||||
if(action.el)
|
||||
self.actions.adopt(action)
|
||||
});
|
||||
},
|
||||
|
||||
updateReleases: function(){
|
||||
var self = this;
|
||||
if(!self.data.releases || self.data.releases.length == 0) return;
|
||||
|
||||
self.data.releases.each(function(release){
|
||||
|
||||
var q = self.quality.getElement('.q_'+ release.quality+(release.is_3d ? '.is_3d' : ':not(.is_3d)')),
|
||||
status = release.status;
|
||||
|
||||
if(!q && (status == 'snatched' || status == 'seeding' || status == 'done'))
|
||||
q = self.addQuality(release.quality, release.is_3d || false);
|
||||
|
||||
if (q && !q.hasClass(status)){
|
||||
q.addClass(status);
|
||||
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status)
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
addQuality: function(quality, is_3d){
|
||||
var self = this,
|
||||
q = Quality.getQuality(quality);
|
||||
|
||||
return new Element('span', {
|
||||
'text': q.label + (is_3d ? ' 3D' : ''),
|
||||
'class': 'q_'+q.identifier + (is_3d ? ' is_3d' : ''),
|
||||
'title': ''
|
||||
}).inject(self.quality);
|
||||
},
|
||||
|
||||
getTitle: function(){
|
||||
var self = this;
|
||||
|
||||
var title = '';
|
||||
|
||||
if(self.data.info.number) {
|
||||
title = 'Season ' + self.data.info.number;
|
||||
} else {
|
||||
// Season 0 / Specials
|
||||
title = 'Specials';
|
||||
}
|
||||
|
||||
return title;
|
||||
},
|
||||
|
||||
getIdentifier: function(){
|
||||
var self = this;
|
||||
|
||||
try {
|
||||
return self.get('identifiers').imdb;
|
||||
}
|
||||
catch (e){ }
|
||||
|
||||
return self.get('imdb');
|
||||
},
|
||||
|
||||
get: function(attr){
|
||||
return this.data[attr] || this.data.info[attr]
|
||||
}
|
||||
});
|
||||
@@ -616,7 +616,7 @@
|
||||
.shows .options .table .item:nth-child(even) {
|
||||
background: rgba(255,255,255,0.05);
|
||||
}
|
||||
.shows .options .table .item:not(.head):hover {
|
||||
.shows .options .table .item:not(.head):not(.data):hover {
|
||||
background: rgba(255,255,255,0.03);
|
||||
}
|
||||
|
||||
@@ -717,6 +717,10 @@
|
||||
transition: all .6s cubic-bezier(0.9,0,0.1,1);
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.data {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.data span.episode {
|
||||
width: 40px;
|
||||
padding: 0 10px;
|
||||
@@ -734,6 +738,31 @@
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.season:hover {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.season .data {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
height: auto;
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.season .data span.name {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.season .data span.quality {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item.season:hover .data span.quality {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.shows .list .episodes .episode-options {
|
||||
display: block;
|
||||
|
||||
@@ -765,16 +794,44 @@
|
||||
width: 85px;
|
||||
}
|
||||
|
||||
.shows .list .episodes .episode-actions {
|
||||
.shows .list .episodes .item-actions {
|
||||
position: absolute;
|
||||
width: auto;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
display: none;
|
||||
opacity: 0;
|
||||
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.shows .list .show .episodes .episode-actions .refresh {
|
||||
.shows .list .episodes .item:hover .item-actions {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item:hover .item-action {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item .item-action {
|
||||
display: inline-block;
|
||||
height: 22px;
|
||||
min-width: 33px;
|
||||
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
|
||||
margin-left: 1px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.shows .list .episodes .item .item-action:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.shows .list .show .episodes .refresh {
|
||||
color: #cbeecc;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,21 +47,9 @@ var Episodes = new Class({
|
||||
|
||||
createSeason: function(season) {
|
||||
var self = this,
|
||||
title = '';
|
||||
s = new Season(self.show, self.options, season);
|
||||
|
||||
if(season.info.number) {
|
||||
title = 'Season ' + season.info.number;
|
||||
} else {
|
||||
// Season 0 / Specials
|
||||
title = 'Specials';
|
||||
}
|
||||
|
||||
season['el'] = new Element('div', {
|
||||
'class': 'item head',
|
||||
'id': 'season_'+season._id
|
||||
}).adopt(
|
||||
new Element('span.name', {'text': title})
|
||||
).inject(self.episodes_container);
|
||||
$(s).inject(self.episodes_container);
|
||||
},
|
||||
|
||||
createEpisode: function(episode){
|
||||
|
||||
@@ -107,6 +107,7 @@ class Episode(Base):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class Season(Base):
|
||||
type = 'show.season'
|
||||
|
||||
@@ -121,7 +122,7 @@ class Season(Base):
|
||||
log.info2('Wrong: releases with identifier ranges are not supported yet')
|
||||
return False
|
||||
|
||||
required = fireEvent('media.identifier', media['library'], single = True)
|
||||
required = fireEvent('library.identifier', media, single = True)
|
||||
|
||||
if identifier != required:
|
||||
log.info2('Wrong: required identifier (%s) does not match release identifier (%s)', (required, identifier))
|
||||
|
||||
@@ -117,7 +117,7 @@ class EpisodeSearcher(SearcherBase, ShowTypeBase):
|
||||
# Remove releases that aren't found anymore
|
||||
for release in releases:
|
||||
if release.get('status') == 'available' and release.get('identifier') not in found_releases:
|
||||
fireEvent('release.delete', release.get('id'), single = True)
|
||||
fireEvent('release.delete', release.get('_id'), single = True)
|
||||
else:
|
||||
log.info('Better quality (%s) already available or snatched for %s', (q_identifier, query))
|
||||
fireEvent('media.restatus', media['_id'])
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from couchpotato import get_db, Env
|
||||
from couchpotato.api import addApiView
|
||||
from couchpotato.core.event import addEvent, fireEventAsync
|
||||
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.media._base.searcher.base import SearcherBase
|
||||
from couchpotato.core.media.movie.searcher import SearchSetupError
|
||||
from couchpotato.core.media.show import ShowTypeBase
|
||||
|
||||
log = CPLog(__name__)
|
||||
@@ -19,6 +21,7 @@ class SeasonSearcher(SearcherBase, ShowTypeBase):
|
||||
|
||||
addEvent('%s.searcher.all' % self.getType(), self.searchAll)
|
||||
addEvent('%s.searcher.single' % self.getType(), self.single)
|
||||
addEvent('searcher.correct_release', self.correctRelease)
|
||||
|
||||
addApiView('%s.searcher.full_search' % self.getType(), self.searchAllView, docs = {
|
||||
'desc': 'Starts a full search for all wanted seasons',
|
||||
@@ -34,21 +37,136 @@ class SeasonSearcher(SearcherBase, ShowTypeBase):
|
||||
def searchAll(self, manual = False):
|
||||
pass
|
||||
|
||||
def single(self, media, show, profile):
|
||||
def single(self, media, profile = None, quality_order = None, search_protocols = None, manual = False):
|
||||
db = get_db()
|
||||
|
||||
# Check if any episode is already snatched
|
||||
active = 0
|
||||
episodes = media.get('episodes', {})
|
||||
for ex in episodes:
|
||||
episode = episodes.get(ex)
|
||||
related = fireEvent('library.related', media, single = True)
|
||||
|
||||
if episode.get('status') in ['active']:
|
||||
active += 1
|
||||
# TODO search_protocols, profile, quality_order can be moved to a base method
|
||||
# Find out search type
|
||||
try:
|
||||
if not search_protocols:
|
||||
search_protocols = fireEvent('searcher.protocols', single = True)
|
||||
except SearchSetupError:
|
||||
return
|
||||
|
||||
if active != len(episodes):
|
||||
if not profile and related['show']['profile_id']:
|
||||
profile = db.get('id', related['show']['profile_id'])
|
||||
|
||||
if not quality_order:
|
||||
quality_order = fireEvent('quality.order', single = True)
|
||||
|
||||
# Find 'active' episodes
|
||||
episodes = related['episodes']
|
||||
episodes_active = []
|
||||
|
||||
for episode in episodes:
|
||||
if episode.get('status') != 'active':
|
||||
continue
|
||||
|
||||
episodes_active.append(episode)
|
||||
|
||||
if len(episodes_active) == len(episodes):
|
||||
# All episodes are 'active', try and search for full season
|
||||
if self.search(media, profile, quality_order, search_protocols):
|
||||
# Success, end season search
|
||||
return True
|
||||
else:
|
||||
log.info('Unable to find season pack, searching for individual episodes...')
|
||||
|
||||
# Search for each episode individually
|
||||
for episode in episodes_active:
|
||||
fireEvent('show.episode.searcher.single', episode, profile, quality_order, search_protocols, manual)
|
||||
|
||||
# TODO (testing) only grab one episode
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def search(self, media, profile, quality_order, search_protocols):
|
||||
# TODO: check episode status
|
||||
# TODO: check air date
|
||||
#if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']):
|
||||
# too_early_to_search.append(quality_type['quality']['identifier'])
|
||||
# return
|
||||
|
||||
ret = False
|
||||
has_better_quality = None
|
||||
found_releases = []
|
||||
too_early_to_search = []
|
||||
|
||||
releases = fireEvent('release.for_media', media['_id'], single = True)
|
||||
query = fireEvent('library.query', media, condense = False, single = True)
|
||||
|
||||
index = 0
|
||||
for q_identifier in profile.get('qualities'):
|
||||
quality_custom = {
|
||||
'quality': q_identifier,
|
||||
'finish': profile['finish'][index],
|
||||
'wait_for': profile['wait_for'][index],
|
||||
'3d': profile['3d'][index] if profile.get('3d') else False
|
||||
}
|
||||
|
||||
has_better_quality = 0
|
||||
|
||||
# See if better quality is available
|
||||
for release in releases:
|
||||
if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']:
|
||||
has_better_quality += 1
|
||||
|
||||
# Don't search for quality lower then already available.
|
||||
if has_better_quality is 0:
|
||||
|
||||
log.info('Searching for %s in %s', (query, q_identifier))
|
||||
quality = fireEvent('quality.single', identifier = q_identifier, single = True)
|
||||
quality['custom'] = quality_custom
|
||||
|
||||
results = fireEvent('searcher.search', search_protocols, media, quality, single = True)
|
||||
if len(results) == 0:
|
||||
log.debug('Nothing found for %s in %s', (query, q_identifier))
|
||||
|
||||
# Add them to this movie releases list
|
||||
found_releases += fireEvent('release.create_from_search', results, media, quality, single = True)
|
||||
|
||||
# Try find a valid result and download it
|
||||
if fireEvent('release.try_download_result', results, media, quality, single = True):
|
||||
ret = True
|
||||
|
||||
# Remove releases that aren't found anymore
|
||||
for release in releases:
|
||||
if release.get('status') == 'available' and release.get('identifier') not in found_releases:
|
||||
fireEvent('release.delete', release.get('_id'), single = True)
|
||||
else:
|
||||
log.info('Better quality (%s) already available or snatched for %s', (q_identifier, query))
|
||||
fireEvent('media.restatus', media['_id'])
|
||||
break
|
||||
|
||||
# Break if CP wants to shut down
|
||||
if self.shuttingDown() or ret:
|
||||
break
|
||||
|
||||
if len(too_early_to_search) > 0:
|
||||
log.info2('Too early to search for %s, %s', (too_early_to_search, query))
|
||||
|
||||
return len(found_releases) > 0
|
||||
|
||||
def correctRelease(self, release = None, media = None, quality = None, **kwargs):
|
||||
if media.get('type') != 'show.season':
|
||||
return
|
||||
|
||||
retention = Env.setting('retention', section = 'nzb')
|
||||
|
||||
if release.get('seeders') is None and 0 < retention < release.get('age', 0):
|
||||
log.info2('Wrong: Outside retention, age is %s, needs %s or lower: %s', (release['age'], retention, release['name']))
|
||||
return False
|
||||
|
||||
# Try and search for full season
|
||||
# TODO:
|
||||
# Check for required and ignored words
|
||||
if not fireEvent('searcher.correct_words', release['name'], media, single = True):
|
||||
return False
|
||||
|
||||
# TODO Matching is quite costly, maybe we should be caching release matches somehow? (also look at caper optimizations)
|
||||
match = fireEvent('matcher.match', release, media, quality, single = True)
|
||||
if match:
|
||||
return match.weight
|
||||
|
||||
return False
|
||||
|
||||
@@ -54,36 +54,26 @@ class ShowSearcher(SearcherBase, ShowTypeBase):
|
||||
|
||||
fireEvent('notify.frontend', type = 'show.searcher.started.%s' % media['_id'], data = True, message = 'Searching for "%s"' % show_title)
|
||||
|
||||
media = self.extendShow(media)
|
||||
show_tree = fireEvent('library.tree', media, single = True)
|
||||
|
||||
db = get_db()
|
||||
|
||||
profile = db.get('id', media['profile_id'])
|
||||
quality_order = fireEvent('quality.order', single = True)
|
||||
|
||||
seasons = media.get('seasons', {})
|
||||
for sx in seasons:
|
||||
for season in show_tree.get('seasons', []):
|
||||
if not season.get('info'):
|
||||
continue
|
||||
|
||||
# Skip specials for now TODO: set status for specials to skipped by default
|
||||
if sx == 0: continue
|
||||
# Skip specials (and seasons missing 'number') for now
|
||||
# TODO: set status for specials to skipped by default
|
||||
if not season['info'].get('number'):
|
||||
continue
|
||||
|
||||
season = seasons.get(sx)
|
||||
# Check if full season can be downloaded
|
||||
fireEvent('show.season.searcher.single', season, profile, quality_order, search_protocols, manual)
|
||||
|
||||
# Check if full season can be downloaded TODO: add
|
||||
season_success = fireEvent('show.season.searcher.single', season, media, profile)
|
||||
|
||||
# Do each episode seperately
|
||||
if not season_success:
|
||||
episodes = season.get('episodes', {})
|
||||
for ex in episodes:
|
||||
episode = episodes.get(ex)
|
||||
|
||||
fireEvent('show.episode.searcher.single', episode, season, media, profile, quality_order, search_protocols)
|
||||
|
||||
# TODO
|
||||
return
|
||||
|
||||
# TODO
|
||||
# TODO (testing) only snatch one season
|
||||
return
|
||||
|
||||
fireEvent('notify.frontend', type = 'show.searcher.ended.%s' % media['_id'], data = True)
|
||||
|
||||
19
couchpotato/core/plugins/score/main.py
Normal file → Executable file
19
couchpotato/core/plugins/score/main.py
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
from couchpotato.core.event import addEvent
|
||||
from couchpotato.core.event import addEvent, fireEvent
|
||||
from couchpotato.core.helpers.encoding import toUnicode
|
||||
from couchpotato.core.helpers.variable import getTitle, splitString, removeDuplicate
|
||||
from couchpotato.core.logger import CPLog
|
||||
@@ -16,17 +16,20 @@ class Score(Plugin):
|
||||
def __init__(self):
|
||||
addEvent('score.calculate', self.calculate)
|
||||
|
||||
def calculate(self, nzb, movie):
|
||||
def calculate(self, nzb, media):
|
||||
""" Calculate the score of a NZB, used for sorting later """
|
||||
|
||||
# Fetch root media item (movie, show)
|
||||
root = fireEvent('library.root', media, single = True)
|
||||
|
||||
# Merge global and category
|
||||
preferred_words = splitString(Env.setting('preferred_words', section = 'searcher').lower())
|
||||
try: preferred_words = removeDuplicate(preferred_words + splitString(movie['category']['preferred'].lower()))
|
||||
try: preferred_words = removeDuplicate(preferred_words + splitString(media['category']['preferred'].lower()))
|
||||
except: pass
|
||||
|
||||
score = nameScore(toUnicode(nzb['name']), movie['info'].get('year'), preferred_words)
|
||||
score = nameScore(toUnicode(nzb['name']), root['info'].get('year'), preferred_words)
|
||||
|
||||
for movie_title in movie['info']['titles']:
|
||||
for movie_title in root['info']['titles']:
|
||||
score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title))
|
||||
score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_title))
|
||||
|
||||
@@ -44,15 +47,15 @@ class Score(Plugin):
|
||||
score += providerScore(nzb['provider'])
|
||||
|
||||
# Duplicates in name
|
||||
score += duplicateScore(nzb['name'], getTitle(movie))
|
||||
score += duplicateScore(nzb['name'], getTitle(root))
|
||||
|
||||
# Merge global and category
|
||||
ignored_words = splitString(Env.setting('ignored_words', section = 'searcher').lower())
|
||||
try: ignored_words = removeDuplicate(ignored_words + splitString(movie['category']['ignored'].lower()))
|
||||
try: ignored_words = removeDuplicate(ignored_words + splitString(media['category']['ignored'].lower()))
|
||||
except: pass
|
||||
|
||||
# Partial ignored words
|
||||
score += partialIgnoredScore(nzb['name'], getTitle(movie), ignored_words)
|
||||
score += partialIgnoredScore(nzb['name'], getTitle(root), ignored_words)
|
||||
|
||||
# Ignore single downloads from multipart
|
||||
score += halfMultipartScore(nzb['name'])
|
||||
|
||||
Reference in New Issue
Block a user