Added ability to set a default indexer for trakt notifier used for adding shows from watch list so that SickRage knows what indexer to set the show as.

Indexer mapping now uses indexer api calls to gather its information and then stores it to a new table called indexer_mapping for instant lookups later on.

Fixed trakt related issues for adding new shows and syncing.

Centered items at bottom of pages to just look a little nicer and fit properly.
This commit is contained in:
echel0n 2014-07-23 21:44:11 -07:00
parent b63dffa3a0
commit de5db9be64
20 changed files with 278 additions and 241 deletions

View file

@ -1184,6 +1184,20 @@
<span class="component-desc">Get your key at: <a href="http://trakt.tv/settings/api" rel="noreferrer" onclick="window.open('${sickbeard.ANON_REDIRECT}' + this.href, '_blank'); return false;">http://trakt.tv/settings/api</a></span>
</label>
</div>
<div class="field-pair">
<label class="nocheck clearfix" for="trakt_default_indexer">
<span class="component-title">Default Indexer:</span>
<span class="component-desc">
<select id="trakt_default_indexer" name="trakt_default_indexer">
#for $indexer in $sickbeard.indexerApi().indexers
<option value="$indexer" #if $indexer == $sickbeard.TRAKT_DEFAULT_INDEXER then "selected=\"selected\"" else ""#>$sickbeard.indexerApi().indexers[$indexer]</option>
#end for
</select>
</span>
</label>
</div
</div>
<div class="field-pair">
<input type="checkbox" class="enabler" name="trakt_sync" id="trakt_sync" #if $sickbeard.TRAKT_SYNC then "checked=\"checked\"" else ""# />
<label class="clearfix" for="trakt_sync">

View file

@ -7,7 +7,7 @@
</div>
<div class="footer clearfix">
<div class="meta" style="float:left;font-size: 12px;">
<div class="meta" style="float:center;font-size: 12px;">
#set $myDB = $db.DBConnection()
#set $today = str($datetime.date.today().toordinal())
#set status_quality = '(' + ','.join([str(quality) for quality in $Quality.SNATCHED + $Quality.SNATCHED_PROPER]) + ')'
@ -40,14 +40,12 @@
#end if
<b>$shows_total</b> Shows (<b>$shows_active</b> Active) <b>|</b> <b><%=ep_downloaded%>#if $ep_snatched > 0 then " (+" + str($ep_snatched) + " snatched)" else ""# / $ep_total</b> Episodes Downloaded <b>|</b> Daily Search: <b><%=str(sickbeard.dailySearchScheduler.timeLeft()).split('.')[0]%></b> <b>|</b> Backlog Search: <b>$sbdatetime.sbdatetime.sbfdate($sickbeard.backlogSearchScheduler.nextRun())</b>
<p>
<a href="$sbRoot/manage/manageSearches/forceVersionCheck"><img src="$sbRoot/images/menu/update16.png" alt="" width="16" height="16" />Force Version Check</a>
<a href="$sbRoot/home/restart/?pid=$sbPID" class="confirm"><img src="$sbRoot/images/menu/restart16.png" alt="" width="16" height="16" />Restart</a>
<a href="$sbRoot/home/shutdown/?pid=$sbPID" class="confirm"><img src="$sbRoot/images/menu/shutdown16.png" alt="" width="16" height="16" />Shutdown</a>
</div>
<ul style="float:right; font-size: 12px;">
<li><a href="$sbRoot/manage/manageSearches/forceVersionCheck"><img src="$sbRoot/images/menu/update16.png" alt="" width="16" height="16" />Force Version Check</a></li>
<li><a href="$sbRoot/home/restart/?pid=$sbPID" class="confirm"><img src="$sbRoot/images/menu/restart16.png" alt="" width="16" height="16" />Restart</a></li>
<li><a href="$sbRoot/home/shutdown/?pid=$sbPID" class="confirm"><img src="$sbRoot/images/menu/shutdown16.png" alt="" width="16" height="16" />Shutdown</a></li>
</ul>
</div>
</div>
</body>

View file

@ -534,6 +534,11 @@ class Tvdb:
self.config['url_seriesBanner'] = u"%(base_url)s/api/%(apikey)s/series/%%s/banners.xml" % self.config
self.config['url_artworkPrefix'] = u"%(base_url)s/banners/%%s" % self.config
self.config['url_updates_all'] = u"%(base_url)s/api/%(apikey)s/updates_all.zip" % self.config
self.config['url_updates_month'] = u"%(base_url)s/api/%(apikey)s/updates_month.zip" % self.config
self.config['url_updates_week'] = u"%(base_url)s/api/%(apikey)s/updates_week.zip" % self.config
self.config['url_updates_day'] = u"%(base_url)s/api/%(apikey)s/updates_day.zip" % self.config
def _getTempDir(self):
"""Returns the [system temp dir]/tvdb_api-u501 (or
tvdb_api-myuser)

View file

@ -377,6 +377,8 @@ class TVRage:
self.config['url_seriesInfo'] = u"%(base_url)s/myfeeds/showinfo.php" % self.config
self.config['params_seriesInfo'] = {"key": self.config['apikey'], "sid": ""}
self.config['url_updtes_all'] = u"%(base_url)s/myfeeds/currentshows.php" % self.config
def _getTempDir(self):
"""Returns the [system temp dir]/tvrage_api-u501 (or
tvrage_api-myuser)

