diff --git a/SickBeard.py b/SickBeard.py index 00d0a84d..947ed781 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -21,6 +21,7 @@ from __future__ import with_statement import time +import signal import sys import shutil import subprocess @@ -52,15 +53,15 @@ if sys.hexversion >= 0x020600F0: import locale import datetime import threading -import signal import traceback import getopt import sickbeard +from sickbeard.event_queue import Events from sickbeard import db from sickbeard.tv import TVShow -from sickbeard import logger +from sickbeard import logger, network_timezones, failed_history, name_cache from sickbeard.webserveInit import SRWebServer from sickbeard.version import SICKBEARD_VERSION from sickbeard.databases.mainDB import MIN_DB_VERSION @@ -68,14 +69,16 @@ from sickbeard.databases.mainDB import MAX_DB_VERSION from lib.configobj import ConfigObj +throwaway = datetime.datetime.strptime('20110101', '%Y%m%d') + signal.signal(signal.SIGINT, sickbeard.sig_handler) signal.signal(signal.SIGTERM, sickbeard.sig_handler) -throwaway = datetime.datetime.strptime('20110101', '%Y%m%d') - class SickRage(object): def __init__(self): + sickbeard.events = Events(self.shutdown) + self.webserver = None self.runAsDaemon = False self.CREATEPID = False @@ -313,6 +316,16 @@ class SickRage(object): # Fire up all our threads sickbeard.start() + # Build internal name cache + name_cache.buildNameCache() + + # refresh network timezones + network_timezones.update_network_dict() + + # sure, why not? + if sickbeard.USE_FAILED_DOWNLOADS: + failed_history.trimHistory() + # Start an update if we're supposed to if self.forceUpdate or sickbeard.UPDATE_SHOWS_ON_START: sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable @@ -320,7 +333,8 @@ class SickRage(object): if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon): sickbeard.launchBrowser(self.startPort) - while(sickbeard.started): + # main loop + while(True): time.sleep(1) def daemonize(self): @@ -421,56 +435,54 @@ class SickRage(object): except: return False + def shutdown(self, type): + if sickbeard.started: + # stop all tasks + sickbeard.halt() + + # shutdown web server + if self.webserver: + self.webserver.shutDown() + self.webserver = None + + # save all shows to DB + sickbeard.saveAll() + + # if run as daemon delete the pidfile + if self.runAsDaemon and self.CREATEPID: + self.remove_pid_file(self.PIDFILE) + + if type == sickbeard.events.SystemEvent.RESTART: + install_type = sickbeard.versionCheckScheduler.action.install_type + + popen_list = [] + + if install_type in ('git', 'source'): + popen_list = [sys.executable, sickbeard.MY_FULLNAME] + elif install_type == 'win': + if hasattr(sys, 'frozen'): + # c:\dir\to\updater.exe 12345 c:\dir\to\sickbeard.exe + popen_list = [os.path.join(sickbeard.PROG_DIR, 'updater.exe'), str(sickbeard.PID), sys.executable] + else: + logger.log(u"Unknown SB launch method, please file a bug report about this", logger.ERROR) + popen_list = [sys.executable, os.path.join(sickbeard.PROG_DIR, 'updater.py'), str(sickbeard.PID), + sys.executable, + sickbeard.MY_FULLNAME] + + if popen_list: + popen_list += sickbeard.MY_ARGS + if '--nolaunch' not in popen_list: + popen_list += ['--nolaunch'] + logger.log(u"Restarting SickRage with " + str(popen_list)) + logger.close() + subprocess.Popen(popen_list, cwd=os.getcwd()) + + # system exit + os._exit(0) + if __name__ == "__main__": if sys.hexversion >= 0x020600F0: freeze_support() - sr = None - try: - # init sickrage - sr = SickRage() - - # start sickrage - sr.start() - - # shutdown web server - sr.webserver.shutDown() - sr.webserver.join() - sr.webserver = None - - # if run as daemon delete the pidfile - if sr.runAsDaemon and sr.CREATEPID: - sr.remove_pid_file(sr.PIDFILE) - - if not sickbeard.shutdown: - install_type = sickbeard.versionCheckScheduler.action.install_type - - popen_list = [] - - if install_type in ('git', 'source'): - popen_list = [sys.executable, sickbeard.MY_FULLNAME] - elif install_type == 'win': - if hasattr(sys, 'frozen'): - # c:\dir\to\updater.exe 12345 c:\dir\to\sickbeard.exe - popen_list = [os.path.join(sickbeard.PROG_DIR, 'updater.exe'), str(sickbeard.PID), sys.executable] - else: - logger.log(u"Unknown SB launch method, please file a bug report about this", logger.ERROR) - popen_list = [sys.executable, os.path.join(sickbeard.PROG_DIR, 'updater.py'), str(sickbeard.PID), sys.executable, - sickbeard.MY_FULLNAME] - - if popen_list: - popen_list += sickbeard.MY_ARGS - if '--nolaunch' not in popen_list: - popen_list += ['--nolaunch'] - logger.log(u"Restarting SickRage with " + str(popen_list)) - logger.close() - subprocess.Popen(popen_list, cwd=os.getcwd()) - - # exit process - os._exit(0) - except: - if sr: - logger.log(traceback.format_exc(), logger.ERROR) - else: - print(traceback.format_exc()) - sys.exit(1) \ No newline at end of file + # start sickrage + SickRage().start() \ No newline at end of file diff --git a/gui/slick/images/network/bs11.png b/gui/slick/images/network/bs11.png new file mode 100644 index 00000000..24b92199 Binary files /dev/null and b/gui/slick/images/network/bs11.png differ diff --git a/gui/slick/images/network/niconico.png b/gui/slick/images/network/niconico.png new file mode 100644 index 00000000..41169023 Binary files /dev/null and b/gui/slick/images/network/niconico.png differ diff --git a/gui/slick/interfaces/default/home.tmpl b/gui/slick/interfaces/default/home.tmpl index 58c3fa9d..03a9c624 100644 --- a/gui/slick/interfaces/default/home.tmpl +++ b/gui/slick/interfaces/default/home.tmpl @@ -229,7 +229,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name)) #set $den = $curShowAll[0] #end if #else - #set $dlStat = "0" + #set $dlStat = "0 / 0" #set $nom = 0 #set $den = 1 #end if diff --git a/gui/slick/interfaces/default/home_newShow.tmpl b/gui/slick/interfaces/default/home_newShow.tmpl index 60ce3e43..964978e5 100644 --- a/gui/slick/interfaces/default/home_newShow.tmpl +++ b/gui/slick/interfaces/default/home_newShow.tmpl @@ -39,7 +39,7 @@ #else: - + * @@ -50,7 +50,7 @@ #end for -

