SickGear/sickbeard/scene_numbering.py

759 lines
28 KiB
Python
Raw Normal View History

2014-04-22 08:02:43 +00:00
# Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear 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
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
#
# Created on Sep 20, 2012
# @author: Dermot Buckley <dermot@buckley.ie>
# @copyright: Dermot Buckley
#
import time
import datetime
import traceback
import sickbeard
from sickbeard import logger
from sickbeard import db
from sickbeard.exceptions import ex
2015-12-06 11:36:45 +00:00
from sickbeard.scene_exceptions import xem_ids_list
2015-07-25 09:19:46 +00:00
def get_scene_numbering(indexer_id, indexer, season, episode, fallback_to_xem=True):
"""
Returns a tuple, (season, episode), with the scene numbering (if there is one),
2015-12-06 11:36:45 +00:00
otherwise returns the xem numbering (if fallback_to_xem is set), otherwise
2014-03-11 02:32:02 +00:00
returns the TVDB and TVRAGE numbering.
(so the return values will always be set)
2015-12-06 11:36:45 +00:00
@param indexer_id: int
@param season: int
@param episode: int
@param fallback_to_xem: bool If set (the default), check xem for matches if there is no local scene numbering
2015-12-06 11:36:45 +00:00
@return: (int, int) a tuple with (season, episode)
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is season or None is episode:
return season, episode
2015-07-25 09:19:46 +00:00
show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(indexer_id))
if show_obj and not show_obj.is_scene:
return season, episode
result = find_scene_numbering(int(indexer_id), int(indexer), season, episode)
if result:
return result
else:
if fallback_to_xem:
xem_result = find_xem_numbering(int(indexer_id), int(indexer), season, episode)
if xem_result:
return xem_result
2015-07-25 09:19:46 +00:00
return season, episode
def find_scene_numbering(indexer_id, indexer, season, episode):
"""
Same as get_scene_numbering(), but returns None if scene numbering is not set
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is season or None is episode:
return season, episode
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT scene_season, scene_episode FROM scene_numbering WHERE indexer = ? and indexer_id = ? and season = ? and episode = ? and (scene_season or scene_episode) != 0',
[indexer, indexer_id, season, episode])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['scene_season']), int(rows[0]['scene_episode'])
def get_scene_absolute_numbering(indexer_id, indexer, absolute_number, fallback_to_xem=True):
"""
Returns a tuple, (season, episode), with the scene numbering (if there is one),
otherwise returns the xem numbering (if fallback_to_xem is set), otherwise
returns the TVDB and TVRAGE numbering.
(so the return values will always be set)
@param indexer_id: int
2014-06-07 12:36:50 +00:00
@param absolute_number: int
@param fallback_to_xem: bool If set (the default), check xem for matches if there is no local scene numbering
@return: (int, int) a tuple with (season, episode)
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is absolute_number:
return absolute_number
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, indexer_id)
if show_obj and not show_obj.is_scene:
return absolute_number
result = find_scene_absolute_numbering(indexer_id, indexer, absolute_number)
if result:
return result
else:
if fallback_to_xem:
xem_result = find_xem_absolute_numbering(indexer_id, indexer, absolute_number)
if xem_result:
return xem_result
return absolute_number
def find_scene_absolute_numbering(indexer_id, indexer, absolute_number):
"""
Same as get_scene_numbering(), but returns None if scene numbering is not set
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is absolute_number:
return absolute_number
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT scene_absolute_number FROM scene_numbering WHERE indexer = ? and indexer_id = ? and absolute_number = ? and scene_absolute_number != 0',
[indexer, indexer_id, absolute_number])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['scene_absolute_number'])
def get_indexer_numbering(indexer_id, indexer, sceneSeason, sceneEpisode, fallback_to_xem=True):
"""
2014-03-11 02:32:02 +00:00
Returns a tuple, (season, episode) with the TVDB and TVRAGE numbering for (sceneSeason, sceneEpisode)
(this works like the reverse of get_scene_numbering)
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is sceneSeason or None is sceneEpisode:
return sceneSeason, sceneEpisode
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT season, episode FROM scene_numbering WHERE indexer = ? and indexer_id = ? and scene_season = ? and scene_episode = ?',
[indexer, indexer_id, sceneSeason, sceneEpisode])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['season']), int(rows[0]['episode'])
else:
if fallback_to_xem:
return get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode)
2015-07-25 09:19:46 +00:00
return sceneSeason, sceneEpisode
def get_indexer_absolute_numbering(indexer_id, indexer, sceneAbsoluteNumber, fallback_to_xem=True, scene_season=None):
"""
Returns a tuple, (season, episode, absolute_number) with the TVDB and TVRAGE numbering for (sceneAbsoluteNumber)
(this works like the reverse of get_absolute_numbering)
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is sceneAbsoluteNumber:
return sceneAbsoluteNumber
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
if None is scene_season:
rows = my_db.select(
'SELECT absolute_number FROM scene_numbering WHERE indexer = ? and indexer_id = ? and scene_absolute_number = ?',
[indexer, indexer_id, sceneAbsoluteNumber])
else:
2015-07-25 09:19:46 +00:00
rows = my_db.select(
'SELECT absolute_number FROM scene_numbering WHERE indexer = ? and indexer_id = ? and scene_absolute_number = ? and scene_season = ?',
[indexer, indexer_id, sceneAbsoluteNumber, scene_season])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['absolute_number'])
else:
if fallback_to_xem:
return get_indexer_absolute_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNumber, scene_season)
return sceneAbsoluteNumber
def set_scene_numbering(indexer_id, indexer, season=None, episode=None, absolute_number=None, sceneSeason=None,
sceneEpisode=None, sceneAbsolute=None):
"""
Set scene numbering for a season/episode.
To clear the scene numbering, leave both sceneSeason and sceneEpisode as None.
2015-12-06 11:36:45 +00:00
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
if None is not season and None is not episode:
2015-07-25 09:19:46 +00:00
my_db.action(
'INSERT OR IGNORE INTO scene_numbering (indexer, indexer_id, season, episode) VALUES (?,?,?,?)',
[indexer, indexer_id, season, episode])
2015-07-25 09:19:46 +00:00
my_db.action(
'UPDATE scene_numbering SET scene_season = ?, scene_episode = ? WHERE indexer = ? and indexer_id = ? and season = ? and episode = ?',
[sceneSeason, sceneEpisode, indexer, indexer_id, season, episode])
elif absolute_number:
2015-07-25 09:19:46 +00:00
my_db.action(
'INSERT OR IGNORE INTO scene_numbering (indexer, indexer_id, absolute_number) VALUES (?,?,?)',
[indexer, indexer_id, absolute_number])
2015-07-25 09:19:46 +00:00
my_db.action(
'UPDATE scene_numbering SET scene_absolute_number = ? WHERE indexer = ? and indexer_id = ? and absolute_number = ?',
[sceneAbsolute, indexer, indexer_id, absolute_number])
def find_xem_numbering(indexer_id, indexer, season, episode):
"""
Returns the scene numbering, as retrieved from xem.
Refreshes/Loads as needed.
2015-12-06 11:36:45 +00:00
@param indexer_id: int
@param season: int
@param episode: int
@return: (int, int) a tuple of scene_season, scene_episode, or None if there is no special mapping.
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is season or None is episode:
return season, episode
indexer_id = int(indexer_id)
indexer = int(indexer)
xem_refresh(indexer_id, indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT scene_season, scene_episode FROM tv_episodes WHERE indexer = ? and showid = ? and season = ? and episode = ? and (scene_season or scene_episode) != 0',
[indexer, indexer_id, season, episode])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['scene_season']), int(rows[0]['scene_episode'])
def find_xem_absolute_numbering(indexer_id, indexer, absolute_number):
"""
Returns the scene numbering, as retrieved from xem.
Refreshes/Loads as needed.
@param indexer_id: int
2014-06-07 12:36:50 +00:00
@param absolute_number: int
@return: int
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is absolute_number:
return absolute_number
indexer_id = int(indexer_id)
indexer = int(indexer)
xem_refresh(indexer_id, indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and absolute_number = ? and scene_absolute_number != 0',
[indexer, indexer_id, absolute_number])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['scene_absolute_number'])
def get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode):
"""
Reverse of find_xem_numbering: lookup a tvdb season and episode using scene numbering
2015-12-06 11:36:45 +00:00
@param indexer_id: int
@param sceneSeason: int
@param sceneEpisode: int
2015-12-06 11:36:45 +00:00
@return: (int, int) a tuple of (season, episode)
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is sceneSeason or None is sceneEpisode:
return sceneSeason, sceneEpisode
indexer_id = int(indexer_id)
indexer = int(indexer)
xem_refresh(indexer_id, indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT season, episode FROM tv_episodes WHERE indexer = ? and showid = ? and scene_season = ? and scene_episode = ?',
[indexer, indexer_id, sceneSeason, sceneEpisode])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['season']), int(rows[0]['episode'])
2015-07-25 09:19:46 +00:00
return sceneSeason, sceneEpisode
def get_indexer_absolute_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNumber, scene_season=None):
"""
Reverse of find_xem_numbering: lookup a tvdb season and episode using scene numbering
@param indexer_id: int
2014-06-07 12:36:50 +00:00
@param sceneAbsoluteNumber: int
@return: int
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id or None is sceneAbsoluteNumber:
return sceneAbsoluteNumber
indexer_id = int(indexer_id)
indexer = int(indexer)
xem_refresh(indexer_id, indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
if None is scene_season:
rows = my_db.select(
'SELECT absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and scene_absolute_number = ?',
[indexer, indexer_id, sceneAbsoluteNumber])
else:
2015-07-25 09:19:46 +00:00
rows = my_db.select(
'SELECT absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and scene_absolute_number = ? and scene_season = ?',
[indexer, indexer_id, sceneAbsoluteNumber, scene_season])
if rows:
2015-07-25 09:19:46 +00:00
return int(rows[0]['absolute_number'])
return sceneAbsoluteNumber
def get_scene_numbering_for_show(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
Will be empty if there are no scene numbers set
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return {}
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT season, episode, scene_season, scene_episode FROM scene_numbering WHERE indexer = ? and indexer_id = ? and (scene_season or scene_episode) != 0 ORDER BY season, episode',
[indexer, indexer_id])
result = {}
for row in rows:
season = int(row['season'])
episode = int(row['episode'])
scene_season = int(row['scene_season'])
scene_episode = int(row['scene_episode'])
result[(season, episode)] = (scene_season, scene_episode)
return result
def get_xem_numbering_for_show(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
Will be empty if there are no scene numbers set in xem
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return {}
indexer_id = int(indexer_id)
indexer = int(indexer)
xem_refresh(indexer_id, indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT season, episode, scene_season, scene_episode FROM tv_episodes WHERE indexer = ? and showid = ? and (scene_season or scene_episode) != 0 ORDER BY season, episode',
[indexer, indexer_id])
result = {}
for row in rows:
season = int(row['season'])
episode = int(row['episode'])
scene_season = int(row['scene_season'])
scene_episode = int(row['scene_episode'])
result[(season, episode)] = (scene_season, scene_episode)
return result
def get_scene_absolute_numbering_for_show(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
Will be empty if there are no scene numbers set
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return {}
indexer_id = int(indexer_id)
indexer = int(indexer)
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT absolute_number, scene_absolute_number FROM scene_numbering WHERE indexer = ? and indexer_id = ? and scene_absolute_number != 0 ORDER BY absolute_number',
[indexer, indexer_id])
result = {}
for row in rows:
absolute_number = int(row['absolute_number'])
scene_absolute_number = int(row['scene_absolute_number'])
result[absolute_number] = scene_absolute_number
return result
def get_xem_absolute_numbering_for_show(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
Will be empty if there are no scene numbers set in xem
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return {}
indexer_id = int(indexer_id)
indexer = int(indexer)
xem_refresh(indexer_id, indexer)
result = {}
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT absolute_number, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ? and scene_absolute_number != 0 ORDER BY absolute_number',
[indexer, indexer_id])
for row in rows:
absolute_number = int(row['absolute_number'])
scene_absolute_number = int(row['scene_absolute_number'])
result[absolute_number] = scene_absolute_number
return result
def xem_refresh(indexer_id, indexer, force=False):
"""
Refresh data from xem for a tv show
2015-12-06 11:36:45 +00:00
@param indexer_id: int
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return
indexer_id = int(indexer_id)
indexer = int(indexer)
2017-05-17 15:55:59 +00:00
if 'xem_origin' not in sickbeard.indexerApi(indexer).config or indexer_id not in xem_ids_list.get(indexer, []):
return
# XEM API URL
2015-07-25 09:19:46 +00:00
url = 'http://thexem.de/map/all?id=%s&origin=%s&destination=scene' % (
indexer_id, sickbeard.indexerApi(indexer).config['xem_origin'])
2015-07-25 09:19:46 +00:00
max_refresh_age_secs = 86400 # 1 day
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select('SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?',
[indexer, indexer_id])
if rows:
2015-07-25 09:19:46 +00:00
last_refresh = int(rows[0]['last_refreshed'])
refresh = int(time.mktime(datetime.datetime.today().timetuple())) > last_refresh + max_refresh_age_secs
else:
refresh = True
if refresh or force:
logger.log(
2015-07-25 09:19:46 +00:00
u'Looking up XEM scene mapping for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name),
logger.DEBUG)
# mark refreshed
2015-07-25 09:19:46 +00:00
my_db.upsert('xem_refresh',
{'indexer': indexer, 'last_refreshed': int(time.mktime(datetime.datetime.today().timetuple()))},
{'indexer_id': indexer_id})
try:
2015-07-25 09:19:46 +00:00
parsed_json = sickbeard.helpers.getURL(url, json=True, timeout=90)
if not parsed_json or '' == parsed_json:
logger.log(u'No XEM data for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name), logger.MESSAGE)
return
2015-07-25 09:19:46 +00:00
if 'success' in parsed_json['result']:
cl = []
2015-07-25 09:19:46 +00:00
for entry in parsed_json['data']:
if 'scene' in entry:
cl.append([
2015-07-25 09:19:46 +00:00
'UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?',
[entry['scene']['season'],
entry['scene']['episode'],
entry['scene']['absolute'],
indexer_id,
entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'],
entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode']
2015-07-25 09:19:46 +00:00
]])
if 'scene_2' in entry: # for doubles
cl.append([
2015-07-25 09:19:46 +00:00
'UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?',
[entry['scene_2']['season'],
entry['scene_2']['episode'],
entry['scene_2']['absolute'],
indexer_id,
entry[sickbeard.indexerApi(indexer).config['xem_origin']]['season'],
entry[sickbeard.indexerApi(indexer).config['xem_origin']]['episode']
2015-07-25 09:19:46 +00:00
]])
2015-07-25 09:19:46 +00:00
if 0 < len(cl):
my_db = db.DBConnection()
my_db.mass_action(cl)
else:
2015-07-25 09:19:46 +00:00
logger.log(u'Empty lookup result - no XEM data for show %s on %s' % (
indexer_id, sickbeard.indexerApi(indexer).name), logger.DEBUG)
except Exception as e:
logger.log(
2015-07-25 09:19:46 +00:00
u'Exception while refreshing XEM data for show ' + str(indexer_id) + ' on ' + sickbeard.indexerApi(
indexer).name + ': ' + ex(e), logger.WARNING)
logger.log(traceback.format_exc(), logger.ERROR)
2015-07-25 09:19:46 +00:00
def fix_xem_numbering(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
Will be empty if there are no scene numbers set in xem
"""
2015-07-25 09:19:46 +00:00
if None is indexer_id:
return {}
indexer_id = int(indexer_id)
indexer = int(indexer)
# query = [{
# "name": self.show.name,
# "seasons": [{
# "episodes": [{
# "episode_number": None,
# "name": None
# }],
# "season_number": None,
# }],
# "/tv/tv_program/number_of_seasons": [],
# "/tv/tv_program/number_of_episodes": [],
# "/tv/tv_program/thetvdb_id": [],
# "/tv/tv_program/tvrage_id": [],
# "type": "/tv/tv_program",
# }]
#
#
# url = 'https://www.googleapis.com/freebase/v1/mqlread'
# api_key = "AIzaSyCCHNp4dhVHxJYzbLiCE4y4a1rgTnX4fDE"
# params = {
# 'query': json.dumps(query),
# 'key': api_key
# }
#
#
# def get_from_api(url, params=None):
# """Build request and return results
# """
# import xmltodict
#
# response = requests.get(url, params=params)
# if response.status_code == 200:
# try:
# return response.json()
# except ValueError:
# return xmltodict.parse(response.text)['Data']
#
# # Get query results
# tmp = get_from_api(url, params=params)['result']
2015-07-25 09:19:46 +00:00
my_db = db.DBConnection()
rows = my_db.select(
'SELECT season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ?',
[indexer, indexer_id])
last_absolute_number = None
last_scene_season = None
last_scene_episode = None
last_scene_absolute_number = None
update_absolute_number = False
update_scene_season = False
update_scene_episode = False
update_scene_absolute_number = False
logger.log(
2015-07-25 09:19:46 +00:00
u'Fixing any XEM scene mapping issues for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name),
logger.DEBUG)
Fixed issues with editing/saving custom scene exceptions. Fixed charmap issues for anime show names. Fixed issues with display show page and epCat key errors. Fixed duplicate log messages for clearing provider caches. Fixed issues with email notifier ep names not properly being encoded to UTF-8. TVDB<->TVRAGE Indexer ID mapping is now performed on demand to be used when needed such as newznab providers can be searched with tvrage_id's and some will return tvrage_id's that later can be used to create show objects from for faster and more accurate name parsing, mapping is done via Trakt API calls. Added stop event signals to schedualed tasks, SR now waits indefinate till task has been fully stopped before completing a restart or shutdown event. NameParserCache is now persistent and stores 200 parsed results at any given time for quicker lookups and better performance, this helps maintain results between updates or shutdown/startup events. Black and White lists for anime now only get used for anime shows as intended, performance gain for non-anime shows that dont need to load these lists. Internal name cache now builds it self on demand when needed per show request plus checks if show is already in cache and if true exits routine to save time. Schedualer and QueueItems classes are now a sub-class of threading.Thread and a stop threading event signal has been added to each. If I forgot to list something it doesn't mean its not fixed so please test and report back if anything is wrong or has been corrected by this new release.
2014-07-15 02:00:53 +00:00
cl = []
for row in rows:
season = int(row['season'])
episode = int(row['episode'])
if not int(row['scene_season']) and last_scene_season:
scene_season = last_scene_season + 1
update_scene_season = True
else:
scene_season = int(row['scene_season'])
if last_scene_season and scene_season < last_scene_season:
scene_season = last_scene_season + 1
update_scene_season = True
if not int(row['scene_episode']) and last_scene_episode:
scene_episode = last_scene_episode + 1
update_scene_episode = True
else:
scene_episode = int(row['scene_episode'])
if last_scene_episode and scene_episode < last_scene_episode:
scene_episode = last_scene_episode + 1
update_scene_episode = True
# check for unset values and correct them
if not int(row['absolute_number']) and last_absolute_number:
absolute_number = last_absolute_number + 1
update_absolute_number = True
else:
absolute_number = int(row['absolute_number'])
if last_absolute_number and absolute_number < last_absolute_number:
absolute_number = last_absolute_number + 1
update_absolute_number = True
if not int(row['scene_absolute_number']) and last_scene_absolute_number:
scene_absolute_number = last_scene_absolute_number + 1
update_scene_absolute_number = True
else:
scene_absolute_number = int(row['scene_absolute_number'])
if last_scene_absolute_number and scene_absolute_number < last_scene_absolute_number:
scene_absolute_number = last_scene_absolute_number + 1
update_scene_absolute_number = True
# store values for lookup on next iteration
last_absolute_number = absolute_number
last_scene_season = scene_season
last_scene_episode = scene_episode
last_scene_absolute_number = scene_absolute_number
if update_absolute_number:
Fixed issues with editing/saving custom scene exceptions. Fixed charmap issues for anime show names. Fixed issues with display show page and epCat key errors. Fixed duplicate log messages for clearing provider caches. Fixed issues with email notifier ep names not properly being encoded to UTF-8. TVDB<->TVRAGE Indexer ID mapping is now performed on demand to be used when needed such as newznab providers can be searched with tvrage_id's and some will return tvrage_id's that later can be used to create show objects from for faster and more accurate name parsing, mapping is done via Trakt API calls. Added stop event signals to schedualed tasks, SR now waits indefinate till task has been fully stopped before completing a restart or shutdown event. NameParserCache is now persistent and stores 200 parsed results at any given time for quicker lookups and better performance, this helps maintain results between updates or shutdown/startup events. Black and White lists for anime now only get used for anime shows as intended, performance gain for non-anime shows that dont need to load these lists. Internal name cache now builds it self on demand when needed per show request plus checks if show is already in cache and if true exits routine to save time. Schedualer and QueueItems classes are now a sub-class of threading.Thread and a stop threading event signal has been added to each. If I forgot to list something it doesn't mean its not fixed so please test and report back if anything is wrong or has been corrected by this new release.
2014-07-15 02:00:53 +00:00
cl.append([
2015-07-25 09:19:46 +00:00
'UPDATE tv_episodes SET absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?',
[absolute_number,
indexer_id,
season,
episode
2015-07-25 09:19:46 +00:00
]])
update_absolute_number = False
if update_scene_season:
Fixed issues with editing/saving custom scene exceptions. Fixed charmap issues for anime show names. Fixed issues with display show page and epCat key errors. Fixed duplicate log messages for clearing provider caches. Fixed issues with email notifier ep names not properly being encoded to UTF-8. TVDB<->TVRAGE Indexer ID mapping is now performed on demand to be used when needed such as newznab providers can be searched with tvrage_id's and some will return tvrage_id's that later can be used to create show objects from for faster and more accurate name parsing, mapping is done via Trakt API calls. Added stop event signals to schedualed tasks, SR now waits indefinate till task has been fully stopped before completing a restart or shutdown event. NameParserCache is now persistent and stores 200 parsed results at any given time for quicker lookups and better performance, this helps maintain results between updates or shutdown/startup events. Black and White lists for anime now only get used for anime shows as intended, performance gain for non-anime shows that dont need to load these lists. Internal name cache now builds it self on demand when needed per show request plus checks if show is already in cache and if true exits routine to save time. Schedualer and QueueItems classes are now a sub-class of threading.Thread and a stop threading event signal has been added to each. If I forgot to list something it doesn't mean its not fixed so please test and report back if anything is wrong or has been corrected by this new release.
2014-07-15 02:00:53 +00:00
cl.append([
2015-07-25 09:19:46 +00:00
'UPDATE tv_episodes SET scene_season = ? WHERE showid = ? AND season = ? AND episode = ?',
[scene_season,
indexer_id,
season,
episode
2015-07-25 09:19:46 +00:00
]])
update_scene_season = False
if update_scene_episode:
Fixed issues with editing/saving custom scene exceptions. Fixed charmap issues for anime show names. Fixed issues with display show page and epCat key errors. Fixed duplicate log messages for clearing provider caches. Fixed issues with email notifier ep names not properly being encoded to UTF-8. TVDB<->TVRAGE Indexer ID mapping is now performed on demand to be used when needed such as newznab providers can be searched with tvrage_id's and some will return tvrage_id's that later can be used to create show objects from for faster and more accurate name parsing, mapping is done via Trakt API calls. Added stop event signals to schedualed tasks, SR now waits indefinate till task has been fully stopped before completing a restart or shutdown event. NameParserCache is now persistent and stores 200 parsed results at any given time for quicker lookups and better performance, this helps maintain results between updates or shutdown/startup events. Black and White lists for anime now only get used for anime shows as intended, performance gain for non-anime shows that dont need to load these lists. Internal name cache now builds it self on demand when needed per show request plus checks if show is already in cache and if true exits routine to save time. Schedualer and QueueItems classes are now a sub-class of threading.Thread and a stop threading event signal has been added to each. If I forgot to list something it doesn't mean its not fixed so please test and report back if anything is wrong or has been corrected by this new release.
2014-07-15 02:00:53 +00:00
cl.append([
2015-07-25 09:19:46 +00:00
'UPDATE tv_episodes SET scene_episode = ? WHERE showid = ? AND season = ? AND episode = ?',
[scene_episode,
indexer_id,
season,
episode
2015-07-25 09:19:46 +00:00
]])
update_scene_episode = False
if update_scene_absolute_number:
Fixed issues with editing/saving custom scene exceptions. Fixed charmap issues for anime show names. Fixed issues with display show page and epCat key errors. Fixed duplicate log messages for clearing provider caches. Fixed issues with email notifier ep names not properly being encoded to UTF-8. TVDB<->TVRAGE Indexer ID mapping is now performed on demand to be used when needed such as newznab providers can be searched with tvrage_id's and some will return tvrage_id's that later can be used to create show objects from for faster and more accurate name parsing, mapping is done via Trakt API calls. Added stop event signals to schedualed tasks, SR now waits indefinate till task has been fully stopped before completing a restart or shutdown event. NameParserCache is now persistent and stores 200 parsed results at any given time for quicker lookups and better performance, this helps maintain results between updates or shutdown/startup events. Black and White lists for anime now only get used for anime shows as intended, performance gain for non-anime shows that dont need to load these lists. Internal name cache now builds it self on demand when needed per show request plus checks if show is already in cache and if true exits routine to save time. Schedualer and QueueItems classes are now a sub-class of threading.Thread and a stop threading event signal has been added to each. If I forgot to list something it doesn't mean its not fixed so please test and report back if anything is wrong or has been corrected by this new release.
2014-07-15 02:00:53 +00:00
cl.append([
2015-07-25 09:19:46 +00:00
'UPDATE tv_episodes SET scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?',
[scene_absolute_number,
indexer_id,
season,
episode
2015-07-25 09:19:46 +00:00
]])
update_scene_absolute_number = False
2015-07-25 09:19:46 +00:00
if 0 < len(cl):
my_db = db.DBConnection()
my_db.mass_action(cl)
Change overhaul and add API functions Change API version... start with 10 Change set application response header to 'SickGear' + add API version Change return timezone (of network) in API Add indexer to calls Add SickGear Command tip for old SickBeard commands Add warning old sickbeard API calls only support tvdb shows Add "tvdbid" fallback only for sickbeard calls Add listcommands Add list of all commands (old + new) in listcommand page at the beginning Change hide 'listcommands' command from commands list, since it needs the API builder CSS + is html not json Add missing help in webapi Add episode info: absolute_number, scene_season, scene_episode, scene_absolute_number Add fork to SB command Add sg Add sg.activatescenenumbering Add sg.addrootdir Add sg.checkscheduler Add sg.deleterootdir Add sg.episode Add sg.episode.search Add sg.episode.setstatus Add sg.episode.subtitlesearch Add sg.exceptions Add sg.forcesearch Add sg.future Add sg.getdefaults Add sg.getindexericon Add sg.getindexers to list all indexers Add sg.getmessages Add sg.getnetworkicon Add sg.getrootdirs Add sg.getqualities Add sg.getqualitystrings Add sg.history Add sg.history.clear Add sg.history.trim Add sg.listtraktaccounts Add sg.listignorewords Add sg.listrequiedwords Add sg.logs Add sg.pausebacklog Add sg.postprocess Add sg.ping Add sg.restart Add sg.searchqueue Add sg.searchtv to search all indexers Add sg.setexceptions Add sg.setignorewords Add sg.setrequiredwords Add sg.setscenenumber Add sg.show Add sg.show.addexisting Add sg.show.addnew Add sg.show.cache Add sg.show.delete Add sg.show.getbanner Add sg.show.getfanart Add sg.show.getposter Add sg.show.getquality Add sg.show.listfanart Add sg.show.ratefanart Add sg.show.seasonlist Add sg.show.seasons Add sg.show.setquality Add sg.show.stats Add sg.show.refresh Add sg.show.pause Add sg.show.update Add sg.shows Add sg.shows.browsetrakt Add sg.shows.forceupdate Add sg.shows.queue Add sg.shows.stats Change sickbeard to sickgear Change sickbeard_call to property Change sg.episode.setstatus allow setting of quality Change sg.history, history command output Change sg.searchtv to list of indexers Add uhd4kweb to qualities Add upgrade_once to add existing shows Add upgrade_once to add new show Add upgrade_once to show quality settings (get/set) Add 'ids' to Show + Shows Add ids to coming eps + get tvdb id from ids Add 'status_str' to coming eps Add 'local_datetime' to comming eps + runtime Add X-Filename response header to getbanner, getposter Add X-Fanartname response header for sg.show.getfanart Add missing fields to sb.show Add missing fields to sb.shows Change sb.seasons Change overview optional Change make overview optional in shows Add setscenenumber to API builder Change move set_scene_numbering_helper into scnene_numbering for use in web interface and API Change use quality_map instead of fixed list Add eigthlevel for API/builder page Change limit indexer param to valid values Fix wrong parameter in existing apiBuilder.tmpl that prevents javascript from continuing + add console error message for it Fixed: filter missed shows correctly Add @gen.coroutine
2016-08-24 19:02:12 +00:00
def set_scene_numbering_helper(indexerid, indexer, forSeason=None, forEpisode=None, forAbsolute=None,
sceneSeason=None, sceneEpisode=None, sceneAbsolute=None):
# sanitize:
indexerid = None if indexerid in [None, 'null', ''] else int(indexerid)
indexer = None if indexer in [None, 'null', ''] else int(indexer)
show_obj = sickbeard.helpers.find_show_by_id(sickbeard.showList, {indexer: indexerid}, no_mapped_ids=True)
if not show_obj:
result = {'success': False}
return result
if not show_obj.is_anime:
for_season = None if forSeason in [None, 'null', ''] else int(forSeason)
for_episode = None if forEpisode in [None, 'null', ''] else int(forEpisode)
scene_season = None if sceneSeason in [None, 'null', ''] else int(sceneSeason)
scene_episode = None if sceneEpisode in [None, 'null', ''] else int(sceneEpisode)
action_log = u'Set episode scene numbering to %sx%s for episode %sx%s of "%s"' \
% (scene_season, scene_episode, for_season, for_episode, show_obj.name)
ep_args = {'show': indexerid, 'season': for_season, 'episode': for_episode}
scene_args = {'indexer_id': indexerid, 'indexer': indexer, 'season': for_season, 'episode': for_episode,
'sceneSeason': scene_season, 'sceneEpisode': scene_episode}
result = {'forSeason': for_season, 'forEpisode': for_episode, 'sceneSeason': None, 'sceneEpisode': None}
else:
for_absolute = None if forAbsolute in [None, 'null', ''] else int(forAbsolute)
scene_absolute = None if sceneAbsolute in [None, 'null', ''] else int(sceneAbsolute)
action_log = u'Set absolute scene numbering to %s for episode %s of "%s"' \
% (scene_absolute, for_absolute, show_obj.name)
ep_args = {'show': indexerid, 'absolute': for_absolute}
scene_args = {'indexer_id': indexerid, 'indexer': indexer, 'absolute_number': for_absolute,
'sceneAbsolute': scene_absolute}
result = {'forAbsolute': for_absolute, 'sceneAbsolute': None}
if ep_args.get('absolute'):
ep_obj = show_obj.getEpisode(absolute_number=int(ep_args['absolute']))
elif None is not ep_args['season'] and None is not ep_args['episode']:
ep_obj = show_obj.getEpisode(int(ep_args['season']), int(ep_args['episode']))
else:
ep_obj = 'Invalid paramaters'
if ep_obj is None:
ep_obj = "Episode couldn't be retrieved"
result['success'] = not isinstance(ep_obj, str)
if result['success']:
logger.log(action_log, logger.DEBUG)
set_scene_numbering(**scene_args)
show_obj.flushEpisodes()
else:
result['errorMessage'] = ep_obj
if not show_obj.is_anime:
scene_numbering = get_scene_numbering(indexerid, indexer, for_season, for_episode)
if scene_numbering:
(result['sceneSeason'], result['sceneEpisode']) = scene_numbering
else:
scene_numbering = get_scene_absolute_numbering(indexerid, indexer, for_absolute)
if scene_numbering:
result['sceneAbsolute'] = scene_numbering
return result