View file

@ -357,6 +357,7 @@ TRAKT_METHOD_ADD = 0
TRAKT_START_PAUSED = False
TRAKT_USE_RECOMMENDED = False
TRAKT_SYNC = False
TRAKT_DEFAULT_INDEXER = None
USE_PYTIVO = False
PYTIVO_NOTIFY_ONSNATCH = False
@ -447,7 +448,7 @@ def initialize(consoleLogging=True):
TORRENT_USERNAME, TORRENT_PASSWORD, TORRENT_HOST, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, TORRENT_HIGH_BANDWIDTH, TORRENT_LABEL, TORRENT_VERIFY_CERT, \
USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, \
XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, BACKLOG_FREQUENCY, \
USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, \
USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, \
USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_UPDATE_LIBRARY, \
PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \
showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, SORT_ARTICLE, showList, loadingShowList, \
@ -799,6 +800,7 @@ def initialize(consoleLogging=True):
TRAKT_START_PAUSED = bool(check_setting_int(CFG, 'Trakt', 'trakt_start_paused', 0))
TRAKT_USE_RECOMMENDED = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_recommended', 0))
TRAKT_SYNC = bool(check_setting_int(CFG, 'Trakt', 'trakt_sync', 0))
TRAKT_DEFAULT_INDEXER = check_setting_int(CFG, 'Trakt', 'trakt_default_indexer', 1)
CheckSection(CFG, 'pyTivo')
USE_PYTIVO = bool(check_setting_int(CFG, 'pyTivo', 'use_pytivo', 0))
@ -1619,6 +1621,7 @@ def save_config():
new_config['Trakt']['trakt_start_paused'] = int(TRAKT_START_PAUSED)
new_config['Trakt']['trakt_use_recommended'] = int(TRAKT_USE_RECOMMENDED)
new_config['Trakt']['trakt_sync'] = int(TRAKT_SYNC)
new_config['Trakt']['trakt_default_indexer'] = int(TRAKT_DEFAULT_INDEXER)
new_config['pyTivo'] = {}
new_config['pyTivo']['use_pytivo'] = int(USE_PYTIVO)

View file

@ -145,7 +145,6 @@ class TorrentSearchResult(SearchResult):
"""
resultType = "torrent"
class AllShowsListUI:
"""
This class is for indexer api. Instead of prompting with a UI to pick the

View file

@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek
from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
MIN_DB_VERSION = 9 # oldest db version we support migrating from
MAX_DB_VERSION = 38
MAX_DB_VERSION = 39
class MainSanityCheck(db.DBSanityCheck):
def check(self):
@ -168,7 +168,7 @@ class InitialSchema(db.SchemaUpgrade):
"CREATE TABLE info (last_backlog NUMERIC, last_indexer NUMERIC, last_proper_search NUMERIC)",
"CREATE TABLE scene_numbering(indexer TEXT, indexer_id INTEGER, season INTEGER, episode INTEGER,scene_season INTEGER, scene_episode INTEGER, PRIMARY KEY(indexer_id, season, episode))",
"CREATE TABLE tv_shows (show_id INTEGER PRIMARY KEY, indexer_id NUMERIC, indexer TEXT, show_name TEXT, location TEXT, network TEXT, genre TEXT, classification TEXT, runtime NUMERIC, quality NUMERIC, airs TEXT, status TEXT, flatten_folders NUMERIC, paused NUMERIC, startyear NUMERIC, air_by_date NUMERIC, lang TEXT, subtitles NUMERIC, notify_list TEXT, imdb_id TEXT, last_update_indexer NUMERIC, dvdorder NUMERIC, archive_firstmatch NUMERIC, rls_require_words TEXT, rls_ignore_words TEXT, sports NUMERIC);",
"CREATE TABLE tv_episodes (episode_id INTEGER PRIMARY KEY, showid NUMERIC, indexerid NUMERIC, indexer TEXT, name TEXT, season NUMERIC, episode NUMERIC, description TEXT, airdate NUMERIC, hasnfo NUMERIC, hastbn NUMERIC, status NUMERIC, location TEXT, file_size NUMERIC, release_name TEXT, subtitles TEXT, subtitles_searchcount NUMERIC, subtitles_lastsearch TIMESTAMP, is_proper NUMERIC, scene_season NUMERIC, scene_episode NUMERIC);",
"CREATE TABLE tv_episodes (episode_id INTEGER PRIMARY KEY, showid/ NUMERIC, indexerid NUMERIC, indexer TEXT, name TEXT, season NUMERIC, episode NUMERIC, description TEXT, airdate NUMERIC, hasnfo NUMERIC, hastbn NUMERIC, status NUMERIC, location TEXT, file_size NUMERIC, release_name TEXT, subtitles TEXT, subtitles_searchcount NUMERIC, subtitles_lastsearch TIMESTAMP, is_proper NUMERIC, scene_season NUMERIC, scene_episode NUMERIC);",
"CREATE UNIQUE INDEX idx_indexer_id ON tv_shows (indexer_id)",
"CREATE INDEX idx_showid ON tv_episodes (showid);",
"CREATE INDEX idx_sta_epi_air ON tv_episodes (status,episode, airdate);",
@ -886,3 +886,18 @@ class AddSceneToTvShows(AddXemRefresh):
self.incDBVersion()
class AddIndexerMapping(AddSceneToTvShows):
def test(self):
return self.checkDBVersion() >= 39
def execute(self):
backupDatabase(39)
if self.hasTable("indexer_mapping"):
self.connection.action("DROP TABLE indexer_mapping")
logger.log(u"Adding table indexer_mapping")
self.connection.action(
"CREATE TABLE indexer_mapping (indexer_id INTEGER, indexer NUMERIC, mindexer_id INTEGER, mindexer NUMERIC, PRIMARY KEY (indexer_id, indexer))")
self.incDBVersion()