+

* This will only affect the language of the retrieved metadata file contents and episode filenames.
This DOES NOT allow SickRage to download non-english TV episodes!
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 218466b8..ce787008 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -41,7 +41,6 @@ from sickbeard import helpers, db, exceptions, show_queue, search_queue, schedul from sickbeard import logger from sickbeard import naming from sickbeard import dailysearcher -from sickbeard import maintenance from sickbeard import scene_numbering, scene_exceptions, name_cache from indexers.indexer_api import indexerApi from indexers.indexer_exceptions import indexer_shownotfound, indexer_exception, indexer_error, indexer_episodenotfound, \ @@ -50,7 +49,6 @@ from sickbeard.common import SD, SKIPPED, NAMING_REPEAT from sickbeard.databases import mainDB, cache_db, failed_db from lib.configobj import ConfigObj -from tornado.ioloop import IOLoop import xml.etree.ElementTree as ElementTree PID = None @@ -76,7 +74,9 @@ PIDFILE = '' DAEMON = None NO_RESIZE = False -maintenanceScheduler = None +# system events +events = None + dailySearchScheduler = None backlogSearchScheduler = None showUpdateScheduler = None @@ -105,7 +105,6 @@ CUR_COMMIT_HASH = None INIT_LOCK = Lock() started = False -shutdown = False ACTUAL_LOG_DIR = None LOG_DIR = None @@ -479,7 +478,7 @@ def initialize(consoleLogging=True): USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, \ AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \ ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \ - ANIME_SPLIT_HOME, maintenanceScheduler, SCENE_DEFAULT + ANIME_SPLIT_HOME, SCENE_DEFAULT if __INITIALIZED__: return False @@ -872,7 +871,7 @@ def initialize(consoleLogging=True): USE_ANIDB = check_setting_str(CFG, 'ANIDB', 'use_anidb', '') ANIDB_USERNAME = check_setting_str(CFG, 'ANIDB', 'anidb_username', '') ANIDB_PASSWORD = check_setting_str(CFG, 'ANIDB', 'anidb_password', '') - ANIDB_USE_MYLIST = check_setting_str(CFG, 'ANIDB', 'anidb_use_mylist', '') + ANIDB_USE_MYLIST = bool(check_setting_int(CFG, 'ANIDB', 'anidb_use_mylist', 0)) ANIME_SPLIT_HOME = bool(check_setting_int(CFG, 'ANIME', 'anime_split_home', 0)) METADATA_XBMC = check_setting_str(CFG, 'General', 'metadata_xbmc', '0|0|0|0|0|0|0|0|0|0') @@ -957,10 +956,6 @@ def initialize(consoleLogging=True): threadName="CHECKVERSION", silent=False) - maintenanceScheduler = scheduler.Scheduler(maintenance.Maintenance(), - cycleTime=datetime.timedelta(hours=1), - threadName="MAINTENANCE") - showQueueScheduler = scheduler.Scheduler(show_queue.ShowQueue(), cycleTime=datetime.timedelta(seconds=3), threadName="SHOWQUEUE") @@ -1123,7 +1118,7 @@ def initialize(consoleLogging=True): def start(): - global __INITIALIZED__, maintenanceScheduler, backlogSearchScheduler, \ + global __INITIALIZED__, backlogSearchScheduler, \ showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ subtitlesFinderScheduler, USE_SUBTITLES,traktCheckerScheduler, \ @@ -1133,9 +1128,6 @@ def start(): if __INITIALIZED__: - # start the maintenance scheduler - maintenanceScheduler.thread.start() - # start the daily search scheduler dailySearchScheduler.thread.start() @@ -1171,11 +1163,11 @@ def start(): def halt(): - global __INITIALIZED__, maintenanceScheduler, backlogSearchScheduler, \ + global __INITIALIZED__, backlogSearchScheduler, \ showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ subtitlesFinderScheduler, traktCheckerScheduler, \ - dailySearchScheduler, started + dailySearchScheduler, events, started with INIT_LOCK: @@ -1183,12 +1175,10 @@ def halt(): logger.log(u"Aborting all threads") - # abort all the threads - - maintenanceScheduler.abort = True - logger.log(u"Waiting for the MAINTENANCE scheduler thread to exit") + events.alive = False + logger.log(u"Waiting for the EVENTS thread to exit") try: - maintenanceScheduler.thread.join(10) + events.join(10) except: pass @@ -1277,7 +1267,7 @@ def halt(): def sig_handler(signum=None, frame=None): if type(signum) != type(None): logger.log(u"Signal %i caught, saving and exiting..." % int(signum)) - saveAndShutdown() + events.put(events.SystemEvent.SHUTDOWN) def saveAll(): global showList @@ -1291,32 +1281,6 @@ def saveAll(): logger.log(u"Saving config file to disk") save_config() -def saveAndShutdown(restart=False): - global shutdown, started - - # flag restart/shutdown - if not restart: - shutdown = True - - # proceed with shutdown - started = False - -def invoke_command(to_call, *args, **kwargs): - - def delegate(): - to_call(*args, **kwargs) - - logger.log(u"Placed invoked command: " + repr(delegate) + " for " + repr(to_call) + " with " + repr( - args) + " and " + repr(kwargs), logger.DEBUG) - - IOLoop.current().add_callback(delegate) - -def invoke_restart(soft=True): - invoke_command(restart, soft=soft) - -def invoke_shutdown(): - invoke_command(saveAndShutdown, False) - def restart(soft=True): if soft: halt() @@ -1324,7 +1288,7 @@ def restart(soft=True): logger.log(u"Re-initializing all data") initialize() else: - saveAndShutdown(True) + events.put(events.SystemEvent.RESTART) def save_config(): diff --git a/sickbeard/common.py b/sickbeard/common.py index dcc466f5..2e532750 100644 --- a/sickbeard/common.py +++ b/sickbeard/common.py @@ -222,13 +222,9 @@ class Quality: return Quality.RAWHDTV elif checkName(["1080p", "hdtv", "x264"], all): return Quality.FULLHDTV - elif checkName(["720p", "web.dl", "h.?264"], all) or checkName(["720p", "itunes", "h.?264"], all): + elif checkName(["720p", "web.dl|webrip"], all) or checkName(["720p", "itunes", "h.?264"], all): return Quality.HDWEBDL - elif checkName(["1080p", "web.dl", "h.?264"], all) or checkName(["1080p", "itunes", "h.?264"], all): - return Quality.FULLHDWEBDL - elif checkName(["720p", "webrip", "x264"], all): - return Quality.HDWEBDL - elif checkName(["1080p", "webrip", "x264"], all): + elif checkName(["1080p", "web.dl|webrip"], all) or checkName(["1080p", "itunes", "h.?264"], all): return Quality.FULLHDWEBDL elif checkName(["720p", "bluray|hddvd|b[r|d]rip", "x264"], all): return Quality.HDBLURAY diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py index ac528d1e..60ce9cff 100644 --- a/sickbeard/dailysearcher.py +++ b/sickbeard/dailysearcher.py @@ -44,7 +44,7 @@ class DailySearcher(): for curProviderCount, curProvider in enumerate(providers): try: - logger.log(u"Updating [" + curProvider.name + "} RSS cache ...") + logger.log(u"Updating [" + curProvider.name + "] RSS cache ...") curProvider.cache.updateCache() except exceptions.AuthException, e: logger.log(u"Authentication error: " + ex(e), logger.ERROR) diff --git a/sickbeard/event_queue.py b/sickbeard/event_queue.py new file mode 100644 index 00000000..1b32558a --- /dev/null +++ b/sickbeard/event_queue.py @@ -0,0 +1,45 @@ +from threading import Thread +from Queue import Queue, Empty +from tornado.ioloop import IOLoop + +class Event: + def __init__(self, type): + self._type = type + + @property + def type(self): + return self._type + +class Events(Thread): + def __init__(self, callback): + super(Events, self).__init__() + self.queue = Queue() + self.daemon = True + self.alive = True + self.callback = callback + self.name = "EVENT-QUEUE" + + # auto-start + self.start() + + def put(self, type): + self.queue.put_nowait(type) + + def run(self): + while(self.alive): + try: + # get event type + type = self.queue.get(True, 1) + + # perform callback if we got a event type + self.callback(type) + + # event completed + self.queue.task_done() + except Empty: + type = None + + # System Events + class SystemEvent(Event): + RESTART = "RESTART" + SHUTDOWN = "SHUTDOWN" \ No newline at end of file diff --git a/sickbeard/maintenance.py b/sickbeard/maintenance.py deleted file mode 100644 index ccc3f871..00000000 --- a/sickbeard/maintenance.py +++ /dev/null @@ -1,53 +0,0 @@ -# Author: Nic Wolfe -# URL: http://code.google.com/p/sickbeard/ -# -# This file is part of SickRage. -# -# SickRage 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. -# -# SickRage 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 SickRage. If not, see . - -from __future__ import with_statement -import threading -import sickbeard - -from sickbeard import scene_exceptions -from sickbeard import failed_history -from sickbeard import network_timezones -from sickbeard import name_cache - -class Maintenance(): - def __init__(self): - self.lock = threading.Lock() - - self.amActive = False - - def run(self, force=False): - self.amActive = True - - # clear internal name cache - name_cache.clearCache() - - # get and update scene exceptions lists - scene_exceptions.retrieve_exceptions() - - # build internal name cache for searches and parsing - name_cache.buildNameCache() - - # refresh network timezones - network_timezones.update_network_dict() - - # sure, why not? - if sickbeard.USE_FAILED_DOWNLOADS: - failed_history.trimHistory() - - self.amActive = False \ No newline at end of file diff --git a/sickbeard/name_cache.py b/sickbeard/name_cache.py index 6661b89d..401db5dc 100644 --- a/sickbeard/name_cache.py +++ b/sickbeard/name_cache.py @@ -96,7 +96,10 @@ def buildNameCache(): # clear internal name cache clearCache() - logger.log(u"Updating internal name cache", logger.MESSAGE) + # update scene exception names + sickbeard.scene_exceptions.retrieve_exceptions() + + logger.log(u"Building internal name cache", logger.MESSAGE) cacheDB = db.DBConnection('cache.db') cache_results = cacheDB.select("SELECT * FROM scene_names") @@ -111,5 +114,4 @@ def buildNameCache(): for name in sickbeard.scene_exceptions.get_scene_exceptions(show.indexerid, season=curSeason): nameCache[sickbeard.helpers.full_sanitizeSceneName(name)] = show.indexerid - logger.log(u"Updated internal name cache", logger.MESSAGE) logger.log(u"Internal name cache set to: " + str(nameCache), logger.DEBUG) \ No newline at end of file diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 74f163a8..a77eaae7 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with SickRage. If not, see . +import time import re import datetime import os.path @@ -123,8 +124,8 @@ class NameParser(object): if not self.showObj and not self.naming_pattern: # Regex pattern to return the Show / Series Name regardless of the file pattern tossed at it, matched 53 show name examples from regexes.py show_patterns = [ - '''^(?P.*?)\W+(?:(?:S\d[\dE._ -])|(?:\d\d?x)|(?:\d{4}\W\d\d\W\d\d)|(?:(?:part|pt)[\._ -]?(\d|[ivx]))|Season\W+\d+\W+|E\d+\W+|(?:\d{1,3}.+\d{1,}[a-zA-Z]{2}\W+[a-zA-Z]{3,}\W+\d{4}.+))''', - '''^((\[.*?\])|(\d+[\.-]))*[ _\.]*(?P.*?)(([ ._-]+\d+)|([ ._-]+s\d{2})).*''' + '''^(?P.*)\W+(?:(?:S\d[\dE._ -])|(?:\d\d?x)|(?:\d{4}\W\d\d\W\d\d)|(?:(?:part|pt)[\._ -]?(\d|[ivx]))|Season\W+\d+\W+|E\d+\W+|(?:\d{1,3}.+\d{1,}[a-zA-Z]{2}\W+[a-zA-Z]{3,}\W+\d{4}.+))''', + '''^((\[.*?\])|(\d+[\.-]))*[ _\.]*(?P.*)(([ ._-]+\d+)|([ ._-]+s\d{2})).*''' ] # find show object @@ -133,6 +134,8 @@ class NameParser(object): if self.showObj: break else: + time.sleep(0.05) + raise InvalidShowException( "Unable to parse " + name.encode(sickbeard.SYS_ENCODING, 'xmlcharrefreplace')) @@ -251,6 +254,8 @@ class NameParser(object): result.score += 1 matches.append(result) + time.sleep(0.05) + if len(matches): result = max(sorted(matches, reverse=True, key=lambda x: x.which_regex), key=lambda x: x.score) diff --git a/sickbeard/providers/rsstorrent.py b/sickbeard/providers/rsstorrent.py index 64d6e64d..52166a8f 100644 --- a/sickbeard/providers/rsstorrent.py +++ b/sickbeard/providers/rsstorrent.py @@ -41,6 +41,7 @@ class TorrentRssProvider(generic.TorrentProvider): self.url = re.sub('\/$', '', url) self.url = url self.enabled = True + self.ratio = None self.supportsBacklog = False self.search_mode = search_mode @@ -164,6 +165,8 @@ class TorrentRssProvider(generic.TorrentProvider): logger.log(u"Saved custom_torrent html dump " + dumpName + " ", logger.MESSAGE) return True + def seedRatio(self): + return self.ratio class TorrentRssCache(tvcache.TVCache): def __init__(self, provider): @@ -186,4 +189,4 @@ class TorrentRssCache(tvcache.TVCache): return None logger.log(u"Attempting to add item to cache: " + title, logger.DEBUG) - return self._addCacheEntry(title, url) \ No newline at end of file + return self._addCacheEntry(title, url) diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py index c1968440..dfd4f863 100644 --- a/sickbeard/search_queue.py +++ b/sickbeard/search_queue.py @@ -43,9 +43,6 @@ class SearchQueue(generic_queue.GenericQueue): generic_queue.GenericQueue.__init__(self) self.queue_name = "SEARCHQUEUE" - def __del__(self): - pass - def is_in_queue(self, show, segment): for cur_item in self.queue: if isinstance(cur_item, BacklogQueueItem) and cur_item.show == show and cur_item.segment == segment: @@ -77,17 +74,20 @@ class SearchQueue(generic_queue.GenericQueue): def add_item(self, item): if isinstance(item, DailySearchQueueItem) and not self.is_in_queue(item.show, item.segment): + sickbeard.name_cache.buildNameCache() generic_queue.GenericQueue.add_item(self, item) elif isinstance(item, BacklogQueueItem) and not self.is_in_queue(item.show, item.segment): + sickbeard.name_cache.buildNameCache() generic_queue.GenericQueue.add_item(self, item) elif isinstance(item, ManualSearchQueueItem) and not self.is_in_queue(item.show, item.segment): + sickbeard.name_cache.buildNameCache() generic_queue.GenericQueue.add_item(self, item) elif isinstance(item, FailedQueueItem) and not self.is_in_queue(item.show, item.segment): + sickbeard.name_cache.buildNameCache() generic_queue.GenericQueue.add_item(self, item) else: logger.log(u"Not adding item, it's already in the queue", logger.DEBUG) - class DailySearchQueueItem(generic_queue.QueueItem): def __init__(self, show, segment): generic_queue.QueueItem.__init__(self, 'Daily Search', DAILY_SEARCH) diff --git a/sickbeard/showUpdater.py b/sickbeard/showUpdater.py index 8d371af3..46c0734c 100644 --- a/sickbeard/showUpdater.py +++ b/sickbeard/showUpdater.py @@ -37,6 +37,13 @@ class ShowUpdater(): update_datetime = datetime.datetime.now() update_date = update_datetime.date() + # refresh network timezones + network_timezones.update_network_dict() + + # sure, why not? + if sickbeard.USE_FAILED_DOWNLOADS: + failed_history.trimHistory() + logger.log(u"Doing full update on all shows") # clean out cache directory, remove everything > 12 hours old diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 3b9beb32..57ac05bb 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -66,7 +66,6 @@ class TVShow(object): self._indexerid = int(indexerid) self._indexer = int(indexer) self._name = "" - self._location = "" self._imdbid = "" self._network = "" self._genre = "" @@ -93,6 +92,7 @@ class TVShow(object): self.dirty = True + self._location = "" self.lock = threading.Lock() self.isDirGood = False self.episodes = {} @@ -103,9 +103,6 @@ class TVShow(object): self.loadFromDB() - def __del__(self): - pass - name = property(lambda self: self._name, dirty_setter("_name")) indexerid = property(lambda self: self._indexerid, dirty_setter("_indexerid")) indexer = property(lambda self: self._indexer, dirty_setter("_indexer")) @@ -172,7 +169,7 @@ class TVShow(object): logger.log(u"Setter sets location to " + newLocation, logger.DEBUG) # Don't validate dir if user wants to add shows without creating a dir if sickbeard.ADD_SHOWS_WO_DIR or ek.ek(os.path.isdir, newLocation): - self._location = newLocation + dirty_setter("_location")(self, newLocation) self._isDirGood = True else: raise exceptions.NoNFOException("Invalid folder for the show!") @@ -834,7 +831,7 @@ class TVShow(object): self.flatten_folders = int(sqlResults[0]["flatten_folders"]) self.paused = int(sqlResults[0]["paused"]) - self._location = sqlResults[0]["location"] + self.location = sqlResults[0]["location"] if not self.lang: self.lang = sqlResults[0]["lang"] diff --git a/sickbeard/versionChecker.py b/sickbeard/versionChecker.py index 4e9e60dc..4b45a355 100644 --- a/sickbeard/versionChecker.py +++ b/sickbeard/versionChecker.py @@ -64,7 +64,7 @@ class CheckVersion(): if sickbeard.versionCheckScheduler.action.update(): logger.log(u"Update was successful!") ui.notifications.message('Update was successful') - threading.Timer(2, sickbeard.invoke_restart, [False]).start() + sickbeard.events.put(sickbeard.events.SystemEvent.RESTART) def find_install_type(self): """ diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 4ec6d45b..7ded782f 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -1524,7 +1524,7 @@ class CMD_SickBeardRestart(ApiCall): def run(self): """ restart sickbeard """ - threading.Timer(2, sickbeard.invoke_restart, [False]).start() + sickbeard.events.put(sickbeard.events.SystemEvent.RESTART) return _responds(RESULT_SUCCESS, msg="SickRage is restarting...") @@ -1701,7 +1701,7 @@ class CMD_SickBeardShutdown(ApiCall): def run(self): """ shutdown sickbeard """ - threading.Timer(2, sickbeard.invoke_shutdown).start() + sickbeard.events.put(sickbeard.events.SystemEvent.SHUTDOWN) return _responds(RESULT_SUCCESS, msg="SickRage is shutting down...") diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 2ef84235..b83e9615 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -487,7 +487,8 @@ class MainHandler(RequestHandler): class PageTemplate(Template): def __init__(self, headers, *args, **KWs): - KWs['file'] = os.path.join(sickbeard.PROG_DIR, "gui/" + sickbeard.GUI_NAME + "/interfaces/default/",KWs['file']) + KWs['file'] = os.path.join(sickbeard.PROG_DIR, "gui/" + sickbeard.GUI_NAME + "/interfaces/default/", + KWs['file']) super(PageTemplate, self).__init__(*args, **KWs) self.sbRoot = sickbeard.WEB_ROOT @@ -531,6 +532,7 @@ class PageTemplate(Template): kwargs['cacheDirForModuleFiles'] = os.path.join(sickbeard.CACHE_DIR, 'cheetah') return super(PageTemplate, self).compile(*args, **kwargs) + class IndexerWebUI(MainHandler): def __init__(self, config, log=None): self.config = config @@ -3432,7 +3434,7 @@ class Home(MainHandler): if str(pid) != str(sickbeard.PID): redirect("/home/") - threading.Timer(2, sickbeard.invoke_shutdown).start() + sickbeard.events.put(sickbeard.events.SystemEvent.SHUTDOWN) title = "Shutting down" message = "SickRage is shutting down..." @@ -3448,7 +3450,7 @@ class Home(MainHandler): t.submenu = HomeMenu() # restart - threading.Timer(5, sickbeard.invoke_restart, [False]).start() + sickbeard.events.put(sickbeard.events.SystemEvent.RESTART) return _munge(t) @@ -3460,7 +3462,7 @@ class Home(MainHandler): updated = sickbeard.versionCheckScheduler.action.update() # @UndefinedVariable if updated: # do a hard restart - threading.Timer(2, sickbeard.invoke_restart, [False]).start() + sickbeard.events.put(sickbeard.events.SystemEvent.RESTART) t = PageTemplate(headers=self.request.headers, file="restart_bare.tmpl") return _munge(t) @@ -3643,8 +3645,6 @@ class Home(MainHandler): else: return self._genericMessage("Error", errString) - showObj.exceptions = scene_exceptions.get_scene_exceptions(showObj.indexerid) - if not location and not anyQualities and not bestQualities and not flatten_folders: t = PageTemplate(headers=self.request.headers, file="editShow.tmpl") t.submenu = HomeMenu() @@ -3727,54 +3727,56 @@ class Home(MainHandler): else: do_update_exceptions = True - bwl = BlackAndWhiteList(showObj.indexerid) - if whitelist: - whitelist = whitelist.split(",") - shortWhiteList = [] - if helpers.set_up_anidb_connection(): - for groupName in whitelist: - group = sickbeard.ADBA_CONNECTION.group(gname=groupName) - for line in group.datalines: - if line["shortname"]: - shortWhiteList.append(line["shortname"]) - else: - if not groupName in shortWhiteList: - shortWhiteList.append(groupName) + # If directCall from mass_edit_update no scene exceptions handling + if not directCall: + bwl = BlackAndWhiteList(showObj.indexerid) + if whitelist: + whitelist = whitelist.split(",") + shortWhiteList = [] + if helpers.set_up_anidb_connection(): + for groupName in whitelist: + group = sickbeard.ADBA_CONNECTION.group(gname=groupName) + for line in group.datalines: + if line["shortname"]: + shortWhiteList.append(line["shortname"]) + else: + if not groupName in shortWhiteList: + shortWhiteList.append(groupName) + else: + shortWhiteList = whitelist + bwl.set_white_keywords_for("release_group", shortWhiteList) else: - shortWhiteList = whitelist - bwl.set_white_keywords_for("release_group", shortWhiteList) - else: - bwl.set_white_keywords_for("release_group", []) + bwl.set_white_keywords_for("release_group", []) - if blacklist: - blacklist = blacklist.split(",") - shortBlacklist = [] - if helpers.set_up_anidb_connection(): - for groupName in blacklist: - group = sickbeard.ADBA_CONNECTION.group(gname=groupName) - for line in group.datalines: - if line["shortname"]: - shortBlacklist.append(line["shortname"]) - else: - if not groupName in shortBlacklist: - shortBlacklist.append(groupName) + if blacklist: + blacklist = blacklist.split(",") + shortBlacklist = [] + if helpers.set_up_anidb_connection(): + for groupName in blacklist: + group = sickbeard.ADBA_CONNECTION.group(gname=groupName) + for line in group.datalines: + if line["shortname"]: + shortBlacklist.append(line["shortname"]) + else: + if not groupName in shortBlacklist: + shortBlacklist.append(groupName) + else: + shortBlacklist = blacklist + bwl.set_black_keywords_for("release_group", shortBlacklist) else: - shortBlacklist = blacklist - bwl.set_black_keywords_for("release_group", shortBlacklist) - else: - bwl.set_black_keywords_for("release_group", []) + bwl.set_black_keywords_for("release_group", []) - if whiteWords: - whiteWords = [x.strip() for x in whiteWords.split(",")] - bwl.set_white_keywords_for("global", whiteWords) - else: - bwl.set_white_keywords_for("global", []) + if whiteWords: + whiteWords = [x.strip() for x in whiteWords.split(",")] + bwl.set_white_keywords_for("global", whiteWords) + else: + bwl.set_white_keywords_for("global", []) - if blackWords: - blackWords = [x.strip() for x in blackWords.split(",")] - bwl.set_black_keywords_for("global", blackWords) - else: - bwl.set_black_keywords_for("global", []) + if blackWords: + blackWords = [x.strip() for x in blackWords.split(",")] + bwl.set_black_keywords_for("global", blackWords) + else: + bwl.set_black_keywords_for("global", []) errors = [] with showObj.lock: @@ -3825,14 +3827,14 @@ class Home(MainHandler): # if we change location clear the db of episodes, change it, write to db, and rescan if os.path.normpath(showObj._location) != os.path.normpath(location): logger.log(os.path.normpath(showObj._location) + " != " + os.path.normpath(location), logger.DEBUG) - if not ek.ek(os.path.isdir, location): + if not ek.ek(os.path.isdir, location) and not sickbeard.CREATE_MISSING_SHOW_DIRS: errors.append("New location %s does not exist" % location) # don't bother if we're going to update anyway elif not do_update: # change it try: - showObj.location = location + showObj._location = location try: sickbeard.showQueueScheduler.action.refreshShow(showObj) # @UndefinedVariable except exceptions.CantRefreshException, e: @@ -3858,6 +3860,7 @@ class Home(MainHandler): if do_update_exceptions: try: scene_exceptions.update_scene_exceptions(showObj.indexerid, exceptions_list) # @UndefinedVariable + showObj.exceptions = scene_exceptions.get_scene_exceptions(showObj.indexerid) time.sleep(cpu_presets[sickbeard.CPU_PRESET]) except exceptions.CantUpdateException, e: errors.append("Unable to force an update on scene exceptions of the show.") diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py index 2dd33df1..ee95b01a 100644 --- a/sickbeard/webserveInit.py +++ b/sickbeard/webserveInit.py @@ -122,13 +122,6 @@ class SRWebServer(threading.Thread): try: self.io_loop.start() self.io_loop.close(True) - - # stop all tasks - sickbeard.halt() - - # save all shows to DB - sickbeard.saveAll() - except ValueError: # Ignore errors like "ValueError: I/O operation on closed kqueue fd". These might be thrown during a reload. pass