View file

@ -321,6 +321,10 @@ def _processUpgrade(connection, upgradeClass):
result = connection.select("SELECT db_version FROM db_version")
if result:
version = int(result[0]["db_version"])
# close db before attempting restore
connection.close()
if restoreDatabase(version):
# initialize the main SB database
upgradeDatabase(DBConnection(), sickbeard.mainDB.InitialSchema)

View file

@ -62,7 +62,7 @@ from lib import trakt
urllib._urlopener = classes.SickBeardURLopener()
session = requests.Session()
indexerMap = {}
def indentXML(elem, level=0):
'''
@ -85,6 +85,7 @@ def indentXML(elem, level=0):
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def remove_extension(name):
"""
Remove download or media extension from name (if any)
@ -97,6 +98,7 @@ def remove_extension(name):
return name
def remove_non_release_groups(name):
"""
Remove non release groups from name
@ -109,6 +111,7 @@ def remove_non_release_groups(name):
return name
def replaceExtension(filename, newExt):
'''
>>> replaceExtension('foo.avi', 'mkv')
@ -291,12 +294,10 @@ def findCertainShow(showList, indexerid):
if indexerid:
results = filter(lambda x: int(x.indexerid) == int(indexerid), showList)
if len(results) == 0:
return None
if len(results):
return results[0]
elif len(results) > 1:
raise MultipleShowObjectsException()
else:
return results[0]
def makeDir(path):
@ -379,9 +380,9 @@ def searchIndexerForShowID(regShowName, indexer=None, indexer_id=None, ui=None):
continue
if str(name).lower() == str(seriesname).lower and not indexer_id:
return (seriesname, int(sickbeard.indexerApi(i).config['id']), int(series_id))
return (seriesname, i, int(series_id))
elif int(indexer_id) == int(series_id):
return (seriesname, int(sickbeard.indexerApi(i).config['id']), int(indexer_id))
return (seriesname, i, int(indexer_id))
if indexer:
break
@ -464,7 +465,9 @@ def hardlinkFile(srcFile, destFile):
def symlink(src, dst):
if os.name == 'nt':
import ctypes
if ctypes.windll.kernel32.CreateSymbolicLinkW(unicode(dst), unicode(src), 1 if os.path.isdir(src) else 0) in [0,1280]: raise ctypes.WinError()
if ctypes.windll.kernel32.CreateSymbolicLinkW(unicode(dst), unicode(src), 1 if os.path.isdir(src) else 0) in [0,
1280]: raise ctypes.WinError()
else:
os.symlink(src, dst)
@ -718,26 +721,24 @@ def get_absolute_number_from_season_and_episode(show, season, episode):
return None
def get_all_episodes_from_absolute_number(show, indexer_id, absolute_numbers):
def get_all_episodes_from_absolute_number(show, absolute_numbers, indexer_id=None):
if len(absolute_numbers) == 0:
raise EpisodeNotFoundByAbsoluteNumberException
episodes = []
season = None
if not show and not indexer_id:
return (season, episodes)
if not show and indexer_id:
show = findCertainShow(sickbeard.showList, indexer_id)
for absolute_number in absolute_numbers:
ep = show.getEpisode(None, None, absolute_number=absolute_number)
if ep:
episodes.append(ep.episode)
else:
raise EpisodeNotFoundByAbsoluteNumberException
season = ep.season # this will always take the last found seson so eps that cross the season border are not handeled well
if show:
for absolute_number in absolute_numbers:
ep = show.getEpisode(None, None, absolute_number=absolute_number)
if ep:
episodes.append(ep.episode)
else:
raise EpisodeNotFoundByAbsoluteNumberException
season = ep.season # this will always take the last found seson so eps that cross the season border are not handeled well
return (season, episodes)
@ -1086,26 +1087,31 @@ def _check_against_names(nameInQuestion, show, season=-1):
return False
def get_show(name, indexer_id=0, useIndexer=False):
def get_show(name, tryIndexers=False):
if not sickbeard.showList:
return
showObj = None
fromCache = False
try:
# check cache for show
showObj = sickbeard.name_cache.retrieveShowFromCache(name, indexer_id=indexer_id)
if showObj:
return showObj
cache = sickbeard.name_cache.retrieveNameFromCache(name)
if cache:
fromCache = True
showObj = findCertainShow(sickbeard.showList, int(cache))
if useIndexer and sickbeard.showList and not showObj:
(sn, idx, id) = searchIndexerForShowID(full_sanitizeSceneName(name), ui=classes.ShowListUI)
if id:
showObj = findCertainShow(sickbeard.showList, int(id))
if not showObj and tryIndexers:
showObj = findCertainShow(sickbeard.showList,
searchIndexerForShowID(full_sanitizeSceneName(name), ui=classes.ShowListUI)[2])
# add show to cache
if showObj:
if showObj and not fromCache:
sickbeard.name_cache.addNameToCache(name, showObj.indexerid)
except Exception as e:
logger.log(u"Error when attempting to find show: " + name + " in SickRage: " + str(e), logger.DEBUG)
return showObj
except:
pass
return showObj
def is_hidden_folder(folder):
"""
@ -1216,26 +1222,48 @@ def extractZip(archive, targetDir):
def mapIndexersToShow(showObj):
global indexerMap
mapped = {showObj.indexer: showObj.indexerid}
mapped = {'tvdb_id': 0, 'tvrage_id': 0}
myDB = db.DBConnection()
if showObj.name in indexerMap:
logger.log(u"Found TVDB<->TVRAGE indexer mapping in cache for show: " + showObj.name, logger.DEBUG)
return indexerMap[showObj.name]
sqlResults = myDB.select(
"SELECT * FROM indexer_mapping WHERE indexer_id = ? AND indexer = ?",
[showObj.indexerid, showObj.indexer])
logger.log(u"Mapping indexers TVDB<->TVRAGE for show: " + showObj.name, logger.DEBUG)
results = trakt.TraktCall("search/shows.json/%API%?query=" + sanitizeSceneName(showObj.name),
sickbeard.TRAKT_API_KEY)
# for each mapped entry
for curResult in sqlResults:
logger.log(u"Found " + sickbeard.indexerApi(showObj.indexer).name + "<->" + sickbeard.indexerApi(
int(curResult['mindexer'])).name + " mapping in cache for show: " + showObj.name, logger.DEBUG)
if results:
result = filter(lambda x: int(showObj.indexerid) in [int(x['tvdb_id']), int(x['tvrage_id'])], results)
if len(result):
mapped['tvdb_id'] = int(result[0]['tvdb_id'])
mapped['tvrage_id'] = int(result[0]['tvrage_id'])
mapped[int(curResult['mindexer'])] = int(curResult['mindexer_id'])
else:
sql_l = []
for indexer in sickbeard.indexerApi().indexers:
if indexer == showObj.indexer:
mapped[indexer] = showObj.indexerid
continue
logger.log(u"Adding TVDB<->TVRAGE indexer mapping to cache for show: " + showObj.name, logger.DEBUG)
indexerMap[showObj.name] = mapped
lINDEXER_API_PARMS = sickbeard.indexerApi(indexer).api_params.copy()
lINDEXER_API_PARMS['custom_ui'] = classes.ShowListUI
t = sickbeard.indexerApi(indexer).indexer(**lINDEXER_API_PARMS)
mapped_show = t[showObj.name]
if len(mapped_show) and not len(mapped_show) > 1:
logger.log(u"Mapping " + sickbeard.indexerApi(showObj.indexer).name + "<->" + sickbeard.indexerApi(
indexer).name + " for show " + showObj.name,
logger.DEBUG)
mapped[indexer] = int(mapped_show[0]['id'])
logger.log(u"Adding " + sickbeard.indexerApi(showObj.indexer).name + "<->" + sickbeard.indexerApi(
indexer).name + " mapping to DB for show: " + showObj.name, logger.DEBUG)
sql_l.append([
"INSERT OR IGNORE INTO indexer_mapping (indexer_id, indexer, mindexer_id, mindexer) VALUES (?,?,?,?)",
[showObj.indexerid, showObj.indexer, int(mapped_show[0]['id']), indexer]])
if len(sql_l) > 0:
myDB.mass_action(sql_l)
return mapped

View file

@ -57,4 +57,4 @@ class indexerApi(object):
@property
def indexers(self):
return dict((x['id'], x['name']) for x in indexerConfig.values())
return dict((int(x['id']), x['name']) for x in indexerConfig.values())

View file

@ -55,17 +55,6 @@ def retrieveNameFromCache(name):
if name in nameCache:
return int(nameCache[name])
def retrieveShowFromCache(name, indexer_id=0):
global nameCache
if not indexer_id:
indexer_id = retrieveNameFromCache(name)
if indexer_id:
return sickbeard.helpers.findCertainShow(sickbeard.showList, int(indexer_id))
def clearCache():
"""
Deletes all "unknown" entries from the cache (names with indexer_id of 0).

View file

@ -35,12 +35,12 @@ class NameParser(object):
SPORTS_REGEX = 1
ANIME_REGEX = 2
def __init__(self, file_name=True, showObj=None, useIndexers=False, convert=False,
def __init__(self, file_name=True, showObj=None, tryIndexers=False, convert=False,
naming_pattern=False):
self.file_name = file_name
self.showObj = showObj
self.useIndexers = useIndexers
self.tryIndexers = tryIndexers
self.convert = convert
self.naming_pattern = naming_pattern
@ -132,7 +132,7 @@ class NameParser(object):
# get show object
if not result.show and not self.naming_pattern:
result.show = helpers.get_show(result.series_name, useIndexer=self.useIndexers)
result.show = helpers.get_show(result.series_name, self.tryIndexers)
elif self.showObj and self.naming_pattern:
result.show = self.showObj
@ -245,7 +245,7 @@ class NameParser(object):
for epAbsNo in bestResult.ab_episode_numbers:
try:
(s, e) = helpers.get_all_episodes_from_absolute_number(bestResult.show, None, [epAbsNo])
(s, e) = helpers.get_all_episodes_from_absolute_number(bestResult.show, [epAbsNo])
except exceptions.EpisodeNotFoundByAbsoluteNumberException:
pass
else:
@ -531,7 +531,7 @@ class ParseResult(object):
True, scene_season)
if ab:
try:
(s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, [ab])
(s, e) = helpers.get_all_episodes_from_absolute_number(self.show, [ab])
except exceptions.EpisodeNotFoundByAbsoluteNumberException:
logger.log(str(self.show.indexerid) + ": Indexer object absolute number " + str(
ab) + " is incomplete, skipping this episode")

View file

@ -472,7 +472,7 @@ class PostProcessor(object):
name = helpers.remove_non_release_groups(helpers.remove_extension(name))
# parse the name to break it into show name, season, and episode
np = NameParser(file, useIndexers=True, convert=True)
np = NameParser(file, tryIndexers=True, convert=True)
parse_result = np.parse(name)
# show object
@ -493,54 +493,6 @@ class PostProcessor(object):
self._finalize(parse_result)
return to_return
def _analyze_anidb(self, filePath):
# TODO: rewrite this
return (None, None, None, None)
if not helpers.set_up_anidb_connection():
return (None, None, None, None)
ep = self._build_anidb_episode(sickbeard.ADBA_CONNECTION, filePath)
try:
self._log(u"Trying to lookup " + str(filePath) + " on anidb", logger.MESSAGE)
ep.load_data()
except Exception, e:
self._log(u"exception msg: " + str(e))
raise InvalidNameException
else:
self.anidbEpisode = ep
# TODO: clean code. it looks like it's from hell
for name in ep.allNames:
indexer_id = name_cache.retrieveNameFromCache(name)
if not indexer_id:
show = helpers.get_show(name)
if show:
indexer_id = show.indexerid
else:
indexer_id = 0
if indexer_id:
name_cache.addNameToCache(name, indexer_id)
if indexer_id:
try:
show = helpers.findCertainShow(sickbeard.showList, indexer_id)
(season, episodes) = helpers.get_all_episodes_from_absolute_number(show, None, [ep.epno])
except exceptions.EpisodeNotFoundByAbsoluteNumberException:
self._log(str(indexer_id) + ": Indexer object absolute number " + str(
ep.epno) + " is incomplete, skipping this episode")
else:
if len(episodes):
self._log(u"Lookup successful from anidb. ", logger.DEBUG)
return (show, season, episodes, None)
if ep.anidb_file_name:
self._log(u"Lookup successful, using anidb filename " + str(ep.anidb_file_name), logger.DEBUG)
return self._analyze_name(ep.anidb_file_name)
raise InvalidNameException
def _build_anidb_episode(self, connection, filePath):
ep = adba.Episode(connection, filePath=filePath,
paramsF=["quality", "anidb_file_name", "crc32"],
@ -583,10 +535,7 @@ class PostProcessor(object):
lambda: self._analyze_name(self.file_path),
# try to analyze the dir + file name together as one name
lambda: self._analyze_name(self.folder_name + u' ' + self.file_name),
# try to analyze the file path with the help of aniDB
lambda: self._analyze_anidb(self.file_path)
lambda: self._analyze_name(self.folder_name + u' ' + self.file_name)
]
# attempt every possible method to get our info

View file

@ -27,7 +27,7 @@ from sickbeard import classes
from sickbeard import scene_exceptions
from sickbeard import logger
from sickbeard import tvcache
from sickbeard.helpers import sanitizeSceneName, mapIndexersToShow
from sickbeard.helpers import sanitizeSceneName
from sickbeard.exceptions import ex, AuthException
from lib import jsonrpclib

View file

@ -23,25 +23,26 @@ import datetime
import os
import re
import itertools
import Queue
import sickbeard
import requests
from lib import requests
from lib.feedparser import feedparser
from sickbeard import helpers, classes, logger, db
from sickbeard.common import MULTI_EP_RESULT, SEASON_RESULT, cpu_presets
from sickbeard.common import MULTI_EP_RESULT, SEASON_RESULT
from sickbeard import tvcache
from sickbeard import encodingKludge as ek
from sickbeard.exceptions import ex
from lib.hachoir_parser import createParser
from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
from sickbeard.common import Quality
from lib.hachoir_parser import createParser
class GenericProvider:
NZB = "nzb"
TORRENT = "torrent"
def __init__(self, name):
self.queue = Queue.Queue()
# these need to be set in the subclass
self.providerType = None

View file

@ -98,9 +98,9 @@ class NewznabProvider(generic.NZBProvider):
cur_params['season'] = str(ep_obj.scene_season)
# search
indexers = helpers.mapIndexersToShow(ep_obj.show)
if indexers['tvrage_id']:
cur_params['rid'] = indexers['tvrage_id']
mindexers = helpers.mapIndexersToShow(ep_obj.show)
if 2 in mindexers:
cur_params['rid'] = mindexers[2]
to_return.append(cur_params)
else:
# add new query strings for exceptions
@ -131,9 +131,9 @@ class NewznabProvider(generic.NZBProvider):
params['ep'] = ep_obj.scene_episode
# search
indexers = helpers.mapIndexersToShow(ep_obj.show)
if indexers['tvrage_id']:
params['rid'] = indexers['tvrage_id']
mindexers = helpers.mapIndexersToShow(ep_obj.show)
if 2 in mindexers:
params['rid'] = mindexers[2]
to_return.append(params)
else:
# add new query strings for exceptions

View file

@ -54,15 +54,19 @@ class TraktChecker():
except Exception:
logger.log(traceback.format_exc(), logger.DEBUG)
def findShow(self, indexerid):
def findShow(self, indexer, indexerid):
library = TraktCall("user/library/shows/all.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API,
sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD)
results = filter(lambda x: int(x['tvdb_id']) == int(indexerid), library)
if len(results) == 0:
return None
else:
return results[0]
if not library:
logger.log(u"Could not connect to trakt service, aborting library check", logger.ERROR)
return
for show in library:
if int(indexer) == 1 and int(show['tvdb_id']) == int(indexerid):
return show
elif int(indexer) == 2 and int(show['tvrage_id']) == int(indexerid):
return show
def syncLibrary(self):
logger.log(u"Syncing library to trakt.tv show library", logger.DEBUG)
@ -71,20 +75,23 @@ class TraktChecker():
self.addShowToTraktLibrary(myShow)
def removeShowFromTraktLibrary(self, show_obj):
if not self.findShow(show_obj.indexerid):
return
if self.findShow(show_obj.indexer, show_obj.indexerid):
# URL parameters
data = {}
if show_obj.indexer == 1:
data['tvdb_id'] = show_obj.indexerid
data['title'] = show_obj.name
data['year'] = show_obj.startyear
# URL parameters
data = {
'tvdb_id': show_obj.indexerid,
'title': show_obj.name,
'year': show_obj.startyear,
}
elif show_obj.indexer == 2:
data['tvrage_id'] = show_obj.indexerid
data['title'] = show_obj.name
data['year'] = show_obj.startyear
if data is not None:
logger.log(u"Removing " + show_obj.name + " from trakt.tv library", logger.DEBUG)
TraktCall("show/unlibrary/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD,
data)
if data is not None:
logger.log(u"Removing " + show_obj.name + " from trakt.tv library", logger.DEBUG)
TraktCall("show/unlibrary/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD,
data)
def addShowToTraktLibrary(self, show_obj):
"""
@ -93,20 +100,23 @@ class TraktChecker():
show_obj: The TVShow object to add to trakt
"""
if self.findShow(show_obj.indexerid):
return
if not self.findShow(show_obj.indexer, show_obj.indexerid):
# URL parameters
data = {}
if show_obj.indexer == 1:
data['tvdb_id'] = show_obj.indexerid
data['title'] = show_obj.name
data['year'] = show_obj.startyear
# URL parameters
data = {
'tvdb_id': show_obj.indexerid,
'title': show_obj.name,
'year': show_obj.startyear,
}
elif show_obj.indexer == 2:
data['tvrage_id'] = show_obj.indexerid
data['title'] = show_obj.name
data['year'] = show_obj.startyear
if data is not None:
logger.log(u"Adding " + show_obj.name + " to trakt.tv library", logger.DEBUG)
TraktCall("show/library/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD,
data)
if data is not None:
logger.log(u"Adding " + show_obj.name + " to trakt.tv library", logger.DEBUG)
TraktCall("show/library/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD,
data)
def updateShows(self):
logger.log(u"Starting trakt show watchlist check", logger.DEBUG)
@ -117,19 +127,25 @@ class TraktChecker():
return
for show in watchlist:
if int(sickbeard.TRAKT_METHOD_ADD) != 2:
self.addDefaultShow(show["tvdb_id"], show["title"], SKIPPED)
indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
if indexer == 2:
indexer_id = int(show["tvrage_id"])
else:
self.addDefaultShow(show["tvdb_id"], show["title"], WANTED)
indexer_id = int(show["tvdb_id"])
if int(sickbeard.TRAKT_METHOD_ADD) != 2:
self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED)
else:
self.addDefaultShow(indexer, indexer_id, show["title"], WANTED)
if int(sickbeard.TRAKT_METHOD_ADD) == 1:
newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"]))
newShow = helpers.findCertainShow(sickbeard.showList, indexer_id)
if newShow is not None:
self.setEpisodeToWanted(newShow, 1, 1)
self.startBacklog(newShow)
else:
self.todoWanted.append((int(show["tvdb_id"]), 1, 1))
self.todoWanted.append((int(show["tvdb_id"]), -1, -1)) # used to pause new shows if the settings say to
self.todoWanted.append((indexer_id, 1, 1))
self.todoWanted.append((indexer_id, -1, -1)) # used to pause new shows if the settings say to
def updateEpisodes(self):
"""
@ -143,69 +159,79 @@ class TraktChecker():
return
for show in watchlist:
self.addDefaultShow(int(show["tvdb_id"]), show["title"], SKIPPED)
newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"]))
for episode in show["episodes"]:
if newShow is not None:
self.setEpisodeToWanted(newShow, episode["season"], episode["number"])
else:
self.todoWanted.append((int(show["tvdb_id"]), episode["season"], episode["number"]))
self.startBacklog(newShow)
indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
if indexer == 2:
indexer_id = int(show["tvrage_id"])
else:
indexer_id = int(show["tvdb_id"])
def addDefaultShow(self, indexerid, name, status):
self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED)
newShow = helpers.findCertainShow(sickbeard.showList, indexer_id)
if newShow and int(newShow['indexer']) == indexer:
for episode in show["episodes"]:
if newShow is not None:
self.setEpisodeToWanted(newShow, episode["season"], episode["number"])
else:
self.todoWanted.append((indexer_id, episode["season"], episode["number"]))
self.startBacklog(newShow)
def addDefaultShow(self, indexer, indexer_id, name, status):
"""
Adds a new show with the default settings
"""
if helpers.findCertainShow(sickbeard.showList, int(indexerid)):
return
if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)):
logger.log(u"Adding show " + str(indexer_id))
root_dirs = sickbeard.ROOT_DIRS.split('|')
logger.log(u"Adding show " + str(indexerid))
root_dirs = sickbeard.ROOT_DIRS.split('|')
try:
location = root_dirs[int(root_dirs[0]) + 1]
except:
location = None
try:
location = root_dirs[int(root_dirs[0]) + 1]
except:
location = None
if location:
showPath = ek.ek(os.path.join, location, helpers.sanitizeFileName(name))
dir_exists = helpers.makeDir(showPath)
if not dir_exists:
logger.log(u"Unable to create the folder " + showPath + ", can't add the show", logger.ERROR)
return
else:
helpers.chmodAsParent(showPath)
if location:
showPath = ek.ek(os.path.join, location, helpers.sanitizeFileName(name))
dir_exists = helpers.makeDir(showPath)
if not dir_exists:
logger.log(u"Unable to create the folder " + showPath + ", can't add the show", logger.ERROR)
return
sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath, status,
int(sickbeard.QUALITY_DEFAULT),
int(sickbeard.FLATTEN_FOLDERS_DEFAULT))
else:
helpers.chmodAsParent(showPath)
sickbeard.showQueueScheduler.action.addShow(1, int(indexerid), showPath, status,
int(sickbeard.QUALITY_DEFAULT),
int(sickbeard.FLATTEN_FOLDERS_DEFAULT))
else:
logger.log(u"There was an error creating the show, no root directory setting found", logger.ERROR)
return
logger.log(u"There was an error creating the show, no root directory setting found", logger.ERROR)
return
def setEpisodeToWanted(self, show, s, e):
"""
Sets an episode to wanted, only is it is currently skipped
"""
epObj = show.getEpisode(int(s), int(e))
if epObj == None:
return
with epObj.lock:
if epObj.status != SKIPPED:
return
logger.log(u"Setting episode s" + str(s) + "e" + str(e) + " of show " + show.name + " to wanted")
# figure out what segment the episode is in and remember it so we can backlog it
if epObj.show.air_by_date or epObj.show.sports:
ep_segment = str(epObj.airdate)[:7]
else:
ep_segment = epObj.season
if epObj:
epObj.status = WANTED
epObj.saveToDB()
ep_segment = {}
backlog = (show, ep_segment)
if self.todoBacklog.count(backlog) == 0:
self.todoBacklog.append(backlog)
with epObj.lock:
if epObj.status != SKIPPED:
return
logger.log(u"Setting episode s" + str(s) + "e" + str(e) + " of show " + show.name + " to wanted")
# figure out what segment the episode is in and remember it so we can backlog it
if epObj.season in ep_segment:
ep_segment[epObj.season].append(epObj)
else:
ep_segment[epObj.season] = [epObj]
epObj.status = WANTED
epObj.saveToDB()
backlog = (show, ep_segment)
if self.todoBacklog.count(backlog) == 0:
self.todoBacklog.append(backlog)
def manageNewShow(self, show):
@ -223,8 +249,8 @@ class TraktChecker():
for segment in segments:
cur_backlog_queue_item = search_queue.BacklogQueueItem(show, segment[1])
sickbeard.searchQueueScheduler.action.add_item(cur_backlog_queue_item)
logger.log(u"Starting backlog for " + show.name + " season " + str(
segment[1]) + " because some eps were set to wanted")
self.todoBacklog.remove(segment)
for season in segment[1]:
logger.log(u"Starting backlog for " + show.name + " season " + str(
season) + " because some eps were set to wanted")
self.todoBacklog.remove(segment)

View file

@ -428,7 +428,7 @@ class TVShow(object):
try:
parse_result = None
np = NameParser(False, showObj=self, useIndexers=True)
np = NameParser(False, showObj=self, tryIndexers=True)
parse_result = np.parse(ep_file_name)
except (InvalidNameException, InvalidShowException):
pass
@ -612,7 +612,7 @@ class TVShow(object):
logger.log(str(self.indexerid) + u": Creating episode object from " + file, logger.DEBUG)
try:
myParser = NameParser(True, showObj=self, useIndexers=True)
myParser = NameParser(True, showObj=self, tryIndexers=True)
parse_result = myParser.parse(file)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + file + " into a valid episode", logger.DEBUG)

View file

@ -975,14 +975,14 @@ class CMD_EpisodeSetStatus(ApiCall):
sql_l = []
for epObj in ep_list:
if self.status == WANTED:
# figure out what episodes are wanted so we can backlog them
if epObj.season in ep_segment:
ep_segment[epObj.season].append(epObj)
else:
ep_segment[epObj.season] = [epObj]
with epObj.lock:
if self.status == WANTED:
# figure out what episodes are wanted so we can backlog them
if epObj.season in ep_segment:
ep_segment[epObj.season].append(epObj)
else:
ep_segment[epObj.season] = [epObj]
# don't let them mess up UNAIRED episodes
if epObj.status == UNAIRED:
if self.e != None: # setting the status of a unaired is only considert a failure if we directly wanted this episode, but is ignored on a season request
@ -1723,6 +1723,8 @@ class CMD_Show(ApiCall):
if not showObj:
return _responds(RESULT_FAILURE, msg="Show not found")
mindexers = helpers.mapIndexersToShow(showObj)
showDict = {}
showDict["season_list"] = CMD_ShowSeasonList(self.handler, (), {"indexerid": self.indexerid}).run()["data"]
showDict["cache"] = CMD_ShowCache(self.handler, (), {"indexerid": self.indexerid}).run()["data"]
@ -1753,7 +1755,7 @@ class CMD_Show(ApiCall):
showDict["anime"] = showObj.anime
#clean up tvdb horrible airs field
showDict["airs"] = str(showObj.airs).replace('am', ' AM').replace('pm', ' PM').replace(' ', ' ')
showDict["tvrage_id"] = helpers.mapIndexersToShow(showObj)['tvrage_id']
showDict["tvrage_id"] = mindexers[2] if 2 in mindexers else 0
showDict["tvrage_name"] = showObj.name
showDict["network"] = showObj.network
if not showDict["network"]:
@ -2522,6 +2524,7 @@ class CMD_Shows(ApiCall):
if self.paused != None and bool(self.paused) != bool(curShow.paused):
continue
mindexers = helpers.mapIndexersToShow(curShow)
showDict = {
"paused": curShow.paused,
"quality": _get_quality_string(curShow.quality),
@ -2530,8 +2533,8 @@ class CMD_Shows(ApiCall):
"sports": curShow.sports,
"anime": curShow.anime,
"indexerid": curShow.indexerid,
"tvdbid": helpers.mapIndexersToShow(curShow)['tvdb_id'],
"tvrage_id": helpers.mapIndexersToShow(curShow)['tvrage_id'],
"tvdbid": mindexers[1] if 1 in mindexers else 0,
"tvrage_id": mindexers[2] if 2 in mindexers else 0,
"tvrage_name": curShow.name,
"network": curShow.network,
"show_name": curShow.name,

View file

@ -2213,7 +2213,7 @@ class ConfigNotifications(MainHandler):
use_nmjv2=None, nmjv2_host=None, nmjv2_dbloc=None, nmjv2_database=None,
use_trakt=None, trakt_username=None, trakt_password=None, trakt_api=None,
trakt_remove_watchlist=None, trakt_use_watchlist=None, trakt_method_add=None,
trakt_start_paused=None, trakt_use_recommended=None, trakt_sync=None,
trakt_start_paused=None, trakt_use_recommended=None, trakt_sync=None, trakt_default_indexer=None,
use_synologynotifier=None, synologynotifier_notify_onsnatch=None,
synologynotifier_notify_ondownload=None, synologynotifier_notify_onsubtitledownload=None,
use_pytivo=None, pytivo_notify_onsnatch=None, pytivo_notify_ondownload=None,
@ -2326,6 +2326,7 @@ class ConfigNotifications(MainHandler):
sickbeard.TRAKT_START_PAUSED = config.checkbox_to_value(trakt_start_paused)
sickbeard.TRAKT_USE_RECOMMENDED = config.checkbox_to_value(trakt_use_recommended)
sickbeard.TRAKT_SYNC = config.checkbox_to_value(trakt_sync)
sickbeard.TRAKT_DEFAULT_INDEXER = int(trakt_default_indexer)
if sickbeard.USE_TRAKT:
sickbeard.traktCheckerScheduler.silent = False