diff --git a/.build/Gruntfile.js b/.build/Gruntfile.js
index ec48f3d4ceee0ad6bf425aeabd20ae85d2c4aea6..75c80b26ba227f702a46e5fe6b23ccb8626988cc 100644
--- a/.build/Gruntfile.js
+++ b/.build/Gruntfile.js
@@ -4,7 +4,11 @@ module.exports = function(grunt) {
     grunt.initConfig({
         clean: {
             dist: './dist/',
-            bower_components: './bower_components' // jshint ignore:line
+            bower_components: './bower_components', // jshint ignore:line
+            fonts: '../gui/slick/css/*.ttf',
+            options: {
+                force: true
+            }
         },
         bower: {
             install: {
@@ -28,6 +32,10 @@ module.exports = function(grunt) {
                         'dist/js/widgets/widget-stickyHeaders.min.js',
                         'dist/css/theme.blue.min.css'
                     ],
+                    'bootstrap': [
+                        'dist/css/bootstrap.min.css',
+                        'dist/js/bootstrap.min.js'
+                    ],
                     'bootstrap-formhelpers': [
                         'dist/js/bootstrap-formhelpers.min.js'
                     ],
@@ -44,6 +52,34 @@ module.exports = function(grunt) {
                 }
             }
         },
+        copy: {
+            openSans: {
+                files: [{
+                    expand: true,
+                    dot: true,
+                    cwd: 'bower_components/openSans',
+                    src: [
+                        '*.ttf'
+                    ],
+                    dest: '../gui/slick/css/'
+                }]
+            },
+            glyphicon: {
+                files: [{
+                    expand: true,
+                    dot: true,
+                    cwd: 'bower_components/bootstrap/fonts',
+                    src: [
+                        '*.eot',
+                        '*.svg',
+                        '*.ttf',
+                        '*.woff',
+                        '*.woff2'
+                    ],
+                    dest: '../gui/slick/fonts/'
+                }]
+            }
+        },
         uglify: {
             bower: {
                 files: {
@@ -106,6 +142,7 @@ module.exports = function(grunt) {
     grunt.loadNpmTasks('grunt-contrib-clean');
     grunt.loadNpmTasks('grunt-bower-task');
     grunt.loadNpmTasks('grunt-bower-concat');
+    grunt.loadNpmTasks('grunt-contrib-copy');
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.loadNpmTasks('grunt-contrib-cssmin');
     grunt.loadNpmTasks('grunt-contrib-jshint');
@@ -115,6 +152,7 @@ module.exports = function(grunt) {
         'clean',
         'bower',
         'bower_concat',
+        'copy',
         'uglify',
         'sass',
         'cssmin',
diff --git a/.build/bower.json b/.build/bower.json
index ecbd37d1a176433864df18c5b7a47957d5167861..47138f5c29af7280d4d0304e9783f9c58912c101 100644
--- a/.build/bower.json
+++ b/.build/bower.json
@@ -1,6 +1,5 @@
 {
   "name": "SickRage",
-  "version": "4.0.72",
   "private": true,
   "ignore": [
     "**/.*",
@@ -24,7 +23,8 @@
     "tablesorter": "jquery.tablesorter#~2.24.5",
     "jquery-confirm": "~2.5.2",
     "bootstrap-formhelpers": "~2.3.0",
-    "isotope": "~2.2.2"
+    "isotope": "~2.2.2",
+    "openSans": "https://google-fonts.azurewebsites.net/googleFonts/openSans?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic"
   },
   "resolutions": {
     "bootstrap": "~3.3.5"
diff --git a/.build/package.json b/.build/package.json
index ab73bd48a706d57dd108d5cfbaf4618023aea6b7..f0208e63db0f2c64ef0cac177d9225300bc19d45 100644
--- a/.build/package.json
+++ b/.build/package.json
@@ -21,6 +21,7 @@
     "grunt-bower-task": "^0.4.0",
     "grunt-cli": "^0.1.13",
     "grunt-contrib-clean": "^0.7.0",
+    "grunt-contrib-copy": "^0.8.2",
     "grunt-contrib-cssmin": "^0.14.0",
     "grunt-contrib-jshint": "^0.11.3",
     "grunt-contrib-sass": "^0.9.2",
diff --git a/COPYING.txt b/COPYING.txt
index d64d8b2f7f6064ff4fe25de14efea324e1d44a6f..937249688f24a6af0effa6d4ec4ef2bc1717b338 100644
--- a/COPYING.txt
+++ b/COPYING.txt
@@ -641,7 +641,7 @@ the "copyright" line and a pointer to where the full notice is found.
 
     This program 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
+    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
diff --git a/SickBeard.py b/SickBeard.py
index f6ce75ba73a9863d2e649cc49284aeb4f80bf2f6..72390d16304b8831170ae87eb8d7efcc83e526de 100755
--- a/SickBeard.py
+++ b/SickBeard.py
@@ -12,68 +12,90 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # Check needed software dependencies to nudge users to fix their setup
 
-# pylint: disable=broad-except
-# Catching too general exception
+# pylint: disable=line-too-long
 
-import codecs
+"""
+Usage: SickBeard.py [OPTION]...
 
-codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
+Options:
+  -h,  --help            Prints this message
+  -q,  --quiet           Disables logging to console
+       --nolaunch        Suppress launching web browser on startup
 
-import time
+  -d,  --daemon          Run as double forked daemon (with --quiet --nolaunch)
+                         On Windows and MAC, this option is ignored but still
+                         applies --quiet --nolaunch
+       --pidfile=[FILE]  Combined with --daemon creates a pid file
+
+  -p,  --port=[PORT]     Override default/configured port to listen on
+       --datadir=[PATH]  Override folder (full path) as location for
+                         storing database, config file, cache, and log files
+                         Default SickRage directory
+       --config=[FILE]   Override config filename for loading configuration
+                         Default config.ini in SickRage directory or
+                         location specified with --datadir
+       --noresize        Prevent resizing of the banner/posters even if PIL
+                         is installed
+"""
+
+from __future__ import unicode_literals
+from __future__ import print_function
+
+import codecs
+import datetime
+import getopt
+import io
+import locale
+import os
+import shutil
 import signal
-import sys
 import subprocess
+import sys
+import threading
+import time
 import traceback
 
-import os
+codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
 sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib')))
 
-import shutil
-import shutil_custom
-
-shutil.copyfile = shutil_custom.copyfile_custom
-
 if sys.version_info < (2, 7):
-    print "Sorry, requires Python 2.7.x"
+    print('Sorry, requires Python 2.7.x')
     sys.exit(1)
 
+# pylint: disable=wrong-import-position
 # https://mail.python.org/pipermail/python-dev/2014-September/136300.html
 if sys.version_info >= (2, 7, 9):
     import ssl
-    # pylint: disable=protected-access
-    # Access to a protected member of a client class
-    ssl._create_default_https_context = ssl._create_unverified_context
+    ssl._create_default_https_context = ssl._create_unverified_context  # pylint: disable=protected-access
 
-import locale
-import datetime
-import threading
-import getopt
+import shutil_custom  # pylint: disable=import-error
+shutil.copyfile = shutil_custom.copyfile_custom
 
 # Do this before importing sickbeard, to prevent locked files and incorrect import
-oldtornado = os.path.abspath(os.path.join(os.path.dirname(__file__), 'tornado'))
-if os.path.isdir(oldtornado):
-    shutil.move(oldtornado, oldtornado + '_kill')
-    shutil.rmtree(oldtornado + '_kill')
+OLD_TORNADO = os.path.abspath(os.path.join(os.path.dirname(__file__), 'tornado'))
+if os.path.isdir(OLD_TORNADO):
+    shutil.move(OLD_TORNADO, OLD_TORNADO + '_kill')
+    shutil.rmtree(OLD_TORNADO + '_kill')
 
 import sickbeard
-from sickbeard import db, logger, network_timezones, failed_history, name_cache
+from sickbeard import db, logger, network_timezones, failed_history  # , name_cache
 from sickbeard.tv import TVShow
 from sickbeard.webserveInit import SRWebServer
 from sickbeard.event_queue import Events
-from configobj import ConfigObj
+from configobj import ConfigObj  # pylint: disable=import-error
 
 from sickrage.helper.encoding import ek
 
 # http://bugs.python.org/issue7980#msg221094
-throwaway = datetime.datetime.strptime('20110101', '%Y%m%d')
+THROWAWAY = datetime.datetime.strptime('20110101', '%Y%m%d')
 
 signal.signal(signal.SIGINT, sickbeard.sig_handler)
 signal.signal(signal.SIGTERM, sickbeard.sig_handler)
@@ -81,73 +103,58 @@ signal.signal(signal.SIGTERM, sickbeard.sig_handler)
 
 class SickRage(object):
     # pylint: disable=too-many-instance-attributes
-    # Too many instance attributes
+    """
+    Main SickRage module
+    """
+
     def __init__(self):
         # system event callback for shutdown/restart
         sickbeard.events = Events(self.shutdown)
 
         # daemon constants
-        self.runAsDaemon = False
-        self.CREATEPID = False
-        self.PIDFILE = ''
+        self.run_as_daemon = False
+        self.create_pid = False
+        self.pid_file = ''
 
-        # webserver constants
-        self.webserver = None
-        self.forcedPort = None
-        self.noLaunch = False
+        # web server constants
+        self.web_server = None
+        self.forced_port = None
+        self.no_launch = False
 
-        self.webhost = '0.0.0.0'
-        self.startPort = sickbeard.WEB_PORT
+        self.web_host = '0.0.0.0'
+        self.start_port = sickbeard.WEB_PORT
         self.web_options = {}
 
         self.log_dir = None
-        self.consoleLogging = True
+        self.console_logging = True
 
     @staticmethod
     def clear_cache():
+        """
+        Remove the Mako cache directory
+        """
         try:
             cache_folder = ek(os.path.join, sickbeard.CACHE_DIR, 'mako')
             if os.path.isdir(cache_folder):
                 shutil.rmtree(cache_folder)
-        except Exception:
-            logger.log(u"Unable to remove the cache/mako directory!", logger.WARNING)
+        except Exception:  # pylint: disable=broad-except
+            logger.log('Unable to remove the cache/mako directory!', logger.WARNING)  # pylint: disable=no-member
 
     @staticmethod
     def help_message():
         """
-        print help message for commandline options
+        Print help message for commandline options
         """
-        help_msg = "\n"
-        help_msg += "Usage: " + sickbeard.MY_FULLNAME + " <option> <another option>\n"
-        help_msg += "\n"
-        help_msg += "Options:\n"
-        help_msg += "\n"
-        help_msg += "    -h          --help              Prints this message\n"
-        help_msg += "    -q          --quiet             Disables logging to console\n"
-        help_msg += "                --nolaunch          Suppress launching web browser on startup\n"
-
-        if sys.platform == 'win32' or sys.platform == 'darwin':
-            help_msg += "    -d          --daemon            Running as real daemon is not supported on Windows\n"
-            help_msg += "                                    On Windows and MAC, --daemon is substituted with: --quiet --nolaunch\n"
-        else:
-            help_msg += "    -d          --daemon            Run as double forked daemon (includes options --quiet --nolaunch)\n"
-            help_msg += "                --pidfile=<path>    Combined with --daemon creates a pidfile (full path including filename)\n"
-
-        help_msg += "    -p <port>   --port=<port>       Override default/configured port to listen on\n"
-        help_msg += "                --datadir=<path>    Override folder (full path) as location for\n"
-        help_msg += "                                    storing database, configfile, cache, logfiles \n"
-        help_msg += "                                    Default: " + sickbeard.PROG_DIR + "\n"
-        help_msg += "                --config=<path>     Override config filename (full path including filename)\n"
-        help_msg += "                                    to load configuration from \n"
-        help_msg += "                                    Default: config.ini in " + sickbeard.PROG_DIR + " or --datadir location\n"
-        help_msg += "                --noresize          Prevent resizing of the banner/posters even if PIL is installed\n"
+        help_msg = __doc__
+        help_msg = help_msg.replace('SickBeard.py', sickbeard.MY_FULLNAME)
+        help_msg = help_msg.replace('SickRage directory', sickbeard.PROG_DIR)
 
         return help_msg
 
-    # pylint: disable=too-many-branches,too-many-statements
-    # Too many branches
-    # Too many statements
-    def start(self):
+    def start(self):  # pylint: disable=too-many-branches,too-many-statements
+        """
+        Start SickRage
+        """
         # do some preliminary stuff
         sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__))
         sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME)
@@ -156,169 +163,167 @@ class SickRage(object):
         sickbeard.MY_ARGS = sys.argv[1:]
 
         try:
-            locale.setlocale(locale.LC_ALL, "")
+            locale.setlocale(locale.LC_ALL, '')
             sickbeard.SYS_ENCODING = locale.getpreferredencoding()
         except (locale.Error, IOError):
             sickbeard.SYS_ENCODING = 'UTF-8'
 
         # pylint: disable=no-member
         if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ('ansi_x3.4-1968', 'us-ascii', 'ascii', 'charmap') or \
-            (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')):
+                (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')):
             sickbeard.SYS_ENCODING = 'UTF-8'
 
         # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems
-        if not hasattr(sys, "setdefaultencoding"):
+        if not hasattr(sys, 'setdefaultencoding'):
             reload(sys)
 
         try:
-            # pylint: disable=no-member
             # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError
-            sys.setdefaultencoding(sickbeard.SYS_ENCODING)
-        except Exception:
-            sys.exit("Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n" +
-                     "or find another way to force Python to use " + sickbeard.SYS_ENCODING + " for string encoding.")
+            sys.setdefaultencoding(sickbeard.SYS_ENCODING)  # pylint: disable=no-member
+        except (AttributeError, LookupError):
+            sys.exit('Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n'
+                     'or find another way to force Python to use %s for string encoding.' % sickbeard.SYS_ENCODING)
 
         # Need console logging for SickBeard.py and SickBeard-console.exe
-        self.consoleLogging = (not hasattr(sys, "frozen")) or (sickbeard.MY_NAME.lower().find('-console') > 0)
+        self.console_logging = (not hasattr(sys, 'frozen')) or (sickbeard.MY_NAME.lower().find('-console') > 0)
 
         # Rename the main thread
-        threading.currentThread().name = u"MAIN"
+        threading.currentThread().name = 'MAIN'
 
         try:
             opts, _ = getopt.getopt(
-                sys.argv[1:], "hqdp::",
+                sys.argv[1:], 'hqdp::',
                 ['help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize']
             )
         except getopt.GetoptError:
             sys.exit(self.help_message())
 
-        for o, a in opts:
+        for option, value in opts:
             # Prints help message
-            if o in ('-h', '--help'):
+            if option in ('-h', '--help'):
                 sys.exit(self.help_message())
 
             # For now we'll just silence the logging
-            if o in ('-q', '--quiet'):
-                self.consoleLogging = False
+            if option in ('-q', '--quiet'):
+                self.console_logging = False
 
             # Suppress launching web browser
             # Needed for OSes without default browser assigned
             # Prevent duplicate browser window when restarting in the app
-            if o in ('--nolaunch',):
-                self.noLaunch = True
+            if option in ('--nolaunch',):
+                self.no_launch = True
 
             # Override default/configured port
-            if o in ('-p', '--port'):
+            if option in ('-p', '--port'):
                 try:
-                    self.forcedPort = int(a)
+                    self.forced_port = int(value)
                 except ValueError:
-                    sys.exit("Port: " + str(a) + " is not a number. Exiting.")
+                    sys.exit('Port: %s is not a number. Exiting.' % value)
 
             # Run as a double forked daemon
-            if o in ('-d', '--daemon'):
-                self.runAsDaemon = True
-                # When running as daemon disable consoleLogging and don't start browser
-                self.consoleLogging = False
-                self.noLaunch = True
+            if option in ('-d', '--daemon'):
+                self.run_as_daemon = True
+                # When running as daemon disable console_logging and don't start browser
+                self.console_logging = False
+                self.no_launch = True
 
                 if sys.platform == 'win32' or sys.platform == 'darwin':
-                    self.runAsDaemon = False
+                    self.run_as_daemon = False
 
-            # Write a pidfile if requested
-            if o in ('--pidfile',):
-                self.CREATEPID = True
-                self.PIDFILE = str(a)
+            # Write a pid file if requested
+            if option in ('--pidfile',):
+                self.create_pid = True
+                self.pid_file = str(value)
 
-                # If the pidfile already exists, sickbeard may still be running, so exit
-                if ek(os.path.exists, self.PIDFILE):
-                    sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.")
+                # If the pid file already exists, SickRage may still be running, so exit
+                if ek(os.path.exists, self.pid_file):
+                    sys.exit('PID file: %s already exists. Exiting.' % self.pid_file)
 
             # Specify folder to load the config file from
-            if o in ('--config',):
-                sickbeard.CONFIG_FILE = ek(os.path.abspath, a)
+            if option in ('--config',):
+                sickbeard.CONFIG_FILE = ek(os.path.abspath, value)
 
-            # Specify folder to use as the data dir
-            if o in ('--datadir',):
-                sickbeard.DATA_DIR = ek(os.path.abspath, a)
+            # Specify folder to use as the data directory
+            if option in ('--datadir',):
+                sickbeard.DATA_DIR = ek(os.path.abspath, value)
 
             # Prevent resizing of the banner/posters even if PIL is installed
-            if o in ('--noresize',):
+            if option in ('--noresize',):
                 sickbeard.NO_RESIZE = True
 
-        # The pidfile is only useful in daemon mode, make sure we can write the file properly
-        if self.CREATEPID:
-            if self.runAsDaemon:
-                pid_dir = ek(os.path.dirname, self.PIDFILE)
+        # The pid file is only useful in daemon mode, make sure we can write the file properly
+        if self.create_pid:
+            if self.run_as_daemon:
+                pid_dir = ek(os.path.dirname, self.pid_file)
                 if not ek(os.access, pid_dir, os.F_OK):
-                    sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.")
+                    sys.exit('PID dir: %s doesn\'t exist. Exiting.' % pid_dir)
                 if not ek(os.access, pid_dir, os.W_OK):
-                    sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.")
+                    sys.exit('PID dir: %s must be writable (write permissions). Exiting.' % pid_dir)
 
             else:
-                if self.consoleLogging:
-                    sys.stdout.write(u"Not running in daemon mode. PID file creation disabled.\n")
+                if self.console_logging:
+                    sys.stdout.write('Not running in daemon mode. PID file creation disabled.\n')
 
-                self.CREATEPID = False
+                self.create_pid = False
 
         # If they don't specify a config file then put it in the data dir
         if not sickbeard.CONFIG_FILE:
-            sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, "config.ini")
+            sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, 'config.ini')
 
         # Make sure that we can create the data dir
         if not ek(os.access, sickbeard.DATA_DIR, os.F_OK):
             try:
-                ek(os.makedirs, sickbeard.DATA_DIR, 0744)
+                ek(os.makedirs, sickbeard.DATA_DIR, 0o744)
             except os.error:
-                raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'")
+                raise SystemExit('Unable to create data directory: %s' % sickbeard.DATA_DIR)
 
         # Make sure we can write to the data dir
         if not ek(os.access, sickbeard.DATA_DIR, os.W_OK):
-            raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'")
+            raise SystemExit('Data directory must be writeable: %s' % sickbeard.DATA_DIR)
 
         # Make sure we can write to the config file
         if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK):
             if ek(os.path.isfile, sickbeard.CONFIG_FILE):
-                raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.")
+                raise SystemExit('Config file must be writeable: %s' % sickbeard.CONFIG_FILE)
             elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK):
-                raise SystemExit(
-                    "Config file root dir '" + ek(os.path.dirname, sickbeard.CONFIG_FILE) + "' must be writeable.")
+                raise SystemExit('Config file root dir must be writeable: %s' % ek(os.path.dirname, sickbeard.CONFIG_FILE))
 
         ek(os.chdir, sickbeard.DATA_DIR)
 
         # Check if we need to perform a restore first
-        restoreDir = ek(os.path.join, sickbeard.DATA_DIR, 'restore')
-        if ek(os.path.exists, restoreDir):
-            success = self.restoreDB(restoreDir, sickbeard.DATA_DIR)
-            if self.consoleLogging:
-                sys.stdout.write(u"Restore: restoring DB and config.ini %s!\n" % ("FAILED", "SUCCESSFUL")[success])
+        restore_dir = ek(os.path.join, sickbeard.DATA_DIR, 'restore')
+        if ek(os.path.exists, restore_dir):
+            success = self.restore_db(restore_dir, sickbeard.DATA_DIR)
+            if self.console_logging:
+                sys.stdout.write('Restore: restoring DB and config.ini %s!\n' % ('FAILED', 'SUCCESSFUL')[success])
 
         # Load the config and publish it to the sickbeard package
-        if self.consoleLogging and not ek(os.path.isfile, sickbeard.CONFIG_FILE):
-            sys.stdout.write(u"Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!" + "\n")
+        if self.console_logging and not ek(os.path.isfile, sickbeard.CONFIG_FILE):
+            sys.stdout.write('Unable to find %s, all settings will be default!\n' % sickbeard.CONFIG_FILE)
 
         sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE)
 
         # Initialize the config and our threads
-        sickbeard.initialize(consoleLogging=self.consoleLogging)
+        sickbeard.initialize(consoleLogging=self.console_logging)
 
-        if self.runAsDaemon:
+        if self.run_as_daemon:
             self.daemonize()
 
         # Get PID
         sickbeard.PID = os.getpid()
 
         # Build from the DB to start with
-        self.loadShowsFromDB()
+        self.load_shows_from_db()
 
-        logger.log(u"Starting up SickRage [%s] from '%s'" % (sickbeard.BRANCH, sickbeard.CONFIG_FILE))
+        logger.log('Starting SickRage [%s] from \'%s\'' % (sickbeard.BRANCH, sickbeard.CONFIG_FILE))
 
         self.clear_cache()
 
-        if self.forcedPort:
-            logger.log(u"Forcing web server to port %s" % self.forcedPort)
-            self.startPort = self.forcedPort
+        if self.forced_port:
+            logger.log('Forcing web server to port %s' % self.forced_port)
+            self.start_port = self.forced_port
         else:
-            self.startPort = sickbeard.WEB_PORT
+            self.start_port = sickbeard.WEB_PORT
 
         if sickbeard.WEB_LOG:
             self.log_dir = sickbeard.LOG_DIR
@@ -328,17 +333,14 @@ class SickRage(object):
         # sickbeard.WEB_HOST is available as a configuration value in various
         # places but is not configurable. It is supported here for historic reasons.
         if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0':
-            self.webhost = sickbeard.WEB_HOST
+            self.web_host = sickbeard.WEB_HOST
         else:
-            if sickbeard.WEB_IPV6:
-                self.webhost = ''
-            else:
-                self.webhost = '0.0.0.0'
+            self.web_host = '' if sickbeard.WEB_IPV6 else '0.0.0.0'
 
         # web server options
         self.web_options = {
-            'port': int(self.startPort),
-            'host': self.webhost,
+            'port': int(self.start_port),
+            'host': self.web_host,
             'data_root': ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME),
             'web_root': sickbeard.WEB_ROOT,
             'log_dir': self.log_dir,
@@ -351,16 +353,16 @@ class SickRage(object):
         }
 
         # start web server
-        self.webserver = SRWebServer(self.web_options)
-        self.webserver.start()
+        self.web_server = SRWebServer(self.web_options)
+        self.web_server.start()
 
         # Fire up all our threads
         sickbeard.start()
 
         # Build internal name cache
-        name_cache.buildNameCache()
+        # name_cache.buildNameCache()
 
-        # Prepopulate network timezones, it isn't thread safe
+        # Pre-populate network timezones, it isn't thread safe
         network_timezones.update_network_dict()
 
         # sure, why not?
@@ -371,8 +373,8 @@ class SickRage(object):
         # sickbeard.showUpdateScheduler.forceRun()
 
         # Launch browser
-        if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon):
-            sickbeard.launchBrowser('https' if sickbeard.ENABLE_HTTPS else 'http', self.startPort, sickbeard.WEB_ROOT)
+        if sickbeard.LAUNCH_BROWSER and not (self.no_launch or self.run_as_daemon):
+            sickbeard.launchBrowser('https' if sickbeard.ENABLE_HTTPS else 'http', self.start_port, sickbeard.WEB_ROOT)
 
         # main loop
         while True:
@@ -390,8 +392,8 @@ class SickRage(object):
             pid = os.fork()  # @UndefinedVariable - only available in UNIX
             if pid != 0:
                 os._exit(0)
-        except OSError as e:
-            sys.stderr.write(u"fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
+        except OSError as error_message:
+            sys.stderr.write('fork #1 failed: %d (%s)\n' % (error_message.errno, error_message.strerror))
             sys.exit(1)
 
         os.setsid()  # @UndefinedVariable - only available in UNIX
@@ -399,7 +401,7 @@ class SickRage(object):
         # https://github.com/SickRage/sickrage-issues/issues/2969
         # http://www.microhowto.info/howto/cause_a_process_to_become_a_daemon_in_c.html#idp23920
         # https://www.safaribooksonline.com/library/view/python-cookbook/0596001673/ch06s08.html
-        # Previous code simply set the umask to whatever it was because it was ANDing instead of ORring
+        # Previous code simply set the umask to whatever it was because it was ANDing instead of OR-ing
         # Daemons traditionally run with umask 0 anyways and this should not have repercussions
         os.umask(0)
 
@@ -408,28 +410,27 @@ class SickRage(object):
             pid = os.fork()  # @UndefinedVariable - only available in UNIX
             if pid != 0:
                 os._exit(0)
-        except OSError as e:
-            sys.stderr.write(u"fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
+        except OSError as error_message:
+            sys.stderr.write('fork #2 failed: %d (%s)\n' % (error_message.errno, error_message.strerror))
             sys.exit(1)
 
         # Write pid
-        if self.CREATEPID:
-            pid = str(os.getpid())
-            logger.log(u"Writing PID: " + pid + " to " + str(self.PIDFILE))
+        if self.create_pid:
+            pid = os.getpid()
+            logger.log('Writing PID: %s to %s' % (pid, self.pid_file))
 
             try:
-                file(self.PIDFILE, 'w').write("%s\n" % pid)
-            except IOError as e:
-                logger.log_error_and_exit(
-                    u"Unable to write PID file: " + self.PIDFILE + " Error: " + str(e.strerror) + " [" + str(
-                        e.errno) + "]")
+                with io.open(self.pid_file, 'w') as f_pid:
+                    f_pid.write('%s\n' % pid)
+            except EnvironmentError as error_message:
+                logger.log_error_and_exit('Unable to write PID file: %s Error: %s [%s]' % (self.pid_file, error_message.strerror, error_message.errno))
 
         # Redirect all output
         sys.stdout.flush()
         sys.stderr.flush()
 
         devnull = getattr(os, 'devnull', '/dev/null')
-        stdin = file(devnull, 'r')
+        stdin = file(devnull)
         stdout = file(devnull, 'a+')
         stderr = file(devnull, 'a+')
 
@@ -438,77 +439,90 @@ class SickRage(object):
         os.dup2(stderr.fileno(), getattr(sys.stderr, 'device', sys.stderr).fileno())
 
     @staticmethod
-    def remove_pid_file(PIDFILE):
+    def remove_pid_file(pid_file):
+        """
+        Remove pid file
+
+        :param pid_file: to remove
+        :return:
+        """
         try:
-            if ek(os.path.exists, PIDFILE):
-                ek(os.remove, PIDFILE)
-        except (IOError, OSError):
+            if ek(os.path.exists, pid_file):
+                ek(os.remove, pid_file)
+        except EnvironmentError:
             return False
 
         return True
 
     @staticmethod
-    def loadShowsFromDB():
+    def load_shows_from_db():
         """
         Populates the showList with shows from the database
         """
-        logger.log(u"Loading initial show list", logger.DEBUG)
+        logger.log('Loading initial show list', logger.DEBUG)  # pylint: disable=no-member
 
-        myDB = db.DBConnection()
-        sqlResults = myDB.select("SELECT indexer, indexer_id, location FROM tv_shows;")
+        my_db = db.DBConnection()
+        sql_results = my_db.select('SELECT indexer, indexer_id, location FROM tv_shows;')
 
         sickbeard.showList = []
-        for sqlShow in sqlResults:
+        for sql_show in sql_results:
             try:
-                curShow = TVShow(int(sqlShow["indexer"]), int(sqlShow["indexer_id"]))
-                curShow.nextEpisode()
-                sickbeard.showList.append(curShow)
-            except Exception as e:
-                logger.log(
-                    u"There was an error creating the show in " + sqlShow["location"] + ": " + str(e).decode('utf-8'),
-                    logger.ERROR)
-                logger.log(traceback.format_exc(), logger.DEBUG)
+                cur_show = TVShow(sql_show[b'indexer'], sql_show[b'indexer_id'])
+                cur_show.nextEpisode()
+                sickbeard.showList.append(cur_show)
+            except Exception as error_msg:  # pylint: disable=broad-except
+                logger.log('There was an error creating the show in %s: %s' %  # pylint: disable=no-member
+                           (sql_show[b'location'], str(error_msg).decode()), logger.ERROR)
+                logger.log(traceback.format_exc(), logger.DEBUG)  # pylint: disable=no-member
 
     @staticmethod
-    def restoreDB(srcDir, dstDir):
+    def restore_db(src_dir, dst_dir):
+        """
+        Restore the Database from a backup
+
+        :param src_dir: Directory containing backup
+        :param dst_dir: Directory to restore to
+        :return:
+        """
         try:
-            filesList = ['sickbeard.db', 'config.ini', 'failed.db', 'cache.db']
-
-            for filename in filesList:
-                srcFile = ek(os.path.join, srcDir, filename)
-                dstFile = ek(os.path.join, dstDir, filename)
-                bakFile = ek(os.path.join, dstDir, '{0}.bak-{1}'.format(filename, datetime.datetime.now().strftime('%Y%m%d_%H%M%S')))
-                if ek(os.path.isfile, dstFile):
-                    shutil.move(dstFile, bakFile)
-                shutil.move(srcFile, dstFile)
+            files_list = ['sickbeard.db', 'config.ini', 'failed.db', 'cache.db']
+
+            for filename in files_list:
+                src_file = ek(os.path.join, src_dir, filename)
+                dst_file = ek(os.path.join, dst_dir, filename)
+                bak_file = ek(os.path.join, dst_dir, '%s.bak-%s' % (filename, datetime.datetime.now().strftime('%Y%m%d_%H%M%S')))
+                if ek(os.path.isfile, dst_file):
+                    shutil.move(dst_file, bak_file)
+                shutil.move(src_file, dst_file)
             return True
-        except Exception:
+        except Exception:  # pylint: disable=broad-except
             return False
 
     def shutdown(self, event):
-        if sickbeard.started:
-            # stop all tasks
-            sickbeard.halt()
+        """
+        Shut down SickRage
 
-            # save all shows to DB
-            sickbeard.saveAll()
+        :param event: Type of shutdown event, used to see if restart required
+        """
+        if sickbeard.started:
+            sickbeard.halt()  # stop all tasks
+            sickbeard.saveAll()  # save all shows to DB
 
             # shutdown web server
-            if self.webserver:
-                logger.log(u"Shutting down Tornado")
-                self.webserver.shutDown()
+            if self.web_server:
+                logger.log('Shutting down Tornado')  # pylint: disable=no-member
+                self.web_server.shutDown()
 
                 try:
-                    self.webserver.join(10)
-                except Exception:
+                    self.web_server.join(10)
+                except Exception:  # pylint: disable=broad-except
                     pass
 
-            # Clean cache
-            self.clear_cache()
+            self.clear_cache()  # Clean cache
 
-            # if run as daemon delete the pidfile
-            if self.runAsDaemon and self.CREATEPID:
-                self.remove_pid_file(self.PIDFILE)
+            # if run as daemon delete the pid file
+            if self.run_as_daemon and self.create_pid:
+                self.remove_pid_file(self.pid_file)
 
             if event == sickbeard.event_queue.Events.SystemEvent.RESTART:
                 install_type = sickbeard.versionCheckScheduler.action.install_type
@@ -518,23 +532,23 @@ class SickRage(object):
                 if install_type in ('git', 'source'):
                     popen_list = [sys.executable, sickbeard.MY_FULLNAME]
                 elif install_type == 'win':
-                    logger.log(u"You are using a binary Windows build of SickRage. Please switch to using git.", logger.ERROR)
+                    logger.log('You are using a binary Windows build of SickRage. '  # pylint: disable=no-member
+                               'Please switch to using git.', logger.ERROR)
 
                 if popen_list and not sickbeard.NO_RESTART:
                     popen_list += sickbeard.MY_ARGS
                     if '--nolaunch' not in popen_list:
                         popen_list += ['--nolaunch']
-                    logger.log(u"Restarting SickRage with " + str(popen_list))
-                    logger.shutdown()  # shutdown the logger to make sure it's released the logfile BEFORE it restarts SR.
+                    logger.log('Restarting SickRage with %s' % popen_list)  # pylint: disable=no-member
+                    # shutdown the logger to make sure it's released the logfile BEFORE it restarts SR.
+                    logger.shutdown()  # pylint: disable=no-member
                     subprocess.Popen(popen_list, cwd=os.getcwd())
 
-        # system exit
-        logger.shutdown()  # Make sure the logger has stopped, just in case
-        # pylint: disable=protected-access
-        # Access to a protected member of a client class
-        os._exit(0)
+        # Make sure the logger has stopped, just in case
+        logger.shutdown()  # pylint: disable=no-member
+        os._exit(0)  # pylint: disable=protected-access
 
 
-if __name__ == "__main__":
-    # start sickrage
+if __name__ == '__main__':
+    # start SickRage
     SickRage().start()
diff --git a/gui/slick/css/1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf b/gui/slick/css/1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..d7d7cd1fcc97d7aaeb1ffa373ea86d0c2ee13b5e
Binary files /dev/null and b/gui/slick/css/1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf differ
diff --git a/gui/slick/css/702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf b/gui/slick/css/702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..974a7c5edd7f14486c43561220b54244da886885
Binary files /dev/null and b/gui/slick/css/702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf differ
diff --git a/gui/slick/css/JXh38I15wypJXxuGMBp0EAVxt0G0biEntp43Qt6E.ttf b/gui/slick/css/JXh38I15wypJXxuGMBp0EAVxt0G0biEntp43Qt6E.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..53dbf96f7cde8a031fcea31baf7eaf9c9af36fbb
Binary files /dev/null and b/gui/slick/css/JXh38I15wypJXxuGMBp0EAVxt0G0biEntp43Qt6E.ttf differ
diff --git a/gui/slick/css/KeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf b/gui/slick/css/KeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..0dae9c3bbc0b52ccd98b060849e631661a9bebdc
Binary files /dev/null and b/gui/slick/css/KeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf differ
diff --git a/gui/slick/css/_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf b/gui/slick/css/_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..314e983a4bce3320b1ebeea9d21aeea88eaab52e
Binary files /dev/null and b/gui/slick/css/_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf differ
diff --git a/gui/slick/css/bV5DfGHOiMmvb1Xr-honF5uFdDttMLvmWuJdhhgs.ttf b/gui/slick/css/bV5DfGHOiMmvb1Xr-honF5uFdDttMLvmWuJdhhgs.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..569e03a84014d5163582d148d6e090727eb61b53
Binary files /dev/null and b/gui/slick/css/bV5DfGHOiMmvb1Xr-honF5uFdDttMLvmWuJdhhgs.ttf differ
diff --git a/gui/slick/css/browser.css b/gui/slick/css/browser.css
index 571501723e875d0280fb31342a692f3f03755fce..bdc1f3ab3ddf55f015fa8b83f32cadc944dfc2bb 100644
--- a/gui/slick/css/browser.css
+++ b/gui/slick/css/browser.css
@@ -1,30 +1,30 @@
-#fileBrowserDialog {
+.fileBrowserDialog {
     max-height: 480px;
     overflow-y: auto;
 }
 
-#fileBrowserDialog ul {
+.fileBrowserDialog ul {
     margin: 0;
     padding: 0;
 }
 
-#fileBrowserDialog ul li {
+.fileBrowserDialog ul li {
     margin: 2px 0;
     cursor: pointer;
     list-style-type: none;
 }
 
-#fileBrowserDialog ul li a {
+.fileBrowserDialog ul li a {
     display: block;
     padding: 4px 0;
 }
 
-#fileBrowserDialog ul li a:hover {
+.fileBrowserDialog ul li a:hover {
     color: #00f;
     background: none;
 }
 
-#fileBrowserDialog ul li a span.ui-icon {
+.fileBrowserDialog ul li a .ui-icon {
     margin: 0 4px;
     float: left;
 }
diff --git a/gui/slick/css/dark.css b/gui/slick/css/dark.css
index c4964a0678e270ccc1546c9ba739e19043002702..0a1231acc0facfa3be3a3b07a4df47eb2bfb10c2 100644
--- a/gui/slick/css/dark.css
+++ b/gui/slick/css/dark.css
@@ -880,16 +880,16 @@ pre {
 browser.css overrides
 ========================================================================== */
 
-#fileBrowserDialog ul li {
+.fileBrowserDialog ul li {
     margin: 2px 0;
     list-style-type: none;
     cursor: pointer;
-    background: #333;
+    background: #333 !important;
 }
 
-#fileBrowserDialog ul li a:hover {
+.fileBrowserDialog ul li a:hover {
     color: #09a2ff;
-    background: none;
+    background: none !important;
 }
 
 /* =======================================================================
diff --git a/gui/slick/css/fonts/OpenSans-Bold-webfont.eot b/gui/slick/css/fonts/OpenSans-Bold-webfont.eot
deleted file mode 100644
index 5d4a1c47770fd38b715d6f8e119869fed1f4d8ab..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Bold-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Bold-webfont.svg b/gui/slick/css/fonts/OpenSans-Bold-webfont.svg
deleted file mode 100644
index 1557f6807473930ef85ef8eb6a5ce9e54ec657f5..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Bold-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Bold-webfont.ttf b/gui/slick/css/fonts/OpenSans-Bold-webfont.ttf
deleted file mode 100644
index 7ab5d85bfdd1886b621b98b46e5a9d3609f2429c..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Bold-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Bold-webfont.woff b/gui/slick/css/fonts/OpenSans-Bold-webfont.woff
deleted file mode 100644
index 869a9ed8af705e6a216a97d137e5e4c838657a73..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Bold-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.eot b/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.eot
deleted file mode 100644
index ad6518076e32b52ad56d50ccb0e48d8a093b7efb..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.svg b/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.svg
deleted file mode 100644
index 24661f35f983413963336ab60be8470cb1941e36..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.ttf b/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.ttf
deleted file mode 100644
index 6a30fa9dd37f5da9f303e421c1e9d52f45bd3433..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.woff b/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.woff
deleted file mode 100644
index 46778a21796d14b21754178d21ded6431905dbee..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-BoldItalic-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.eot b/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.eot
deleted file mode 100644
index 2f7ae28d4c5686783e10dfd0dc835f5434e2c589..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.svg b/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.svg
deleted file mode 100644
index c3d6642a2c76659ac540115d8ac13765f2ae0450..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.ttf b/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.ttf
deleted file mode 100644
index dacc5bbb58035bc5203e206454b92cd3250843fa..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.woff b/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.woff
deleted file mode 100644
index de4f8e77e890aa401db7bf258ec31b02ee184053..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBold-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.eot b/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.eot
deleted file mode 100644
index e4f4ab0db8c0172efd8c0b6e49c9db1d916a19b8..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.svg b/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.svg
deleted file mode 100644
index a699015a37eb6c8e47a2e25e794857b608dcdb6e..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.ttf b/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.ttf
deleted file mode 100644
index 7e636eb4c051bfed4971d912387eb4554ee47cbb..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.woff b/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.woff
deleted file mode 100644
index f81b21618a3a5665123072c94044839f6871023c..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-ExtraBoldItalic-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Italic-webfont.eot b/gui/slick/css/fonts/OpenSans-Italic-webfont.eot
deleted file mode 100644
index c31595212fcbd4ff65267f36b92bb733e85f64ff..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Italic-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Italic-webfont.svg b/gui/slick/css/fonts/OpenSans-Italic-webfont.svg
deleted file mode 100644
index 537d20ca6ff85eec8e2e6588989f04d616674631..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Italic-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Italic-webfont.ttf b/gui/slick/css/fonts/OpenSans-Italic-webfont.ttf
deleted file mode 100644
index cb3fda65e9f6e05f49f7cd67ffa9c2850cfffc32..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Italic-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Italic-webfont.woff b/gui/slick/css/fonts/OpenSans-Italic-webfont.woff
deleted file mode 100644
index 03eaf5861873c5b7fdc011e53917d082b0651c6f..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Italic-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Light-webfont.eot b/gui/slick/css/fonts/OpenSans-Light-webfont.eot
deleted file mode 100644
index f17617e0396d6395a3fd3db07604c1754d2e7b1b..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Light-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Light-webfont.svg b/gui/slick/css/fonts/OpenSans-Light-webfont.svg
deleted file mode 100644
index c7ae13a29c9b2ace73247e9ed3ce7f7f8539771c..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Light-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Light-webfont.ttf b/gui/slick/css/fonts/OpenSans-Light-webfont.ttf
deleted file mode 100644
index b83078a6075d5d7800466c2981158fc721fd9419..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Light-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Light-webfont.woff b/gui/slick/css/fonts/OpenSans-Light-webfont.woff
deleted file mode 100644
index ff882b6acaa0fb595bb7658ec36d663394de3fba..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Light-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.eot b/gui/slick/css/fonts/OpenSans-LightItalic-webfont.eot
deleted file mode 100644
index 95c6c619d305e4aec571cad1d0af35ce677d0236..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.svg b/gui/slick/css/fonts/OpenSans-LightItalic-webfont.svg
deleted file mode 100644
index 535e688236feb0b4de25780be74d80c5b1a4e354..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.ttf b/gui/slick/css/fonts/OpenSans-LightItalic-webfont.ttf
deleted file mode 100644
index 3162ff8eb1ecc63453f2c88a43e57fbbee5d5c6c..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.woff b/gui/slick/css/fonts/OpenSans-LightItalic-webfont.woff
deleted file mode 100644
index f6e97d5afd5fe6aaa8d357af39256b24ae6e5f88..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-LightItalic-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Regular-webfont.eot b/gui/slick/css/fonts/OpenSans-Regular-webfont.eot
deleted file mode 100644
index 545b7c15e54a1399b315ebc761936289283eeb90..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Regular-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Regular-webfont.svg b/gui/slick/css/fonts/OpenSans-Regular-webfont.svg
deleted file mode 100644
index ead219a56987b4ebd7ead6c1d9d07af6efe6bb75..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Regular-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Regular-webfont.ttf b/gui/slick/css/fonts/OpenSans-Regular-webfont.ttf
deleted file mode 100644
index a5b2378e5c2f3c0614d06c1d6696e8c6e31c84d3..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Regular-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Regular-webfont.woff b/gui/slick/css/fonts/OpenSans-Regular-webfont.woff
deleted file mode 100644
index 11698afc2c2ae5626334495334d62e3574d839ae..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Regular-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Semibold-webfont.eot b/gui/slick/css/fonts/OpenSans-Semibold-webfont.eot
deleted file mode 100644
index acc32c425dd91d5d9012d14c634bcc3e6f00724f..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Semibold-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Semibold-webfont.svg b/gui/slick/css/fonts/OpenSans-Semibold-webfont.svg
deleted file mode 100644
index 9eaa0b710f45c71d40ac3a929593f58a9b954a8f..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Semibold-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Semibold-webfont.ttf b/gui/slick/css/fonts/OpenSans-Semibold-webfont.ttf
deleted file mode 100644
index a5b9691c1f329bff2acd569b3c82da44d96bb1a2..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Semibold-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-Semibold-webfont.woff b/gui/slick/css/fonts/OpenSans-Semibold-webfont.woff
deleted file mode 100644
index 17fb5dc324fece20ea9acca96ae149804e94e4fa..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-Semibold-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.eot b/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.eot
deleted file mode 100644
index 0048da006db46c22f9d527bd4c0809f8b94c3eb4..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.svg b/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.svg
deleted file mode 100644
index 316b8186d4efb4487362aa0e51b34d1039633892..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.ttf b/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.ttf
deleted file mode 100644
index 61d58bfa37b1f2b143527d72084130a59a5eb053..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.woff b/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.woff
deleted file mode 100644
index 611b39028f17d21ffed411076b8457c66dda9199..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/OpenSans-SemiboldItalic-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/fonts/droidsansmono-webfont.eot b/gui/slick/css/fonts/droidsansmono-webfont.eot
deleted file mode 100644
index aca857ba6567dad052ca8825f4146371ad5212fd..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/droidsansmono-webfont.eot and /dev/null differ
diff --git a/gui/slick/css/fonts/droidsansmono-webfont.svg b/gui/slick/css/fonts/droidsansmono-webfont.svg
deleted file mode 100644
index 584c09ecbf2095b3fcd4642fda2ac80114311898..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/droidsansmono-webfont.svg and /dev/null differ
diff --git a/gui/slick/css/fonts/droidsansmono-webfont.ttf b/gui/slick/css/fonts/droidsansmono-webfont.ttf
deleted file mode 100644
index 1e576a8b31e115c4f14188ba5d7ed6948e309e72..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/droidsansmono-webfont.ttf and /dev/null differ
diff --git a/gui/slick/css/fonts/droidsansmono-webfont.woff b/gui/slick/css/fonts/droidsansmono-webfont.woff
deleted file mode 100644
index ef6964d237603fcc8ad45e4e287aa9616347fa07..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/fonts/droidsansmono-webfont.woff and /dev/null differ
diff --git a/gui/slick/css/iXeptR36kaC0GEAetxi8cqLH4MEiSE0ROcU-qHOA.ttf b/gui/slick/css/iXeptR36kaC0GEAetxi8cqLH4MEiSE0ROcU-qHOA.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..ee892609576fbea2b53f7e6506bba3a8aebca10e
Binary files /dev/null and b/gui/slick/css/iXeptR36kaC0GEAetxi8cqLH4MEiSE0ROcU-qHOA.ttf differ
diff --git a/gui/slick/css/iXeptR36kaC0GEAetxlDMrAYtoOisqqMDW9M_Mqc.ttf b/gui/slick/css/iXeptR36kaC0GEAetxlDMrAYtoOisqqMDW9M_Mqc.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..57e8b7d54ffc5568301c942c4a7bfece55d080f7
Binary files /dev/null and b/gui/slick/css/iXeptR36kaC0GEAetxlDMrAYtoOisqqMDW9M_Mqc.ttf differ
diff --git a/gui/slick/css/iXeptR36kaC0GEAetxp_TkvowlIOtbR7ePgFOpF4.ttf b/gui/slick/css/iXeptR36kaC0GEAetxp_TkvowlIOtbR7ePgFOpF4.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..1e54a3172d1f65d35e75139e5c22def8e95f0435
Binary files /dev/null and b/gui/slick/css/iXeptR36kaC0GEAetxp_TkvowlIOtbR7ePgFOpF4.ttf differ
diff --git a/gui/slick/css/iXeptR36kaC0GEAetxrfB31yxOzP-czbf6AAKCVo.ttf b/gui/slick/css/iXeptR36kaC0GEAetxrfB31yxOzP-czbf6AAKCVo.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..716c390d8f955339bda9fa605908e27038f5d892
Binary files /dev/null and b/gui/slick/css/iXeptR36kaC0GEAetxrfB31yxOzP-czbf6AAKCVo.ttf differ
diff --git a/gui/slick/css/imports/config.less b/gui/slick/css/imports/config.less
deleted file mode 100644
index a9fba3b2c0dbce77481c539d88084e8202994378..0000000000000000000000000000000000000000
--- a/gui/slick/css/imports/config.less
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Variables */ 
-@base-font-face:			"Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
-@alt-font-face:				"Trebuchet MS", Helvetica, Arial, sans-serif;
-@base-font-size:			12px;
-@text-color:				#343434;
-@swatch-blue:				#4183C4;
-@swatch-green:				#BDE433;
-@swatch-grey:				#666666;
-@link-color:				#555555;
-@border-color:				#CCCCCC;
-@msg-bg:					#FFF6A9;
-@msg-bg-success:			#D3FFD7;
-@msg-bg-error:				#FFD3D3;
-
-/* Mixins */
-.rounded(@radius: 5px) {	
-	-moz-border-radius: @radius;
-	-webkit-border-radius: @radius;
-	border-radius: @radius;
-}
-.roundedTop(@radius: 5px) {	
-	-moz-border-radius-topleft: @radius;
-	-moz-border-radius-topright: @radius;
-	-webkit-border-top-right-radius: @radius;
-	-webkit-border-top-left-radius: @radius;
-	border-top-left-radius: @radius;
-	border-top-right-radius: @radius;
-}
-.roundedLeftTop(@radius: 5px) {	
-	-moz-border-radius-topleft: @radius;
-	-webkit-border-top-left-radius: @radius;
-	border-top-left-radius: @radius;
-}
-.roundedRightTop(@radius: 5px) {	
-	-moz-border-radius-topright: @radius;
-	-webkit-border-top-right-radius: @radius;
-	border-top-right-radius: @radius;
-}
-.roundedBottom(@radius: 5px) {	
-	-moz-border-radius-bottomleft: @radius;
-	-moz-border-radius-bottomright: @radius;
-	-webkit-border-bottom-right-radius: @radius;
-	-webkit-border-bottom-left-radius: @radius;
-	border-bottom-left-radius: @radius;
-	border-bottom-right-radius: @radius;
-}
-.roundedLeftBottom(@radius: 5px) {	
-	-moz-border-radius-bottomleft: @radius;
-	-webkit-border-bottom-left-radius: @radius;
-	border-bottom-left-radius: @radius;
-}
-.roundedRightBottom(@radius: 5px) {	
-	-moz-border-radius-bottomright: @radius;
-	-webkit-border-bottom-right-radius: @radius;
-	border-bottom-right-radius: @radius;
-}
-.shadow(@shadow: 0 17px 11px -1px #ced8d9) {
-   -moz-box-shadow: @shadow;
-   -webkit-box-shadow: @shadow;
-   -o-box-shadow: @shadow;
-   box-shadow: @shadow;
-}
-.gradient(@gradientFrom: #FFFFFF, @gradientTo: #EEEEEE){
-	background-image: -moz-linear-gradient(@gradientFrom, @gradientTo) !important;
-	background-image: linear-gradient(@gradientFrom, @gradientTo) !important;
-	background-image: -webkit-linear-gradient(@gradientFrom, @gradientTo) !important;
-	background-image: -o-linear-gradient(@gradientFrom, @gradientTo) !important;
-	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@gradientFrom, endColorstr=@gradientTo) !important;
-	-ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@gradientFrom, endColorstr=@gradientTo) !important;
-}
-.opacity(@opacity_percent:85) {
-	filter: ~"alpha(opacity=85)";
-	-moz-opacity: @opacity_percent / 100 !important; 
-	-khtml-opacity:@opacity_percent / 100 !important;
-	-o-opacity:@opacity_percent / 100 !important;
-	opacity:@opacity_percent / 100 !important;
-}
-
diff --git a/gui/slick/css/lib/bootstrap.min.css b/gui/slick/css/lib/bootstrap.min.css
deleted file mode 100644
index 6dc17a6ab2052a25d92d460e255d70d8688c6f25..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/lib/bootstrap.min.css and /dev/null differ
diff --git a/gui/slick/css/lib/pnotify.custom.min.css b/gui/slick/css/lib/pnotify.custom.min.css
deleted file mode 100644
index 8f2d3eb74d4cf473f30609b7d6711947e16b47d1..0000000000000000000000000000000000000000
Binary files a/gui/slick/css/lib/pnotify.custom.min.css and /dev/null differ
diff --git a/gui/slick/css/style.css b/gui/slick/css/style.css
index 7617360f8b1e73f49d34bbd9316b64ba7c40b17b..9d0bd556156a63bbc4e33f5d70bac1049e098aa2 100644
--- a/gui/slick/css/style.css
+++ b/gui/slick/css/style.css
@@ -1,145 +1,3 @@
-/* =======================================================================
-fonts
-========================================================================== */
-/* Open Sans */
-/* Regular */
-@font-face {
-    font-family: 'Open Sans';
-
-    src: url('fonts/OpenSans-Regular-webfont.eot');
-    src: url('fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-Regular-webfont.woff') format('woff'),
-         url('fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
-    font-weight: normal;
-    font-weight: 400;
-    font-style: normal;
-}
-
-/* Italic */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-Italic-webfont.eot');
-    src: url('fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-Italic-webfont.woff') format('woff'),
-         url('fonts/OpenSans-Italic-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg');
-    font-weight: normal;
-    font-weight: 400;
-    font-style: italic;
-}
-
-/* Light */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-Light-webfont.eot');
-    src: url('fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-Light-webfont.woff') format('woff'),
-         url('fonts/OpenSans-Light-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg');
-    font-weight: 200;
-    font-style: normal;
-}
-
-/* Light Italic */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-LightItalic-webfont.eot');
-    src: url('fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-LightItalic-webfont.woff') format('woff'),
-         url('fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg');
-    font-weight: 200;
-    font-style: italic;
-}
-
-/* Semibold */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-Semibold-webfont.eot');
-    src: url('fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-Semibold-webfont.woff') format('woff'),
-         url('fonts/OpenSans-Semibold-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
-    font-weight: 600;
-    font-style: normal;
-}
-
-/* Semibold Italic */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-SemiboldItalic-webfont.eot');
-    src: url('fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'),
-         url('fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
-    font-weight: 600;
-    font-style: italic;
-}
-
-/* Bold */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-Semibold-webfont.eot');
-    src: url('fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-Semibold-webfont.woff') format('woff'),
-         url('fonts/OpenSans-Semibold-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
-    font-weight: bold;
-    font-weight: 700;
-    font-style: normal;
-}
-
-/* Bold Italic */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-SemiboldItalic-webfont.eot');
-    src: url('fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'),
-         url('fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
-    font-weight: bold;
-    font-weight: 700;
-    font-style: italic;
-}
-
-/* Extra Bold */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-Bold-webfont.eot');
-    src: url('fonts/OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-Bold-webfont.woff') format('woff'),
-         url('fonts/OpenSans-Bold-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-Bold-webfont.svg#OpenSansBold') format('svg');
-    font-weight: 900;
-    font-style: normal;
-}
-
-/* Extra Bold Italic */
-@font-face {
-    font-family: 'Open Sans';
-    src: url('fonts/OpenSans-BoldItalic-webfont.eot');
-    src: url('fonts/OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/OpenSans-BoldItalic-webfont.woff') format('woff'),
-         url('fonts/OpenSans-BoldItalic-webfont.ttf') format('truetype'),
-         url('fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg');
-    font-weight: 900;
-    font-style: italic;
-}
-
-/* Droid Sans */
-@font-face {
-    font-family: 'droid_sans_mono';
-    src: url('fonts/droidsansmono-webfont.eot');
-    src: url('fonts/droidsansmono-webfont.eot?#iefix') format('embedded-opentype'),
-         url('fonts/droidsansmono-webfont.woff') format('woff'),
-         url('fonts/droidsansmono-webfont.ttf') format('truetype'),
-         url('fonts/droidsansmono-webfont.svg#droid_sans_monoregular') format('svg');
-    font-weight: normal;
-    font-style: normal;
-}
-
-
 /* =======================================================================
 inc_top.mako
 ========================================================================== */
diff --git a/gui/slick/css/vender.min.css b/gui/slick/css/vender.min.css
index c23d4637c1e42dbea7d6a89964b962a45fffef9a..8517ed95fe6109d4ec5f505f940db29ede8e54e6 100644
Binary files a/gui/slick/css/vender.min.css and b/gui/slick/css/vender.min.css differ
diff --git a/gui/slick/css/fonts/glyphicons-halflings-regular.eot b/gui/slick/fonts/glyphicons-halflings-regular.eot
similarity index 100%
rename from gui/slick/css/fonts/glyphicons-halflings-regular.eot
rename to gui/slick/fonts/glyphicons-halflings-regular.eot
diff --git a/gui/slick/css/fonts/glyphicons-halflings-regular.svg b/gui/slick/fonts/glyphicons-halflings-regular.svg
similarity index 100%
rename from gui/slick/css/fonts/glyphicons-halflings-regular.svg
rename to gui/slick/fonts/glyphicons-halflings-regular.svg
diff --git a/gui/slick/css/fonts/glyphicons-halflings-regular.ttf b/gui/slick/fonts/glyphicons-halflings-regular.ttf
similarity index 100%
rename from gui/slick/css/fonts/glyphicons-halflings-regular.ttf
rename to gui/slick/fonts/glyphicons-halflings-regular.ttf
diff --git a/gui/slick/css/fonts/glyphicons-halflings-regular.woff b/gui/slick/fonts/glyphicons-halflings-regular.woff
similarity index 100%
rename from gui/slick/css/fonts/glyphicons-halflings-regular.woff
rename to gui/slick/fonts/glyphicons-halflings-regular.woff
diff --git a/gui/slick/css/fonts/glyphicons-halflings-regular.woff2 b/gui/slick/fonts/glyphicons-halflings-regular.woff2
similarity index 100%
rename from gui/slick/css/fonts/glyphicons-halflings-regular.woff2
rename to gui/slick/fonts/glyphicons-halflings-regular.woff2
diff --git a/gui/slick/images/notifiers/telegram.png b/gui/slick/images/notifiers/telegram.png
new file mode 100644
index 0000000000000000000000000000000000000000..427d6cc567cd3c5888721c57552cbe664038193d
Binary files /dev/null and b/gui/slick/images/notifiers/telegram.png differ
diff --git a/gui/slick/images/providers/demonoid.png b/gui/slick/images/providers/demonoid.png
new file mode 100644
index 0000000000000000000000000000000000000000..ea8caa7e85ed4cc5b52052782b7c9aafb5236f7a
Binary files /dev/null and b/gui/slick/images/providers/demonoid.png differ
diff --git a/gui/slick/images/providers/nutech.png b/gui/slick/images/providers/nutech.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a89676a96065d40f29e43471155501de17e2841
Binary files /dev/null and b/gui/slick/images/providers/nutech.png differ
diff --git a/gui/slick/images/xem.png b/gui/slick/images/xem.png
index 634def233941b7029a04dc2e7ffc63c3af727f35..5614d0835f6d7f7a0552171a2637bc470b574a80 100644
Binary files a/gui/slick/images/xem.png and b/gui/slick/images/xem.png differ
diff --git a/gui/slick/js/addShowOptions.js b/gui/slick/js/addShowOptions.js
index 8fa692b068226c5de4539cc6d78358e8bd6e4437..223bf051e5c6f768982fd506dac95bb5a93e6a12 100644
--- a/gui/slick/js/addShowOptions.js
+++ b/gui/slick/js/addShowOptions.js
@@ -31,4 +31,11 @@ $(document).ready(function () {
     $('#statusSelect, #qualityPreset, #flatten_folders, #anyQualities, #bestQualities, #subtitles, #scene, #anime, #statusSelectAfter').change(function () {
         $('#saveDefaultsButton').attr('disabled', false);
     });
+
+    $('#qualityPreset').on('change', function() {
+        //fix issue #181 - force re-render to correct the height of the outer div
+        $('span.prev').click();
+        $('span.next').click();
+    });
+
 });
diff --git a/gui/slick/js/browser.js b/gui/slick/js/browser.js
index b3a447d8159202e16541e6f0e109bd9a1ddeb43e..e9512dd67ab6fac3fa65318b74c949db901e97f3 100644
--- a/gui/slick/js/browser.js
+++ b/gui/slick/js/browser.js
@@ -78,7 +78,7 @@
         // make a fileBrowserDialog object if one doesn't exist already
         if (!fileBrowserDialog) {
             // set up the jquery dialog
-            fileBrowserDialog = $('<div id="fileBrowserDialog" style="display:hidden"></div>').appendTo('body').dialog({
+            fileBrowserDialog = $('<div class="fileBrowserDialog" style="display:hidden"></div>').appendTo('body').dialog({
                 dialogClass: 'browserDialog',
                 title:       options.title,
                 position:    { my: 'center top', at: 'center top+60', of: window },
@@ -89,30 +89,26 @@
                 modal:       true,
                 autoOpen:    false
             });
-        }
-        else {
+        } else {
             // The title may change, even if fileBrowserDialog already exists
-            fileBrowserDialog.dialog('option', 'title', options.title);   
+            fileBrowserDialog.dialog('option', 'title', options.title);
         }
-        
-        fileBrowserDialog.dialog('option', 'buttons', [
-            {
-                text: 'Ok',
-                'class': 'btn',
-                click: function () {
-                    // store the browsed path to the associated text field
-                    callback(currentBrowserPath, options);
-                    $(this).dialog('close');
-                }
-            },
-            {
-                text: 'Cancel',
-                'class': 'btn',
-                click: function () {
-                    $(this).dialog('close');
-                }
+
+        fileBrowserDialog.dialog('option', 'buttons', [{
+            text: 'Ok',
+            'class': 'btn',
+            click: function () {
+                // store the browsed path to the associated text field
+                callback(currentBrowserPath, options);
+                $(this).dialog('close');
+            }
+        }, {
+            text: 'Cancel',
+            'class': 'btn',
+            click: function () {
+                $(this).dialog('close');
             }
-        ]);
+        }]);
 
         // set up the browser and launch the dialog
         var initialDir = '';
diff --git a/gui/slick/js/core.js b/gui/slick/js/core.js
index 63a2a53c5d84fb6c9af01b58780ccb8aba837982..4784e58767dd08beb118a43263ba9d3875683342 100644
--- a/gui/slick/js/core.js
+++ b/gui/slick/js/core.js
@@ -700,6 +700,36 @@ var SICKRAGE = {
                 });
             });
 
+            $('#testTelegram').on('click', function () {
+                var telegram = {};
+                telegram.id = $.trim($('#telegram_id').val());
+                telegram.apikey = $.trim($('#telegram_apikey').val());
+                if (!telegram.id || !telegram.apikey) {
+                    $('#testTelegram-result').html('Please fill out the necessary fields above.');
+                    if (!telegram.id) {
+                        $('#telegram_id').addClass('warning');
+                    } else {
+                        $('#telegram_id').removeClass('warning');
+                    }
+                    if (!telegram.apikey) {
+                        $('#telegram_apikey').addClass('warning');
+                    } else {
+                        $('#telegram_apikey').removeClass('warning');
+                    }
+                    return;
+                }
+                $('#telegram_id,#telegram_apikey').removeClass('warning');
+                $(this).prop('disabled', true);
+                $('#testTelegram-result').html(loading);
+                $.get(srRoot + '/home/testTelegram', {
+                    'telegram_id': telegram.id,
+                    'telegram_apikey': telegram.apikey
+                }).done(function (data) {
+                    $('#testTelegram-result').html(data);
+                    $('#testTelegram').prop('disabled', false);
+                });
+            });
+
             $('#TraktGetPin').on('click', function () {
                 window.open($('#trakt_pin_url').val(), "popUp", "toolbar=no, scrollbars=no, resizable=no, top=200, left=200, width=650, height=550");
                 $('#trakt_pin').removeClass('hide');
@@ -745,7 +775,7 @@ var SICKRAGE = {
                 }
 
                 if (/\s/g.test(trakt.trendingBlacklist)) {
-                    $('#testTrakt-result').html('Check blacklist name; the value need to be a trakt slug');
+                    $('#testTrakt-result').html('Check blacklist name; the value needs to be a trakt slug');
                     $('#trakt_blacklist_name').addClass('warning');
                     return;
                 }
@@ -1805,8 +1835,8 @@ var SICKRAGE = {
             $('#filterShowName').on('input', _.debounce(function() {
                 $('.show-grid').isotope({
                     filter: function () {
-                      var name = $(this).data('name');
-                      return name.toLowerCase();
+                      var name = $(this).attr('data-name').toLowerCase();
+                      return name.indexOf($('#filterShowName').val()) > -1;
                     }
                 });
             }, 500));
@@ -1916,7 +1946,7 @@ var SICKRAGE = {
                             if (f === '') {
                                 test = true;
                             } else {
-                                var result = f.match(/(<|<=|>=|>)\s(\d+)/i);
+                                var result = f.match(/(<|<=|>=|>)\s+(\d+)/i);
                                 if (result) {
                                     if (result[1] === "<") {
                                         if (pct < parseInt(result[2])) {
@@ -1937,7 +1967,7 @@ var SICKRAGE = {
                                     }
                                 }
 
-                                result = f.match(/(\d+)\s(-|to)\s(\d+)/i);
+                                result = f.match(/(\d+)\s(-|to)\s+(\d+)/i);
                                 if (result) {
                                     if ((result[2] === "-") || (result[2] === "to")) {
                                         if ((pct >= parseInt(result[1])) && (pct <= parseInt(result[3]))) {
@@ -1982,8 +2012,8 @@ var SICKRAGE = {
                     },
                     getSortData: {
                         name: function (itemElem) {
-                            var name = $(itemElem).attr('data-name');
-                            return (metaToBool('sickbeard.SORT_ARTICLE') ? (name || '') : (name || '').replace(/^(The|A|An)\s/i,''));
+                            var name = $(itemElem).attr('data-name') || '';
+                            return (metaToBool('sickbeard.SORT_ARTICLE') ? name : name.replace(/^((?:The|A|An)\s)/i, '')).toLowerCase();
                         },
                         network: '[data-network]',
                         date: function (itemElem) {
@@ -2829,7 +2859,7 @@ var SICKRAGE = {
                         getSortData: {
                             name: function(itemElem) {
                                 var name = $(itemElem).attr('data-name') || '';
-                                return (metaToBool('sickbeard.SORT_ARTICLE') ? name : name.replace(/^(The|A|An)\s/i, '')).toLowerCase();
+                                return (metaToBool('sickbeard.SORT_ARTICLE') ? name : name.replace(/^((?:The|A|An)\s)/i, '')).toLowerCase();
                             },
                             rating: '[data-rating] parseInt',
                             votes: '[data-votes] parseInt',
diff --git a/gui/slick/js/core.min.js b/gui/slick/js/core.min.js
index 98337456ec2605e5f2ee671b6fc41e02297cb43c..0e5d8c3ab3dba6c9fa22f35b013eba434e9be19c 100644
Binary files a/gui/slick/js/core.min.js and b/gui/slick/js/core.min.js differ
diff --git a/gui/slick/views/404.mako b/gui/slick/views/404.mako
new file mode 100644
index 0000000000000000000000000000000000000000..e090d5be0512ec7b9d9c9f7ff06a84bd94a3c345
--- /dev/null
+++ b/gui/slick/views/404.mako
@@ -0,0 +1,7 @@
+<%inherit file="/layouts/main.mako"/>
+<%block name="content">
+<h1 class="header">${header}</h1>
+<div class="align-center">
+You have reached this page by accident, please check the url.
+</div>
+</%block>
diff --git a/gui/slick/views/500.mako b/gui/slick/views/500.mako
new file mode 100644
index 0000000000000000000000000000000000000000..4a8547d4ac1b098715758f4b9873ef205ef2b1d0
--- /dev/null
+++ b/gui/slick/views/500.mako
@@ -0,0 +1,25 @@
+<%inherit file="/layouts/main.mako"/>
+
+<%block name="content">
+<h1 class="header">${header}</h1>
+<p>
+A mako error has occured.<br>
+If this happened during an update a simple page refresh may be the solution.<br>
+Mako errors that happen during updates may be a one time error if there were significant ui changes.<br>
+</p>
+<hr>
+<a href="#mako-error" class="btn btn-default" data-toggle="collapse">Show/Hide Error</a>
+<div id="mako-error" class="collapse">
+<br>
+<div class="align-center">
+<pre>
+<% filename, lineno, function, line = backtrace.traceback[-1] %>
+File ${filename}:${lineno}, in ${function}:
+% if line:
+${line}
+% endif
+${str(backtrace.error.__class__.__name__)}: ${backtrace.error}
+</pre>
+</div>
+</div>
+</%block>
diff --git a/gui/slick/views/addShows_popularShows.mako b/gui/slick/views/addShows_popularShows.mako
index 1dae0780983b63bece22c5f4f9cfcfe7d577318f..b5d33a21b56db2906a488bbe49d00e2b27e5897b 100644
--- a/gui/slick/views/addShows_popularShows.mako
+++ b/gui/slick/views/addShows_popularShows.mako
@@ -69,7 +69,7 @@
                         <p>${int(float(cur_rating)*10)}% <img src="${srRoot}/images/heart.png"></p>
                         <i>${cur_votes} votes</i>
                         <div class="traktShowTitleIcons">
-                            <a href="${srRoot}/addShows/addShowByID?indexer_id=${cur_result['imdb_tt']}&amp;show_name=${cur_result['name']}&amp;indexer=IMDB" class="btn btn-xs" data-no-redirect>Add Show</a>
+                            <a href="${srRoot}/addShows/addShowByID?indexer_id=${cur_result['imdb_tt']}&amp;show_name=${cur_result['name'] | u}&amp;indexer=IMDB" class="btn btn-xs" data-no-redirect>Add Show</a>
                         </div>
                     </div>
                 </div>
diff --git a/gui/slick/views/apiBuilder.mako b/gui/slick/views/apiBuilder.mako
index 460f8f8ae460443cb3253352d6fd80380caaa145..970dc6a8966129786f0e8bc54a67fbd80a888d3d 100644
--- a/gui/slick/views/apiBuilder.mako
+++ b/gui/slick/views/apiBuilder.mako
@@ -60,7 +60,7 @@
     <link rel="apple-touch-icon" sizes="72x72" href="${srRoot}/images/ico/favicon-72.png">
     <link rel="apple-touch-icon" href="${srRoot}/images/ico/favicon-57.png">
 
-    <link rel="stylesheet" type="text/css" href="${srRoot}/css/lib/bootstrap.min.css?${sbPID}"/>
+    <link rel="stylesheet" type="text/css" href="${srRoot}/css/vender.min.css?${sbPID}"/>
     <link rel="stylesheet" type="text/css" href="${srRoot}/css/browser.css?${sbPID}" />
     <link rel="stylesheet" type="text/css" href="${srRoot}/css/lib/jquery-ui-1.10.4.custom.min.css?${sbPID}" />
     <link rel="stylesheet" type="text/css" href="${srRoot}/css/style.css?${sbPID}"/>
diff --git a/gui/slick/views/config_notifications.mako b/gui/slick/views/config_notifications.mako
index ac84c8e66d8d1bcbdfc9221543b7605f294b9c42..bed9e956943fedef75dca1d372f06b81cbee975a 100644
--- a/gui/slick/views/config_notifications.mako
+++ b/gui/slick/views/config_notifications.mako
@@ -1388,6 +1388,78 @@
 
                     </fieldset>
                 </div><!-- /freemobile component-group //-->
+                <div class="component-group">
+                    <div class="component-group-desc">
+                        <img class="notifier-icon" src="${srRoot}/images/notifiers/telegram.png" alt="" title="Telegram" />
+                        <h3><a href="${anon_url('https://telegram.org/')}" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">Telegram</a></h3>
+                        <p>Telegram is a cloud-based instant messaging service.</p>
+                    </div>
+                    <fieldset class="component-group-list">
+                        <div class="field-pair">
+                            <label for="use_telegram">
+                                <span class="component-title">Enable</span>
+                                <span class="component-desc">
+                                    <input type="checkbox" class="enabler" name="use_telegram" id="use_telegram" ${('', 'checked="checked"')[bool(sickbeard.USE_TELEGRAM)]}/>
+                                    <p>Send Telegram notifications?</p>
+                                </span>
+                            </label>
+                        </div>
+
+                        <div id="content_use_telegram">
+                            <div class="field-pair">
+                                <label for="telegram_notify_onsnatch">
+                                    <span class="component-title">Notify on snatch</span>
+                                    <span class="component-desc">
+                                        <input type="checkbox" name="telegram_notify_onsnatch" id="telegram_notify_onsnatch" ${('', 'checked="checked"')[bool(sickbeard.TELEGRAM_NOTIFY_ONSNATCH)]}/>
+                                        <p>Send a message when a download starts?</p>
+                                    </span>
+                                </label>
+                            </div>
+                            <div class="field-pair">
+                                <label for="telegram_notify_ondownload">
+                                    <span class="component-title">Notify on download</span>
+                                    <span class="component-desc">
+                                        <input type="checkbox" name="telegram_notify_ondownload" id="telegram_notify_ondownload" ${('', 'checked="checked"')[bool(sickbeard.TELEGRAM_NOTIFY_ONDOWNLOAD)]}/>
+                                        <p>Send a message when a download finishes?</p>
+                                    </span>
+                                </label>
+                            </div>
+                            <div class="field-pair">
+                                <label for="telegram_notify_onsubtitledownload">
+                                    <span class="component-title">Notify on subtitle download</span>
+                                    <span class="component-desc">
+                                        <input type="checkbox" name="telegram_notify_onsubtitledownload" id="telegram_notify_onsubtitledownload" ${('', 'checked="checked"')[bool(sickbeard.TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD)]}/>
+                                        <p>Send a message when subtitles are downloaded?</p>
+                                    </span>
+                                </label>
+                            </div>
+                            <div class="field-pair">
+                                <label for="telegram_id">
+                                    <span class="component-title">User/group ID</span>
+                                    <input type="text" name="telegram_id" id="telegram_id" value="${sickbeard.TELEGRAM_ID}" class="form-control input-sm input250" autocapitalize="off" />
+                                </label>
+                                <label>
+                                    <span class="component-title">&nbsp;</span>
+                                    <span class="component-desc">Contact @myidbot on Telegram to get an ID</span>
+                                </label>
+                            </div>
+                            <div class="field-pair">
+                                <label for="telegram_password">
+                                    <span class="component-title">Bot API token</span>
+                                    <input type="text" name="telegram_apikey" id="telegram_apikey" value="${sickbeard.TELEGRAM_APIKEY}" class="form-control input-sm input250" autocapitalize="off" />
+                                </label>
+                                <label>
+                                    <span class="component-title">&nbsp;</span>
+                                    <span class="component-desc">Contact @BotFather on Telegram to set up one</span>
+                                </label>
+                            </div>
+                            <div class="testNotification" id="testTelegram-result">Click below to test your settings.</div>
+                            <input  class="btn" type="button" value="Test Telegram" id="testTelegram" />
+                            <input type="submit" class="config_submitter btn" value="Save Changes" />
+                        </div><!-- /content_use_telegram //-->
+
+                    </fieldset>
+                </div><!-- /telegram component-group //-->
 
             </div>
 
@@ -1404,7 +1476,7 @@
                                 <span class="component-title">Enable</span>
                                 <span class="component-desc">
                                     <input type="checkbox" class="enabler" name="use_twitter" id="use_twitter" ${('', 'checked="checked"')[bool(sickbeard.USE_TWITTER)]}/>
-                                    <p>should SickRage post tweets on Twitter?</p>
+                                    <p>Should SickRage post tweets on Twitter?</p>
                                 </span>
                             </label>
                             <label>
diff --git a/gui/slick/views/config_postProcessing.mako b/gui/slick/views/config_postProcessing.mako
index e45eca4df6e591acb703f1687cebde1868dafa00..6ae984827353a354b26ba4b8ca86c05b83f305eb 100644
--- a/gui/slick/views/config_postProcessing.mako
+++ b/gui/slick/views/config_postProcessing.mako
@@ -446,7 +446,7 @@
                                           <td>Show.Name.S02E03.HDTV.XviD-RLSGROUP</td>
                                         </tr>
                                         <tr>
-                                          <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SiCKRAGE' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
+                                          <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SickRage' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
                                           <td>%RG</td>
                                           <td>RLSGROUP</td>
                                         </tr>
@@ -654,7 +654,7 @@
                                               <td>Show.Name.2010.03.09.HDTV.XviD-RLSGROUP</td>
                                             </tr>
                                             <tr class="even">
-                                              <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SiCKRAGE' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
+                                              <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SickRage' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
                                               <td>%RG</td>
                                               <td>RLSGROUP</td>
                                             </tr>
@@ -831,7 +831,7 @@
                                               <td>Show.Name.9th.Mar.2011.HDTV.XviD-RLSGROUP</td>
                                             </tr>
                                             <tr class="even">
-                                              <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SiCKRAGE' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
+                                              <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SickRage' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
                                               <td>%RG</td>
                                               <td>RLSGROUP</td>
                                             </tr>
@@ -1004,7 +1004,7 @@
                                               <td>Show.Name.S02E03.HDTV.XviD-RLSGROUP</td>
                                             </tr>
                                             <tr>
-                                              <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SiCKRAGE' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
+                                              <td class="align-right"><i class="glyphicon glyphicon-info-sign" title="'SickRage' is used in place of RLSGROUP if it could not be properly detected"></i> <b>Release Group:</b></td>
                                               <td>%RG</td>
                                               <td>RLSGROUP</td>
                                             </tr>
diff --git a/gui/slick/views/home.mako b/gui/slick/views/home.mako
index 7f72b5311227a9c0267ff3fac6c86b46b47907c7..9c0362e19f50c0d565a59a6b4c70291637e27e46 100644
--- a/gui/slick/views/home.mako
+++ b/gui/slick/views/home.mako
@@ -55,8 +55,8 @@
 
                     <span class="show-option"> Direction:
                         <select id="postersortdirection" class="form-control form-control-inline input-sm">
-                            <option value="true" data-sort="${srRoot}/setPosterSortDir/?direction=1" ${('', 'selected="selected"')[sickbeard.POSTER_SORTDIR == 1]}>A &#10140; Z</option>
-                            <option value="false" data-sort="${srRoot}/setPosterSortDir/?direction=0" ${('', 'selected="selected"')[sickbeard.POSTER_SORTDIR == 0]}>Z &#10140; A</option>
+                            <option value="true" data-sort="${srRoot}/setPosterSortDir/?direction=1" ${('', 'selected="selected"')[sickbeard.POSTER_SORTDIR == 1]}>Ascending </option>
+                            <option value="false" data-sort="${srRoot}/setPosterSortDir/?direction=0" ${('', 'selected="selected"')[sickbeard.POSTER_SORTDIR == 0]}>Descending</option>
                         </select>
                     </span>
                 % endif
diff --git a/gui/slick/views/inc_addShowOptions.mako b/gui/slick/views/inc_addShowOptions.mako
index 673fb4f639549ce8382f886d973516e534dd1111..838a170f3513d4b234edb06c35865121e40273ea 100644
--- a/gui/slick/views/inc_addShowOptions.mako
+++ b/gui/slick/views/inc_addShowOptions.mako
@@ -4,6 +4,17 @@
     from sickbeard.common import Quality, qualityPresets, qualityPresetStrings, statusStrings
     from sickbeard import subtitles
 %>
+
+        <div class="field-pair alt">
+            <label for="customQuality" class="clearfix">
+                <span class="component-title">Preferred Quality</span>
+                <span class="component-desc">
+                    <% anyQualities, bestQualities = Quality.splitQuality(sickbeard.QUALITY_DEFAULT) %>
+                    <%include file="/inc_qualityChooser.mako"/>
+                </span>
+            </label>
+        </div>
+        
         % if sickbeard.USE_SUBTITLES:
         <br><div class="field-pair">
             <label for="subtitles" class="clearfix">
@@ -72,9 +83,6 @@
             </label>
         </div>
 
-        <% anyQualities, bestQualities = Quality.splitQuality(sickbeard.QUALITY_DEFAULT) %>
-        <%include file="/inc_qualityChooser.mako"/>
-
         <br>
         <div class="field-pair alt">
             <label for="saveDefaultsButton" class="nocheck clearfix">
diff --git a/gui/slick/views/layouts/main.mako b/gui/slick/views/layouts/main.mako
index 41f3702157c6cce92f5e20b01898109604545f7c..bd7b8cec570aaa70a07ef6912dfa339c2d93cad0 100644
--- a/gui/slick/views/layouts/main.mako
+++ b/gui/slick/views/layouts/main.mako
@@ -78,7 +78,6 @@
         <link rel="apple-touch-icon" href="${srRoot}/images/ico/favicon-57.png">
 
         <link rel="stylesheet" type="text/css" href="${srRoot}/css/vender.min.css?${sbPID}"/>
-        <link rel="stylesheet" type="text/css" href="${srRoot}/css/lib/bootstrap.min.css?${sbPID}"/>
         <link rel="stylesheet" type="text/css" href="${srRoot}/css/browser.css?${sbPID}" />
         <link rel="stylesheet" type="text/css" href="${srRoot}/css/lib/jquery-ui-1.10.4.custom.min.css?${sbPID}" />
         <link rel="stylesheet" type="text/css" href="${srRoot}/css/lib/jquery.qtip-2.2.1.min.css?${sbPID}"/>
diff --git a/gui/slick/views/trendingShows.mako b/gui/slick/views/trendingShows.mako
index 8dadb403549420755e3232896c02c12cae399377..d0c3dd29a0961db414c059ce7d14d6f683d00a1d 100644
--- a/gui/slick/views/trendingShows.mako
+++ b/gui/slick/views/trendingShows.mako
@@ -39,7 +39,7 @@
             <p>${int(cur_show['show']['rating']*10)}% <img src="${srRoot}/images/heart.png"></p>
             <i>${cur_show['show']['votes']} votes</i>
             <div class="traktShowTitleIcons">
-                <a href="${srRoot}/addShows/addShowByID?indexer_id=${cur_show['show']['ids']['tvdb']}&amp;show_name=${cur_show['show']['title']}" class="btn btn-xs" data-no-redirect>Add Show</a>
+                <a href="${srRoot}/addShows/addShowByID?indexer_id=${cur_show['show']['ids']['tvdb']}&amp;show_name=${cur_show['show']['title'] | u}" class="btn btn-xs" data-no-redirect>Add Show</a>
                 % if blacklist:
                 <a href="${srRoot}/addShows/addShowToBlacklist?indexer_id=${cur_show['show']['ids']['tvdb'] or cur_show['show']['ids']['tvrage']}" class="btn btn-xs">Remove Show</a>
                 % endif
diff --git a/gui/slick/views/viewlogs.mako b/gui/slick/views/viewlogs.mako
index 31e2e53815067fb5b72cb965d23e7966ef3b21eb..e22e8c2472a66ba9deba66075b595acd8f599da9 100644
--- a/gui/slick/views/viewlogs.mako
+++ b/gui/slick/views/viewlogs.mako
@@ -2,7 +2,7 @@
 <%!
     import sickbeard
     from sickbeard import classes
-    from sickbeard.logger import reverseNames
+    from sickbeard.logger import LOGGING_LEVELS
 %>
 <%block name="css">
 <style>
@@ -22,15 +22,15 @@ pre {
 
 <div class="h2footer pull-right">Minimum logging level to display: <select name="minLevel" id="minLevel" class="form-control form-control-inline input-sm">
     <%
-        levels = reverseNames.keys()
-        levels.sort(lambda x, y: cmp(reverseNames[x], reverseNames[y]))
+        levels = LOGGING_LEVELS.keys()
+        levels.sort(lambda x, y: cmp(LOGGING_LEVELS[x], LOGGING_LEVELS[y]))
         if not sickbeard.DEBUG:
             levels.remove('DEBUG')
         if not sickbeard.DBDEBUG:
             levels.remove('DB')
     %>
     % for level in levels:
-        <option value="${reverseNames[level]}" ${('', 'selected="selected"')[minLevel == reverseNames[level]]}>${level.title()}</option>
+        <option value="${LOGGING_LEVELS[level]}" ${('', 'selected="selected"')[minLevel == LOGGING_LEVELS[level]]}>${level.title()}</option>
     % endfor
     </select>
 
diff --git a/lib/stevedore/dispatch.py b/lib/stevedore/dispatch.py
index 226d3ae251925a91b799e47e8aa96a63f2f767f7..424d39b69ed2d6109733182eb0ada736e295b97e 100644
--- a/lib/stevedore/dispatch.py
+++ b/lib/stevedore/dispatch.py
@@ -1,6 +1,7 @@
 import logging
 
 from .enabled import EnabledExtensionManager
+from .exception import NoMatches
 
 LOG = logging.getLogger(__name__)
 
@@ -66,7 +67,7 @@ class DispatchExtensionManager(EnabledExtensionManager):
         """
         if not self.extensions:
             # FIXME: Use a more specific exception class here.
-            raise RuntimeError('No %s extensions found' % self.namespace)
+            raise NoMatches('No %s extensions found' % self.namespace)
         response = []
         for e in self.extensions:
             if filter_func(e, *args, **kwds):
diff --git a/lib/stevedore/driver.py b/lib/stevedore/driver.py
index fedc359bd5dbb7fc84b8e5cd43ad190c13ea4038..a2825aaaf14607aafa6ee78f08e01bf0406f3cbb 100644
--- a/lib/stevedore/driver.py
+++ b/lib/stevedore/driver.py
@@ -1,3 +1,4 @@
+from .exception import NoMatches, MultipleMatches
 from .named import NamedExtensionManager
 
 
@@ -93,14 +94,14 @@ class DriverManager(NamedExtensionManager):
 
         if not self.extensions:
             name = self._names[0]
-            raise RuntimeError('No %r driver found, looking for %r' %
-                               (self.namespace, name))
+            raise NoMatches('No %r driver found, looking for %r' %
+                            (self.namespace, name))
         if len(self.extensions) > 1:
             discovered_drivers = ','.join(e.entry_point_target
                                           for e in self.extensions)
 
-            raise RuntimeError('Multiple %r drivers found: %s' %
-                               (self.namespace, discovered_drivers))
+            raise MultipleMatches('Multiple %r drivers found: %s' %
+                                  (self.namespace, discovered_drivers))
 
     def __call__(self, func, *args, **kwds):
         """Invokes func() for the single loaded extension.
diff --git a/lib/stevedore/example/base.py b/lib/stevedore/example/base.py
index 1c8ca4ca361a7bb19504feaf68089ff7228029fc..ec95424ee177830f025bea92d3410bae651ea6eb 100644
--- a/lib/stevedore/example/base.py
+++ b/lib/stevedore/example/base.py
@@ -5,7 +5,7 @@ import six
 
 @six.add_metaclass(abc.ABCMeta)
 class FormatterBase(object):
-    """Base class for example plugin used in the tutoral.
+    """Base class for example plugin used in the tutorial.
     """
 
     def __init__(self, max_width=60):
diff --git a/lib/stevedore/example/setup.py b/lib/stevedore/example/setup.py
index afc7789c6e4005a83ad8640a1fc5d4feff85eca4..4289971f9a416ebf0e1a0b941f3e6fde885bc3e5 100644
--- a/lib/stevedore/example/setup.py
+++ b/lib/stevedore/example/setup.py
@@ -7,16 +7,14 @@ setup(
     description='Demonstration package for stevedore',
 
     author='Doug Hellmann',
-    author_email='doug.hellmann@dreamhost.com',
+    author_email='doug@doughellmann.com',
 
-    url='https://github.com/dreamhost/stevedore',
-    download_url='https://github.com/dreamhost/stevedore/tarball/master',
+    url='http://git.openstack.org/cgit/openstack/stevedore',
 
     classifiers=['Development Status :: 3 - Alpha',
                  'License :: OSI Approved :: Apache Software License',
                  'Programming Language :: Python',
                  'Programming Language :: Python :: 2',
-                 'Programming Language :: Python :: 2.6',
                  'Programming Language :: Python :: 2.7',
                  'Programming Language :: Python :: 3',
                  'Programming Language :: Python :: 3.4',
@@ -37,7 +35,6 @@ setup(
     entry_points={
         'stevedore.example.formatter': [
             'simple = stevedore.example.simple:Simple',
-            'field = stevedore.example.fields:FieldList',
             'plain = stevedore.example.simple:Simple',
         ],
     },
diff --git a/lib/stevedore/example2/__init__.py b/lib/stevedore/example2/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/stevedore/example/fields.py b/lib/stevedore/example2/fields.py
similarity index 100%
rename from lib/stevedore/example/fields.py
rename to lib/stevedore/example2/fields.py
diff --git a/lib/stevedore/example2/setup.py b/lib/stevedore/example2/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..17fe1300404e4c6ba16809a3deaecc8bb36e49d8
--- /dev/null
+++ b/lib/stevedore/example2/setup.py
@@ -0,0 +1,42 @@
+from setuptools import setup, find_packages
+
+setup(
+    name='stevedore-examples2',
+    version='1.0',
+
+    description='Demonstration package for stevedore',
+
+    author='Doug Hellmann',
+    author_email='doug@doughellmann.com',
+
+    url='http://git.openstack.org/cgit/openstack/stevedore',
+
+    classifiers=['Development Status :: 3 - Alpha',
+                 'License :: OSI Approved :: Apache Software License',
+                 'Programming Language :: Python',
+                 'Programming Language :: Python :: 2',
+                 'Programming Language :: Python :: 2.7',
+                 'Programming Language :: Python :: 3',
+                 'Programming Language :: Python :: 3.4',
+                 'Intended Audience :: Developers',
+                 'Environment :: Console',
+                 ],
+
+    platforms=['Any'],
+
+    scripts=[],
+
+    provides=['stevedore.examples2',
+              ],
+
+    packages=find_packages(),
+    include_package_data=True,
+
+    entry_points={
+        'stevedore.example.formatter': [
+            'field = stevedore.example2.fields:FieldList',
+        ],
+    },
+
+    zip_safe=False,
+)
diff --git a/lib/stevedore/exception.py b/lib/stevedore/exception.py
new file mode 100644
index 0000000000000000000000000000000000000000..10c5cc26bfe864e9e11136af851e38a7cc20cbd1
--- /dev/null
+++ b/lib/stevedore/exception.py
@@ -0,0 +1,10 @@
+class NoUniqueMatch(RuntimeError):
+    """There was more that one on no extensions matching the query."""
+
+
+class NoMatches(NoUniqueMatch):
+    """There were no extensions with the diver name found."""
+
+
+class MultipleMatches(NoUniqueMatch):
+    """There were multiple matches for the given name."""
diff --git a/lib/stevedore/extension.py b/lib/stevedore/extension.py
index 5da97c5d93efe7522fbaa5a28cbfbe9896bf3cfc..d2409885c633ab701c033172ac73160937d23c04 100644
--- a/lib/stevedore/extension.py
+++ b/lib/stevedore/extension.py
@@ -5,6 +5,7 @@ import pkg_resources
 
 import logging
 
+from .exception import NoMatches
 
 LOG = logging.getLogger(__name__)
 
@@ -218,7 +219,7 @@ class ExtensionManager(object):
         """
         if not self.extensions:
             # FIXME: Use a more specific exception class here.
-            raise RuntimeError('No %s extensions found' % self.namespace)
+            raise NoMatches('No %s extensions found' % self.namespace)
         response = []
         for e in self.extensions:
             self._invoke_one_plugin(response.append, func, e, args, kwds)
diff --git a/lib/stevedore/sphinxext.py b/lib/stevedore/sphinxext.py
index 524f9c93c8d17cec963e829f8f92c7c302e0bf7d..3c9b6ce7f9fcd46004473370ec0f12d503cbdb7f 100644
--- a/lib/stevedore/sphinxext.py
+++ b/lib/stevedore/sphinxext.py
@@ -36,12 +36,15 @@ def _simple_list(mgr):
               ext.entry_point.module_name)
 
 
-def _detailed_list(mgr, over='', under='-'):
+def _detailed_list(mgr, over='', under='-', titlecase=False):
     for name in sorted(mgr.names()):
         ext = mgr[name]
         if over:
             yield (over * len(ext.name), ext.entry_point.module_name)
-        yield (ext.name, ext.entry_point.module_name)
+        if titlecase:
+            yield (ext.name.title(), ext.entry_point.module_name)
+        else:
+            yield (ext.name, ext.entry_point.module_name)
         if under:
             yield (under * len(ext.name), ext.entry_point.module_name)
         yield ('\n', ext.entry_point.module_name)
@@ -61,6 +64,7 @@ class ListPluginsDirective(rst.Directive):
     option_spec = {
         'class': directives.class_option,
         'detailed': directives.flag,
+        'titlecase': directives.flag,
         'overline-style': directives.single_char_or_unicode,
         'underline-style': directives.single_char_or_unicode,
     }
@@ -86,9 +90,12 @@ class ListPluginsDirective(rst.Directive):
 
         result = ViewList()
 
+        titlecase = 'titlecase' in self.options
+
         if 'detailed' in self.options:
             data = _detailed_list(
-                mgr, over=overline_style, under=underline_style)
+                mgr, over=overline_style, under=underline_style,
+                titlecase=titlecase)
         else:
             data = _simple_list(mgr)
         for text, source in data:
diff --git a/lib/stevedore/tests/test_driver.py b/lib/stevedore/tests/test_driver.py
index ff9c3eac05744ca7acd72e72c3e4b055cdf30190..0a919cf76b1980263d067560eae9f54f6b7f2263 100644
--- a/lib/stevedore/tests/test_driver.py
+++ b/lib/stevedore/tests/test_driver.py
@@ -4,6 +4,7 @@
 import pkg_resources
 
 from stevedore import driver
+from stevedore import exception
 from stevedore import extension
 from stevedore.tests import test_extension
 from stevedore.tests import utils
@@ -37,7 +38,7 @@ class TestCallback(utils.TestCase):
     def test_no_drivers(self):
         try:
             driver.DriverManager('stevedore.test.extension.none', 't1')
-        except RuntimeError as err:
+        except exception.NoMatches as err:
             self.assertIn("No 'stevedore.test.extension.none' driver found",
                           str(err))
 
@@ -70,7 +71,7 @@ class TestCallback(utils.TestCase):
             dm = driver.DriverManager.make_test_instance(extensions[0])
             # Call the initialization code that verifies the extension
             dm._init_plugins(extensions)
-        except RuntimeError as err:
+        except exception.MultipleMatches as err:
             self.assertIn("Multiple", str(err))
         else:
             self.fail('Should have had an error')
diff --git a/lib/stevedore/tests/test_example_fields.py b/lib/stevedore/tests/test_example_fields.py
index a3eb39775ea02c0ffb273ecd6cfa6ebfee08593a..86aebf912f0f469d657531b40be4fc71c63cf626 100644
--- a/lib/stevedore/tests/test_example_fields.py
+++ b/lib/stevedore/tests/test_example_fields.py
@@ -1,7 +1,7 @@
-"""Tests for stevedore.exmaple.fields
+"""Tests for stevedore.example2.fields
 """
 
-from stevedore.example import fields
+from stevedore.example2 import fields
 from stevedore.tests import utils
 
 
diff --git a/lib/stevedore/tests/test_example_simple.py b/lib/stevedore/tests/test_example_simple.py
index b8ef43119f539f6a9a023c16b378d4a060016c56..2558fb7badb3d75dc1439d0536593dd61683cadf 100644
--- a/lib/stevedore/tests/test_example_simple.py
+++ b/lib/stevedore/tests/test_example_simple.py
@@ -1,4 +1,4 @@
-"""Tests for stevedore.exmaple.simple
+"""Tests for stevedore.example.simple
 """
 
 from stevedore.example import simple
diff --git a/lib/stevedore/tests/test_extension.py b/lib/stevedore/tests/test_extension.py
index b05b377682756efbd8115349d35e6d52a7ad952a..1fe02422e1e70f5b007ab09803767ff748d2e58c 100644
--- a/lib/stevedore/tests/test_extension.py
+++ b/lib/stevedore/tests/test_extension.py
@@ -3,6 +3,7 @@
 
 import mock
 
+from stevedore import exception
 from stevedore import extension
 from stevedore.tests import utils
 
@@ -159,7 +160,7 @@ class TestCallback(utils.TestCase):
                                         )
         try:
             em.map(mapped, 1, 2, a='A', b='B')
-        except RuntimeError as err:
+        except exception.NoMatches as err:
             self.assertEqual(expected_str, str(err))
 
     def test_map_method(self):
diff --git a/lib/subliminal/__init__.py b/lib/subliminal/__init__.py
index 4c0631efd474acb08cb4e46c56fc6a4968914597..25355a08ac99bae06b90931da603cea302c036ea 100644
--- a/lib/subliminal/__init__.py
+++ b/lib/subliminal/__init__.py
@@ -7,8 +7,8 @@ __copyright__ = 'Copyright 2015, Antoine Bertin'
 
 import logging
 
-from .api import (ProviderPool, check_video, provider_manager, download_best_subtitles, download_subtitles,
-                  list_subtitles, save_subtitles)
+from .api import (ProviderManager, ProviderPool, check_video, provider_manager, download_best_subtitles,
+                  download_subtitles, list_subtitles, save_subtitles)
 from .cache import region
 from .exceptions import Error, ProviderError
 from .providers import Provider
diff --git a/lib/subliminal/api.py b/lib/subliminal/api.py
index 3af8809a7d89644a099971b1839dc4bc131f94dd..81cd1e0e5a85b75746269588a25a1d12926e2c43 100644
--- a/lib/subliminal/api.py
+++ b/lib/subliminal/api.py
@@ -4,43 +4,102 @@ import io
 import logging
 import operator
 import os.path
+from pkg_resources import EntryPoint
 import socket
 
 from babelfish import Language
-from pkg_resources import EntryPoint
 import requests
-from stevedore import EnabledExtensionManager, ExtensionManager
+from stevedore import ExtensionManager
 
 from .subtitle import compute_score, get_subtitle_path
 
 logger = logging.getLogger(__name__)
 
 
-class InternalExtensionManager(ExtensionManager):
-    """Add support for internal entry points to the :class:`~stevedore.extension.Extensionmanager`
-    Internal entry points are useful for libraries that ship their own plugins but still keep the entry point open.
-    All other parameters are passed onwards to the :class:`~stevedore.extension.Extensionmanager` constructor.
-    :param internal_entry_points: the internal providers
-    :type internal_entry_points: list of :class:`~pkg_resources.EntryPoint`
+class ProviderManager(ExtensionManager):
+    """Manager for providers based on :class:`~stevedore.extension.ExtensionManager`.
+
+    It allows loading of internal providers without setup and registering/unregistering additional providers.
+
+    Loading is done in this order:
+
+    * Entry point providers
+    * Internal providers
+    * Registered providers
+
     """
-    def __init__(self, namespace, internal_entry_points, **kwargs):
-        self.internal_entry_points = list(internal_entry_points)
-        super(InternalExtensionManager, self).__init__(namespace, **kwargs)
+    internal_providers = [
+      'addic7ed = subliminal.providers.addic7ed:Addic7edProvider',
+      'opensubtitles = subliminal.providers.opensubtitles:OpenSubtitlesProvider',
+      'podnapisi = subliminal.providers.podnapisi:PodnapisiProvider',
+      'subscenter = subliminal.providers.subscenter:SubsCenterProvider',
+      'thesubdb = subliminal.providers.thesubdb:TheSubDBProvider',
+      'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider'
+    ]
+
+    def __init__(self):
+        #: Registered providers with entry point syntax
+        self.registered_providers = []
+
+        super(ProviderManager, self).__init__('subliminal.providers')
 
     def _find_entry_points(self, namespace):
-        return self.internal_entry_points + super(InternalExtensionManager, self)._find_entry_points(namespace)
+        # default entry points
+        eps = super(ProviderManager, self)._find_entry_points(namespace)
+
+        # internal entry points
+        for iep in self.internal_providers:
+            ep = EntryPoint.parse(iep)
+            if ep.name not in [e.name for e in eps]:
+                eps.append(ep)
+
+        # registered entry points
+        for rep in self.registered_providers:
+            ep = EntryPoint.parse(rep)
+            if ep.name not in [e.name for e in eps]:
+                eps.append(ep)
+
+        return eps
 
+    def register(self, entry_point):
+        """Register a provider
 
-provider_manager = InternalExtensionManager('subliminal.providers', [EntryPoint.parse(ep) for ep in (
-    'addic7ed = subliminal.providers.addic7ed:Addic7edProvider',
-    'legendastv = subliminal.providers.legendastv:LegendasTvProvider',
-    'napiprojekt = subliminal.providers.napiprojekt:NapiProjektProvider',
-    'opensubtitles = subliminal.providers.opensubtitles:OpenSubtitlesProvider',
-    'podnapisi = subliminal.providers.podnapisi:PodnapisiProvider',
-    'subscenter = subliminal.providers.subscenter:SubsCenterProvider',
-    'thesubdb = subliminal.providers.thesubdb:TheSubDBProvider',
-    'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider'
-)])
+        :param str entry_point: provider to register (entry point syntax)
+        :raise: ValueError if already registered
+
+        """
+        if entry_point in self.registered_providers:
+            raise ValueError('Entry point already registered')
+
+        ep = EntryPoint.parse(entry_point)
+        if ep.name in self.names():
+            raise ValueError('A provider with the same name already exist')
+
+        ext = self._load_one_plugin(ep, False, (), {}, False)
+        self.extensions.append(ext)
+        if self._extensions_by_name is not None:
+            self._extensions_by_name[ext.name] = ext
+        self.registered_providers.insert(0, entry_point)
+
+    def unregister(self, entry_point):
+        """Unregister a provider
+
+        :param str entry_point: provider to unregister (entry point syntax)
+
+        """
+        if entry_point not in self.registered_providers:
+            raise ValueError('Entry point not registered')
+
+        ep = EntryPoint.parse(entry_point)
+        self.registered_providers.remove(entry_point)
+        if self._extensions_by_name is not None:
+            del self._extensions_by_name[ep.name]
+        for i, ext in enumerate(self.extensions):
+            if ext.name == ep.name:
+                del self.extensions[i]
+                break
+
+provider_manager = ProviderManager()
 
 
 class ProviderPool(object):
@@ -52,8 +111,7 @@ class ProviderPool(object):
           the providers on exit.
         * Automatically discard providers on failure.
 
-    :param providers: name of providers to use, if not all.
-    :type providers: list
+    :param list providers: name of providers to use, if not all.
     :param dict provider_configs: provider configuration as keyword arguments per provider name to pass when
         instanciating the :class:`~subliminal.providers.Provider`.
 
@@ -71,9 +129,6 @@ class ProviderPool(object):
         #: Discarded providers
         self.discarded_providers = set()
 
-        #: Dedicated :data:`provider_manager` as :class:`~stevedore.enabled.EnabledExtensionManager`
-        self.manager = EnabledExtensionManager(provider_manager.namespace, lambda e: e.name in self.providers)
-
     def __enter__(self):
         return self
 
@@ -81,9 +136,11 @@ class ProviderPool(object):
         self.terminate()
 
     def __getitem__(self, name):
+        if name not in self.providers:
+            raise KeyError
         if name not in self.initialized_providers:
             logger.info('Initializing provider %s', name)
-            provider = self.manager[name].plugin(**self.provider_configs.get(name, {}))
+            provider = provider_manager[name].plugin(**self.provider_configs.get(name, {}))
             provider.initialize()
             self.initialized_providers[name] = provider
 
@@ -126,12 +183,12 @@ class ProviderPool(object):
                 continue
 
             # check video validity
-            if not self.manager[name].plugin.check(video):
+            if not provider_manager[name].plugin.check(video):
                 logger.info('Skipping provider %r: not a valid video', name)
                 continue
 
             # check supported languages
-            provider_languages = self.manager[name].plugin.languages & languages
+            provider_languages = provider_manager[name].plugin.languages & languages
             if not provider_languages:
                 logger.info('Skipping provider %r: no language to search for', name)
                 continue
diff --git a/lib/subliminal/providers/addic7ed.py b/lib/subliminal/providers/addic7ed.py
index 6061319cb0f55c7c8286ceca7bdc173841bb5177..f00273f9579c0a2cc2aa1239fbcef5f8ad5590de 100644
--- a/lib/subliminal/providers/addic7ed.py
+++ b/lib/subliminal/providers/addic7ed.py
@@ -14,6 +14,7 @@ from ..subtitle import (Subtitle, fix_line_ending, guess_matches, guess_properti
 from ..video import Episode
 
 logger = logging.getLogger(__name__)
+
 language_converters.register('addic7ed = subliminal.converters.addic7ed:Addic7edConverter')
 
 series_year_re = re.compile('^(?P<series>[ \w\'.:]+)(?: \((?P<year>\d{4})\))?$')
diff --git a/lib/subliminal/providers/legendastv.py b/lib/subliminal/providers/legendastv.py
index 888f5cad2c4fbbda4b7acd1e0bc9a69dffd62feb..258e73647f8fb42a888512d51a5649c211dc762b 100644
--- a/lib/subliminal/providers/legendastv.py
+++ b/lib/subliminal/providers/legendastv.py
@@ -20,6 +20,7 @@ from ..video import Episode, Movie, SUBTITLE_EXTENSIONS
 TIMEOUT = 10
 
 logger = logging.getLogger(__name__)
+
 language_converters.register('legendastv = subliminal.converters.legendastv:LegendasTvConverter')
 
 
diff --git a/lib/subliminal/providers/opensubtitles.py b/lib/subliminal/providers/opensubtitles.py
index 5a06a23b84cdc0f59a175f9e2789b1a1ee06aa28..3bd49e6cc0f1f1038eb7f45dd0aa76fd5132305d 100644
--- a/lib/subliminal/providers/opensubtitles.py
+++ b/lib/subliminal/providers/opensubtitles.py
@@ -121,13 +121,15 @@ class OpenSubtitlesProvider(Provider):
         logger.debug('No operation')
         checked(self.server.NoOperation(self.token))
 
-    def query(self, languages, hash=None, size=None, imdb_id=None, query=None, season=None, episode=None):
+    def query(self, languages, hash=None, size=None, imdb_id=None, query=None, season=None, episode=None, tag=None):
         # fill the search criteria
         criteria = []
         if hash and size:
             criteria.append({'moviehash': hash, 'moviebytesize': str(size)})
         if imdb_id:
             criteria.append({'imdbid': imdb_id})
+        if tag:
+            criteria.append({'tag': tag})
         if query and season and episode:
             criteria.append({'query': query.replace('\'', ''), 'season': season, 'episode': episode})
         elif query:
@@ -176,16 +178,16 @@ class OpenSubtitlesProvider(Provider):
         return subtitles
 
     def list_subtitles(self, video, languages):
-        query = season = episode = None
+        season = episode = None
         if isinstance(video, Episode):
             query = video.series
             season = video.season
             episode = video.episode
-        elif ('opensubtitles' not in video.hashes or not video.size) and not video.imdb_id:
-            query = video.name.split(os.sep)[-1]
+        else:
+            query = video.title
 
         return self.query(languages, hash=video.hashes.get('opensubtitles'), size=video.size, imdb_id=video.imdb_id,
-                          query=query, season=season, episode=episode)
+                          query=query, season=season, episode=episode, tag=os.path.basename(video.name))
 
     def download_subtitle(self, subtitle):
         logger.info('Downloading subtitle %r', subtitle)
diff --git a/lib/subliminal/providers/thesubdb.py b/lib/subliminal/providers/thesubdb.py
index f7f1f2451bc5400e4b4b0335c8584ddee1eee4ac..da325aaf9f8ab573597c4836447bac6b54f865c7 100644
--- a/lib/subliminal/providers/thesubdb.py
+++ b/lib/subliminal/providers/thesubdb.py
@@ -10,8 +10,10 @@ from ..subtitle import Subtitle, fix_line_ending
 
 
 logger = logging.getLogger(__name__)
+
 language_converters.register('thesubdb = subliminal.converters.thesubdb:TheSubDBConverter')
 
+
 class TheSubDBSubtitle(Subtitle):
     provider_name = 'thesubdb'
 
diff --git a/lib/subliminal/providers/tvsubtitles.py b/lib/subliminal/providers/tvsubtitles.py
index 8c4433fc966bd5b0b54eba9b99dfab2291e6db9b..0b491c39e3f631afd5de98f3094bbb45acd8c5f4 100644
--- a/lib/subliminal/providers/tvsubtitles.py
+++ b/lib/subliminal/providers/tvsubtitles.py
@@ -15,6 +15,7 @@ from ..subtitle import Subtitle, fix_line_ending, guess_matches, guess_propertie
 from ..video import Episode
 
 logger = logging.getLogger(__name__)
+
 language_converters.register('tvsubtitles = subliminal.converters.tvsubtitles:TVsubtitlesConverter')
 
 link_re = re.compile('^(?P<series>.+?)(?: \(?\d{4}\)?| \((?:US|UK)\))? \((?P<first_year>\d{4})-\d{4}\)$')
diff --git a/lib/subliminal/video.py b/lib/subliminal/video.py
index b04d535cb60f25ddfb4023837cb9d99ff278a9f1..3384e7b3e3fb8197de318e799078d681e4420ee7 100644
--- a/lib/subliminal/video.py
+++ b/lib/subliminal/video.py
@@ -7,7 +7,7 @@ import os
 import struct
 
 from babelfish import Error as BabelfishError, Language
-from enzyme import Error as EnzymeError, MKV
+from enzyme import MKV
 from guessit import guess_episode_info, guess_file_info, guess_movie_info
 
 logger = logging.getLogger(__name__)
diff --git a/readme.md b/readme.md
index 90d9b117a878cb1cb479daec6927c11ae372f99a..b1816fa1ed8395d4814c54de9574a0bea63a92da 100644
--- a/readme.md
+++ b/readme.md
@@ -39,7 +39,7 @@ Automatic Video Library Manager for TV Shows. It watches for new episodes of you
 
 #### Important
 Before using this with your existing database (sickbeard.db) please make a backup copy of it and delete any other database files such as cache.db and failed.db if present<br>
-We HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own risk
+We HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own risk.
 
 #### Supported providers
 
@@ -48,7 +48,7 @@ A full list can be found here: [Link](https://github.com/SickRage/sickrage-issue
 #### Special Thanks to:
 ![image](https://rarbg.com/favicon.ico)[RARBG](https://rarbg.to)
 ![image](https://torrentproject.se/favicon.ico)[TorrentProject](https://torrentproject.se/about)
-![image](https://thepiratebay.la/favicon.ico)[ThePirateBay](https://thepiratebay.la/)
+![image](https://thepiratebay.se/favicon.ico)[ThePirateBay](https://thepiratebay.se/)
 ![image](http://kat.cr/favicon.ico)[KickAssTorrents](https://kat.cr)
 ![image](https://nzb.cat/favicon.ico)[NZB.cat](https://nzb.cat/)
 ![image](https://nzbgeek.info/favicon.ico)[NZBGeek](https://nzbgeek.info)
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 904c818b9adec751b983044e6a5504824be579c7..f459eaa345995518b4b77f1239f8aba417582688 100644
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import webbrowser
 import datetime
@@ -112,8 +112,7 @@ autoPostProcesserScheduler = None
 subtitlesFinderScheduler = None
 traktCheckerScheduler = None
 
-showList = None
-loadingShowList = None
+showList = []
 
 providerList = []
 newznabProviderList = []
@@ -375,6 +374,13 @@ FREEMOBILE_NOTIFY_ONSUBTITLEDOWNLOAD = False
 FREEMOBILE_ID = ''
 FREEMOBILE_APIKEY = ''
 
+USE_TELEGRAM = False
+TELEGRAM_NOTIFY_ONSNATCH = False
+TELEGRAM_NOTIFY_ONDOWNLOAD = False
+TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = False
+TELEGRAM_ID = ''
+TELEGRAM_APIKEY = ''
+
 USE_PROWL = False
 PROWL_NOTIFY_ONSNATCH = False
 PROWL_NOTIFY_ONDOWNLOAD = False
@@ -590,10 +596,11 @@ def initialize(consoleLogging=True):
             USE_PLEX_SERVER, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_UPDATE_LIBRARY, USE_PLEX_CLIENT, PLEX_CLIENT_USERNAME, PLEX_CLIENT_PASSWORD, \
             PLEX_SERVER_HOST, PLEX_SERVER_TOKEN, PLEX_CLIENT_HOST, PLEX_SERVER_USERNAME, PLEX_SERVER_PASSWORD, PLEX_SERVER_HTTPS, MIN_BACKLOG_FREQUENCY, SKIP_REMOVED_FILES, ALLOWED_EXTENSIONS, \
             USE_EMBY, EMBY_HOST, EMBY_APIKEY, \
-            showUpdateScheduler, __INITIALIZED__, INDEXER_DEFAULT_LANGUAGE, EP_DEFAULT_DELETED_STATUS, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, SORT_ARTICLE, showList, loadingShowList, \
+            showUpdateScheduler, __INITIALIZED__, INDEXER_DEFAULT_LANGUAGE, EP_DEFAULT_DELETED_STATUS, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, SORT_ARTICLE, showList, \
             NEWZNAB_DATA, NZBS, NZBS_UID, NZBS_HASH, INDEXER_DEFAULT, INDEXER_TIMEOUT, USENET_RETENTION, TORRENT_DIR, \
             QUALITY_DEFAULT, FLATTEN_FOLDERS_DEFAULT, SUBTITLES_DEFAULT, STATUS_DEFAULT, STATUS_DEFAULT_AFTER, \
             GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSUBTITLEDOWNLOAD, USE_FREEMOBILE, FREEMOBILE_ID, FREEMOBILE_APIKEY, FREEMOBILE_NOTIFY_ONSNATCH, FREEMOBILE_NOTIFY_ONDOWNLOAD, FREEMOBILE_NOTIFY_ONSUBTITLEDOWNLOAD, \
+            USE_TELEGRAM, TELEGRAM_ID, TELEGRAM_APIKEY, TELEGRAM_NOTIFY_ONSNATCH, TELEGRAM_NOTIFY_ONDOWNLOAD, TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD, \
             USE_GROWL, GROWL_HOST, GROWL_PASSWORD, USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_NOTIFY_ONSUBTITLEDOWNLOAD, PROWL_API, PROWL_PRIORITY, PROWL_MESSAGE_TITLE, \
             USE_PYTIVO, PYTIVO_NOTIFY_ONSNATCH, PYTIVO_NOTIFY_ONDOWNLOAD, PYTIVO_NOTIFY_ONSUBTITLEDOWNLOAD, PYTIVO_UPDATE_LIBRARY, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME, \
             USE_NMA, NMA_NOTIFY_ONSNATCH, NMA_NOTIFY_ONDOWNLOAD, NMA_NOTIFY_ONSUBTITLEDOWNLOAD, NMA_API, NMA_PRIORITY, \
@@ -679,14 +686,14 @@ def initialize(consoleLogging=True):
             fileLogging = False
 
         # init logging
-        logger.initLogging(consoleLogging=consoleLogging, fileLogging=fileLogging, debugLogging=DEBUG, databaseLogging=DBDEBUG)
+        logger.init_logging(console_logging=consoleLogging, file_logging=fileLogging, debug_logging=DEBUG, database_logging=DBDEBUG)
 
         # github api
         try:
             if not (GIT_USERNAME and GIT_PASSWORD):
-                gh = Github(user_agent="SiCKRAGE").get_organization(GIT_ORG).get_repo(GIT_REPO)
+                gh = Github(user_agent="SickRage").get_organization(GIT_ORG).get_repo(GIT_REPO)
             else:
-                gh = Github(login_or_token=GIT_USERNAME, password=GIT_PASSWORD, user_agent="SiCKRAGE").get_organization(GIT_ORG).get_repo(GIT_REPO)
+                gh = Github(login_or_token=GIT_USERNAME, password=GIT_PASSWORD, user_agent="SickRage").get_organization(GIT_ORG).get_repo(GIT_REPO)
         except Exception as e:
             gh = None
             logger.log(u'Unable to setup GitHub properly. GitHub will not be available. Error: %s' % str(e), logger.WARNING)
@@ -756,11 +763,12 @@ def initialize(consoleLogging=True):
                 except Exception as e:
                     logger.log(u"Restore: Unable to remove the restore directory: {0}".format(ex(e)), logger.ERROR)
 
-                for cleanupDir in ['mako', 'sessions', 'indexers']:
+                for cleanupDir in ['mako', 'sessions', 'indexers', 'rss']:
                     try:
                         shutil.rmtree(ek(os.path.join, CACHE_DIR, cleanupDir))
                     except Exception as e:
-                        logger.log(u"Restore: Unable to remove the cache/{0} directory: {1}".format(cleanupDir, ex(e)), logger.WARNING)
+                        if cleanupDir not in ['rss', 'sessions', 'indexers']:
+                            logger.log(u"Restore: Unable to remove the cache/{0} directory: {1}".format(cleanupDir, ex(e)), logger.WARNING)
 
         GUI_NAME = check_setting_str(CFG, 'GUI', 'gui_name', 'slick')
 
@@ -1021,6 +1029,13 @@ def initialize(consoleLogging=True):
         FREEMOBILE_ID = check_setting_str(CFG, 'FreeMobile', 'freemobile_id', '')
         FREEMOBILE_APIKEY = check_setting_str(CFG, 'FreeMobile', 'freemobile_apikey', '')
 
+        USE_TELEGRAM = bool(check_setting_int(CFG, 'Telegram', 'use_telegram', 0))
+        TELEGRAM_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_onsnatch', 0))
+        TELEGRAM_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_ondownload', 0))
+        TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_onsubtitledownload', 0))
+        TELEGRAM_ID = check_setting_str(CFG, 'Telegram', 'telegram_id', '')
+        TELEGRAM_APIKEY = check_setting_str(CFG, 'Telegram', 'telegram_apikey', '')
+
         USE_PROWL = bool(check_setting_int(CFG, 'Prowl', 'use_prowl', 0))
         PROWL_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_notify_onsnatch', 0))
         PROWL_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Prowl', 'prowl_notify_ondownload', 0))
@@ -1452,9 +1467,6 @@ def initialize(consoleLogging=True):
                                                        threadName="FINDSUBTITLES",
                                                        silent=not USE_SUBTITLES)
 
-        showList = []
-        loadingShowList = {}
-
         __INITIALIZED__ = True
         return True
 
@@ -1933,6 +1945,14 @@ def save_config():
     new_config['FreeMobile']['freemobile_id'] = FREEMOBILE_ID
     new_config['FreeMobile']['freemobile_apikey'] = FREEMOBILE_APIKEY
 
+    new_config['Telegram'] = {}
+    new_config['Telegram']['use_telegram'] = int(USE_TELEGRAM)
+    new_config['Telegram']['telegram_notify_onsnatch'] = int(TELEGRAM_NOTIFY_ONSNATCH)
+    new_config['Telegram']['telegram_notify_ondownload'] = int(TELEGRAM_NOTIFY_ONDOWNLOAD)
+    new_config['Telegram']['telegram_notify_onsubtitledownload'] = int(TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD)
+    new_config['Telegram']['telegram_id'] = TELEGRAM_ID
+    new_config['Telegram']['telegram_apikey'] = TELEGRAM_APIKEY
+
     new_config['Prowl'] = {}
     new_config['Prowl']['use_prowl'] = int(USE_PROWL)
     new_config['Prowl']['prowl_notify_onsnatch'] = int(PROWL_NOTIFY_ONSNATCH)
diff --git a/sickbeard/auto_postprocessor.py b/sickbeard/auto_postprocessor.py
index b9a281fbd784c1f4d036e6f51cc96e1ce655e22f..ee7c06f629d7a05748ea1d5a0da77611d00bffa6 100644
--- a/sickbeard/auto_postprocessor.py
+++ b/sickbeard/auto_postprocessor.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os.path
 import threading
@@ -47,7 +47,7 @@ class PostProcessor(object):
             return
 
         if not (force or ek(os.path.isabs, sickbeard.TV_DOWNLOAD_DIR)):
-            logger.log(u"Automatic post-processing attempted but directory is relatve "
+            logger.log(u"Automatic post-processing attempted but directory is relative "
                        u"(and probably not what you really want to process): %s" %
                        sickbeard.TV_DOWNLOAD_DIR, logger.ERROR)
             self.amActive = False
diff --git a/sickbeard/blackandwhitelist.py b/sickbeard/blackandwhitelist.py
index 5d8330fab6babf06944337c5d2057bdaad370580..cef6466b73fefef1389faf6f6ee92e8e9a9a45b5 100644
--- a/sickbeard/blackandwhitelist.py
+++ b/sickbeard/blackandwhitelist.py
@@ -12,11 +12,11 @@
 #
 # Sick Beard 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 from sickbeard import db, logger, helpers
diff --git a/sickbeard/browser.py b/sickbeard/browser.py
index e4853f460bb968aa57fe4e7fc45d9067b46ab066..36d4d9edbb8324c11ef9eb703b7991c62410b73c 100644
--- a/sickbeard/browser.py
+++ b/sickbeard/browser.py
@@ -12,11 +12,13 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import unicode_literals
 
 import os
 import string
@@ -43,31 +45,31 @@ def getWinDrives():
 
 def getFileList(path, includeFiles):
     # prune out directories to protect the user from doing stupid things (already lower case the dir to reduce calls)
-    hideList = ["boot", "bootmgr", "cache", "config.msi", "msocache", "recovery", "$recycle.bin",
-                "recycler", "system volume information", "temporary internet files"]  # windows specific
-    hideList += [".fseventd", ".spotlight", ".trashes", ".vol", "cachedmessages", "caches", "trash"]  # osx specific
-    hideList += [".git"]
+    hide_list = ['boot', 'bootmgr', 'cache', 'config.msi', 'msocache', 'recovery', '$recycle.bin',
+                 'recycler', 'system volume information', 'temporary internet files']  # windows specific
+    hide_list += ['.fseventd', '.spotlight', '.trashes', '.vol', 'cachedmessages', 'caches', 'trash']  # osx specific
+    hide_list += ['.git']
 
-    fileList = []
+    file_list = []
     for filename in ek(os.listdir, path):
-        if filename.lower() in hideList:
+        if filename.lower() in hide_list:
             continue
 
-        fullFilename = ek(os.path.join, path, filename)
-        isDir = ek(os.path.isdir, fullFilename)
+        full_filename = ek(os.path.join, path, filename)
+        is_dir = ek(os.path.isdir, full_filename)
 
-        if not includeFiles and not isDir:
+        if not includeFiles and not is_dir:
             continue
 
         entry = {
             'name': filename,
-            'path': fullFilename
+            'path': full_filename
         }
-        if not isDir:
+        if not is_dir:
             entry['isFile'] = True
-        fileList.append(entry)
+        file_list.append(entry)
 
-    return fileList
+    return file_list
 
 
 def foldersAtPath(path, includeParent=False, includeFiles=False):
@@ -88,36 +90,36 @@ def foldersAtPath(path, includeParent=False, includeFiles=False):
         else:
             path = ek(os.path.dirname, path)
 
-    if path == "":
+    if path == '':
         if os.name == 'nt':
             entries = [{'currentPath': 'Root'}]
             for letter in getWinDrives():
-                letterPath = letter + ':\\'
-                entries.append({'name': letterPath, 'path': letterPath})
+                letter_path = letter + ':\\'
+                entries.append({'name': letter_path, 'path': letter_path})
             return entries
         else:
             path = '/'
 
     # fix up the path and find the parent
     path = ek(os.path.abspath, ek(os.path.normpath, path))
-    parentPath = ek(os.path.dirname, path)
+    parent_path = ek(os.path.dirname, path)
 
     # if we're at the root then the next step is the meta-node showing our drive letters
-    if path == parentPath and os.name == 'nt':
-        parentPath = ""
+    if path == parent_path and os.name == 'nt':
+        parent_path = ''
 
     try:
-        fileList = getFileList(path, includeFiles)
+        file_list = getFileList(path, includeFiles)
     except OSError as e:
-        logger.log(u"Unable to open " + path + ": " + repr(e) + " / " + str(e), logger.WARNING)
-        fileList = getFileList(parentPath, includeFiles)
+        logger.log('Unable to open %s: %s / %s' % (path, repr(e), str(e)), logger.WARNING)
+        file_list = getFileList(parent_path, includeFiles)
 
-    fileList = sorted(fileList,
-                      lambda x, y: cmp(ek(os.path.basename, x['name']).lower(), ek(os.path.basename, y['path']).lower()))
+    file_list = sorted(file_list,
+                       lambda x, y: cmp(ek(os.path.basename, x['name']).lower(), ek(os.path.basename, y['path']).lower()))
 
     entries = [{'currentPath': path}]
-    if includeParent and parentPath != path:
-        entries.append({'name': "..", 'path': parentPath})
-    entries.extend(fileList)
+    if includeParent and parent_path != path:
+        entries.append({'name': '..', 'path': parent_path})
+    entries.extend(file_list)
 
     return entries
diff --git a/sickbeard/bs4_parser.py b/sickbeard/bs4_parser.py
index 43afa8bd65f8d99475bbb6f26b6cf6e7c77b6459..5fb58c20285e69e6f64ce532dff5c05e284253b5 100644
--- a/sickbeard/bs4_parser.py
+++ b/sickbeard/bs4_parser.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from bs4 import BeautifulSoup
 
diff --git a/sickbeard/classes.py b/sickbeard/classes.py
index f59265c139258e431b46319427c4357f81c19380..6e87566fed218866337ab08cec7b9150ed77cf4b 100644
--- a/sickbeard/classes.py
+++ b/sickbeard/classes.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 import re
 import sys
 
diff --git a/sickbeard/clients/__init__.py b/sickbeard/clients/__init__.py
index f1e67523c4484d193c3389757158f6dd91d8fd3f..8be031eeb336d355d96e334a288672e52c594c88 100644
--- a/sickbeard/clients/__init__.py
+++ b/sickbeard/clients/__init__.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 __all__ = [
     'utorrent',
diff --git a/sickbeard/clients/deluge_client.py b/sickbeard/clients/deluge_client.py
index 6e6a92a141c3990fa9b5ea42f32d4d246db10434..9ac79d8317883c4097ca39ac0b8d8e3d7a0f240e 100644
--- a/sickbeard/clients/deluge_client.py
+++ b/sickbeard/clients/deluge_client.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import json
 from base64 import b64encode
diff --git a/sickbeard/clients/mlnet_client.py b/sickbeard/clients/mlnet_client.py
index abd4634a0bd71d1b51269c37cb5182c7665b51a2..c5fe1926d69f67406a83f6f969177bca186ed16e 100644
--- a/sickbeard/clients/mlnet_client.py
+++ b/sickbeard/clients/mlnet_client.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard.clients.generic import GenericClient
 
diff --git a/sickbeard/clients/qbittorrent_client.py b/sickbeard/clients/qbittorrent_client.py
index d68e12f75e94843318f73c11b07e6cb282199ea6..dcd008525e3cba26ed2218a6df2556ab33463e64 100644
--- a/sickbeard/clients/qbittorrent_client.py
+++ b/sickbeard/clients/qbittorrent_client.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 from sickbeard import logger
@@ -82,9 +82,9 @@ class qbittorrentAPI(GenericClient):
         if result.show.is_anime:
             label = sickbeard.TORRENT_LABEL_ANIME
 
-        if self.api > 6:
+        if self.api > 6 and label:
             self.url = self.host + 'command/setLabel'
-            data = {'hashes': result.hash.lower(), 'label': label}
+            data = {'hashes': result.hash.lower(), 'label': label.replace(' ','_')}
             return self._request(method='post', data=data, cookies=self.session.cookies)
         return None
 
diff --git a/sickbeard/clients/rtorrent_client.py b/sickbeard/clients/rtorrent_client.py
index a7bf52aaae5a53eaa6d8da590e39553a19d503a2..5fe7e4b2f4c888e223196c9d89120267c91c21fe 100644
--- a/sickbeard/clients/rtorrent_client.py
+++ b/sickbeard/clients/rtorrent_client.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import traceback
 
diff --git a/sickbeard/clients/transmission_client.py b/sickbeard/clients/transmission_client.py
index c26a8391271e5bb51138e10eed47932fff194648..6a1d42c57e6449284a61ecf2b6e001c7f0c1d230 100644
--- a/sickbeard/clients/transmission_client.py
+++ b/sickbeard/clients/transmission_client.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import json
diff --git a/sickbeard/clients/utorrent_client.py b/sickbeard/clients/utorrent_client.py
index 68a8a7ec63263f3ddf97c685128249481dee4298..05b26d094dca2d91e13399e4ec22fb7fce8179ff 100644
--- a/sickbeard/clients/utorrent_client.py
+++ b/sickbeard/clients/utorrent_client.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 
diff --git a/sickbeard/common.py b/sickbeard/common.py
index d28c3654e9a657d6726504772f674b066552462c..9f68d6fb7595dab3207c6e2a353b16978fcc4000 100644
--- a/sickbeard/common.py
+++ b/sickbeard/common.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Common interface for Quality and Status
diff --git a/sickbeard/config.py b/sickbeard/config.py
index 5b6ce6acf6eabcd7e8d0cf44aa2d1f81917f33df..caaa003fcb2887e8c28d0fa548d690feba736d7a 100644
--- a/sickbeard/config.py
+++ b/sickbeard/config.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os.path
 import datetime
@@ -117,7 +117,7 @@ def change_LOG_DIR(log_dir, web_log):
             sickbeard.ACTUAL_LOG_DIR = ek(os.path.normpath, log_dir)
             sickbeard.LOG_DIR = abs_log_dir
 
-            logger.initLogging()
+            logger.init_logging()
             logger.log(u"Initialized new log file in " + sickbeard.LOG_DIR)
             log_dir_changed = True
 
@@ -592,9 +592,9 @@ def check_setting_str(config, cfg_name, item_name, def_val, silent=True, censor_
             config[cfg_name] = {}
             config[cfg_name][item_name] = helpers.encrypt(my_val, encryption_version)
 
-    if censor_log or (cfg_name, item_name) in logger.censoredItems.iteritems():
+    if censor_log or (cfg_name, item_name) in logger.censored_items.iteritems():
         if not item_name.endswith('custom_url'):
-            logger.censoredItems[cfg_name, item_name] = my_val
+            logger.censored_items[cfg_name, item_name] = my_val
 
     if not silent:
         logger.log(item_name + " -> " + my_val, logger.DEBUG)
diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py
index 0d47acd9622e033e196c161bef54b24cf4e4ae90..64152a28deb9b8f4bbf26af48d91ceec49c22991 100644
--- a/sickbeard/dailysearcher.py
+++ b/sickbeard/dailysearcher.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import threading
diff --git a/sickbeard/databases/__init__.py b/sickbeard/databases/__init__.py
index 2e67a9dd6a0c8ced186cafd0005d0066ebe250e3..0d2c8b8080695aac5bacd00ba41287ddb1039f64 100644
--- a/sickbeard/databases/__init__.py
+++ b/sickbeard/databases/__init__.py
@@ -12,10 +12,10 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 __all__ = ["mainDB", "cache", "failed"]
diff --git a/sickbeard/databases/cache_db.py b/sickbeard/databases/cache_db.py
index 5b4c2d1a04627f484f4ee1af4db837fa36fd5898..ea2ca13bc262d8c512c40ea2dde86d9aa7157639 100644
--- a/sickbeard/databases/cache_db.py
+++ b/sickbeard/databases/cache_db.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard import db
 
diff --git a/sickbeard/databases/failed_db.py b/sickbeard/databases/failed_db.py
index 6a91a8af1c042300c5c5517b25742b1571f8745b..05c21c685cdab0e43f90f7d24993758c7b747db7 100644
--- a/sickbeard/databases/failed_db.py
+++ b/sickbeard/databases/failed_db.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard import db
 from sickbeard.common import Quality
diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py
index 62af35149a123ed32d3920b20ae270cb3562c0e7..59f56709d73ed4d2fcdfca7520aac824fb4314fd 100644
--- a/sickbeard/databases/mainDB.py
+++ b/sickbeard/databases/mainDB.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 
diff --git a/sickbeard/db.py b/sickbeard/db.py
index 584efe471e34b1dd8a19949d791db12687320818..781e0527b3b19056d094b4711c60e896d3dee1ff 100644
--- a/sickbeard/db.py
+++ b/sickbeard/db.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 
 import os.path
diff --git a/sickbeard/failedProcessor.py b/sickbeard/failedProcessor.py
index 3b794c9ac2b0ee0d4725b690dba2772d0900cb65..2b8675aaa60efa8f5c67847866e302b4f7f39174 100644
--- a/sickbeard/failedProcessor.py
+++ b/sickbeard/failedProcessor.py
@@ -12,7 +12,7 @@
 #
 # 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
+# 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
diff --git a/sickbeard/failed_history.py b/sickbeard/failed_history.py
index 052e7a3fa50153a098fb16fecc5b403bfe114962..e86576ff7d03d8cda4a9b7893020de0663202bc8 100644
--- a/sickbeard/failed_history.py
+++ b/sickbeard/failed_history.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import urllib
diff --git a/sickbeard/generic_queue.py b/sickbeard/generic_queue.py
index e999a57895a8ad4622675a6974426927ef35c41d..bdb917f0d404b83521628b7e69c1ccf0ffd214c2 100644
--- a/sickbeard/generic_queue.py
+++ b/sickbeard/generic_queue.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import threading
diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py
index 372fd5d50cfc6427e0887c6b81cf9f9135ef76b2..e477f4ce7dd445c21a4b01e63f082b9133653c7d 100644
--- a/sickbeard/helpers.py
+++ b/sickbeard/helpers.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import io
@@ -51,12 +51,11 @@ from socket import timeout as SocketTimeout
 from sickbeard import logger, classes
 from sickbeard.common import USER_AGENT
 from sickbeard import db
-from sickbeard.notifiers.synoindex import notifier as synoindex_notifier
+from sickbeard.notifiers import synoindex_notifier
 from sickrage.helper.common import http_code_description, media_extensions, pretty_file_size, subtitle_extensions
 from sickrage.helper.encoding import ek
 from sickrage.helper.exceptions import ex
 from sickrage.show.Show import Show
-from cachecontrol import CacheControl, caches
 from itertools import izip, cycle
 
 import shutil
@@ -127,6 +126,7 @@ def remove_non_release_groups(name):
         r'\.GiuseppeTnT$': 'searchre',
         r'\.Renc$': 'searchre',
         r'\.gz$': 'searchre',
+        r'(?<![57])\.1$': 'searchre',
         r'-NZBGEEK$': 'searchre',
         r'-Siklopentan$': 'searchre',
         r'-Chamele0n$': 'searchre',
@@ -252,7 +252,7 @@ def makeDir(path):
         try:
             ek(os.makedirs, path)
             # do the library update for synoindex
-            synoindex_notifier().addFolder(path)
+            synoindex_notifier.addFolder(path)
         except OSError:
             return False
     return True
@@ -472,7 +472,7 @@ def make_dirs(path):
                     # use normpath to remove end separator, otherwise checks permissions against itself
                     chmodAsParent(ek(os.path.normpath, sofar))
                     # do the library update for synoindex
-                    synoindex_notifier().addFolder(sofar)
+                    synoindex_notifier.addFolder(sofar)
                 except (OSError, IOError) as e:
                     logger.log(u"Failed creating %s : %r" % (sofar, ex(e)), logger.ERROR)
                     return False
@@ -552,7 +552,7 @@ def delete_empty_folders(check_empty_dir, keep_dir=None):
                 # need shutil.rmtree when ignore_items is really implemented
                 ek(os.rmdir, check_empty_dir)
                 # do the library update for synoindex
-                synoindex_notifier().deleteFolder(check_empty_dir)
+                synoindex_notifier.deleteFolder(check_empty_dir)
             except OSError as e:
                 logger.log(u"Unable to delete %s. Error: %r" % (check_empty_dir, repr(e)), logger.WARNING)
                 break
@@ -1771,8 +1771,8 @@ def getTVDBFromID(indexer_id, indexer):
 
 
 def is_ip_private(ip):
-    priv_lo = re.compile("^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
-    priv_24 = re.compile("^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
-    priv_20 = re.compile("^192\.168\.\d{1,3}.\d{1,3}$")
-    priv_16 = re.compile("^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$")
+    priv_lo = re.compile(r"^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
+    priv_24 = re.compile(r"^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
+    priv_20 = re.compile(r"^192\.168\.\d{1,3}.\d{1,3}$")
+    priv_16 = re.compile(r"^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$")
     return priv_lo.match(ip) or priv_24.match(ip) or priv_20.match(ip) or priv_16.match(ip)
diff --git a/sickbeard/history.py b/sickbeard/history.py
index ad725382fd677ec09c5bad9bacefd565ad01ac3e..7b6140b52bbd92a933ea794c32bb50e5e87437cc 100644
--- a/sickbeard/history.py
+++ b/sickbeard/history.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import db
 import datetime
diff --git a/sickbeard/image_cache.py b/sickbeard/image_cache.py
index ebf03d950a63197f15b04f863b3c57335a0c09de..16516b39b1c5d90557218548eb8e395196a6f22e 100644
--- a/sickbeard/image_cache.py
+++ b/sickbeard/image_cache.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os.path
 
diff --git a/sickbeard/indexers/__init__.py b/sickbeard/indexers/__init__.py
index eb63e387f91550866b4e3a5959a0022b65c85bac..bd7e9a933423f2a347fdd621554335d223f66a5e 100644
--- a/sickbeard/indexers/__init__.py
+++ b/sickbeard/indexers/__init__.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from . import indexer_api
 from . import indexer_exceptions
diff --git a/sickbeard/indexers/indexer_api.py b/sickbeard/indexers/indexer_api.py
index a8c5e92e86a755b4bcc21a5a2125a4e175511b46..b4307ac05fe15b50bf7d2d244d9a51cdf4e68048 100644
--- a/sickbeard/indexers/indexer_api.py
+++ b/sickbeard/indexers/indexer_api.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import sickbeard
diff --git a/sickbeard/logger.py b/sickbeard/logger.py
index 2c20fc430a3ae8b51ca78dbc74ba6320bd949ad6..253cb9eff65221c51aec6bec20858115f0d7e07e 100644
--- a/sickbeard/logger.py
+++ b/sickbeard/logger.py
@@ -12,12 +12,17 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
+"""
+Custom Logger for SickRage
+"""
+
+from __future__ import unicode_literals
 
 import io
 import os
@@ -25,12 +30,13 @@ import re
 import sys
 import logging
 import logging.handlers
+from logging import NullHandler
 import threading
 import platform
 import locale
 import traceback
 
-from github import Github, InputFileContent
+from github import Github, InputFileContent  # pylint: disable=import-error
 
 import sickbeard
 from sickbeard import classes
@@ -40,6 +46,8 @@ from sickrage.helper.encoding import ek
 from sickrage.helper.exceptions import ex
 from sickrage.helper.common import dateTimeFormat
 
+# pylint: disable=line-too-long
+
 # log levels
 ERROR = logging.ERROR
 WARNING = logging.WARNING
@@ -47,45 +55,50 @@ INFO = logging.INFO
 DEBUG = logging.DEBUG
 DB = 5
 
-reverseNames = {
-    u'ERROR': ERROR,
-    u'WARNING': WARNING,
-    u'INFO': INFO,
-    u'DEBUG': DEBUG,
-    u'DB': DB
+LOGGING_LEVELS = {
+    'ERROR': ERROR,
+    'WARNING': WARNING,
+    'INFO': INFO,
+    'DEBUG': DEBUG,
+    'DB': DB,
 }
 
-censoredItems = {}
-
-
-class NullHandler(logging.Handler):
-    def emit(self, record):
-        pass
+censored_items = {}  # pylint: disable=invalid-name
 
 
 class CensoredFormatter(logging.Formatter, object):
+    """
+    Censor information such as API keys, user names, and passwords from the Log
+    """
     def __init__(self, fmt=None, datefmt=None, encoding='utf-8'):
         super(CensoredFormatter, self).__init__(fmt, datefmt)
         self.encoding = encoding
 
     def format(self, record):
-        """Strips censored items from string"""
+        """
+        Strips censored items from string
+
+        :param record: to censor
+        """
         msg = super(CensoredFormatter, self).format(record)
 
         if not isinstance(msg, unicode):
             msg = msg.decode(self.encoding, 'replace')  # Convert to unicode
 
-        for _, v in censoredItems.iteritems():
-            if not isinstance(v, unicode):
-                v = v.decode(self.encoding, 'replace')  # Convert to unicode
-            msg = msg.replace(v, len(v) * u'*')
+        for _, value in censored_items.iteritems():
+            if not isinstance(value, unicode):
+                value = value.decode(self.encoding, 'replace')  # Convert to unicode
+            msg = msg.replace(value, len(value) * '*')
 
         # Needed because Newznab apikey isn't stored as key=value in a section.
-        msg = re.sub(ur'([&?]r|[&?]apikey|[&?]api_key)=[^&]*([&\w]?)', ur'\1=**********\2', msg)
+        msg = re.sub(r'([&?]r|[&?]apikey|[&?]api_key)=[^&]*([&\w]?)', r'\1=**********\2', msg)
         return msg
 
 
 class Logger(object):  # pylint: disable=too-many-instance-attributes
+    """
+    Logger to create log entries
+    """
     def __init__(self):
         self.logger = logging.getLogger('sickrage')
 
@@ -97,26 +110,31 @@ class Logger(object):  # pylint: disable=too-many-instance-attributes
             # logging.getLogger('tornado.access'),
         ]
 
-        self.consoleLogging = False
-        self.fileLogging = False
-        self.debugLogging = False
-        self.databaseLogging = False
-        self.logFile = None
+        self.console_logging = False
+        self.file_logging = False
+        self.debug_logging = False
+        self.database_logging = False
+        self.log_file = None
 
         self.submitter_running = False
 
-    def initLogging(self, consoleLogging=False, fileLogging=False, debugLogging=False, databaseLogging=False):
-        self.logFile = self.logFile or ek(os.path.join, sickbeard.LOG_DIR, 'sickrage.log')
-        self.debugLogging = debugLogging
-        self.consoleLogging = consoleLogging
-        self.fileLogging = fileLogging
-        self.databaseLogging = databaseLogging
+    def init_logging(self, console_logging=False, file_logging=False, debug_logging=False, database_logging=False):
+        """
+        Initialize logging
 
-        # add a new logging level DB
-        logging.addLevelName(DB, 'DB')
+        :param console_logging: True if logging to console
+        :param file_logging: True if logging to file
+        :param debug_logging: True if debug logging is enabled
+        :param database_logging: True if logging database access
+        """
+        self.log_file = self.log_file or ek(os.path.join, sickbeard.LOG_DIR, 'sickrage.log')
+        self.debug_logging = debug_logging
+        self.console_logging = console_logging
+        self.file_logging = file_logging
+        self.database_logging = database_logging
 
-        # nullify root logger
-        logging.getLogger().addHandler(NullHandler())
+        logging.addLevelName(DB, 'DB')  # add a new logging level DB
+        logging.getLogger().addHandler(NullHandler())  # nullify root logger
 
         # set custom root logger
         for logger in self.loggers:
@@ -124,43 +142,54 @@ class Logger(object):  # pylint: disable=too-many-instance-attributes
                 logger.root = self.logger
                 logger.parent = self.logger
 
-        loglevel = DB if self.databaseLogging else DEBUG if self.debugLogging else INFO
+        log_level = DB if self.database_logging else DEBUG if self.debug_logging else INFO
 
         # set minimum logging level allowed for loggers
         for logger in self.loggers:
-            logger.setLevel(loglevel)
+            logger.setLevel(log_level)
 
         # console log handler
-        if self.consoleLogging:
+        if self.console_logging:
             console = logging.StreamHandler()
-            console.setFormatter(CensoredFormatter(u'%(asctime)s %(levelname)s::%(message)s', '%H:%M:%S', encoding='utf-8'))
-            console.setLevel(loglevel)
+            console.setFormatter(CensoredFormatter('%(asctime)s %(levelname)s::%(message)s', '%H:%M:%S'))
+            console.setLevel(log_level)
 
             for logger in self.loggers:
                 logger.addHandler(console)
 
         # rotating log file handler
-        if self.fileLogging:
-            rfh = logging.handlers.RotatingFileHandler(self.logFile, maxBytes=int(sickbeard.LOG_SIZE * 1048576), backupCount=sickbeard.LOG_NR, encoding='utf-8')
-            rfh.setFormatter(CensoredFormatter(u'%(asctime)s %(levelname)-8s %(message)s', dateTimeFormat, encoding='utf-8'))
-            rfh.setLevel(loglevel)
+        if self.file_logging:
+            rfh = logging.handlers.RotatingFileHandler(self.log_file, maxBytes=int(sickbeard.LOG_SIZE * 1048576), backupCount=sickbeard.LOG_NR, encoding='utf-8')
+            rfh.setFormatter(CensoredFormatter('%(asctime)s %(levelname)-8s %(message)s', dateTimeFormat))
+            rfh.setLevel(log_level)
 
             for logger in self.loggers:
                 logger.addHandler(rfh)
 
     @staticmethod
     def shutdown():
+        """
+        Shut down the logger
+        """
         logging.shutdown()
 
     def log(self, msg, level=INFO, *args, **kwargs):
-        meThread = threading.currentThread().getName()
+        """
+        Create log entry
+
+        :param msg: to log
+        :param level: of log, e.g. DEBUG, INFO, etc.
+        :param args: to pass to logger
+        :param kwargs: to pass to logger
+        """
+        cur_thread = threading.currentThread().getName()
         if sickbeard.CUR_COMMIT_HASH and len(sickbeard.CUR_COMMIT_HASH) > 6 and level in [ERROR, WARNING]:
             msg += ' [%s]' % sickbeard.CUR_COMMIT_HASH[:7]
 
-        message = meThread + u" :: " + msg
+        message = '%s :: %s' % (cur_thread, msg)
 
         # Change the SSL error to a warning with a link to information about how to fix it.
-        check = re.sub(ur'error \[Errno 1\] _ssl.c:\d{3}: error:\d{8}:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error', 'See: http://git.io/vuU5V', message)
+        check = re.sub(r'error \[Errno 1\] _ssl.c:\d{3}: error:\d{8}:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error', 'See: http://git.io/vuU5V', message)
         if check != message:
             message = check
             level = WARNING
@@ -178,18 +207,18 @@ class Logger(object):  # pylint: disable=too-many-instance-attributes
     def log_error_and_exit(self, error_msg, *args, **kwargs):
         self.log(error_msg, ERROR, *args, **kwargs)
 
-        if not self.consoleLogging:
+        if not self.console_logging:
             sys.exit(error_msg.encode(sickbeard.SYS_ENCODING, 'xmlcharrefreplace'))
         else:
             sys.exit(1)
 
     def submit_errors(self):  # pylint: disable=too-many-branches,too-many-locals
 
-        submitter_result = u''
+        submitter_result = ''
         issue_id = None
 
         if not (sickbeard.GIT_USERNAME and sickbeard.GIT_PASSWORD and sickbeard.DEBUG and len(classes.ErrorViewer.errors) > 0):
-            submitter_result = u'Please set your GitHub username and password in the config and enable debug. Unable to submit issue ticket to GitHub!'
+            submitter_result = 'Please set your GitHub username and password in the config and enable debug. Unable to submit issue ticket to GitHub!'
             return submitter_result, issue_id
 
         try:
@@ -197,16 +226,16 @@ class Logger(object):  # pylint: disable=too-many-instance-attributes
             checkversion = CheckVersion()
             checkversion.check_for_new_version()
             commits_behind = checkversion.updater.get_num_commits_behind()
-        except Exception:
-            submitter_result = u'Could not check if your SickRage is updated, unable to submit issue ticket to GitHub!'
+        except Exception:  # pylint: disable=broad-except
+            submitter_result = 'Could not check if your SickRage is updated, unable to submit issue ticket to GitHub!'
             return submitter_result, issue_id
 
         if commits_behind is None or commits_behind > 0:
-            submitter_result = u'Please update SickRage, unable to submit issue ticket to GitHub with an outdated version!'
+            submitter_result = 'Please update SickRage, unable to submit issue ticket to GitHub with an outdated version!'
             return submitter_result, issue_id
 
         if self.submitter_running:
-            submitter_result = u'Issue submitter is running, please wait for it to complete'
+            submitter_result = 'Issue submitter is running, please wait for it to complete'
             return submitter_result, issue_id
 
         self.submitter_running = True
@@ -214,118 +243,125 @@ class Logger(object):  # pylint: disable=too-many-instance-attributes
         gh_org = sickbeard.GIT_ORG or 'SickRage'
         gh_repo = 'sickrage-issues'
 
-        gh = Github(login_or_token=sickbeard.GIT_USERNAME, password=sickbeard.GIT_PASSWORD, user_agent="SiCKRAGE")
+        git = Github(login_or_token=sickbeard.GIT_USERNAME, password=sickbeard.GIT_PASSWORD, user_agent='SickRage')
 
-        try:
+        try:  # pylint: disable=too-many-nested-blocks
             # read log file
             log_data = None
 
-            if ek(os.path.isfile, self.logFile):
-                with io.open(self.logFile, 'r', encoding='utf-8') as f:
-                    log_data = f.readlines()
+            if ek(os.path.isfile, self.log_file):
+                with io.open(self.log_file, encoding='utf-8') as log_f:
+                    log_data = log_f.readlines()
 
             for i in range(1, int(sickbeard.LOG_NR)):
-                if ek(os.path.isfile, self.logFile + ".%i" % i) and (len(log_data) <= 500):
-                    with io.open(self.logFile + ".%i" % i, 'r', encoding='utf-8') as f:
-                        log_data += f.readlines()
+                f_name = '%s.%i' % (self.log_file, i)
+                if ek(os.path.isfile, f_name) and (len(log_data) <= 500):
+                    with io.open(f_name, encoding='utf-8') as log_f:
+                        log_data += log_f.readlines()
 
             log_data = [line for line in reversed(log_data)]
 
             # parse and submit errors to issue tracker
-            for curError in sorted(classes.ErrorViewer.errors, key=lambda error: error.time, reverse=True)[:500]:
-
+            for cur_error in sorted(classes.ErrorViewer.errors, key=lambda error: error.time, reverse=True)[:500]:
                 try:
-                    title_Error = ss(str(curError.title))
-                    if not len(title_Error) or title_Error == 'None':
-                        title_Error = re.match(r"^[A-Z0-9\-\[\] :]+::\s*(.*)(?: \[[\w]{7}\])$", ss(curError.message)).group(1)
+                    title_error = ss(str(cur_error.title))
+                    if not len(title_error) or title_error == 'None':
+                        title_error = re.match(r'^[A-Z0-9\-\[\] :]+::\s*(.*)(?: \[[\w]{7}\])$', ss(cur_error.message)).group(1)
+
+                    if len(title_error) > 1000:
+                        title_error = title_error[0:1000]
 
-                    if len(title_Error) > 1000:
-                        title_Error = title_Error[0:1000]
-                except Exception as e:
-                    self.log("Unable to get error title : " + ex(e), ERROR)
+                except Exception as err_msg:  # pylint: disable=broad-except
+                    self.log('Unable to get error title : %s' % ex(err_msg), ERROR)
 
                 gist = None
-                regex = ur"^(%s)\s+([A-Z]+)\s+([0-9A-Z\-]+)\s*(.*)(?: \[[\w]{7}\])$" % curError.time
-                for i, x in enumerate(log_data):
-                    match = re.match(regex, x)
+                regex = r'^(%s)\s+([A-Z]+)\s+([0-9A-Z\-]+)\s*(.*)(?: \[[\w]{7}\])$' % cur_error.time
+                for i, data in enumerate(log_data):
+                    match = re.match(regex, data)
                     if match:
                         level = match.group(2)
-                        if reverseNames[level] == ERROR:
-                            paste_data = u"".join(log_data[i:i + 50])
+                        if LOGGING_LEVELS[level] == ERROR:
+                            paste_data = ''.join(log_data[i:i + 50])
                             if paste_data:
-                                gist = gh.get_user().create_gist(True, {"sickrage.log": InputFileContent(paste_data)})
+                                gist = git.get_user().create_gist(True, {'sickrage.log': InputFileContent(paste_data)})
                             break
                     else:
                         gist = 'No ERROR found'
 
-                message = u"### INFO\n"
-                message += u"Python Version: **" + sys.version[:120].replace('\n', '') + "**\n"
-                message += u"Operating System: **" + platform.platform() + "**\n"
                 try:
-                    message += u"Locale: " + locale.getdefaultlocale()[1] + "\n"
-                except Exception:
-                    message += u"Locale: unknown" + "\n"
-                message += u"Branch: **" + sickbeard.BRANCH + "**\n"
-                message += u"Commit: SickRage/SickRage@" + sickbeard.CUR_COMMIT_HASH + "\n"
+                    locale_name = locale.getdefaultlocale()[1]
+                except Exception:  # pylint: disable=broad-except
+                    locale_name = 'unknown'
+
                 if gist and gist != 'No ERROR found':
-                    message += u"Link to Log: " + gist.html_url + "\n"
+                    log_link = 'Link to Log: %s' % gist.html_url
                 else:
-                    message += u"No Log available with ERRORS: " + "\n"
-                message += u"### ERROR\n"
-                message += u"```\n"
-                message += curError.message + "\n"
-                message += u"```\n"
-                message += u"---\n"
-                message += u"_STAFF NOTIFIED_: @SickRage/owners @SickRage/moderators"
-
-                title_Error = u"[APP SUBMITTED]: " + title_Error
-                reports = gh.get_organization(gh_org).get_repo(gh_repo).get_issues(state="all")
+                    log_link = 'No Log available with ERRORS:'
+
+                msg = [
+                    '### INFO',
+                    'Python Version: **%s**' % sys.version[:120].replace('\n', ''),
+                    'Operating System: **%s**' % platform.platform(),
+                    'Locale: %s' % locale_name,
+                    'Branch: **%s**' % sickbeard.BRANCH,
+                    'Commit: SickRage/SickRage@%s' % sickbeard.CUR_COMMIT_HASH,
+                    log_link,
+                    '### ERROR',
+                    '```',
+                    cur_error.message,
+                    '```',
+                    '---',
+                    '_STAFF NOTIFIED_: @SickRage/owners @SickRage/moderators',
+                ]
+
+                message = '\n'.join(msg)
+                title_error = '[APP SUBMITTED]: %s' % title_error
+                reports = git.get_organization(gh_org).get_repo(gh_repo).get_issues(state='all')
 
                 def is_ascii_error(title):
                     # [APP SUBMITTED]: 'ascii' codec can't encode characters in position 00-00: ordinal not in range(128)
                     # [APP SUBMITTED]: 'charmap' codec can't decode byte 0x00 in position 00: character maps to <undefined>
-                    return re.search(ur".* codec can't .*code .* in position .*:", title) is not None
+                    return re.search(r'.* codec can\'t .*code .* in position .*:', title) is not None
 
                 def is_malformed_error(title):
                     # [APP SUBMITTED]: not well-formed (invalid token): line 0, column 0
-                    return re.search(ur".* not well-formed \(invalid token\): line .* column .*", title) is not None
+                    return re.search(r'.* not well-formed \(invalid token\): line .* column .*', title) is not None
 
-                ascii_error = is_ascii_error(title_Error)
-                malformed_error = is_malformed_error(title_Error)
+                ascii_error = is_ascii_error(title_error)
+                malformed_error = is_malformed_error(title_error)
 
                 issue_found = False
                 for report in reports:
-                    if title_Error.rsplit(' :: ')[-1] in report.title or \
+                    if title_error.rsplit(' :: ')[-1] in report.title or \
                         (malformed_error and is_malformed_error(report.title)) or \
                             (ascii_error and is_ascii_error(report.title)):
 
                         issue_id = report.number
                         if not report.raw_data['locked']:
                             if report.create_comment(message):
-                                submitter_result = u'Commented on existing issue #%s successfully!' % issue_id
+                                submitter_result = 'Commented on existing issue #%s successfully!' % issue_id
                             else:
-                                submitter_result = u'Failed to comment on found issue #%s!' % issue_id
+                                submitter_result = 'Failed to comment on found issue #%s!' % issue_id
                         else:
-                            submitter_result = u'Issue #%s is locked, check github to find info about the error.' % issue_id
+                            submitter_result = 'Issue #%s is locked, check GitHub to find info about the error.' % issue_id
 
                         issue_found = True
                         break
 
                 if not issue_found:
-                    issue = gh.get_organization(gh_org).get_repo(gh_repo).create_issue(title_Error, message)
+                    issue = git.get_organization(gh_org).get_repo(gh_repo).create_issue(title_error, message)
                     if issue:
                         issue_id = issue.number
-                        submitter_result = u'Your issue ticket #%s was submitted successfully!' % issue_id
+                        submitter_result = 'Your issue ticket #%s was submitted successfully!' % issue_id
                     else:
-                        submitter_result = u'Failed to create a new issue!'
+                        submitter_result = 'Failed to create a new issue!'
 
-                if issue_id and curError in classes.ErrorViewer.errors:
+                if issue_id and cur_error in classes.ErrorViewer.errors:
                     # clear error from error list
-                    classes.ErrorViewer.errors.remove(curError)
-
-        except Exception as e:
+                    classes.ErrorViewer.errors.remove(cur_error)
+        except Exception:  # pylint: disable=broad-except
             self.log(traceback.format_exc(), ERROR)
-            submitter_result = u'Exception generated in issue submitter, please check the log'
+            submitter_result = 'Exception generated in issue submitter, please check the log'
             issue_id = None
         finally:
             self.submitter_running = False
@@ -347,4 +383,4 @@ class Wrapper(object):
             return getattr(self.instance, name)
 
 
-_globals = sys.modules[__name__] = Wrapper(sys.modules[__name__])
+_globals = sys.modules[__name__] = Wrapper(sys.modules[__name__])  # pylint: disable=invalid-name
diff --git a/sickbeard/metadata/__init__.py b/sickbeard/metadata/__init__.py
index aa6862f5e8bc3a20f7961fea9949e4f8bff5902a..4c37192e418615e45d043a63e17aae53015bea37 100644
--- a/sickbeard/metadata/__init__.py
+++ b/sickbeard/metadata/__init__.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sys
 from sickbeard.metadata import kodi, kodi_12plus, mediabrowser, ps3, wdtv, tivo, mede8er, generic, helpers
diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py
index 72e54aefd5d40897ab7644764382a8cb58743c3a..e9decefa7f36f96f4ab25342ac8bc1cc5831a77c 100644
--- a/sickbeard/metadata/generic.py
+++ b/sickbeard/metadata/generic.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import io
diff --git a/sickbeard/metadata/helpers.py b/sickbeard/metadata/helpers.py
index 31ad1d509ebceea3467d85a4f12482315429da20..fe20a17ac497e1957e66afc436fc92bb29e51e1e 100644
--- a/sickbeard/metadata/helpers.py
+++ b/sickbeard/metadata/helpers.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard import helpers
 from sickbeard import logger
diff --git a/sickbeard/metadata/kodi.py b/sickbeard/metadata/kodi.py
index b7445073ee1d7389bfb5641e52336c05c51112f8..f95e4661b9eeba9379d190ab071b74dd63d30c0a 100644
--- a/sickbeard/metadata/kodi.py
+++ b/sickbeard/metadata/kodi.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 
diff --git a/sickbeard/metadata/kodi_12plus.py b/sickbeard/metadata/kodi_12plus.py
index 8693e5e780eac68c6d7c973b8e263a8ca52ecccd..57f65461f7cdff19c50f6ea3e849835fa6fce6ed 100644
--- a/sickbeard/metadata/kodi_12plus.py
+++ b/sickbeard/metadata/kodi_12plus.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import datetime
diff --git a/sickbeard/metadata/mede8er.py b/sickbeard/metadata/mede8er.py
index 2f924f982f5628c569a1d346ab3a13af31d834ca..19aaa1cf30da075ef817aa81c04d1b6cb4508322 100644
--- a/sickbeard/metadata/mede8er.py
+++ b/sickbeard/metadata/mede8er.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import io
 import os
diff --git a/sickbeard/metadata/mediabrowser.py b/sickbeard/metadata/mediabrowser.py
index f053d00e51ce559c6409ef5c30b9f8cd90074f8a..d98dad2cc8a3a3fdc9b4c03cee4275dba5dc9f9e 100644
--- a/sickbeard/metadata/mediabrowser.py
+++ b/sickbeard/metadata/mediabrowser.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import os
diff --git a/sickbeard/metadata/ps3.py b/sickbeard/metadata/ps3.py
index e11da1389730c8a43f62755c921ea48ab2f5ad36..4ecf99a9652c71c6d90fa60ae322e4f0d5680e74 100644
--- a/sickbeard/metadata/ps3.py
+++ b/sickbeard/metadata/ps3.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 
diff --git a/sickbeard/metadata/tivo.py b/sickbeard/metadata/tivo.py
index 0fe70790143f6645a8c5129df5f1eaf19b08bdbb..436ec20e7acaeab540fbbeaa9f31580b2f9250b4 100644
--- a/sickbeard/metadata/tivo.py
+++ b/sickbeard/metadata/tivo.py
@@ -13,11 +13,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 
 import io
diff --git a/sickbeard/metadata/wdtv.py b/sickbeard/metadata/wdtv.py
index 1fea81914b1b6507f352416c5c4df85aa70ca7a8..f003726bb0a5b4885a6356e71dba59347b376a88 100644
--- a/sickbeard/metadata/wdtv.py
+++ b/sickbeard/metadata/wdtv.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import os
diff --git a/sickbeard/name_cache.py b/sickbeard/name_cache.py
index 515743cc5ab0af2331d8489e2a461495b2584dab..71f5b9473594eecbcd5b6af1e85c11205ffba4c6 100644
--- a/sickbeard/name_cache.py
+++ b/sickbeard/name_cache.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 import threading
 import sickbeard
 from sickbeard import db
diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py
index 584650beaeedd1b9b505576ef46f3ae9cacf1e25..c608d5f0b03cebb51d8859377102f4ca0fcae0c0 100644
--- a/sickbeard/name_parser/parser.py
+++ b/sickbeard/name_parser/parser.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import time
diff --git a/sickbeard/name_parser/regexes.py b/sickbeard/name_parser/regexes.py
index d164ee8b82758cb8f1b38b70c5c0d7501295ac34..650dcd0865ddf3c4f5f8d0188b2fa0835f989c94 100644
--- a/sickbeard/name_parser/regexes.py
+++ b/sickbeard/name_parser/regexes.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # all regexes are case insensitive
 
diff --git a/sickbeard/naming.py b/sickbeard/naming.py
index 1cf1b1e2ca7321ca858b2a909d0c8d7787c91ab4..250b51e889fbeeb41a98f5716c4e191b68f3cc8a 100644
--- a/sickbeard/naming.py
+++ b/sickbeard/naming.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import os
diff --git a/sickbeard/network_timezones.py b/sickbeard/network_timezones.py
index 8db68734247fc9456405a7f89bfc4bae72c06cc5..c8236ab252cd88154e816b7936f37c73a94a383f 100644
--- a/sickbeard/network_timezones.py
+++ b/sickbeard/network_timezones.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import datetime
diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py
index ab4472ec4acc4b3d791af006584f468f8dbb7867..7936a8974fb056b874bcd2653888fe4e8d650201 100644
--- a/sickbeard/notifiers/__init__.py
+++ b/sickbeard/notifiers/__init__.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 
 import kodi
@@ -37,6 +37,8 @@ import nma
 import pushalot
 import pushbullet
 import freemobile
+import telegram
+
 
 import tweet
 import trakt
@@ -61,6 +63,7 @@ nma_notifier = nma.NMA_Notifier()
 pushalot_notifier = pushalot.PushalotNotifier()
 pushbullet_notifier = pushbullet.PushbulletNotifier()
 freemobile_notifier = freemobile.FreeMobileNotifier()
+telegram_notifier = telegram.TelegramNotifier()
 # social
 twitter_notifier = tweet.TwitterNotifier()
 trakt_notifier = trakt.TraktNotifier()
@@ -77,6 +80,7 @@ notifiers = [
     pytivo_notifier,
     growl_notifier,
     freemobile_notifier,
+    telegram_notifier,
     prowl_notifier,
     pushover_notifier,
     boxcar2_notifier,
diff --git a/sickbeard/notifiers/boxcar2.py b/sickbeard/notifiers/boxcar2.py
index f99ce0088ed5bf4f40b0c334d71821ed622e38ee..230d7c1c47d14a94e323dcb1f95a396ecbbf0050 100644
--- a/sickbeard/notifiers/boxcar2.py
+++ b/sickbeard/notifiers/boxcar2.py
@@ -14,11 +14,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 import urllib2
diff --git a/sickbeard/notifiers/emailnotify.py b/sickbeard/notifiers/emailnotify.py
index ce8d4ead9d3e3935946f8e9dcbb20cf63b963be1..4b5bcf6ffafe8b4ebe589edeaa60909cec235987 100644
--- a/sickbeard/notifiers/emailnotify.py
+++ b/sickbeard/notifiers/emailnotify.py
@@ -15,11 +15,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
diff --git a/sickbeard/notifiers/emby.py b/sickbeard/notifiers/emby.py
index acfbcc300a187bee6a49d061d30c9772c2b6b7d6..dc1a1a98f7a2e9b7eab0edda630ecf63d885c217 100644
--- a/sickbeard/notifiers/emby.py
+++ b/sickbeard/notifiers/emby.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 import urllib2
diff --git a/sickbeard/notifiers/freemobile.py b/sickbeard/notifiers/freemobile.py
index 75c42df2e4d4d506833c497f5ca6e38d8293ed3f..84760b05177a912f8c4b195415ef5bc0d85bf2f8 100644
--- a/sickbeard/notifiers/freemobile.py
+++ b/sickbeard/notifiers/freemobile.py
@@ -14,11 +14,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 import urllib2
 
 import sickbeard
diff --git a/sickbeard/notifiers/growl.py b/sickbeard/notifiers/growl.py
index 94742af06023ea780ab7d448e93f45b071646ff7..dd2d22b99cd812dc04af1c54791be32654640ce0 100644
--- a/sickbeard/notifiers/growl.py
+++ b/sickbeard/notifiers/growl.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import socket
 
diff --git a/sickbeard/notifiers/kodi.py b/sickbeard/notifiers/kodi.py
index 9ff6c6dbc1c17ca2704a86ee9e47463bc93338bb..7db920504b2cb17e1bdeb0981a3af61ec273715f 100644
--- a/sickbeard/notifiers/kodi.py
+++ b/sickbeard/notifiers/kodi.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import httplib
 import urllib
diff --git a/sickbeard/notifiers/libnotify.py b/sickbeard/notifiers/libnotify.py
index 644701570e2f182fc3960d1db07dd772fc41e8a9..3051ed58d119edbfb48a9ee558cfcf6f586ee12e 100644
--- a/sickbeard/notifiers/libnotify.py
+++ b/sickbeard/notifiers/libnotify.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import cgi
diff --git a/sickbeard/notifiers/nmj.py b/sickbeard/notifiers/nmj.py
index c9ddbda4a096e2bbf387f2d8d45097aefdb42576..dc047a3a7cb4b96963f175a85ab19df52ccddd82 100644
--- a/sickbeard/notifiers/nmj.py
+++ b/sickbeard/notifiers/nmj.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 import urllib2
diff --git a/sickbeard/notifiers/nmjv2.py b/sickbeard/notifiers/nmjv2.py
index 5ac7bfc3b9ee3039296ac8916909646769f9134d..881432c2f3aa48b9ff842941174210e6c48c7692 100644
--- a/sickbeard/notifiers/nmjv2.py
+++ b/sickbeard/notifiers/nmjv2.py
@@ -13,11 +13,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib2
 from xml.dom.minidom import parseString
diff --git a/sickbeard/notifiers/plex.py b/sickbeard/notifiers/plex.py
index 217485ad7a921c8f5ba35a23d15c786949566654..4709e920efda867e760aedd6a6aad97d4fbdd728 100644
--- a/sickbeard/notifiers/plex.py
+++ b/sickbeard/notifiers/plex.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 import urllib2
diff --git a/sickbeard/notifiers/prowl.py b/sickbeard/notifiers/prowl.py
index 24b0f145e6d783546ce4c98bd3caa6caecd614c7..22cc114416455d67a8b85cb08b979ac9f40a7a6f 100644
--- a/sickbeard/notifiers/prowl.py
+++ b/sickbeard/notifiers/prowl.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
diff --git a/sickbeard/notifiers/pushalot.py b/sickbeard/notifiers/pushalot.py
index 6a3c82b02a0c457172d6ea3cbee246f93e18c0f6..3efb5aa5fa1671ee41574da4bde045cbdda62300 100644
--- a/sickbeard/notifiers/pushalot.py
+++ b/sickbeard/notifiers/pushalot.py
@@ -13,11 +13,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import socket
 from httplib import HTTPSConnection, HTTPException
diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py
index e2e2b89f5bae5152e1708ca7d2bb693fdebae716..4bd0fb27c8d19bb24c62f0ba4fb599c0f80f83c8 100644
--- a/sickbeard/notifiers/pushover.py
+++ b/sickbeard/notifiers/pushover.py
@@ -13,11 +13,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import httplib
 import urllib
diff --git a/sickbeard/notifiers/pytivo.py b/sickbeard/notifiers/pytivo.py
index 1c28eccfc322c8392c412e8004a5a5c85b235f1f..fe4a98788aa27bf59f52b9afb65a6c1d19df5e1a 100644
--- a/sickbeard/notifiers/pytivo.py
+++ b/sickbeard/notifiers/pytivo.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import sickbeard
diff --git a/sickbeard/notifiers/synoindex.py b/sickbeard/notifiers/synoindex.py
index abdee673a4f06c4137a84fc93443c8274c49ed04..42f9b44d4d31f209a90a6b0428ddb938a45b1edd 100644
--- a/sickbeard/notifiers/synoindex.py
+++ b/sickbeard/notifiers/synoindex.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import subprocess
diff --git a/sickbeard/notifiers/synologynotifier.py b/sickbeard/notifiers/synologynotifier.py
index bbdcfbb82cd238da5d0d5691419d76c35c4f51a4..f67d95578aae8fe4bd3adc9a8912d57d2d2ce9d0 100644
--- a/sickbeard/notifiers/synologynotifier.py
+++ b/sickbeard/notifiers/synologynotifier.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import subprocess
diff --git a/sickbeard/notifiers/telegram.py b/sickbeard/notifiers/telegram.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf4a663aba4017a420fb646fd6896085ba49be85
--- /dev/null
+++ b/sickbeard/notifiers/telegram.py
@@ -0,0 +1,133 @@
+# coding=utf-8
+
+# Author: Marvin Pinto <me@marvinp.ca>
+# Author: Dennis Lutter <lad1337@gmail.com>
+# Author: Aaron Bieber <deftly@gmail.com>
+# 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 <http://www.gnu.org/licenses/>.
+import urllib
+import urllib2
+
+import sickbeard
+from sickbeard import logger
+from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD, NOTIFY_SUBTITLE_DOWNLOAD, NOTIFY_GIT_UPDATE, NOTIFY_GIT_UPDATE_TEXT, NOTIFY_GIT_UPDATE_TEXT
+
+
+class TelegramNotifier(object):
+
+    def test_notify(self, id=None, apiKey=None):
+        return self._notifyTelegram('Test', "This is a test notification from SickRage", id, apiKey, force=True)
+
+    def _sendTelegramMsg(self, title, msg, id=None, apiKey=None):
+        """
+        Sends a Telegram notification
+
+        title: The title of the notification to send
+        msg: The message string to send
+        id: The Telegram user/group id to send the message to
+        apikey: Your Telegram bot API token
+
+        returns: True if the message succeeded, False otherwise
+        """
+
+        if id is None:
+            id = sickbeard.TELEGRAM_ID
+        if apiKey is None:
+            apiKey = sickbeard.TELEGRAM_APIKEY
+
+        logger.log(u"Telegram in use with API KEY: " + apiKey, logger.DEBUG)
+
+        message = title.encode('utf-8') + ": " + msg.encode('utf-8')
+        payload = urllib.urlencode({'chat_id': id, 'text': message})
+        TELEGRAM_API = "https://api.telegram.org/bot%s/%s"
+
+        req = urllib2.Request(TELEGRAM_API % (apiKey, "sendMessage"), payload)
+
+        try:
+            urllib2.urlopen(req)
+        except IOError as e:
+            if hasattr(e, 'code'):
+                if e.code == 400:
+                    message = "Missing parameter(s)."
+                    logger.log(message, logger.ERROR)
+                    return False, message
+                if e.code == 401:
+                    message = "Authentication failed."
+                    logger.log(message, logger.ERROR)
+                    return False, message
+                if e.code == 420:
+                    message = "Too many messages."
+                    logger.log(message, logger.ERROR)
+                    return False, message
+                if e.code == 500:
+                    message = "Server error. Please retry in few moment."
+                    logger.log(message, logger.ERROR)
+                    return False, message
+        except Exception as e:
+            message = u"Error while sending Telegram message: {0}".format(e)
+            logger.log(message, logger.ERROR)
+            return False, message
+
+        message = "Telegram message sent successfully."
+        logger.log(message, logger.INFO)
+        return True, message
+
+    def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]):
+        if sickbeard.TELEGRAM_NOTIFY_ONSNATCH:
+            self._notifyTelegram(title, ep_name)
+
+    def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]):
+        if sickbeard.TELEGRAM_NOTIFY_ONDOWNLOAD:
+            self._notifyTelegram(title, ep_name)
+
+    def notify_subtitle_download(self, ep_name, lang, title=notifyStrings[NOTIFY_SUBTITLE_DOWNLOAD]):
+        if sickbeard.TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD:
+            self._notifyTelegram(title, ep_name + ": " + lang)
+
+    def notify_git_update(self, new_version="??"):
+        if sickbeard.USE_TELEGRAM:
+            update_text = notifyStrings[NOTIFY_GIT_UPDATE_TEXT]
+            title = notifyStrings[NOTIFY_GIT_UPDATE]
+            self._notifyTelegram(title, update_text + new_version)
+
+    def notify_login(self, ipaddress=""):
+        if sickbeard.USE_TELEGRAM:
+            update_text = common.notifyStrings[common.NOTIFY_LOGIN_TEXT]
+            title = common.notifyStrings[common.NOTIFY_LOGIN]
+            self._notifyTelegram(title, update_text.format(ipaddress))
+
+    def _notifyTelegram(self, title, message, id=None, apiKey=None, force=False):
+        """
+        Sends a Telegram notification
+
+        title: The title of the notification to send
+        message: The message string to send
+        id: The Telegram user/group id to send the message to
+        apikey: Your Telegram bot API token
+        force: Enforce sending, for instance for testing
+        """
+
+        if not sickbeard.USE_TELEGRAM and not force:
+            logger.log("Notification for Telegram not enabled, skipping this notification", logger.DEBUG)
+            return False, "Disabled"
+
+        logger.log("Sending a Telegram message for " + message, logger.DEBUG)
+
+        return self._sendTelegramMsg(title, message, id, apiKey)
+
+
+notifier = TelegramNotifier
diff --git a/sickbeard/notifiers/trakt.py b/sickbeard/notifiers/trakt.py
index 33c4a2873bdebb2bc3a5328ab56ae5dc8e04ed31..8036ecd730c1066d4ef513394ba2df24991ae834 100644
--- a/sickbeard/notifiers/trakt.py
+++ b/sickbeard/notifiers/trakt.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 from sickbeard import logger
diff --git a/sickbeard/notifiers/tweet.py b/sickbeard/notifiers/tweet.py
index 9005a66411aee1e91356572bfdb094d6d30c657c..7e747b960c173fe83956884737c0522ae95f9b13 100644
--- a/sickbeard/notifiers/tweet.py
+++ b/sickbeard/notifiers/tweet.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickbeard/nzbSplitter.py b/sickbeard/nzbSplitter.py
index 9528d44716a66fe089b759f9742e74d35962d158..9309dedafffd785e211ca1e9dc87736820b3d85e 100644
--- a/sickbeard/nzbSplitter.py
+++ b/sickbeard/nzbSplitter.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # pylint: disable=line-too-long
 
diff --git a/sickbeard/nzbget.py b/sickbeard/nzbget.py
index 0d054fca8532c89d7c59fedb26f2919475660c63..9a8e3e983c0e73485298414dcef7f20a261f47d4 100644
--- a/sickbeard/nzbget.py
+++ b/sickbeard/nzbget.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import httplib
 import datetime
diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py
index a1e8275b8ea73c3e8ea03173aecef23013aae45e..237b689a91e907832e06d978a961d1fc31517ca0 100644
--- a/sickbeard/postProcessor.py
+++ b/sickbeard/postProcessor.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import glob
 import fnmatch
diff --git a/sickbeard/processTV.py b/sickbeard/processTV.py
index 5970a8e15528e7f3b573f793e44c167b8fcbdeb9..5858b449f73c14d514604af6ccae50ee1a135c64 100644
--- a/sickbeard/processTV.py
+++ b/sickbeard/processTV.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import stat
@@ -267,14 +267,16 @@ def processDir(dirName, nzbName=None, process_method=None, force=False, is_prior
                     if process_method != u"move" or not result.result or (proc_type == u"manual" and not delete_on):
                         continue
 
-                    delete_files(processPath, notwantedFiles, result)
+                # These need done regardless what part of the above `if` is executed.
+                delete_files(processPath, notwantedFiles, result)
+                delete_folder(ek(os.path.join, processPath, u'@eaDir'))
+                if all([not sickbeard.NO_DELETE or proc_type == u"manual",
+                        process_method == u"move",
+                        ek(os.path.normpath, processPath) != ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR)]
+                       ):
+                    if delete_folder(processPath, check_empty=True):
+                        result.output += logHelper(u"Deleted folder: %s" % processPath, logger.DEBUG)
 
-                    if all([not sickbeard.NO_DELETE or proc_type == u"manual",
-                            process_method == u"move",
-                            ek(os.path.normpath, processPath) != ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR)]
-                           ):
-                        if delete_folder(processPath, check_empty=True):
-                            result.output += logHelper(u"Deleted folder: %s" % processPath, logger.DEBUG)
             else:
                 result.output += logHelper(u"Found temporary sync files: %s in path: %s" % (SyncFiles, processPath))
                 result.output += logHelper(u"Skipping post processing for folder: %s" % processPath)
diff --git a/sickbeard/properFinder.py b/sickbeard/properFinder.py
index bb28758ae7007ae095e48e91b7800eee571393a0..b1e254beb341ea0e8a43d915689032a342a4a615 100644
--- a/sickbeard/properFinder.py
+++ b/sickbeard/properFinder.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import time
diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py
index 55c1993661f3501a1b403bfe59ef86ff583acf9e..a32b9ef8c9fda8834ca2e8453ac024c2876ca66a 100644
--- a/sickbeard/providers/__init__.py
+++ b/sickbeard/providers/__init__.py
@@ -12,28 +12,27 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from os import sys
 from random import shuffle
 
 import sickbeard
-from sickbeard import logger
 from sickbeard.providers import btn, newznab, rsstorrent, womble, thepiratebay, torrentleech, kat, iptorrents, torrentz, \
-    omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, hounddawgs, speedcd, nyaatorrents, animenzb, bluetigers, cpasbien, fnt, xthor, torrentbytes, \
-    freshontv, titansoftv, morethantv, bitsoup, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, extratorrent, \
+    omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, hounddawgs, speedcd, nyaatorrents, bluetigers, fnt, xthor, torrentbytes, \
+    freshontv, morethantv, bitsoup, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, extratorrent, \
     scenetime, btdigg, transmitthenet, tvchaosuk, bitcannon, pretome, gftracker, hdspace, newpct, elitetorrent, bitsnoop, danishbits, hd4free, limetorrents
 
 __all__ = [
     'womble', 'btn', 'thepiratebay', 'kat', 'torrentleech', 'scc', 'hdtorrents',
     'torrentday', 'hdbits', 'hounddawgs', 'iptorrents', 'omgwtfnzbs',
-    'speedcd', 'nyaatorrents', 'animenzb', 'torrentbytes', 'freshontv', 'titansoftv',
+    'speedcd', 'nyaatorrents', 'torrentbytes', 'freshontv',
     'morethantv', 'bitsoup', 't411', 'tokyotoshokan', 'alpharatio',
-    'shazbat', 'rarbg', 'tntvillage', 'binsearch', 'bluetigers', 'cpasbien',
+    'shazbat', 'rarbg', 'tntvillage', 'binsearch', 'bluetigers',
     'fnt', 'xthor', 'scenetime', 'btdigg', 'transmitthenet', 'tvchaosuk',
     'torrentproject', 'extratorrent', 'bitcannon', 'torrentz', 'pretome', 'gftracker',
     'hdspace', 'newpct', 'elitetorrent', 'bitsnoop', 'danishbits', 'hd4free', 'limetorrents'
diff --git a/sickbeard/providers/alpharatio.py b/sickbeard/providers/alpharatio.py
index 39dd4d8ba6306856628f072d89dc3df4cd71a276..b080b4e20632498cdf62b94121c869028689050e 100644
--- a/sickbeard/providers/alpharatio.py
+++ b/sickbeard/providers/alpharatio.py
@@ -1,7 +1,6 @@
 # coding=utf-8
-
-# Author: Bill Nasty
-# URL: https://github.com/SickRage/SickRage
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -19,15 +18,17 @@
 # along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
-import traceback
+from urllib import urlencode
+from requests.utils import dict_from_cookiejar
 
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class AlphaRatioProvider(TorrentProvider):
+class AlphaRatioProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -39,25 +40,26 @@ class AlphaRatioProvider(TorrentProvider):
         self.minseed = None
         self.minleech = None
 
-        self.urls = {'base_url': 'http://alpharatio.cc/',
-                     'login': 'http://alpharatio.cc/login.php',
-                     'detail': 'http://alpharatio.cc/torrents.php?torrentid=%s',
-                     'search': 'http://alpharatio.cc/torrents.php?searchstr=%s%s',
-                     'download': 'http://alpharatio.cc/%s'}
-
-        self.url = self.urls['base_url']
-
-        self.categories = "&filter_cat[1]=1&filter_cat[2]=1&filter_cat[3]=1&filter_cat[4]=1&filter_cat[5]=1"
+        self.url = 'http://alpharatio.cc/'
+        self.urls = {
+            'login': self.url + 'login.php',
+            'search': self.url + 'torrents.php',
+        }
 
         self.proper_strings = ['PROPER', 'REPACK']
 
         self.cache = AlphaRatioCache(self)
 
     def login(self):
-        login_params = {'username': self.username,
-                        'password': self.password,
-                        'remember_me': 'on',
-                        'login': 'submit'}
+        if any(dict_from_cookiejar(self.session.cookies).values()):
+            return True
+
+        login_params = {
+            'username': self.username,
+            'password': self.password,
+            'remember_me': 'on',
+            'login': 'submit'
+        }
 
         response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
         if not response:
@@ -71,75 +73,89 @@ class AlphaRatioProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        search_params = {
+            'searchstr': '',
+            'filter_cat[1]': 1,
+            'filter_cat[2]': 1,
+            'filter_cat[3]': 1,
+            'filter_cat[4]': 1,
+            'filter_cat[5]': 1
+        }
+
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (search_string, self.categories)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_params['searchstr'] = search_string
+                search_url = self.urls['search'] + '?' + urlencode(search_params)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
-                try:
-                    with BS4Parser(data, 'html5lib') as html:
-                        torrent_table = html.find('table', attrs={'id': 'torrent_table'})
-                        torrent_rows = torrent_table.find_all('tr') if torrent_table else []
-
-                        # Continue only if one Release is found
-                        if len(torrent_rows) < 2:
-                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('table', id='torrent_table')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
+
+                    # Continue only if one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                        continue
+
+                    def process_column_header(td):
+                        result = ''
+                        if td.a and td.a.img:
+                            result = td.a.img.get('title', td.a.get_text(strip=True))
+                        if not result:
+                            result = td.get_text(strip=True)
+                        return result
+
+                    # '', '', 'Name /Year', 'Files', 'Time', 'Size', 'Snatches', 'Seeders', 'Leechers'
+                    labels = [process_column_header(label) for label in torrent_rows[0].find_all('td')]
+
+                    # Skip column headers
+                    for result in torrent_rows[1:]:
+                        cells = result.find_all('td')
+                        if len(cells) < len(labels):
                             continue
 
-                        for result in torrent_rows[1:]:
-                            cells = result.find_all('td')
-                            link = result.find('a', attrs={'dir': 'ltr'})
-                            url = result.find('a', attrs={'title': 'Download'})
-
-                            try:
-                                title = link.contents[0]
-                                download_url = self.urls['download'] % (url['href'])
-                                seeders = cells[len(cells) - 2].contents[0]
-                                leechers = cells[len(cells) - 1].contents[0]
-                                # FIXME
-                                size = -1
-                            except (AttributeError, TypeError):
-                                continue
-
+                        try:
+                            title = cells[labels.index('Name /Year')].find('a', dir='ltr').get_text(strip=True)
+                            download_url = self.url + cells[labels.index('Name /Year')].find('a', title='Download')['href']
                             if not all([title, download_url]):
                                 continue
 
-                            # Filter unseeded torrent
+                            seeders = try_int(cells[labels.index('Seeders')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('Leechers')].get_text(strip=True))
                             if seeders < self.minseed or leechers < self.minleech:
                                 if mode != 'RSS':
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
+                            torrent_size = cells[labels.index('Size')].get_text(strip=True)
+                            size = convert_size(torrent_size) or -1
+
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
-
-                except Exception:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.WARNING)
+                            items.append(item)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/animenzb.py b/sickbeard/providers/animenzb.py
deleted file mode 100644
index 77a5bffb92c6a6f640e6060d1a6a4d9745c823ee..0000000000000000000000000000000000000000
--- a/sickbeard/providers/animenzb.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# coding=utf-8
-
-# Author: Nic Wolfe <nic@wolfeden.ca>
-# URL: http://code.google.com/p/sickbeard/
-#
-# This file is part of Sick Beard.
-#
-# Sick Beard 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.
-#
-# Sick Beard 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 Sick Beard.  If not, see <http://www.gnu.org/licenses/>.
-
-import urllib
-import datetime
-
-
-from sickbeard import classes
-from sickbeard import show_name_helpers
-
-from sickbeard import logger
-
-from sickbeard import tvcache
-from sickrage.providers.nzb.NZBProvider import NZBProvider
-
-
-class animenzb(NZBProvider):
-
-    def __init__(self):
-
-        NZBProvider.__init__(self, "AnimeNZB")
-
-        self.supports_backlog = False
-        self.public = True
-        self.supports_absolute_numbering = True
-        self.anime_only = True
-
-        self.urls = {'base_url': 'http://animenzb.com/'}
-        self.url = self.urls['base_url']
-
-        self.cache = animenzbCache(self)
-
-    def _get_season_search_strings(self, ep_obj):
-        return [x for x in show_name_helpers.makeSceneSeasonSearchString(self.show, ep_obj)]
-
-    def _get_episode_search_strings(self, ep_obj, add_string=''):
-        return [x for x in show_name_helpers.makeSceneSearchString(self.show, ep_obj)]
-
-    def search(self, search_string, age=0, ep_obj=None):
-
-        logger.log(u"Search string: %s " % search_string, logger.DEBUG)
-
-        if self.show and not self.show.is_anime:
-            return []
-
-        params = {
-            "cat": "anime",
-            "q": search_string.encode('utf-8'),
-            "max": "100"
-        }
-
-        searchURL = self.url + "rss?" + urllib.urlencode(params)
-        logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-        results = []
-        if 'entries' in self.cache.getRSSFeed(searchURL): 
-            for curItem in self.cache.getRSSFeed(searchURL)['entries']:
-                (title, url) = self._get_title_and_url(curItem)
-    
-                if title and url:
-                    results.append(curItem)
-                    logger.log(u"Found result: %s " % title, logger.DEBUG)
-    
-            # For each search mode sort all the items by seeders if available if available
-            results.sort(key=lambda tup: tup[0], reverse=True)
-
-        return results
-
-    def find_propers(self, search_date=None):
-
-        results = []
-
-        for item in self.search("v2|v3|v4|v5"):
-
-            (title, url) = self._get_title_and_url(item)
-
-            if 'published_parsed' in item and item['published_parsed']:
-                result_date = item.published_parsed
-                if result_date:
-                    result_date = datetime.datetime(*result_date[0:6])
-            else:
-                continue
-
-            if not search_date or result_date > search_date:
-                search_result = classes.Proper(title, url, result_date, self.show)
-                results.append(search_result)
-
-        return results
-
-
-class animenzbCache(tvcache.TVCache):
-
-    def __init__(self, provider_obj):
-
-        tvcache.TVCache.__init__(self, provider_obj)
-
-        # only poll animenzb every 20 minutes max
-        self.minTime = 20
-
-    def _getRSSData(self):
-
-        params = {
-            "cat": "anime".encode('utf-8'),
-            "max": "100".encode('utf-8')
-        }
-
-        rss_url = self.provider.url + 'rss?' + urllib.urlencode(params)
-
-        return self.getRSSFeed(rss_url)
-
-provider = animenzb()
diff --git a/sickbeard/providers/binsearch.py b/sickbeard/providers/binsearch.py
index c0ea97c706d4e496143ed8235f6596441f768d0e..2be047ce6d0adee3cbaffbe984ac1eb264b1b32e 100644
--- a/sickbeard/providers/binsearch.py
+++ b/sickbeard/providers/binsearch.py
@@ -10,7 +10,7 @@
 #
 # Sick Beard 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
+# 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
diff --git a/sickbeard/providers/bitcannon.py b/sickbeard/providers/bitcannon.py
index 12f4cdaf2d66c251b730af57956c0905962fb254..1c169e8b030548087be5787db1c923934846622c 100644
--- a/sickbeard/providers/bitcannon.py
+++ b/sickbeard/providers/bitcannon.py
@@ -11,21 +11,22 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import traceback
 from urllib import urlencode
 
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class BitCannonProvider(TorrentProvider):
+class BitCannonProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "BitCannon")
@@ -46,13 +47,12 @@ class BitCannonProvider(TorrentProvider):
             'apiKey': ''
         }
 
-    def search(self, search_strings, age=0, ep_obj=None):
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-statements, too-many-locals
         # search_strings comes in one of these formats:
         #      {'Episode': ['Italian Works S05E10']}
         #      {'Season': ['Italian Works S05']}
         #      {'RSS': ['tv', 'anime']}
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
 
         # select the correct category (TODO:  Add more categories?)
         anime = (self.show and self.show.anime) or (ep_obj and ep_obj.show and ep_obj.show.anime) or False
@@ -62,7 +62,8 @@ class BitCannonProvider(TorrentProvider):
         if self.api_key:
             self.search_params['apiKey'] = self.api_key
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -95,10 +96,11 @@ class BitCannonProvider(TorrentProvider):
                                 title = result.get('title', '')
                                 info_hash = result.get('infoHash', '')
                                 swarm = result.get('swarm', None)
-                                size = int(result.get('size', 0))
                                 if swarm is not None:
                                     seeders = int(swarm.get('seeders', 0))
                                     leechers = int(swarm.get('leechers', 0))
+                                torrent_size = result.get('size', 0)
+                                size = convert_size(torrent_size) or -1
                                 download_url = "magnet:?xt=urn:btih:" + info_hash
 
                             except (AttributeError, TypeError, KeyError, ValueError):
@@ -113,14 +115,14 @@ class BitCannonProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %r" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/bitsnoop.py b/sickbeard/providers/bitsnoop.py
index 5e89e174debd1c478522c4f23be6a953f3d850f0..545ca65c194eb4ceebea2ff88c5abba1b03060f8 100644
--- a/sickbeard/providers/bitsnoop.py
+++ b/sickbeard/providers/bitsnoop.py
@@ -10,11 +10,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import traceback
 from bs4 import BeautifulSoup
@@ -22,7 +22,7 @@ from bs4 import BeautifulSoup
 import sickbeard
 from sickbeard import logger
 from sickbeard import tvcache
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
@@ -48,11 +48,9 @@ class BitSnoopProvider(TorrentProvider):  # pylint: disable=too-many-instance-at
         self.cache = BitSnoopCache(self)
 
     def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-branches,too-many-locals
-
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -71,10 +69,7 @@ class BitSnoopProvider(TorrentProvider):  # pylint: disable=too-many-instance-at
                         continue
 
                     data = BeautifulSoup(data, 'html5lib')
-
-                    entries = entries = data.findAll('item')
-
-                    for item in entries:
+                    for item in data.findAll('item'):
                         try:
                             if not item.category.text.endswith(('TV', 'Anime')):
                                 continue
@@ -92,9 +87,10 @@ class BitSnoopProvider(TorrentProvider):  # pylint: disable=too-many-instance-at
                             if not (title and download_url):
                                 continue
 
-                            seeders = try_int(item.find('numseeders').text, 0)
-                            leechers = try_int(item.find('numleechers').text, 0)
-                            size = try_int(item.find('size').text, -1)
+                            seeders = try_int(item.find('numseeders').text)
+                            leechers = try_int(item.find('numleechers').text)
+                            torrent_size = item.find('size').text
+                            size = convert_size(torrent_size) or -1
 
                             info_hash = item.find('infohash').text
 
@@ -111,15 +107,14 @@ class BitSnoopProvider(TorrentProvider):  # pylint: disable=too-many-instance-at
                         if mode != 'RSS':
                             logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        items[mode].append(item)
+                        items.append(item)
 
                 except (AttributeError, TypeError, KeyError, ValueError):
                     logger.log(u"Failed parsing provider. Traceback: %r" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/bitsoup.py b/sickbeard/providers/bitsoup.py
index 639bc49bf2eb64e2547e9d89bf67b878d2c4c0ae..92bc89c22d7f1cdb4f5824772738d224e79e784d 100644
--- a/sickbeard/providers/bitsoup.py
+++ b/sickbeard/providers/bitsoup.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import traceback
@@ -23,10 +23,11 @@ import traceback
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class BitSoupProvider(TorrentProvider):
+class BitSoupProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, "BitSoup")
 
@@ -77,18 +78,15 @@ class BitSoupProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
-
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
@@ -119,9 +117,7 @@ class BitSoupProvider(TorrentProvider):
                                 seeders = int(cells[10].getText().replace(',', ''))
                                 leechers = int(cells[11].getText().replace(',', ''))
                                 torrent_size = cells[8].getText()
-                                size = -1
-                                if re.match(r"\d+([,\.]\d+)?\s*[KkMmGgTt]?[Bb]", torrent_size):
-                                    size = self._convertSize(torrent_size.rstrip())
+                                size = convert_size(torrent_size) or -1
                             except (AttributeError, TypeError):
                                 continue
 
@@ -141,38 +137,21 @@ class BitSoupProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.WARNING)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, sizeString):
-        size = sizeString[:-2].strip()
-        modifier = sizeString[-2:].upper()
-        try:
-            size = float(size)
-            if modifier in 'KB':
-                size *= 1024 ** 1
-            elif modifier in 'MB':
-                size *= 1024 ** 2
-            elif modifier in 'GB':
-                size *= 1024 ** 3
-            elif modifier in 'TB':
-                size *= 1024 ** 4
-        except Exception:
-            size = -1
-        return long(size)
-
 
 class BitSoupCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/bluetigers.py b/sickbeard/providers/bluetigers.py
index 5a7da1f3d660e6febd64706d862cce78a5a8836b..0ff1201fb7a44511fa3ab3a6a8e1ba51df55cac2 100644
--- a/sickbeard/providers/bluetigers.py
+++ b/sickbeard/providers/bluetigers.py
@@ -11,7 +11,7 @@
 #
 # Sick Beard 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
+# 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
@@ -21,7 +21,6 @@ import traceback
 import requests
 import re
 
-from requests.auth import AuthBase
 from sickbeard.bs4_parser import BS4Parser
 
 from sickbeard import logger
@@ -29,7 +28,7 @@ from sickbeard import tvcache
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class BLUETIGERSProvider(TorrentProvider):
+class BlueTigersProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, "BLUETIGERS")
 
@@ -38,7 +37,7 @@ class BLUETIGERSProvider(TorrentProvider):
         self.ratio = None
         self.token = None
 
-        self.cache = BLUETIGERSCache(self)
+        self.cache = BlueTigersCache(self)
 
         self.urls = {
             'base_url': 'https://www.bluetigers.ca/',
@@ -79,15 +78,13 @@ class BLUETIGERSProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -131,15 +128,15 @@ class BLUETIGERSProvider(TorrentProvider):
                                 if mode != 'RSS':
                                     logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                                items[mode].append(item)
+                                items.append(item)
 
-                except Exception as e:
+                except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -147,17 +144,7 @@ class BLUETIGERSProvider(TorrentProvider):
         return self.ratio
 
 
-class BLUETIGERSAuth(AuthBase):
-    """Attaches HTTP Authentication to the given Request object."""
-    def __init__(self, token):
-        self.token = token
-
-    def __call__(self, r):
-        r.headers['Authorization'] = self.token
-        return r
-
-
-class BLUETIGERSCache(tvcache.TVCache):
+class BlueTigersCache(tvcache.TVCache):
     def __init__(self, provider_obj):
         tvcache.TVCache.__init__(self, provider_obj)
 
@@ -169,4 +156,4 @@ class BLUETIGERSCache(tvcache.TVCache):
         return {'entries': self.provider.search(search_strings)}
 
 
-provider = BLUETIGERSProvider()
+provider = BlueTigersProvider()
diff --git a/sickbeard/providers/btdigg.py b/sickbeard/providers/btdigg.py
index 099b7116b2f3467e8a36ba51c16b7668813240b0..2b3db677319d07e4f0df5ca0a5dcb291530732cb 100644
--- a/sickbeard/providers/btdigg.py
+++ b/sickbeard/providers/btdigg.py
@@ -13,19 +13,21 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
+import traceback
 
 from urllib import urlencode
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class BTDIGGProvider(TorrentProvider):
+class BTDiggProvider(TorrentProvider):
 
     def __init__(self):
         TorrentProvider.__init__(self, "BTDigg")
@@ -45,13 +47,12 @@ class BTDIGGProvider(TorrentProvider):
 
         self.cache = BTDiggCache(self)
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
         search_params = {'p': 0}
 
         for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
                 search_params['q'] = search_string.encode('utf-8')
@@ -70,45 +71,52 @@ class BTDIGGProvider(TorrentProvider):
                     logger.log(u"No data returned to be parsed!!!", logger.DEBUG)
                     continue
 
-                for torrent in jdata:
-                    if not torrent['name']:
-                        logger.log(u"Ignoring result since it has no name", logger.DEBUG)
-                        continue
+                try:
+
+                    for torrent in jdata:
+                        if not torrent['name']:
+                            logger.log(u"Ignoring result since it has no name", logger.DEBUG)
+                            continue
+
+                        if torrent['ff']:
+                            logger.log(u"Ignoring result for %s since it's a fake (level = %s)" % (torrent['name'], torrent['ff']), logger.DEBUG)
+                            continue
 
-                    if torrent['ff']:
-                        logger.log(u"Ignoring result for %s since it's a fake (level = %s)" % (torrent['name'], torrent['ff']), logger.DEBUG)
-                        continue
+                        if not torrent['files']:
+                            logger.log(u"Ignoring result for %s without files" % torrent['name'], logger.DEBUG)
+                            continue
 
-                    if not torrent['files']:
-                        logger.log(u"Ignoring result for %s without files" % torrent['name'], logger.DEBUG)
-                        continue
+                        download_url = torrent['magnet'] + self._custom_trackers if torrent['magnet'] else None
 
-                    download_url = torrent['magnet'] + self._custom_trackers
+                        # Provider doesn't provide seeders/leechers
+                        seeders = 1
+                        leechers = 0
+                        title = torrent['name']
+                        torrent_size = torrent['size']
+                        size = convert_size(torrent_size) or -1
 
-                    if not download_url:
-                        logger.log(u"Ignoring result for %s without a url" % torrent['name'], logger.DEBUG)
-                        continue
+                        if not all([title, download_url]):
+                            continue
 
-                    # FIXME
-                    seeders = 1
-                    leechers = 0
+                        # Filter unseeded torrent (Unsupported)
+                        #if seeders < self.minseed or leechers < self.minleech:
+                        #    if mode != 'RSS':
+                        #        logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                        #    continue
 
-                    # # Filter unseeded torrent (Unsupported)
-                    # if seeders < self.minseed or leechers < self.minleech:
-                    #    if mode != 'RSS':
-                    #        logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                    #    continue
+                        item = title, download_url, size, seeders, leechers
+                        if mode != 'RSS':
+                            logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                    if mode != 'RSS':
-                        logger.log(u"Found result: %s" % torrent['name'], logger.DEBUG)
+                        items.append(item)
 
-                    item = torrent['name'], download_url, torrent['size'], seeders, leechers
-                    items[mode].append(item)
+                except Exception:
+                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.WARNING)
 
-            # # For each search mode sort all the items by seeders if available (Unsupported)
-            # items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            # For each search mode sort all the items by seeders if available
+            #items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -130,4 +138,4 @@ class BTDiggCache(tvcache.TVCache):
         search_params = {'RSS': ['x264', 'x264.HDTV', '720.HDTV.x264']}
         return {'entries': self.provider.search(search_params)}
 
-provider = BTDIGGProvider()
+provider = BTDiggProvider()
diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py
index f648fefc8019acd2f8bc887239c0a459b37b54cb..6384558798dfaee6d5d4bf5b8535dfebbe774588 100644
--- a/sickbeard/providers/btn.py
+++ b/sickbeard/providers/btn.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import time
 import socket
diff --git a/sickbeard/providers/cpasbien.py b/sickbeard/providers/cpasbien.py
index 83ed1e9349a8fb4cdef3740266ff228e2316b337..b4f509d356a2b02ff91832078c6132685de1b860 100644
--- a/sickbeard/providers/cpasbien.py
+++ b/sickbeard/providers/cpasbien.py
@@ -11,17 +11,16 @@
 #
 # Sick Beard 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.
+# 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 Sick Beard.  If not, see <http://www.gnu.org/licenses/>.
-
-import traceback
+import re
 
 from sickbeard import logger
 from sickbeard import tvcache
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickbeard.bs4_parser import BS4Parser
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
@@ -39,102 +38,65 @@ class CpasbienProvider(TorrentProvider):
         self.url = "http://www.cpasbien.io"
 
         self.proper_strings = ['PROPER', 'REPACK']
-
         self.cache = CpasbienCache(self)
 
-    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-statements, too-many-branches
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_params.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
+            for search_string in search_strings[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
-                    searchURL = self.url + '/recherche/' + search_string.replace('.', '-').replace(' ', '-') + '.html'
+                    search_url = self.url + '/recherche/' + search_string.replace('.', '-').replace(' ', '-') + '.html,trie-seeds-d'
                 else:
-                    searchURL = self.url + '/view_cat.php?categorie=series&trie=date-d'
-
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                data = self.get_url(searchURL)
+                    search_url = self.url + '/view_cat.php?categorie=series&trie=date-d'
 
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
-                try:
-                    with BS4Parser(data, 'html5lib') as html:
-                        line = 0
-                        torrents = []
-                        while True:
-                            resultlin = html.findAll(class_='ligne%i' % line)
-                            if not resultlin:
-                                break
-
-                            torrents += resultlin
-                            line += 1
-
-                        for torrent in torrents:
-                            try:
-                                title = torrent.find(class_="titre").get_text(strip=True).replace("HDTV", "HDTV x264-CPasBien")
-                                tmp = torrent.find("a")['href'].split('/')[-1].replace('.html', '.torrent').strip()
-                                download_url = (self.url + '/telechargement/%s' % tmp)
-                                size = self._convertSize(torrent.find(class_="poid").get_text(strip=True))
-                                seeders = try_int(torrent.find(class_="up").get_text(strip=True))
-                                leechers = try_int(torrent.find(class_="down").get_text(strip=True))
-                            except (AttributeError, TypeError, KeyError, IndexError):
-                                continue
-
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_rows = html.find_all(class_=re.compile('ligne[01]'))
+                    for result in torrent_rows:
+                        try:
+                            title = result.find(class_="titre").get_text(strip=True).replace("HDTV", "HDTV x264-CPasBien")
+                            tmp = result.find("a")['href'].split('/')[-1].replace('.html', '.torrent').strip()
+                            download_url = (self.url + '/telechargement/%s' % tmp)
                             if not all([title, download_url]):
                                 continue
 
-                            # Filter unseeded torrent
+                            seeders = try_int(result.find(class_="up").get_text(strip=True))
+                            leechers = try_int(result.find(class_="down").get_text(strip=True))
                             if seeders < self.minseed or leechers < self.minleech:
                                 if mode != 'RSS':
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
+                            torrent_size = result.find(class_="poid").get_text(strip=True)
+
+                            units = ['o', 'Ko', 'Mo', 'Go', 'To', 'Po']
+                            size = convert_size(torrent_size, units=units) or -1
+
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
-
-                except Exception:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+                            items.append(item)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    @staticmethod
-    def _convertSize(sizeString):
-        size = sizeString[:-2].strip()
-        modifier = sizeString[-2:].upper()
-        try:
-            size = float(size)
-            if modifier in 'KO':
-                size *= 1024 ** 1
-            elif modifier in 'MO':
-                size *= 1024 ** 2
-            elif modifier in 'GO':
-                size *= 1024 ** 3
-            elif modifier in 'TO':
-                size *= 1024 ** 4
-            else:
-                raise
-        except Exception:
-            size = -1
-
-        return long(size)
-
 
 class CpasbienCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/danishbits.py b/sickbeard/providers/danishbits.py
index b531cbb4d5992375783aef8c11aadeb6cbe26f1c..63573ae6053c1f3fbc8d6c03744f4077de298383 100644
--- a/sickbeard/providers/danishbits.py
+++ b/sickbeard/providers/danishbits.py
@@ -1,6 +1,6 @@
 # coding=utf-8
-# Author: seedboy
-# URL: https://github.com/seedboy
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,19 +11,18 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
-import traceback
-import urllib
-import time
-import re
+from urllib import urlencode
+from requests.utils import dict_from_cookiejar
 
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 from sickbeard.bs4_parser import BS4Parser
@@ -41,165 +40,129 @@ class DanishbitsProvider(TorrentProvider):  # pylint: disable=too-many-instance-
 
         self.cache = DanishbitsCache(self)
 
-        self.urls = {'base_url': 'https://danishbits.org/',
-                     'search': 'https://danishbits.org/torrents.php?action=newbrowse&search=%s%s',
-                     'login_page': 'https://danishbits.org/login.php'}
-
-        self.url = self.urls['base_url']
-
-        self.categories = '&group=3'
-
-        self.last_login_check = None
-
-        self.login_opener = None
+        self.url = 'https://danishbits.org/'
+        self.urls = {
+            'login': self.url + 'login.php',
+            'search': self.url + 'torrents.php',
+        }
 
         self.minseed = 0
         self.minleech = 0
         self.freeleech = True
 
-    @staticmethod
-    def loginSuccess(output):
-        if not output or "<title>Login :: Danishbits.org</title>" in output:
-            return False
-        else:
-            return True
-
     def login(self):
-
-        now = time.time()
-        if self.login_opener and self.last_login_check < (now - 3600):
-            try:
-                output = self.get_url(self.urls['test'])
-                if self.loginSuccess(output):
-                    self.last_login_check = now
-                    return True
-                else:
-                    self.login_opener = None
-            except Exception:
-                self.login_opener = None
-
-        if self.login_opener:
+        if any(dict_from_cookiejar(self.session.cookies).values()):
             return True
 
-        try:
-            data = self.get_url(self.urls['login_page'])
-            if not data:
-                return False
-
-            login_params = {
-                'username': self.username,
-                'password': self.password,
-            }
-            output = self.get_url(self.urls['login_page'], post_data=login_params)
-            if self.loginSuccess(output):
-                self.last_login_check = now
-                self.login_opener = self.session
-                return True
-
-            error = 'unknown'
-        except Exception:
-            error = traceback.format_exc()
-            self.login_opener = None
+        login_params = {
+            'langlang': '',
+            'username': self.username.encode('utf-8'),
+            'password': self.password.encode('utf-8'),
+            'keeplogged': 1,
+            'login': 'Login'
+        }
+
+        response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
+        if not response:
+            logger.log(u"Unable to connect to provider", logger.WARNING)
+            self.session.cookies.clear()
+            return False
 
-        self.login_opener = None
-        logger.log(u"Failed to login: %s" % error, logger.ERROR)
-        return False
+        if '<title>Login :: Danishbits.org</title>' in response:
+            logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
+            self.session.cookies.clear()
+            return False
 
-    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-branches,too-many-locals
+        return True
 
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-branches,too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
-            logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
-                if mode == 'RSS':
-                    continue
+        search_params = {
+            'action': 'newbrowse',
+            'group': 3,
+            'search': '',
+        }
 
+        for mode in search_strings:
+            items = []
+            logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
+            for search_string in search_strings[mode]:
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (urllib.quote(search_string.encode('utf-8')), self.categories)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                data = self.get_url(searchURL)
-                if not data:
-                    continue
-
-                try:
-                    with BS4Parser(data.decode('iso-8859-1'), features=["html5lib", "permissive"]) as html:
-                        # Collecting entries
-                        entries = html.find_all('tr', attrs={'class': 'torrent'})
-
-                        # Xirg STANDARD TORRENTS
-                        # Continue only if one Release is found
-                        if not entries:
-                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
-                            continue
+                search_params['search'] = search_string
 
-                        for result in entries:
+                search_url = "%s?%s" % (self.urls['search'], urlencode(search_params))
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                            # try:
-                            title = result.find('div', attrs={'class': 'croptorrenttext'}).find('b').text
-                            download_url = self.urls['base_url'] + result.find('span', attrs={'class': 'right'}).find('a')['href']
-                            seeders = int(result.find_all('td')[6].text)
-                            leechers = int(result.find_all('td')[7].text)
-                            size = self._convertSize(result.find_all('td')[2].text)
-                            freeleech = result.find('span', class_='freeleech')
-                            # except (AttributeError, TypeError, KeyError):
-                            #     logger.log(u"attrErr: {0}, tErr: {1}, kErr: {2}".format(AttributeError, TypeError, KeyError), logger.DEBUG)
-                            #    continue
-
-                            if self.freeleech and not freeleech:
-                                continue
+                # returns top 15 results by default, expandable in user profile to 100
+                data = self.get_url(search_url)
+                if not data:
+                    continue
 
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('table', class_='torrent_table')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
+
+                    # Continue only if at least one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                        continue
+
+                    def process_column_header(td):
+                        result = ''
+                        if td.img:
+                            result = td.img.get('title')
+                        if not result:
+                            result = td.get_text(strip=True)
+                        return result.encode('utf-8')
+
+                    # Literal:     Navn, Størrelse, Kommentarer, Tilføjet, Snatches, Seeders, Leechers
+                    # Translation: Name, Size,      Comments,    Added,    Snatches, Seeders, Leechers
+                    labels = [process_column_header(label) for label in torrent_rows[0].find_all('td')]
+
+                    for result in torrent_rows[1:]:
+                        try:
+                            title = result.find(class_='croptorrenttext').get_text(strip=True)
+                            download_url = self.url + result.find(title="Direkte download link")['href']
                             if not all([title, download_url]):
                                 continue
 
-                            # Filter unseeded torrent
+                            cells = result.find_all('td')
+
+                            seeders = try_int(cells[labels.index('Seeders')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('Leechers')].get_text(strip=True))
                             if seeders < self.minseed or leechers < self.minleech:
                                 if mode != 'RSS':
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
+                            freeleech = result.find(class_='freeleech')
+                            if self.freeleech and not freeleech:
+                                continue
+
+                            torrent_size = cells[labels.index('Størrelse')].contents[0]
+                            size = convert_size(torrent_size) or -1
+
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
-                except Exception:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
-    @staticmethod
-    def _convertSize(size):
-        regex = re.compile(r'(.+?\w{2})\d+ file\w')
-        m = regex.match(size)
-        size = m.group(1)
-
-        size, modifier = size[:-2], size[-2:]
-        size = size.replace(',', '')  # strip commas from comma separated values
-
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
     def seedRatio(self):
         return self.ratio
 
@@ -213,8 +176,8 @@ class DanishbitsCache(tvcache.TVCache):
         self.minTime = 10
 
     def _getRSSData(self):
-        search_params = {'RSS': ['']}
-        return {'entries': self.provider.search(search_params)}
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
 
 
 provider = DanishbitsProvider()
diff --git a/sickbeard/providers/elitetorrent.py b/sickbeard/providers/elitetorrent.py
index 984e84a24781c3522ef8a384204a4a1233215f6d..a267c8dc5d281204582e8750048a618244d9132c 100644
--- a/sickbeard/providers/elitetorrent.py
+++ b/sickbeard/providers/elitetorrent.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import traceback
 import re
@@ -27,6 +27,8 @@ from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
+from sickrage.helper.common import try_int
+
 
 class elitetorrentProvider(TorrentProvider):
     def __init__(self):
@@ -65,14 +67,12 @@ class elitetorrentProvider(TorrentProvider):
 
         }
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         lang_info = '' if not ep_obj or not ep_obj.show else ep_obj.show.lang
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
 
             # Only search if user conditions are true
@@ -87,41 +87,36 @@ class elitetorrentProvider(TorrentProvider):
                 search_string = re.sub(r'S0*(\d*)E(\d*)', r'\1x\2', search_string)
                 self.search_params['buscar'] = search_string.strip() if mode != 'RSS' else ''
 
-                searchURL = self.urls['search'] + '?' + urllib.parse.urlencode(self.search_params)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-
-                data = self.get_url(searchURL, timeout=30)
+                search_url = self.urls['search'] + '?' + urllib.parse.urlencode(self.search_params)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
+                data = self.get_url(search_url, timeout=30)
                 if not data:
                     continue
 
                 try:
                     with BS4Parser(data, 'html5lib') as html:
                         torrent_table = html.find('table', class_='fichas-listado')
+                        torrent_rows = []
 
-                        if torrent_table is None:
-                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
-                            continue
+                        if torrent_table is not None:
+                            torrent_rows = torrent_table.findAll('tr')
 
-                        torrent_rows = torrent_table.findAll('tr')
-                        if torrent_rows is None:
-                            logger.log(u"Torrent table does not have any rows", logger.DEBUG)
+                        if not torrent_rows:
+                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
                             continue
 
                         for row in torrent_rows[1:]:
                             try:
-                                seeders_raw = row.find('td', class_='semillas').text
-                                leechers_raw = row.find('td', class_='clientes').text
-
-                                download_url = self.urls['base_url'] + row.findAll('a')[0].get('href', '')
-                                title = self._processTitle(row.findAll('a')[1].text)
-                                seeders = seeders_raw if seeders_raw.isnumeric() else 0
-                                leechers = leechers_raw if leechers_raw.isnumeric() else 0
+                                download_url = self.urls['base_url'] + row.find('a')['href']
+                                title = self._processTitle(row.find('a', class_='nombre')['title'])
+                                seeders = try_int(row.find('td', class_='semillas').get_text(strip=True))
+                                leechers = try_int(row.find('td', class_='clientes').get_text(strip=True))
 
-                                # FIXME: Provider does not provide size
-                                size = 0
+                                # Provider does not provide size
+                                size = -1
 
-                            except (AttributeError, TypeError):
+                            except (AttributeError, TypeError, KeyError, ValueError):
                                 continue
 
                             if not all([title, download_url]):
@@ -137,15 +132,15 @@ class elitetorrentProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.WARNING)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/extratorrent.py b/sickbeard/providers/extratorrent.py
index 73bade79050e843b7be96989e2b5ed81a846e2fc..868c684834216503a8c40a183006115c1eb87030 100644
--- a/sickbeard/providers/extratorrent.py
+++ b/sickbeard/providers/extratorrent.py
@@ -11,19 +11,18 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
-import traceback
 import sickbeard
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.common import USER_AGENT
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickbeard.bs4_parser import BS4Parser
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
@@ -50,11 +49,9 @@ class ExtraTorrentProvider(TorrentProvider):  # pylint: disable=too-many-instanc
         self.search_params = {'cid': 8}
 
     def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
-
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
                 if mode != 'RSS':
@@ -75,9 +72,10 @@ class ExtraTorrentProvider(TorrentProvider):  # pylint: disable=too-many-instanc
                     for item in parser.findAll('item'):
                         try:
                             title = re.sub(r'^<!\[CDATA\[|\]\]>$', '', item.find('title').get_text(strip=True))
-                            size = try_int(item.find('size').get_text(strip=True), -1) if item.find('size') else -1
-                            seeders = try_int(item.find('seeders').get_text(strip=True)) if item.find('seeders') else 0
-                            leechers = try_int(item.find('leechers').get_text(strip=True)) if item.find('leechers') else 0
+                            seeders = try_int(item.find('seeders').get_text(strip=True))
+                            leechers = try_int(item.find('leechers').get_text(strip=True))
+                            torrent_size = item.find('size').get_text()
+                            size = convert_size(torrent_size) or -1
 
                             if sickbeard.TORRENT_METHOD == 'blackhole':
                                 enclosure = item.find('enclosure')  # Backlog doesnt have enclosure
@@ -87,28 +85,27 @@ class ExtraTorrentProvider(TorrentProvider):  # pylint: disable=too-many-instanc
                                 info_hash = item.find('info_hash').get_text(strip=True)
                                 download_url = "magnet:?xt=urn:btih:" + info_hash + "&dn=" + title + self._custom_trackers
 
-                            if not all([title, download_url]):
-                                continue
+                        except (AttributeError, TypeError, KeyError, ValueError):
+                            continue
 
-                                # Filter unseeded torrent
-                            if seeders < self.minseed or leechers < self.minleech:
-                                if mode != 'RSS':
-                                    logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                                continue
+                        if not all([title, download_url]):
+                            continue
 
-                            item = title, download_url, size, seeders, leechers
+                            # Filter unseeded torrent
+                        if seeders < self.minseed or leechers < self.minleech:
                             if mode != 'RSS':
-                                logger.log(u"Found result: %s " % title, logger.DEBUG)
+                                logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                            continue
 
-                            items[mode].append(item)
+                        item = title, download_url, size, seeders, leechers
+                        if mode != 'RSS':
+                            logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        except (AttributeError, TypeError, KeyError, ValueError):
-                            logger.log(u"Failed parsing provider. Traceback: %r" % traceback.format_exc(), logger.WARNING)
+                        items.append(item)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/fnt.py b/sickbeard/providers/fnt.py
index 21cda3b43ca2d12c5348d9eca3455fd548777a25..338afbb69221efa93227a5b09e47f167484ddcb1 100644
--- a/sickbeard/providers/fnt.py
+++ b/sickbeard/providers/fnt.py
@@ -11,7 +11,7 @@
 #
 # Sick Beard 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
+# 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
@@ -27,7 +27,7 @@ from sickbeard.bs4_parser import BS4Parser
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class FNTProvider(TorrentProvider):
+class FNTProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, "FNT")
 
@@ -75,16 +75,13 @@ class FNTProvider(TorrentProvider):
             logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
             return False
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        # check for auth
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -141,15 +138,14 @@ class FNTProvider(TorrentProvider):
                                     if mode != 'RSS':
                                         logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                                    items[mode].append(item)
+                                    items.append(item)
 
-                except Exception as e:
+                except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/freshontv.py b/sickbeard/providers/freshontv.py
index 4ff0277dc7773a01eb854bf1a074631b8415902c..3efefdf0f1655ced937eed5a4c7bb8b95a10048d 100644
--- a/sickbeard/providers/freshontv.py
+++ b/sickbeard/providers/freshontv.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import time
@@ -25,11 +25,11 @@ import traceback
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class FreshOnTVProvider(TorrentProvider):
+class FreshOnTVProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "FreshOnTV")
@@ -101,26 +101,24 @@ class FreshOnTVProvider(TorrentProvider):
 
                     return False
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None): # pylint: disable=too-many-locals, too-many-branches, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        freeleech = '3' if self.freeleech else '0'
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        freeleech = '3' if self.freeleech else '0'
+
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (freeleech, search_string)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                init_html = self.get_url(searchURL)
+                search_url = self.urls['search'] % (freeleech, search_string)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                init_html = self.get_url(search_url)
                 max_page_number = 0
 
                 if not init_html:
@@ -162,9 +160,9 @@ class FreshOnTVProvider(TorrentProvider):
                     for i in range(1, max_page_number):
 
                         time.sleep(1)
-                        page_searchURL = searchURL + '&page=' + str(i)
-                        # '.log(u"Search string: " + page_searchURL, logger.DEBUG)
-                        page_html = self.get_url(page_searchURL)
+                        page_search_url = search_url + '&page=' + str(i)
+                        # '.log(u"Search string: " + page_search_url, logger.DEBUG)
+                        page_html = self.get_url(page_search_url)
 
                         if not page_html:
                             continue
@@ -202,8 +200,8 @@ class FreshOnTVProvider(TorrentProvider):
                                     download_url = self.urls['download'] % (str(torrent_id))
                                     seeders = try_int(individual_torrent.find('td', {'class': 'table_seeders'}).find('span').text.strip(), 1)
                                     leechers = try_int(individual_torrent.find('td', {'class': 'table_leechers'}).find('a').text.strip(), 0)
-                                    # FIXME
-                                    size = -1
+                                    torrent_size = individual_torrent.find('td', {'class': 'table_size'}).get_text()
+                                    size = convert_size(torrent_size) or -1
                                 except Exception:
                                     continue
 
@@ -220,15 +218,14 @@ class FreshOnTVProvider(TorrentProvider):
                                 if mode != 'RSS':
                                     logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                                items[mode].append(item)
+                                items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/gftracker.py b/sickbeard/providers/gftracker.py
index 79da127b9418f064b86bf7bda3e0b8cb42f4e6f4..6b381325eb02c3285d1519f449d413b1dcdeb19c 100644
--- a/sickbeard/providers/gftracker.py
+++ b/sickbeard/providers/gftracker.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import requests
@@ -24,11 +24,12 @@ import traceback
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.helper.exceptions import AuthException
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class GFTrackerProvider(TorrentProvider):
+class GFTrackerProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -83,26 +84,24 @@ class GFTrackerProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (self.categories, search_string)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.urls['search'] % (self.categories, search_string)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
                 # Returns top 30 results by default, expandable in user profile
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
@@ -126,10 +125,7 @@ class GFTrackerProvider(TorrentProvider):
                                 leechers = int(shares[1])
 
                                 torrent_size = cells[7].get_text().split("/", 1)[0]
-                                if re.match(r"\d+([,\.]\d+)?\s*[KkMmGgTt]?[Bb]", torrent_size):
-                                    size = self._convertSize(torrent_size.strip())
-                                else:
-                                    size = -1
+                                size = convert_size(torrent_size) or -1
 
                             except (AttributeError, TypeError):
                                 continue
@@ -147,38 +143,21 @@ class GFTrackerProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, sizeString):
-        size = sizeString[:-2].strip()
-        modifier = sizeString[-2:].upper()
-        try:
-            size = float(size)
-            if modifier in 'KB':
-                size *= 1024 ** 1
-            elif modifier in 'MB':
-                size *= 1024 ** 2
-            elif modifier in 'GB':
-                size *= 1024 ** 3
-            elif modifier in 'TB':
-                size *= 1024 ** 4
-        except Exception:
-            size = -1
-        return long(size)
-
 
 class GFTrackerCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/hd4free.py b/sickbeard/providers/hd4free.py
index 4cf1526a486c0a09a7c3d601c39f5efcb0699fd3..8cfe55a8baea806b99fb8e58f6f0821e884fec48 100644
--- a/sickbeard/providers/hd4free.py
+++ b/sickbeard/providers/hd4free.py
@@ -11,31 +11,35 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from urllib import urlencode
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class HD4FREEProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
+class HD4FreeProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
         TorrentProvider.__init__(self, "HD4Free")
 
-        self.public = True
         self.url = 'https://hd4free.xyz'
-        self.ratio = 0
-        self.cache = HD4FREECache(self)
-        self.minseed, self.minleech = 2 * [None]
+        self.urls = {'search': self.url + '/searchapi.php'}
+
+        self.freeleech = None
         self.username = None
         self.api_key = None
-        self.freeleech = None
+        self.minseed = None
+        self.minleech = None
+        self.ratio = 0
+
+        self.cache = HD4FreeCache(self)
 
     def _check_auth(self):
         if self.username and self.api_key:
@@ -44,34 +48,36 @@ class HD4FREEProvider(TorrentProvider):  # pylint: disable=too-many-instance-att
         logger.log('Your authentication credentials for %s are missing, check your config.' % self.name, logger.WARNING)
         return False
 
-    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self._check_auth:
             return results
-            
+
         search_params = {
             'tv': 'true',
             'username': self.username,
             'apikey': self.api_key
         }
 
-        for mode in search_strings.keys():  # Mode = RSS, Season, Episode
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
-                if mode != 'RSS':
-                    search_params['search'] = search_string.encode('utf-8')
-
-                search_params['fl'] = 'true' if self.freeleech else 'false'
+                if self.freeleech:
+                    search_params['fl'] = 'true'
+                else:
+                    search_params.pop('fl', '')
 
                 if mode != 'RSS':
                     logger.log(u"Search string: " + search_string.strip(), logger.DEBUG)
+                    search_params['search'] = search_string.encode('utf-8')
+                else:
+                    search_params.pop('search', '')
 
-                searchURL = self.url + "/searchapi.php?" + urlencode(search_params)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                jdata = self.get_url(searchURL, json=True)
+                search_url = self.urls['search'] + "?" + urlencode(search_params)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+
+                jdata = self.get_url(search_url, json=True)
                 if not jdata:
                     logger.log(u"No data returned from provider", logger.DEBUG)
                     continue
@@ -80,35 +86,38 @@ class HD4FREEProvider(TorrentProvider):  # pylint: disable=too-many-instance-att
                     if jdata['0']['total_results'] == 0:
                         logger.log(u"Provider has no results for this search", logger.DEBUG)
                         continue
-                except (ValueError, KeyError):
-                    pass
+                except StandardError:
+                    continue
 
                 for i in jdata:
-                    seeders = jdata[i]["seeders"]
-                    leechers = jdata[i]["leechers"]
-                    title = jdata[i]["release_name"]
-                    size = jdata[i]["size"]
-                    download_url = jdata[i]["download_url"]
+                    try:
+                        title = jdata[i]["release_name"]
+                        download_url = jdata[i]["download_url"]
+                        if not all([title, download_url]):
+                            continue
+
+                        seeders = jdata[i]["seeders"]
+                        leechers = jdata[i]["leechers"]
+                        if seeders < self.minseed or leechers < self.minleech:
+                            if mode != 'RSS':
+                                logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                            continue
+
+                        torrent_size = str(jdata[i]["size"]) + ' MB'
+                        size = convert_size(torrent_size) or -1
+                        item = title, download_url, size, seeders, leechers
 
-                    if not all([title, download_url]):
-                        continue
-
-                    # Filter unseeded torrent
-                    if seeders < self.minseed or leechers < self.minleech:
                         if mode != 'RSS':
-                            logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                        continue
+                            logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                    if mode != 'RSS':
-                        logger.log(u"Found result: %s " % title, logger.DEBUG)
-
-                    item = title, download_url, size, seeders, leechers
-                    items[mode].append(item)
+                        items.append(item)
+                    except StandardError:
+                        continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -116,7 +125,7 @@ class HD4FREEProvider(TorrentProvider):  # pylint: disable=too-many-instance-att
         return self.ratio
 
 
-class HD4FREECache(tvcache.TVCache):
+class HD4FreeCache(tvcache.TVCache):
     def __init__(self, provider_obj):
 
         tvcache.TVCache.__init__(self, provider_obj)
@@ -129,4 +138,4 @@ class HD4FREECache(tvcache.TVCache):
         search_params = {'RSS': ['']}
         return {'entries': self.provider.search(search_params)}
 
-provider = HD4FREEProvider()
+provider = HD4FreeProvider()
diff --git a/sickbeard/providers/hdbits.py b/sickbeard/providers/hdbits.py
index bcd271ccc6dcef8d7d374262bd519de2a3864382..24a0b2e2bf543559b3461e97c2fa3097a266214b 100644
--- a/sickbeard/providers/hdbits.py
+++ b/sickbeard/providers/hdbits.py
@@ -8,11 +8,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import urllib
diff --git a/sickbeard/providers/hdspace.py b/sickbeard/providers/hdspace.py
index addac0b45e58dea7e03dfe028294a2fe40f6e9bc..a5a543e6327f1a3cfdc98c20427da74bce2a3f4b 100644
--- a/sickbeard/providers/hdspace.py
+++ b/sickbeard/providers/hdspace.py
@@ -13,11 +13,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import urllib
@@ -26,10 +26,11 @@ from bs4 import BeautifulSoup
 
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class HDSpaceProvider(TorrentProvider):
+class HDSpaceProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, "HDSpace")
 
@@ -81,28 +82,25 @@ class HDSpaceProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-many-branches, too-many-locals, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
-
                 if mode != 'RSS':
-                    searchURL = self.urls['search'] % (urllib.quote_plus(search_string.replace('.', ' ')),)
+                    search_url = self.urls['search'] % (urllib.quote_plus(search_string.replace('.', ' ')),)
                 else:
-                    searchURL = self.urls['search'] % ''
+                    search_url = self.urls['search'] % ''
 
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
                 if mode != 'RSS':
                     logger.log(u"Search string: %s" % search_string, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data or 'please try later' in data:
                     logger.log(u"No data returned from provider", logger.DEBUG)
                     continue
@@ -138,7 +136,8 @@ class HDSpaceProvider(TorrentProvider):
                         download_url = self.urls['base_url'] + dl_href
                         seeders = int(result.find('span', attrs={'class': 'seedy'}).find('a').text)
                         leechers = int(result.find('span', attrs={'class': 'leechy'}).find('a').text)
-                        size = re.match(r'.*?([0-9]+,?\.?[0-9]* [KkMmGg]+[Bb]+).*', str(result), re.DOTALL).group(1)
+                        torrent_size = re.match(r'.*?([0-9]+,?\.?[0-9]* [KkMmGg]+[Bb]+).*', str(result), re.DOTALL).group(1)
+                        size = convert_size(torrent_size) or -1
 
                         if not all([title, download_url]):
                             continue
@@ -153,34 +152,20 @@ class HDSpaceProvider(TorrentProvider):
                         if mode != 'RSS':
                             logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        items[mode].append(item)
+                        items.append(item)
 
                     except (AttributeError, TypeError, KeyError, ValueError):
                         continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, size):
-        size, modifier = size.split(' ')
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
 
 class HDSpaceCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/hdtorrents.py b/sickbeard/providers/hdtorrents.py
index eaa632f75b7f1df3f34afaf21cf6bd552c95acf7..8754a1b5150b585f32bd7e3821af872212740243 100644
--- a/sickbeard/providers/hdtorrents.py
+++ b/sickbeard/providers/hdtorrents.py
@@ -1,7 +1,6 @@
 # coding=utf-8
-# Author: Idan Gutman
-# Modified by jkaberg, https://github.com/jkaberg for SceneAccess
-# URL: http://code.google.com/p/sickbeard/
+# Author: miigotu (Dustyn Gibson) <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -12,24 +11,25 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import urllib
 import requests
-import traceback
 
-from sickbeard.bs4_parser import BS4Parser
 from sickbeard import logger
 from sickbeard import tvcache
+from sickbeard.bs4_parser import BS4Parser
+
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class HDTorrentsProvider(TorrentProvider):
+class HDTorrentsProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "HDTorrents")
@@ -39,6 +39,7 @@ class HDTorrentsProvider(TorrentProvider):
         self.ratio = None
         self.minseed = None
         self.minleech = None
+        self.freeleech = None
 
         self.urls = {'base_url': 'https://hd-torrents.org',
                      'login': 'https://hd-torrents.org/login.php',
@@ -80,147 +81,115 @@ class HDTorrentsProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
                 if mode != 'RSS':
-                    searchURL = self.urls['search'] % (urllib.quote_plus(search_string), self.categories)
+                    search_url = self.urls['search'] % (urllib.quote_plus(search_string), self.categories)
+                    logger.log(u"Search string: %s" % search_string, logger.DEBUG)
                 else:
-                    searchURL = self.urls['rss'] % self.categories
+                    search_url = self.urls['rss'] % self.categories
 
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                if mode != 'RSS':
-                    logger.log(u"Search string: %s" % search_string, logger.DEBUG)
+                if self.freeleech:
+                    search_url = search_url.replace('active=1', 'active=5')
+
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data or 'please try later' in data:
                     logger.log(u"No data returned from provider", logger.DEBUG)
                     continue
 
+                if data.find('No torrents here') != -1:
+                    logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                    continue
+
                 # Search result page contains some invalid html that prevents html parser from returning all data.
                 # We cut everything before the table that contains the data we are interested in thus eliminating
                 # the invalid html portions
                 try:
                     index = data.lower().index('<table class="mainblockcontenttt"')
                 except ValueError:
-                    logger.log(u"Could not find table of torrents mainblockcontenttt", logger.ERROR)
+                    logger.log(u"Could not find table of torrents mainblockcontenttt", logger.DEBUG)
                     continue
 
-                data = urllib.unquote(data[index:].encode('utf-8')).decode('utf-8').replace('\t', '')
+                # data = urllib.unquote(data[index:].encode('utf-8')).decode('utf-8').replace('\t', '')
+                data = data[index:]
 
                 with BS4Parser(data, 'html5lib') as html:
                     if not html:
                         logger.log(u"No html data parsed from provider", logger.DEBUG)
                         continue
 
-                    empty = html.find('No torrents here')
-                    if empty:
-                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
-                        continue
+                    torrent_rows = []
+                    torrent_table = html.find('table', class_='mainblockcontenttt')
+                    if torrent_table:
+                        torrent_rows = torrent_table.find_all('tr')
 
-                    tables = html.find('table', attrs={'class': 'mainblockcontenttt'})
-                    if not tables:
-                        logger.log(u"Could not find table of torrents mainblockcontenttt", logger.ERROR)
+                    if not torrent_rows:
+                        logger.log(u"Could not find results in returned data", logger.DEBUG)
                         continue
 
-                    torrents = tables.findChildren('tr')
-                    if not torrents:
-                        continue
+                    # Cat., Active, Filename, Dl, Wl, Added, Size, Uploader, S, L, C
+                    labels = [label.a.get_text(strip=True) if label.a else label.get_text(strip=True) for label in torrent_rows[0].find_all('td')]
 
                     # Skip column headers
-                    for result in torrents[1:]:
+                    for result in torrent_rows[1:]:
                         try:
-                            cells = result.findChildren('td', attrs={'class': re.compile(r'(green|yellow|red|mainblockcontent)')})
-                            if not cells:
+                            cells = result.findChildren('td')[:len(labels)]
+                            if len(cells) < len(labels):
                                 continue
 
-                            title = download_url = seeders = leechers = size = None
-                            for cell in cells:
-                                try:
-                                    if None is title and cell.get('title') and cell.get('title') in 'Download':
-                                        title = re.search('f=(.*).torrent', cell.a['href']).group(1).replace('+', '.')
-                                        title = title.decode('utf-8')
-                                        download_url = self.urls['home'] % cell.a['href']
-                                        continue
-                                    if None is seeders and cell.get('class')[0] and cell.get('class')[0] in 'green' 'yellow' 'red':
-                                        seeders = int(cell.text)
-                                        if not seeders:
-                                            seeders = 1
-                                            continue
-                                    elif None is leechers and cell.get('class')[0] and cell.get('class')[0] in 'green' 'yellow' 'red':
-                                        leechers = int(cell.text)
-                                        if not leechers:
-                                            leechers = 0
-                                            continue
-
-                                    # Need size for failed downloads handling
-                                    if size is None:
-                                        if re.match(r'[0-9]+,?\.?[0-9]* [KkMmGg]+[Bb]+', cell.text):
-                                            size = self._convertSize(cell.text)
-                                            if not size:
-                                                size = -1
-
-                                except Exception:
-                                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
-
-                            if not all([title, download_url]):
-                                continue
+                            title = cells[labels.index(u'Filename')].a.get_text(strip=True)
+                            seeders = try_int(cells[labels.index(u'S')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index(u'L')].get_text(strip=True))
+                            torrent_size = cells[labels.index(u'Size')].get_text()
 
-                            # Filter unseeded torrent
-                            if seeders < self.minseed or leechers < self.minleech:
-                                if mode != 'RSS':
-                                    logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                                continue
+                            size = convert_size(torrent_size) or -1
+                            download_url = self.url + '/' + cells[labels.index(u'Dl')].a['href']
+                        except (AttributeError, TypeError, KeyError, ValueError, IndexError):
+                            continue
 
-                            item = title, download_url, size, seeders, leechers
+                        if not all([title, download_url]):
+                            continue
+
+                        # Filter unseeded torrent
+                        if seeders < self.minseed or leechers < self.minleech:
                             if mode != 'RSS':
-                                logger.log(u"Found result: %s " % title, logger.DEBUG)
+                                logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                            continue
 
-                            items[mode].append(item)
+                        item = title, download_url, size, seeders, leechers
+                        if mode != 'RSS':
+                            logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        except (AttributeError, TypeError, KeyError, ValueError):
-                            continue
+                        items.append(item)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, size):
-        size, modifier = size.split(' ')
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
 
 class HDTorrentsCache(tvcache.TVCache):
     def __init__(self, provider_obj):
 
         tvcache.TVCache.__init__(self, provider_obj)
 
-        # only poll HDTorrents every 10 minutes max
-        self.minTime = 10
+        # only poll HDTorrents every 30 minutes max
+        self.minTime = 30
 
     def _getRSSData(self):
         search_strings = {'RSS': ['']}
diff --git a/sickbeard/providers/hounddawgs.py b/sickbeard/providers/hounddawgs.py
index f6fa855453df7e21e9dc62d5396efa155c2e9013..05963cff520798c0278e25cfb91916affa8ba147 100644
--- a/sickbeard/providers/hounddawgs.py
+++ b/sickbeard/providers/hounddawgs.py
@@ -11,18 +11,18 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import traceback
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
@@ -90,14 +90,12 @@ class HoundDawgsProvider(TorrentProvider):  # pylint: disable=too-many-instance-
         return True
 
     def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
-
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -149,7 +147,7 @@ class HoundDawgsProvider(TorrentProvider):  # pylint: disable=too-many-instance-
                                 download_url = self.urls['base_url'] + allAs[0].attrs['href']
                                 torrent_size = result.find("td", class_="nobr").find_next_sibling("td").string
                                 if torrent_size:
-                                    size = self._convertSize(torrent_size)
+                                    size = convert_size(torrent_size) or -1
                                 seeders = try_int((result.findAll('td')[6]).text)
                                 leechers = try_int((result.findAll('td')[7]).text)
 
@@ -169,31 +167,18 @@ class HoundDawgsProvider(TorrentProvider):  # pylint: disable=too-many-instance-
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
-    @staticmethod
-    def _convertSize(size):
-        size = re.sub(r'[i, ]+', '', size)
-        matches = re.match(r'([\d.]+)([TGMK])', size.strip().upper())
-        if not matches:
-            return -1
-
-        size = matches.group(1)
-        modifier = matches.group(2)
-
-        mod = {'K': 1, 'M': 2, 'G': 3, 'T': 4}
-        return long(float(size) * 1024 ** mod[modifier])
-
     def seed_ratio(self):
         return self.ratio
 
diff --git a/sickbeard/providers/iptorrents.py b/sickbeard/providers/iptorrents.py
index 778d4342bcc5d0717631af90c7514231c813a371..3e36754a83ffc42bcc27fc4bcc588cab02d1a213 100644
--- a/sickbeard/providers/iptorrents.py
+++ b/sickbeard/providers/iptorrents.py
@@ -11,21 +11,22 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.helper.exceptions import AuthException, ex
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class IPTorrentsProvider(TorrentProvider):
+class IPTorrentsProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "IPTorrents")
@@ -66,26 +67,27 @@ class IPTorrentsProvider(TorrentProvider):
             logger.log(u"Unable to connect to provider", logger.WARNING)
             return False
 
-        if re.search('tries left', response):
-            logger.log(u"You tried too often, please try again after 1 hour! Disable IPTorrents for at least 1 hour", logger.WARNING)
-            return False
-        if re.search('Password not correct', response):
+        # Invalid username and password combination
+        if re.search('Invalid username and password combination', response):
             logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
             return False
 
-        return True
+        # You tried too often, please try again after 2 hours!
+        if re.search('You tried too often', response):
+            logger.log(u"You tried too often, please try again after 2 hours! Disable IPTorrents for at least 2 hours", logger.WARNING)
+            return False
 
-    def search(self, search_params, age=0, ep_obj=None):
+        return True
 
+    def search(self, search_params, age=0, ep_obj=None): # pylint: disable=too-many-locals, too-many-branches, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        freeleech = '&free=on' if self.freeleech else ''
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        freeleech = '&free=on' if self.freeleech else ''
+
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
@@ -93,11 +95,11 @@ class IPTorrentsProvider(TorrentProvider):
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
                 # URL with 50 tv-show results, or max 150 if adjusted in IPTorrents profile
-                searchURL = self.urls['search'] % (self.categories, freeleech, search_string)
-                searchURL += ';o=seeders' if mode != 'RSS' else ''
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.urls['search'] % (self.categories, freeleech, search_string)
+                search_url += ';o=seeders' if mode != 'RSS' else ''
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
@@ -124,9 +126,10 @@ class IPTorrentsProvider(TorrentProvider):
                             try:
                                 title = result.find_all('td')[1].find('a').text
                                 download_url = self.urls['base_url'] + result.find_all('td')[3].find('a')['href']
-                                size = self._convertSize(result.find_all('td')[5].text)
                                 seeders = int(result.find('td', attrs={'class': 'ac t_seeders'}).text)
                                 leechers = int(result.find('td', attrs={'class': 'ac t_leechers'}).text)
+                                torrent_size = result.find_all('td')[5].text
+                                size = convert_size(torrent_size) or -1
                             except (AttributeError, TypeError, KeyError):
                                 continue
 
@@ -143,35 +146,21 @@ class IPTorrentsProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception as e:
                     logger.log(u"Failed parsing provider. Error: %r" % ex(e), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    @staticmethod
-    def _convertSize(size):
-        size, modifier = size.split(' ')
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
 
 class IPTorrentsCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/kat.py b/sickbeard/providers/kat.py
old mode 100755
new mode 100644
index 2472449e29d23dd636b212b45d15e9357ccb73af..8a6a71092dfa2bd449fa6cb0078d18951b48b8fe
--- a/sickbeard/providers/kat.py
+++ b/sickbeard/providers/kat.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import posixpath  # Must use posixpath
 import traceback
@@ -26,11 +26,11 @@ import sickbeard
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.common import USER_AGENT
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class KATProvider(TorrentProvider):
+class KatProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "KickAssTorrents")
@@ -60,17 +60,17 @@ class KATProvider(TorrentProvider):
             'category': 'tv'
         }
 
-        self.cache = KATCache(self)
+        self.cache = KatCache(self)
 
-    def search(self, search_strings, age=0, ep_obj=None):
+    def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-many-branches, too-many-locals, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
 
         # select the correct category
         anime = (self.show and self.show.anime) or (ep_obj and ep_obj.show and ep_obj.show.anime) or False
         self.search_params['category'] = ('tv', 'anime')[anime]
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -82,12 +82,12 @@ class KATProvider(TorrentProvider):
 
                 url_fmt_string = 'usearch' if mode != 'RSS' else search_string
                 try:
-                    searchURL = self.urls['search'] % url_fmt_string + '?' + urlencode(self.search_params)
+                    search_url = self.urls['search'] % url_fmt_string + '?' + urlencode(self.search_params)
                     if self.custom_url:
-                        searchURL = posixpath.join(self.custom_url, searchURL.split(self.url)[1].lstrip('/'))  # Must use posixpath
+                        search_url = posixpath.join(self.custom_url, search_url.split(self.url)[1].lstrip('/'))  # Must use posixpath
 
-                    logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                    data = self.get_url(searchURL)
+                    logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                    data = self.get_url(search_url)
                     if not data:
                         logger.log(u'URL did not return data, maybe try a custom url, or a different one', logger.DEBUG)
                         continue
@@ -114,10 +114,11 @@ class KATProvider(TorrentProvider):
                             if not (title and download_url):
                                 continue
 
-                            seeders = try_int(item.find('torrent:seeds').text, 0)
-                            leechers = try_int(item.find('torrent:peers').text, 0)
-                            verified = bool(try_int(item.find('torrent:verified').text, 0))
-                            size = try_int(item.find('torrent:contentlength').text)
+                            seeders = try_int(item.find('torrent:seeds').text)
+                            leechers = try_int(item.find('torrent:peers').text)
+                            verified = bool(try_int(item.find('torrent:verified').text))
+                            torrent_size = item.find('torrent:contentlength').text
+                            size = convert_size(torrent_size) or -1
 
                             info_hash = item.find('torrent:infohash').text
                             # link = item['link']
@@ -140,15 +141,15 @@ class KATProvider(TorrentProvider):
                         if mode != 'RSS':
                             logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        items[mode].append(item)
+                        items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %r" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -156,7 +157,7 @@ class KATProvider(TorrentProvider):
         return self.ratio
 
 
-class KATCache(tvcache.TVCache):
+class KatCache(tvcache.TVCache):
     def __init__(self, provider_obj):
 
         tvcache.TVCache.__init__(self, provider_obj)
@@ -168,4 +169,4 @@ class KATCache(tvcache.TVCache):
         search_params = {'RSS': ['tv', 'anime']}
         return {'entries': self.provider.search(search_params)}
 
-provider = KATProvider()
+provider = KatProvider()
diff --git a/sickbeard/providers/limetorrents.py b/sickbeard/providers/limetorrents.py
index 6a73e2d846a531f689098b9b59a8e9c465088dcf..83fa9bfd1a8f4aa6b4b5811d9c1a8089baa17612 100644
--- a/sickbeard/providers/limetorrents.py
+++ b/sickbeard/providers/limetorrents.py
@@ -10,18 +10,18 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import traceback
 from bs4 import BeautifulSoup
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.common import USER_AGENT
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
@@ -47,11 +47,9 @@ class LimeTorrentsProvider(TorrentProvider): # pylint: disable=too-many-instance
         self.cache = LimeTorrentsCache(self)
 
     def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-many-branches,too-many-locals
-
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -97,7 +95,10 @@ class LimeTorrentsProvider(TorrentProvider): # pylint: disable=too-many-instance
                                 description = item.find('description').text.partition(',')
                                 seeders = try_int(description[0].lstrip('Seeds: ').strip())
                                 leechers = try_int(description[2].lstrip('Leechers ').strip())
-                            size = try_int(item.find('size').text, -1)
+
+                            torrent_size = item.find('size').text
+
+                            size = convert_size(torrent_size) or -1
 
                         except (AttributeError, TypeError, KeyError, ValueError):
                             continue
@@ -112,15 +113,15 @@ class LimeTorrentsProvider(TorrentProvider): # pylint: disable=too-many-instance
                         if mode != 'RSS':
                             logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        items[mode].append(item)
+                        items.append(item)
 
                 except (AttributeError, TypeError, KeyError, ValueError):
                     logger.log(u"Failed parsing provider. Traceback: %r" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/morethantv.py b/sickbeard/providers/morethantv.py
index 71892f1e7766fad006478162a3a625a596b2ab2d..e5dfac46d5b36b29347ec1838c07a572904d854d 100644
--- a/sickbeard/providers/morethantv.py
+++ b/sickbeard/providers/morethantv.py
@@ -1,6 +1,6 @@
 # coding=utf-8
-# Author: Seamus Wassman
-# URL: http://code.google.com/p/sickbeard/
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,28 +11,25 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
-
-# This file was adapted for MoreThanTV from the freshontv scraper by
-# Sparhawk76, this is my first foray into python, so there most likely
-# are some mistakes or things I could have done better.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
-import requests
-import traceback
+from requests.utils import dict_from_cookiejar
+from urllib import urlencode
 
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import try_int, convert_size
 from sickrage.helper.exceptions import AuthException
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class MoreThanTVProvider(TorrentProvider):
+class MoreThanTVProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -45,17 +42,12 @@ class MoreThanTVProvider(TorrentProvider):
         self.ratio = None
         self.minseed = None
         self.minleech = None
-        # self.freeleech = False
-
-        self.urls = {'base_url': 'https://www.morethan.tv/',
-                     'login': 'https://www.morethan.tv/login.php',
-                     'detail': 'https://www.morethan.tv/torrents.php?id=%s',
-                     'search': 'https://www.morethan.tv/torrents.php?tags_type=1&order_by=time&order_way=desc&action=basic&searchsubmit=1&searchstr=%s',
-                     'download': 'https://www.morethan.tv/torrents.php?action=download&id=%s'}
-
-        self.url = self.urls['base_url']
 
-        self.cookies = None
+        self.url = 'https://www.morethan.tv/'
+        self.urls = {
+            'login': self.url + 'login.php',
+            'search': self.url + 'torrents.php',
+        }
 
         self.proper_strings = ['PROPER', 'REPACK']
 
@@ -69,137 +61,118 @@ class MoreThanTVProvider(TorrentProvider):
         return True
 
     def login(self):
-        if any(requests.utils.dict_from_cookiejar(self.session.cookies).values()):
+        if any(dict_from_cookiejar(self.session.cookies).values()):
             return True
 
-        if self._uid and self._hash:
-            requests.utils.add_dict_to_cookiejar(self.session.cookies, self.cookies)
-        else:
-            login_params = {'username': self.username,
-                            'password': self.password,
-                            'login': 'Log in',
-                            'keeplogged': '1'}
+        login_params = {
+            'username': self.username,
+            'password': self.password,
+            'login': 'Log in',
+            'keeplogged': '1'
+        }
 
-            response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
-            if not response:
-                logger.log(u"Unable to connect to provider", logger.WARNING)
-                return False
+        response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
+        if not response:
+            logger.log(u"Unable to connect to provider", logger.WARNING)
+            return False
 
-            if re.search('Your username or password was incorrect.', response):
-                logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
-                return False
+        if re.search('Your username or password was incorrect.', response):
+            logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
+            return False
 
-            return True
-
-    def search(self, search_params, age=0, ep_obj=None):
+        return True
 
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        # freeleech = '3' if self.freeleech else '0'
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        search_params = {
+            'tags_type': 1,
+            'order_by': 'time',
+            'order_way': 'desc',
+            'action': 'basic',
+            'searchsubmit': 1,
+            'searchstr': ''
+        }
+
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
-
+            for search_string in search_strings[mode]:
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (search_string.replace('(', '').replace(')', ''))
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_params['searchstr'] = search_string
+
+                search_url = "%s?%s" % (self.urls['search'], urlencode(search_params))
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
                 # returns top 15 results by default, expandable in user profile to 100
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
-                try:
-                    with BS4Parser(data, 'html5lib') as html:
-                        torrent_table = html.find('table', attrs={'class': 'torrent_table'})
-                        torrent_rows = torrent_table.findChildren('tr') if torrent_table else []
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('table', class_='torrent_table')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
 
-                        # Continue only if one Release is found
-                        if len(torrent_rows) < 2:
-                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
-                            continue
+                    # Continue only if one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                        continue
 
-                        # skip colheader
-                        for result in torrent_rows[1:]:
-                            cells = result.findChildren('td')
-                            link = cells[1].find('a', attrs={'title': 'Download'})
+                    def process_column_header(td):
+                        result = ''
+                        if td.a and td.a.img:
+                            result = td.a.img.get('title', td.a.get_text(strip=True))
+                        if not result:
+                            result = td.get_text(strip=True)
+                        return result
 
-                            # skip if torrent has been nuked due to poor quality
-                            if cells[1].find('img', alt='Nuked') is not None:
-                                continue
-
-                            torrent_id_long = link['href'].replace('torrents.php?action=download&id=', '')
-
-                            try:
-                                if link.get('title', ''):
-                                    title = cells[1].find('a', {'title': 'View torrent'}).contents[0].strip()
-                                else:
-                                    title = link.contents[0]
-                                download_url = self.urls['download'] % torrent_id_long
-
-                                seeders = cells[6].contents[0]
-
-                                leechers = cells[7].contents[0]
-
-                                size = -1
-                                if re.match(r'\d+([,\.]\d+)?\s*[KkMmGgTt]?[Bb]', cells[4].contents[0]):
-                                    size = self._convertSize(cells[4].text.strip())
+                    labels = [process_column_header(label) for label in torrent_rows[0].find_all('td')]
 
-                            except (AttributeError, TypeError):
+                    # skip colheader
+                    for result in torrent_rows[1:]:
+                        try:
+                            # skip if torrent has been nuked due to poor quality
+                            if result.find('img', alt='Nuked'):
                                 continue
 
+                            title = result.find('a', title='View torrent').get_text(strip=True)
+                            download_url = self.url + result.find('span', title='Download').parent['href']
                             if not all([title, download_url]):
                                 continue
 
-                            # Filter unseeded torrent
+                            cells = result.find_all('td')
+                            seeders = try_int(cells[labels.index('Seeders')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('Leechers')].get_text(strip=True))
                             if seeders < self.minseed or leechers < self.minleech:
                                 if mode != 'RSS':
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
+                            torrent_size = cells[labels.index('Size')].get_text(strip=True)
+                            size = convert_size(torrent_size) or -1
+
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
-
-                except Exception as e:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+                            items.append(item)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, sizeString):
-        size = sizeString[:-2].strip()
-        modifier = sizeString[-2:].upper()
-        try:
-            size = float(size)
-            if modifier in 'KB':
-                size *= 1024 ** 1
-            elif modifier in 'MB':
-                size *= 1024 ** 2
-            elif modifier in 'GB':
-                size *= 1024 ** 3
-            elif modifier in 'TB':
-                size *= 1024 ** 4
-        except Exception:
-            size = -1
-        return long(size)
-
 
 class MoreThanTVCache(tvcache.TVCache):
     def __init__(self, provider_obj):
@@ -210,7 +183,7 @@ class MoreThanTVCache(tvcache.TVCache):
         self.minTime = 20
 
     def _getRSSData(self):
-        search_params = {'RSS': ['']}
-        return {'entries': self.provider.search(search_params)}
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
 
 provider = MoreThanTVProvider()
diff --git a/sickbeard/providers/newpct.py b/sickbeard/providers/newpct.py
index 2a33d293bb3372678bd57126664ef103362a4970..3a9153b5d48031ff918a1dc0c9abea2112048bdf 100644
--- a/sickbeard/providers/newpct.py
+++ b/sickbeard/providers/newpct.py
@@ -13,11 +13,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import traceback
 import re
@@ -27,6 +27,7 @@ from sickbeard import helpers
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
@@ -68,15 +69,15 @@ class newpctProvider(TorrentProvider):
             'bus_de_': 'All'
         }
 
-    def search(self, search_strings, age=0, ep_obj=None):
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
 
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
 
         # Only search if user conditions are true
         lang_info = '' if not ep_obj or not ep_obj.show else ep_obj.show.lang
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
 
             # Only search if user conditions are true
@@ -91,10 +92,10 @@ class newpctProvider(TorrentProvider):
                 self.search_params['q'] = search_string.strip() if mode != 'RSS' else ''
                 self.search_params['bus_de_'] = 'All' if mode != 'RSS' else 'hoy'
 
-                searchURL = self.urls['search'] + '?' + urllib.parse.urlencode(self.search_params)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.urls['search'] + '?' + urllib.parse.urlencode(self.search_params)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL, timeout=30)
+                data = self.get_url(search_url, timeout=30)
                 if not data:
                     continue
 
@@ -113,17 +114,18 @@ class newpctProvider(TorrentProvider):
 
                         for row in torrent_table[:-1]:
                             try:
-                                torrent_size = row.findAll('td')[2]
                                 torrent_row = row.findAll('a')[0]
 
                                 download_url = torrent_row.get('href', '')
-                                size = self._convertSize(torrent_size.text)
+
                                 title = self._processTitle(torrent_row.get('title', ''))
 
-                                # FIXME: Provider does not provide seeders/leechers
+                                # Provider does not provide seeders/leechers
                                 seeders = 1
                                 leechers = 0
+                                torrent_size = row.findAll('td')[2].text
 
+                                size = convert_size(torrent_size) or -1
                             except (AttributeError, TypeError):
                                 continue
 
@@ -140,19 +142,19 @@ class newpctProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.WARNING)
 
             # For each search mode sort all the items by seeders if available (Unsupported)
-            # items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            # items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
-    def get_url(self, url, post_data=None, params=None, timeout=30, json=False, need_bytes=False):
+    def get_url(self, url, post_data=None, params=None, timeout=30, json=False, need_bytes=False):  # pylint: disable=too-many-arguments
         """
         need_bytes=True when trying access to torrent info (For calling torrent client). Previously we must parse
         the URL to get torrent file
@@ -199,19 +201,6 @@ class newpctProvider(TorrentProvider):
 
         return False
 
-    @staticmethod
-    def _convertSize(size):
-        size, modifier = size.split(' ')
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
 
     @staticmethod
     def _processTitle(title):
@@ -219,23 +208,23 @@ class newpctProvider(TorrentProvider):
         title = title[22:]
 
         # Quality - Use re module to avoid case sensitive problems with replace
-        title = re.sub('\[HDTV 1080p[^\[]*]', '1080p HDTV x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[HDTV 720p[^\[]*]', '720p HDTV x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[ALTA DEFINICION 720p[^\[]*]', '720p HDTV x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[HDTV]', 'HDTV x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[DVD[^\[]*]', 'DVDrip x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[BluRay 1080p[^\[]*]', '1080p BlueRay x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[BluRay MicroHD[^\[]*]', '1080p BlueRay x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[MicroHD 1080p[^\[]*]', '1080p BlueRay x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[BLuRay[^\[]*]', '720p BlueRay x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[BRrip[^\[]*]', '720p BlueRay x264', title, flags=re.IGNORECASE)
-        title = re.sub('\[BDrip[^\[]*]', '720p BlueRay x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[HDTV 1080p[^\[]*]', '1080p HDTV x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[HDTV 720p[^\[]*]', '720p HDTV x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[ALTA DEFINICION 720p[^\[]*]', '720p HDTV x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[HDTV]', 'HDTV x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[DVD[^\[]*]', 'DVDrip x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[BluRay 1080p[^\[]*]', '1080p BlueRay x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[BluRay MicroHD[^\[]*]', '1080p BlueRay x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[MicroHD 1080p[^\[]*]', '1080p BlueRay x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[BLuRay[^\[]*]', '720p BlueRay x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[BRrip[^\[]*]', '720p BlueRay x264', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[BDrip[^\[]*]', '720p BlueRay x264', title, flags=re.IGNORECASE)
 
         # Language
-        title = re.sub('\[Spanish[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
-        title = re.sub('\[Castellano[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[Spanish[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
+        title = re.sub(r'\[Castellano[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
         title = re.sub(ur'\[Español[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
-        title = re.sub(u'\[AC3 5\.1 Español[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
+        title = re.sub(ur'\[AC3 5\.1 Español[^\[]*]', 'SPANISH AUDIO', title, flags=re.IGNORECASE)
 
         title += '-NEWPCT'
 
diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py
index 9c458647dfa999ed6a58f5543b19cb66ed3297a8..9ca950d1a47a4870db88b35ebaa647dea347ca24 100644
--- a/sickbeard/providers/newznab.py
+++ b/sickbeard/providers/newznab.py
@@ -14,17 +14,18 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 # pylint: disable=too-many-instance-attributes,too-many-arguments
 
 import os
 import re
 import urllib
 import datetime
+import time
 from bs4 import BeautifulSoup
 
 import sickbeard
@@ -37,9 +38,10 @@ from sickbeard import db
 from sickbeard.common import Quality
 from sickrage.helper.encoding import ek, ss
 from sickrage.show.Show import Show
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 # from sickbeard.common import USER_AGENT
 from sickrage.providers.nzb.NZBProvider import NZBProvider
+from sickbeard.common  import cpu_presets
 
 
 class NewznabProvider(NZBProvider):
@@ -332,6 +334,7 @@ class NewznabProvider(NZBProvider):
         search_url = ek(os.path.join, self.url, 'api?') + urllib.urlencode(params)
         logger.log(u"Search url: %s" % search_url, logger.DEBUG)
         data = self.get_url(search_url)
+        time.sleep(cpu_presets[sickbeard.CPU_PRESET])
         if not data:
             return results
 
@@ -357,15 +360,17 @@ class NewznabProvider(NZBProvider):
                 continue
 
             seeders = leechers = None
-            size = try_int(item.size, -1)
+            torrent_size = item.size
             for attr in item.findAll('newznab:attr') + item.findAll('torznab:attr'):
-                size = try_int(attr['value'], -1) if attr['name'] == 'size' else size
+                torrent_size = attr['value'] if attr['name'] == 'size' else torrent_size
                 seeders = try_int(attr['value'], 1) if attr['name'] == 'seeders' else seeders
-                leechers = try_int(attr['value'], 0) if attr['name'] == 'peers' else leechers
+                leechers = try_int(attr['value']) if attr['name'] == 'peers' else leechers
 
-            if not size or (torznab and (seeders is None or leechers is None)):
+            if not torrent_size or (torznab and (seeders is None or leechers is None)):
                 continue
 
+            size = convert_size(torrent_size) or -1
+
             result = {'title': title, 'link': download_url, 'size': size, 'seeders': seeders, 'leechers': leechers}
             results.append(result)
 
diff --git a/sickbeard/providers/nyaatorrents.py b/sickbeard/providers/nyaatorrents.py
index fddc7b923db01d930122eabd6fa73dfdf8cacf40..e50ba7bf8dc98332e7bbfa077914ab5c030ef0f7 100644
--- a/sickbeard/providers/nyaatorrents.py
+++ b/sickbeard/providers/nyaatorrents.py
@@ -11,21 +11,22 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 import re
 
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class NyaaProvider(TorrentProvider):
+class NyaaProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "NyaaTorrents")
@@ -45,14 +46,13 @@ class NyaaProvider(TorrentProvider):
         self.minleech = 0
         self.confirmed = False
 
-    def search(self, search_strings, age=0, ep_obj=None):
-        if self.show and not self.show.is_anime:
-            return []
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
+        if self.show and not self.show.is_anime:
+            return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
                 if mode != 'RSS':
@@ -67,21 +67,21 @@ class NyaaProvider(TorrentProvider):
                 if mode != 'RSS':
                     params["term"] = search_string.encode('utf-8')
 
-                searchURL = self.url + '?' + urllib.urlencode(params)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.url + '?' + urllib.urlencode(params)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
                 summary_regex = ur"(\d+) seeder\(s\), (\d+) leecher\(s\), \d+ download\(s\) - (\d+.?\d* [KMGT]iB)(.*)"
                 s = re.compile(summary_regex, re.DOTALL)
 
                 results = []
-                for curItem in self.cache.getRSSFeed(searchURL)['entries'] or []:
+                for curItem in self.cache.getRSSFeed(search_url)['entries'] or []:
                     title = curItem['title']
                     download_url = curItem['link']
                     if not all([title, download_url]):
                         continue
 
-                    seeders, leechers, size, verified = s.findall(curItem['summary'])[0]
-                    size = self._convertSize(size)
+                    seeders, leechers, torrent_size, verified = s.findall(curItem['summary'])[0]
+                    size = convert_size(torrent_size) or -1
 
                     # Filter unseeded torrent
                     if seeders < self.minseed or leechers < self.minleech:
@@ -97,29 +97,14 @@ class NyaaProvider(TorrentProvider):
                     if mode != 'RSS':
                         logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                    items[mode].append(item)
+                    items.append(item)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
-    @staticmethod
-    def _convertSize(size):
-        size, modifier = size.split(' ')
-        size = float(size)
-        if modifier in 'KiB':
-            size *= 1024 ** 1
-        elif modifier in 'MiB':
-            size *= 1024 ** 2
-        elif modifier in 'GiB':
-            size *= 1024 ** 3
-        elif modifier in 'TiB':
-            size *= 1024 ** 4
-        return long(size)
-
     def seed_ratio(self):
         return self.ratio
 
diff --git a/sickbeard/providers/omgwtfnzbs.py b/sickbeard/providers/omgwtfnzbs.py
index cabb18cc61df0b058e0145b1e462e75fe0e1ea45..8b1dbda3a24ae5244a6d73b8e35e5d0c0c4551e1 100644
--- a/sickbeard/providers/omgwtfnzbs.py
+++ b/sickbeard/providers/omgwtfnzbs.py
@@ -24,7 +24,6 @@ import sickbeard
 from sickbeard import tvcache
 from sickbeard import classes
 from sickbeard import logger
-from sickbeard import show_name_helpers
 from sickrage.helper.common import try_int
 from sickrage.providers.nzb.NZBProvider import NZBProvider
 
@@ -37,13 +36,17 @@ class OmgwtfnzbsProvider(NZBProvider):
         self.api_key = None
         self.cache = OmgwtfnzbsCache(self)
 
-        self.urls = {'base_url': 'https://omgwtfnzbs.org/'}
-        self.url = self.urls['base_url']
+        self.url = 'https://omgwtfnzbs.org/'
+        self.urls = {
+            'rss': 'https://rss.omgwtfnzbs.org/rss-download.php',
+            'api': 'https://api.omgwtfnzbs.org/json/'
+        }
 
     def _check_auth(self):
 
         if not self.username or not self.api_key:
             logger.log(u"Invalid api key. Check your settings", logger.WARNING)
+            return False
 
         return True
 
@@ -56,15 +59,13 @@ class OmgwtfnzbsProvider(NZBProvider):
             # provider doesn't return xml on error
             return True
         else:
-            parsedJSON = parsed_data
+            if 'notice' in parsed_data:
+                description_text = parsed_data.get('notice')
 
-            if 'notice' in parsedJSON:
-                description_text = parsedJSON.get('notice')
-
-                if 'information is incorrect' in parsedJSON.get('notice'):
+                if 'information is incorrect' in parsed_data.get('notice'):
                     logger.log(u"Invalid api key. Check your settings", logger.WARNING)
 
-                elif '0 results matched your terms' in parsedJSON.get('notice'):
+                elif '0 results matched your terms' in parsed_data.get('notice'):
                     return True
 
                 else:
@@ -73,51 +74,54 @@ class OmgwtfnzbsProvider(NZBProvider):
 
             return True
 
-    def _get_season_search_strings(self, ep_obj):
-        return [x for x in show_name_helpers.makeSceneSeasonSearchString(self.show, ep_obj)]
-
-    def _get_episode_search_strings(self, ep_obj, add_string=''):
-        return [x for x in show_name_helpers.makeSceneSearchString(self.show, ep_obj)]
-
     def _get_title_and_url(self, item):
         return item['release'], item['getnzb']
 
     def _get_size(self, item):
         return try_int(item['sizebytes'], -1)
 
-    def search(self, search, age=0, ep_obj=None):
+    def search(self, search_strings, age=0, ep_obj=None):
+        results = []
+        if not self._check_auth():
+            return results
+
+        search_params = {
+            'user': self.username,
+            'api': self.api_key,
+            'eng': 1,
+            'catid': '19,20',  # SD,HD
+            'retention': sickbeard.USENET_RETENTION,
+        }
+        if age or not search_params['retention']:
+            search_params['retention'] = age
 
-        self._check_auth()
+        for mode in search_strings:
+            items = []
+            logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
+            for search_string in search_strings[mode]:
 
-        params = {'user': self.username,
-                  'api': self.api_key,
-                  'eng': 1,
-                  'catid': '19,20',  # SD,HD
-                  'retention': sickbeard.USENET_RETENTION,
-                  'search': search}
+                search_params['search'] = search_string
 
-        if age or not params['retention']:
-            params['retention'] = age
+                if mode != 'RSS':
+                    logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-        searchURL = 'https://api.omgwtfnzbs.org/json/?' + urllib.urlencode(params)
-        logger.log(u"Search string: %s" % params, logger.DEBUG)
-        logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                logger.log(u"Search URL: %s" % self.urls['api'] + '?' + urllib.urlencode(search_params), logger.DEBUG)
 
-        parsedJSON = self.get_url(searchURL, json=True)
-        if not parsedJSON:
-            return []
+                data = self.get_url(self.urls['api'], params=search_params, json=True)
+                if not data:
+                    continue
 
-        if self._checkAuthFromData(parsedJSON, is_XML=False):
-            results = []
+                if self._checkAuthFromData(data, is_XML=False):
+                    continue
 
-            for item in parsedJSON:
-                if 'release' in item and 'getnzb' in item:
-                    logger.log(u"Found result: %s " % item.get('title'), logger.DEBUG)
-                    results.append(item)
+                for item in data:
+                    if 'release' in item and 'getnzb' in item:
+                        logger.log(u"Found result: %s " % item.get('title'), logger.DEBUG)
+                        items.append(item)
 
-            return results
+            results += items
 
-        return []
+        return results
 
     def find_propers(self, search_date=None):
         search_terms = ['.PROPER.', '.REPACK.']
@@ -126,7 +130,6 @@ class OmgwtfnzbsProvider(NZBProvider):
         for term in search_terms:
             for item in self.search(term, age=4):
                 if 'usenetage' in item:
-
                     title, url = self._get_title_and_url(item)
                     try:
                         result_date = datetime.fromtimestamp(int(item['usenetage']))
@@ -165,12 +168,14 @@ class OmgwtfnzbsCache(tvcache.TVCache):
         return title, url
 
     def _getRSSData(self):
-        params = {'user': provider.username,
-                  'api': provider.api_key,
-                  'eng': 1,
-                  'catid': '19,20'}  # SD,HD
-
-        rss_url = 'https://rss.omgwtfnzbs.org/rss-download.php?' + urllib.urlencode(params)
+        search_params = {
+            'user': provider.username,
+            'api': provider.api_key,
+            'eng': 1,
+            'catid': '19,20'  # SD,HD
+        }
+
+        rss_url = self.provider.urls['rss'] + '?' + urllib.urlencode(search_params)
 
         logger.log(u"Cache update URL: %s" % rss_url, logger.DEBUG)
 
diff --git a/sickbeard/providers/pretome.py b/sickbeard/providers/pretome.py
index 96fcf5ede873ffd568e784f00bf6a6a74b1b5a98..121ea1538a178242e1068f03e2638cfd013d1cb0 100644
--- a/sickbeard/providers/pretome.py
+++ b/sickbeard/providers/pretome.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import urllib
@@ -24,11 +24,11 @@ import traceback
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class PretomeProvider(TorrentProvider):
-
+class PretomeProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "Pretome")
@@ -78,25 +78,23 @@ class PretomeProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-statements, too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (urllib.quote(search_string.encode('utf-8')), self.categories)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.urls['search'] % (urllib.quote(search_string.encode('utf-8')), self.categories)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
@@ -134,10 +132,8 @@ class PretomeProvider(TorrentProvider):
 
                                 # Need size for failed downloads handling
                                 if size is None:
-                                    if re.match(r'[0-9]+,?\.?[0-9]*[KkMmGg]+[Bb]+', cells[7].text):
-                                        size = self._convertSize(cells[7].text)
-                                        if not size:
-                                            size = -1
+                                    torrent_size = cells[7].text
+                                    size = convert_size(torrent_size) or -1
 
                             except (AttributeError, TypeError):
                                 continue
@@ -155,35 +151,21 @@ class PretomeProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
-                except Exception as e:
+                except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, sizeString):
-        size = sizeString[:-2]
-        modifier = sizeString[-2:]
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
 
 class PretomeCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/rarbg.py b/sickbeard/providers/rarbg.py
index b13b62597709ebf13ce143ee834ac65588ef64d5..440a8f0c0adb4f8cfaefe800b51cde58d53564c2 100644
--- a/sickbeard/providers/rarbg.py
+++ b/sickbeard/providers/rarbg.py
@@ -1,6 +1,6 @@
 # coding=utf-8
-# Author: Nic Wolfe <nic@wolfeden.ca>
-# URL: http://code.google.com/p/sickbeard/
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,30 +11,24 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
-import traceback
-import re
-import datetime
-import json
 import time
+import datetime
+from urllib import urlencode
 
-from sickbeard import logger
-from sickbeard import tvcache
-from sickbeard.common import USER_AGENT
+from sickbeard import logger, tvcache
 from sickbeard.indexers.indexer_config import INDEXER_TVDB
+from sickrage.helper.common import try_int
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class GetOutOfLoop(Exception):
-    pass
-
-
-class RarbgProvider(TorrentProvider):
+class RarbgProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
         TorrentProvider.__init__(self, "Rarbg")
@@ -46,68 +40,51 @@ class RarbgProvider(TorrentProvider):
         self.sorting = None
         self.minleech = None
         self.token = None
-        self.tokenExpireDate = None
-
-        self.urls = {'url': u'https://rarbg.com',
-                     'token': u'http://torrentapi.org/pubapi_v2.php?get_token=get_token&format=json&app_id=sickrage2',
-                     'listing': u'http://torrentapi.org/pubapi_v2.php?mode=list&app_id=sickrage2',
-                     'search': u'http://torrentapi.org/pubapi_v2.php?mode=search&app_id=sickrage2&search_string={search_string}',
-                     'search_tvdb': u'http://torrentapi.org/pubapi_v2.php?mode=search&app_id=sickrage2&search_tvdb={tvdb}&search_string={search_string}',
-                     'api_spec': u'https://rarbg.com/pubapi/apidocs.txt'}
-
-        self.url = self.urls['listing']
-
-        self.urlOptions = {
-            'categories': '&category={categories}',
-            'seeders': '&min_seeders={min_seeders}',
-            'leechers': '&min_leechers={min_leechers}',
-            'sorting': '&sort={sorting}',
-            'limit': '&limit={limit}',
-            'format': '&format={format}',
-            'ranked': '&ranked={ranked}',
-            'token': '&token={token}'
-        }
+        self.token_expires = None
 
-        self.defaultOptions = self.urlOptions['categories'].format(categories='tv') + \
-                              self.urlOptions['limit'].format(limit='100') + \
-                              self.urlOptions['format'].format(format='json_extended')
+        # Spec: https://torrentapi.org/apidocs_v2.txt
+        self.url = u'https://rarbg.com'
+        self.url_api = u'http://torrentapi.org/pubapi_v2.php'
 
         self.proper_strings = ['{{PROPER|REPACK}}']
 
-        self.next_request = datetime.datetime.now()
-
-        self.headers.update({'User-Agent': USER_AGENT})
-
         self.cache = RarbgCache(self)
 
     def login(self):
-        if self.token and self.tokenExpireDate and datetime.datetime.now() < self.tokenExpireDate:
+        if self.token and self.token_expires and datetime.datetime.now() < self.token_expires:
             return True
 
-        response = self.get_url(self.urls['token'], timeout=30, json=True)
+        login_params = {
+            'get_token': 'get_token',
+            'format': 'json',
+            'app_id': 'sickrage2'
+        }
+
+        response = self.get_url(self.url_api, params=login_params, timeout=30, json=True)
         if not response:
             logger.log(u"Unable to connect to provider", logger.WARNING)
             return False
 
-        try:
-            if response['token']:
-                self.token = response['token']
-                self.tokenExpireDate = datetime.datetime.now() + datetime.timedelta(minutes=14)
-                return True
-        except Exception as e:
-            logger.log(u"No token found", logger.WARNING)
-            logger.log(u"No token found: %s" % repr(e), logger.DEBUG)
-
-        return False
-
-    def search(self, search_params, age=0, ep_obj=None):
+        self.token = response.get('token')
+        self.token_expires = datetime.datetime.now() + datetime.timedelta(minutes=14) if self.token else None
+        return self.token is not None
 
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
+        search_params = {
+            'app_id': 'sickrage2',
+            'categories': 'tv',
+            'seeders': try_int(self.minseed),
+            'leechers': try_int(self.minleech),
+            'limit': 100,
+            'format': 'json_extended',
+            'ranked': try_int(self.ranked),
+            'token': self.token,
+        }
+
         if ep_obj is not None:
             ep_indexerid = ep_obj.show.indexerid
             ep_indexer = ep_obj.show.indexer
@@ -115,130 +92,59 @@ class RarbgProvider(TorrentProvider):
             ep_indexerid = None
             ep_indexer = None
 
-        for mode in search_params.keys():  # Mode = RSS, Season, Episode
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
+            if mode == 'RSS':
+                search_params['sorting'] = 'last'
+                search_params['mode'] = 'list'
+                search_params.pop('search_string', None)
+                search_params.pop('search_tvdb', None)
+            else:
+
+                search_params['sorting'] = self.sorting if self.sorting else 'seeders'
+                search_params['mode'] = 'search'
+
+                if ep_indexer == INDEXER_TVDB and ep_indexerid:
+                    search_params['search_tvdb'] = ep_indexerid
+                else:
+                    search_params.pop('search_tvdb', None)
 
+            for search_string in search_strings[mode]:
                 if mode != 'RSS':
+                    search_params['search_string'] = search_string
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                if mode == 'RSS':
-                    searchURL = self.urls['listing'] + self.defaultOptions
-                elif mode == 'Season':
-                    if ep_indexer == INDEXER_TVDB:
-                        searchURL = self.urls['search_tvdb'].format(search_string=search_string, tvdb=ep_indexerid) + self.defaultOptions
-                    else:
-                        searchURL = self.urls['search'].format(search_string=search_string) + self.defaultOptions
-                elif mode == 'Episode':
-                    if ep_indexer == INDEXER_TVDB:
-                        searchURL = self.urls['search_tvdb'].format(search_string=search_string, tvdb=ep_indexerid) + self.defaultOptions
-                    else:
-                        searchURL = self.urls['search'].format(search_string=search_string) + self.defaultOptions
-                else:
-                    logger.log(u"Invalid search mode: %s " % mode, logger.ERROR)
-
-                if self.minleech:
-                    searchURL += self.urlOptions['leechers'].format(min_leechers=int(self.minleech))
-
-                if self.minseed:
-                    searchURL += self.urlOptions['seeders'].format(min_seeders=int(self.minseed))
-
-                searchURL += self.urlOptions['sorting'].format(sorting=(self.sorting if self.sorting else 'seeders', 'last')[mode == 'RSS'])
-
-                if self.ranked:
-                    searchURL += self.urlOptions['ranked'].format(ranked=int(self.ranked))
-
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-
-                try:
-                    retry = 3
-                    while retry > 0:
-                        time_out = 0
-                        while (datetime.datetime.now() < self.next_request) and time_out <= 15:
-                            time_out += 1
-                            time.sleep(1)
-
-                        data = self.get_url(searchURL + self.urlOptions['token'].format(token=self.token))
-
-                        self.next_request = datetime.datetime.now() + datetime.timedelta(seconds=10)
-
-                        if not data:
-                            logger.log(u"No data returned from provider", logger.DEBUG)
-                            raise GetOutOfLoop
-                        if re.search('ERROR', data):
-                            logger.log(u"Error returned from provider", logger.DEBUG)
-                            raise GetOutOfLoop
-                        if re.search('No results found', data):
-                            logger.log(u"No results found", logger.DEBUG)
-                            raise GetOutOfLoop
-                        if re.search('Invalid token set!', data):
-                            logger.log(u"Invalid token!", logger.WARNING)
-                            return results
-                        if re.search('Too many requests per minute. Please try again later!', data):
-                            logger.log(u"Too many requests per minute", logger.WARNING)
-                            retry -= 1
-                            time.sleep(10)
-                            continue
-                        if re.search('Cant find search_tvdb in database. Are you sure this imdb exists?', data):
-                            logger.log(u"No results found. The tvdb id: %s do not exist on provider" % ep_indexerid, logger.WARNING)
-                            raise GetOutOfLoop
-                        if re.search('Invalid token. Use get_token for a new one!', data):
-                            logger.log(u"Invalid token, retrieving new token", logger.DEBUG)
-                            retry -= 1
-                            self.token = None
-                            self.tokenExpireDate = None
-                            if not self.login():
-                                logger.log(u"Failed retrieving new token", logger.DEBUG)
-                                return results
-                            logger.log(u"Using new token", logger.DEBUG)
-                            continue
-
-                        # No error found break
-                        break
-                    else:
-                        logger.log(u"Retried 3 times without getting results", logger.DEBUG)
-                        continue
-                except GetOutOfLoop:
+                logger.log(u"Search URL: %s" % self.url_api + '?' + urlencode(search_params), logger.DEBUG)
+                data = self.get_url(self.url_api, params=search_params, json=True)
+                if not all([isinstance(data, dict), data.get('torrent_results')]):
+                    logger.log(u"No data returned from provider", logger.DEBUG)
                     continue
 
-                try:
-                    data = re.search(r'\[\{\"title\".*\}\]', data)
-                    if data is not None:
-                        data_json = json.loads(data.group())
-                    else:
-                        data_json = {}
-                except Exception:
-                    logger.log(u"JSON load failed: %s" % traceback.format_exc(), logger.ERROR)
-                    logger.log(u"JSON load failed. Data dump: %s" % data, logger.DEBUG)
-                    continue
-
-                try:
-                    for item in data_json:
-                        try:
-                            title = item['title']
-                            download_url = item['download']
-                            size = item['size']
-                            seeders = item['seeders']
-                            leechers = item['leechers']
-                            # pubdate = item['pubdate']
-
-                            if not all([title, download_url]):
-                                continue
+                for item in data.get('torrent_results', []):
+                    try:
+                        title = item.get('title')
+                        download_url = item.get('download')
+                        seeders = item.get('seeders', 0)
+                        leechers = item.get('leechers', 0)
+                        size = convert_size(item.get('size', -1)) or -1
+                    except Exception:
+                        logger.log(u"Skipping invalid result. JSON item: %s" % item, logger.DEBUG)
+                        continue
 
-                            item = title, download_url, size, seeders, leechers
-                            if mode != 'RSS':
-                                logger.log(u"Found result: %s " % title, logger.DEBUG)
-                            items[mode].append(item)
+                    if not all([title, download_url]):
+                        continue
 
-                        except Exception:
-                            logger.log(u"Skipping invalid result. JSON item: %s" % item, logger.DEBUG)
+                    item = title, download_url, size, seeders, leechers
+                    if mode != 'RSS':
+                        logger.log(u"Found result: %s " % title, logger.DEBUG)
+                    items.append(item)
 
-                except Exception:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+                time.sleep(10)
 
             # For each search mode sort all the items by seeders
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
@@ -255,8 +161,8 @@ class RarbgCache(tvcache.TVCache):
         self.minTime = 10
 
     def _getRSSData(self):
-        search_params = {'RSS': ['']}
-        return {'entries': self.provider.search(search_params)}
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
 
 
 provider = RarbgProvider()
diff --git a/sickbeard/providers/rsstorrent.py b/sickbeard/providers/rsstorrent.py
index 411bc2a4c0ea26fc99807b23c63ff2de602c51cb..eb2cde31cb036fb1cd275f0ca6c4675c2cc65a36 100644
--- a/sickbeard/providers/rsstorrent.py
+++ b/sickbeard/providers/rsstorrent.py
@@ -10,11 +10,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import io
 import os
diff --git a/sickbeard/providers/scc.py b/sickbeard/providers/scc.py
index 0aac6ce591f12b9fcd8d9e56e8119a0a1a3af58b..250b2e1ec12b69cea4c8e0b10953d51f0c6a6e3e 100644
--- a/sickbeard/providers/scc.py
+++ b/sickbeard/providers/scc.py
@@ -12,11 +12,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import time
@@ -26,6 +26,7 @@ import sickbeard
 from sickbeard.common import cpu_presets
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickbeard.bs4_parser import BS4Parser
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
@@ -85,26 +86,24 @@ class SCCProvider(TorrentProvider):  # pylint: disable=too-many-instance-attribu
         title = r'<title>.+? \| %s</title>' % section
         return re.search(title, text, re.IGNORECASE)
 
-    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals,too-many-branches
-
-        items = {'Season': [], 'Episode': [], 'RSS': []}
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals,too-many-branches, too-many-statements
         results = []
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             if mode != 'RSS':
                 logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (urllib.quote(search_string), self.categories[mode])
+                search_url = self.urls['search'] % (urllib.quote(search_string), self.categories[mode])
 
                 try:
-                    logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                    data = self.get_url(searchURL)
+                    logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                    data = self.get_url(search_url)
                     time.sleep(cpu_presets[sickbeard.CPU_PRESET])
                 except Exception as e:
                     logger.log(u"Unable to fetch data. Error: %s" % repr(e), logger.WARNING)
@@ -136,7 +135,9 @@ class SCCProvider(TorrentProvider):  # pylint: disable=too-many-instance-attribu
                             download_url = self.urls['download'] % url['href']
                             seeders = int(result.find('td', attrs={'class': 'ttr_seeders'}).string)
                             leechers = int(result.find('td', attrs={'class': 'ttr_leechers'}).string)
-                            size = self._convertSize(result.find('td', attrs={'class': 'ttr_size'}).contents[0])
+                            torrent_size = result.find('td', attrs={'class': 'ttr_size'}).contents[0]
+
+                            size = convert_size(torrent_size) or -1
                         except (AttributeError, TypeError):
                             continue
 
@@ -153,32 +154,18 @@ class SCCProvider(TorrentProvider):  # pylint: disable=too-many-instance-attribu
                         if mode != 'RSS':
                             logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        items[mode].append(item)
+                        items.append(item)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    @staticmethod
-    def _convertSize(size):
-        size, base = size.split()
-        size = float(size)
-        if base in 'KB':
-            size *= 1024 ** 1
-        elif base in 'MB':
-            size *= 1024 ** 2
-        elif base in 'GB':
-            size *= 1024 ** 3
-        elif base in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
 
 class SCCCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/scenetime.py b/sickbeard/providers/scenetime.py
index 351761c2c91f3031597636a1900219d5de2d40f5..8e3eba84fb7153e1586852eb50dbbe9ec73d0c17 100644
--- a/sickbeard/providers/scenetime.py
+++ b/sickbeard/providers/scenetime.py
@@ -11,23 +11,25 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import urllib
-import traceback
 
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
+from sickrage.helper.common import try_int
 
-class SceneTimeProvider(TorrentProvider):
+
+class SceneTimeProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -67,86 +69,80 @@ class SceneTimeProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (urllib.quote(search_string), self.categories)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.urls['search'] % (urllib.quote(search_string), self.categories)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
-                try:
-                    with BS4Parser(data, 'html5lib') as html:
-                        torrent_table = html.select("#torrenttable table")
-                        torrent_rows = torrent_table[0].select("tr") if torrent_table else []
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('div', id="torrenttable")
+                    torrent_rows = []
+                    if torrent_table:
+                        torrent_rows = torrent_table.select("tr")
 
-                        # Continue only if one Release is found
-                        if len(torrent_rows) < 2:
-                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
-                            continue
+                    # Continue only if one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                        continue
 
-                        # Scenetime apparently uses different number of cells in #torrenttable based
-                        # on who you are. This works around that by extracting labels from the first
-                        # <tr> and using their index to find the correct download/seeders/leechers td.
-                        labels = [label.get_text() for label in torrent_rows[0].find_all('td')]
+                    # Scenetime apparently uses different number of cells in #torrenttable based
+                    # on who you are. This works around that by extracting labels from the first
+                    # <tr> and using their index to find the correct download/seeders/leechers td.
+                    labels = [label.get_text(strip=True) for label in torrent_rows[0].find_all('td')]
 
-                        for result in torrent_rows[1:]:
+                    for result in torrent_rows[1:]:
+                        try:
                             cells = result.find_all('td')
 
                             link = cells[labels.index('Name')].find('a')
+                            torrent_id = link['href'].replace('details.php?id=', '').split("&")[0]
 
-                            full_id = link['href'].replace('details.php?id=', '')
-                            torrent_id = full_id.split("&")[0]
+                            title = link.get_text(strip=True)
+                            download_url = self.urls['download'] % (torrent_id, "%s.torrent" % title.replace(" ", "."))
 
-                            try:
-                                title = link.contents[0].get_text()
-                                filename = "%s.torrent" % title.replace(" ", ".")
-                                download_url = self.urls['download'] % (torrent_id, filename)
+                            seeders = try_int(cells[labels.index('Seeders')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('Leechers')].get_text(strip=True))
+                            torrent_size = cells[labels.index('Size')].get_text()
 
-                                seeders = int(cells[labels.index('Seeders')].get_text())
-                                leechers = int(cells[labels.index('Leechers')].get_text())
-                                # FIXME
-                                size = -1
+                            size = convert_size(torrent_size) or -1
 
-                            except (AttributeError, TypeError):
-                                continue
-
-                            if not all([title, download_url]):
-                                continue
+                        except (AttributeError, TypeError, KeyError, ValueError):
+                            continue
 
-                            # Filter unseeded torrent
-                            if seeders < self.minseed or leechers < self.minleech:
-                                if mode != 'RSS':
-                                    logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                                continue
+                        if not all([title, download_url]):
+                            continue
 
-                            item = title, download_url, size, seeders, leechers
+                        # Filter unseeded torrent
+                        if seeders < self.minseed or leechers < self.minleech:
                             if mode != 'RSS':
-                                logger.log(u"Found result: %s " % title, logger.DEBUG)
+                                logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                            continue
 
-                            items[mode].append(item)
+                        item = title, download_url, size, seeders, leechers
+                        if mode != 'RSS':
+                            logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                except Exception as e:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+                        items.append(item)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/shazbat.py b/sickbeard/providers/shazbat.py
index 959d9e20e7faf8111db86d124c57ac37e5653542..940a35eef6fb70d2c05b4ea58d3945e226b45c22 100644
--- a/sickbeard/providers/shazbat.py
+++ b/sickbeard/providers/shazbat.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard import logger
 from sickbeard import tvcache
diff --git a/sickbeard/providers/speedcd.py b/sickbeard/providers/speedcd.py
index d231611da1b1fa3896696c512fb76ec33e08e1a2..924dbcc0d326b8f1b347ba1a89ea88a5a3be07c3 100644
--- a/sickbeard/providers/speedcd.py
+++ b/sickbeard/providers/speedcd.py
@@ -1,6 +1,6 @@
 # coding=utf-8
-# Author: Mr_Orange
-# URL: https://github.com/mr-orange/Sick-Beard
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,20 +11,24 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
+from urllib import urlencode
+from requests.utils import dict_from_cookiejar
 
 from sickbeard import logger
 from sickbeard import tvcache
+from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class SpeedCDProvider(TorrentProvider):
+class SpeedCDProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -37,24 +41,24 @@ class SpeedCDProvider(TorrentProvider):
         self.minseed = None
         self.minleech = None
 
-        self.urls = {'base_url': 'http://speed.cd/',
-                     'login': 'http://speed.cd/take.login.php',
-                     'detail': 'http://speed.cd/t/%s',
-                     'search': 'http://speed.cd/V3/API/API.php',
-                     'download': 'http://speed.cd/download.php?torrent=%s'}
-
-        self.url = self.urls['base_url']
-
-        self.categories = {'Season': {'c14': 1}, 'Episode': {'c2': 1, 'c49': 1}, 'RSS': {'c14': 1, 'c2': 1, 'c49': 1}}
+        self.url = 'http://speed.cd/'
+        self.urls = {
+            'login': self.url + 'take.login.php',
+            'search': self.url + 'browse.php',
+        }
 
         self.proper_strings = ['PROPER', 'REPACK']
 
         self.cache = SpeedCDCache(self)
 
     def login(self):
+        if any(dict_from_cookiejar(self.session.cookies).values()):
+            return True
 
-        login_params = {'username': self.username,
-                        'password': self.password}
+        login_params = {
+            'username': self.username,
+            'password': self.password
+        }
 
         response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
         if not response:
@@ -67,66 +71,96 @@ class SpeedCDProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        # http://speed.cd/browse.php?c49=1&c50=1&c52=1&c41=1&c55=1&c2=1&c30=1&freeleech=on&search=arrow&d=on
+        search_params = {
+            'c2': 1,  # TV/Episodes
+            'c30': 1,  # Anime
+            'c41': 1,  # TV/Packs
+            'c49': 1,  # TV/HD
+            'c50': 1,  # TV/Sports
+            'c52': 1,  # TV/B-Ray
+            'c55': 1,  # TV/Kids
+            'search': '',
+        }
+        if self.freeleech:
+            search_params['freeleech'] = 'on'
+
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
-
+            for search_string in search_strings[mode]:
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                search_string = '+'.join(search_string.split())
-
-                post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 4, 'jxw': 'b', 'search': search_string},
-                                 **self.categories[mode])
+                search_params['search'] = search_string
 
-                parsedJSON = self.get_url(self.urls['search'], post_data=post_data, json=True)
-                if not parsedJSON:
-                    continue
+                search_url = "%s?%s" % (self.urls['search'], urlencode(search_params))
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                try:
-                    torrents = parsedJSON.get('Fs', [])[0].get('Cn', {}).get('torrents', [])
-                except Exception:
+                # returns top 15 results by default, expandable in user profile to 100
+                data = self.get_url(search_url)
+                if not data:
                     continue
 
-                for torrent in torrents:
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('div', class_='boxContent').find('table')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
 
-                    if self.freeleech and not torrent['free']:
+                    # Continue only if one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
                         continue
 
-                    title = re.sub('<[^>]*>', '', torrent['name'])
-                    download_url = self.urls['download'] % (torrent['id'])
-                    seeders = int(torrent['seed'])
-                    leechers = int(torrent['leech'])
-                    # FIXME
-                    size = -1
-
-                    if not all([title, download_url]):
-                        continue
-
-                    # Filter unseeded torrent
-                    if seeders < self.minseed or leechers < self.minleech:
-                        if mode != 'RSS':
-                            logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                        continue
-
-                    item = title, download_url, size, seeders, leechers
-                    if mode != 'RSS':
-                        logger.log(u"Found result: %s " % title, logger.DEBUG)
-
-                    items[mode].append(item)
+                    def process_column_header(td):
+                        result = ''
+                        if td.a and td.a.img:
+                            result = td.a.img.get('alt', td.a.get_text(strip=True))
+                        if td.img and not result:
+                            result = td.img.get('alt', '')
+                        if not result:
+                            result = td.get_text(strip=True)
+                        return result
+
+                    labels = [process_column_header(label) for label in torrent_rows[0].find_all('th')]
+
+                    # skip colheader
+                    for result in torrent_rows[1:]:
+                        try:
+                            cells = result.find_all('td')
+
+                            title = cells[labels.index('Title')].find('a', class_='torrent').get_text()
+                            download_url = self.url + cells[labels.index('Download')].find(title='Download').parent['href']
+                            if not all([title, download_url]):
+                                continue
+
+                            seeders = try_int(cells[labels.index('Seeders')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('Leechers')].get_text(strip=True))
+                            if seeders < self.minseed or leechers < self.minleech:
+                                if mode != 'RSS':
+                                    logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                                continue
+
+                            torrent_size = cells[labels.index('Size')].get_text()
+                            # TODO: Make convert_size work with 123.12GB
+                            torrent_size = torrent_size[:-2] + ' ' + torrent_size[-2:]
+                            size = convert_size(torrent_size) or -1
+
+                            item = title, download_url, size, seeders, leechers
+                            if mode != 'RSS':
+                                logger.log(u"Found result: %s " % title, logger.DEBUG)
+
+                            items.append(item)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
@@ -143,7 +177,8 @@ class SpeedCDCache(tvcache.TVCache):
         self.minTime = 20
 
     def _getRSSData(self):
-        search_params = {'RSS': ['']}
-        return {'entries': self.provider.search(search_params)}
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
+
 
 provider = SpeedCDProvider()
diff --git a/sickbeard/providers/strike.py b/sickbeard/providers/strike.py
index d48b0f9ea96ea9ff15ceaeab364d700c23d146db..c3955871da1a408fb8bd4d9677f626939d43dfd8 100644
--- a/sickbeard/providers/strike.py
+++ b/sickbeard/providers/strike.py
@@ -11,18 +11,19 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class STRIKEProvider(TorrentProvider):
+class StrikeProvider(TorrentProvider):
 
     def __init__(self):
         TorrentProvider.__init__(self, "Strike")
@@ -34,20 +35,18 @@ class STRIKEProvider(TorrentProvider):
         self.minseed, self.minleech = 2 * [None]
 
     def search(self, search_strings, age=0, ep_obj=None):
-
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_strings.keys():  # Mode = RSS, Season, Episode
+        for mode in search_strings:  # Mode = RSS, Season, Episode
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: " + search_string.strip(), logger.DEBUG)
 
-                searchURL = self.url + "api/v2/torrents/search/?category=TV&phrase=" + search_string
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                jdata = self.get_url(searchURL, json=True)
+                search_url = self.url + "api/v2/torrents/search/?category=TV&phrase=" + search_string
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                jdata = self.get_url(search_url, json=True)
                 if not jdata:
                     logger.log(u"No data returned from provider", logger.DEBUG)
                     return []
@@ -58,7 +57,8 @@ class STRIKEProvider(TorrentProvider):
                     seeders = ('seeds' in item and item['seeds']) or 0
                     leechers = ('leeches' in item and item['leeches']) or 0
                     title = ('torrent_title' in item and item['torrent_title']) or ''
-                    size = ('size' in item and item['size']) or 0
+                    torrent_size = ('size' in item and item['size'])
+                    size = convert_size(torrent_size) or -1
                     download_url = ('magnet_uri' in item and item['magnet_uri']) or ''
 
                     if not all([title, download_url]):
@@ -74,12 +74,12 @@ class STRIKEProvider(TorrentProvider):
                         logger.log(u"Found result: %s " % title, logger.DEBUG)
 
                     item = title, download_url, size, seeders, leechers
-                    items[mode].append(item)
+                    items.append(item)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -101,4 +101,4 @@ class StrikeCache(tvcache.TVCache):
         search_params = {'RSS': ['x264']}
         return {'entries': self.provider.search(search_params)}
 
-provider = STRIKEProvider()
+provider = StrikeProvider()
diff --git a/sickbeard/providers/t411.py b/sickbeard/providers/t411.py
index 9ef558461bbd259749e1500bffd3ecb908d0d6ea..4775e25bf6f119c4f0691ccb61ba6b5197b9476f 100644
--- a/sickbeard/providers/t411.py
+++ b/sickbeard/providers/t411.py
@@ -11,7 +11,7 @@
 #
 # Sick Beard 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
+# 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
@@ -24,10 +24,11 @@ from requests.auth import AuthBase
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.common import USER_AGENT
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class T411Provider(TorrentProvider):
+class T411Provider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, "T411")
 
@@ -72,32 +73,30 @@ class T411Provider(TorrentProvider):
         if response and 'token' in response:
             self.token = response['token']
             self.tokenLastUpdate = time.time()
-            self.uid = response['uid'].encode('ascii', 'ignore')
+            # self.uid = response['uid'].encode('ascii', 'ignore')
             self.session.auth = T411Auth(self.token)
             return True
         else:
             logger.log(u"Token not found in authentication response", logger.WARNING)
             return False
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-locals, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURLS = ([self.urls['search'] % (search_string, u) for u in self.subcategories], [self.urls['rss']])[mode == 'RSS']
-                for searchURL in searchURLS:
-                    logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                    data = self.get_url(searchURL, json=True)
+                search_urlS = ([self.urls['search'] % (search_string, u) for u in self.subcategories], [self.urls['rss']])[mode == 'RSS']
+                for search_url in search_urlS:
+                    logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                    data = self.get_url(search_url, json=True)
                     if not data:
                         continue
 
@@ -123,10 +122,11 @@ class T411Provider(TorrentProvider):
                                 if not all([title, download_url]):
                                     continue
 
-                                size = int(torrent['size'])
                                 seeders = int(torrent['seeders'])
                                 leechers = int(torrent['leechers'])
                                 verified = bool(torrent['isVerified'])
+                                torrent_size = torrent['size']
+                                size = convert_size(torrent_size) or -1
 
                                 # Filter unseeded torrent
                                 if seeders < self.minseed or leechers < self.minleech:
@@ -142,7 +142,7 @@ class T411Provider(TorrentProvider):
                                 if mode != 'RSS':
                                     logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                                items[mode].append(item)
+                                items.append(item)
 
                             except Exception:
                                 logger.log(u"Invalid torrent data, skipping result: %s" % torrent, logger.DEBUG)
@@ -153,9 +153,9 @@ class T411Provider(TorrentProvider):
                         logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -163,7 +163,7 @@ class T411Provider(TorrentProvider):
         return self.ratio
 
 
-class T411Auth(AuthBase):
+class T411Auth(AuthBase):  # pylint: disable=too-few-public-methods
     """Attaches HTTP Authentication to the given Request object."""
     def __init__(self, token):
         self.token = token
diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py
index 56b05cf07403c77ac593fb6e0f17094bb81bf77a..f0c680e6108ac8e614dd821e7a09f9d5148a01c0 100644
--- a/sickbeard/providers/thepiratebay.py
+++ b/sickbeard/providers/thepiratebay.py
@@ -1,6 +1,6 @@
 # coding=utf-8
-# Author: Mr_Orange <mr_orange@hotmail.it>
-# URL: http://code.google.com/p/sickbeard/
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,22 +11,23 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import posixpath  # Must use posixpath
 from urllib import urlencode
 from sickbeard import logger
 from sickbeard import tvcache
-from sickbeard.common import USER_AGENT
+from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class ThePirateBayProvider(TorrentProvider):
+class ThePirateBayProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "ThePirateBay")
@@ -40,22 +41,21 @@ class ThePirateBayProvider(TorrentProvider):
 
         self.cache = ThePirateBayCache(self)
 
+        self.url = 'https://thepiratebay.ms/'
         self.urls = {
-            'base_url': 'https://thepiratebay.ms/',
-            'search': 'https://thepiratebay.ms/s/',
-            'rss': 'https://thepiratebay.ms/tv/latest'
+            'search': self.url + 's/',
+            'rss': self.url + 'tv/latest'
         }
 
-        self.url = self.urls['base_url']
         self.custom_url = None
 
-        self.headers.update({'User-Agent': USER_AGENT})
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
+        results = []
         """
         205 = SD, 208 = HD, 200 = All Videos
         https://pirateproxy.pl/s/?q=Game of Thrones&type=search&orderby=7&page=0&category=200
         """
-        self.search_params = {
+        search_params = {
             'q': '',
             'type': 'search',
             'orderby': 7,
@@ -63,82 +63,86 @@ class ThePirateBayProvider(TorrentProvider):
             'category': 200
         }
 
-        self.re_title_url = r'/torrent/(?P<id>\d+)/(?P<title>.*?)".+?(?P<url>magnet.*?)".+?Size (?P<size>[\d\.]*&nbsp;[TGKMiB]{2,3}).+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>'
-
-    def search(self, search_strings, age=0, ep_obj=None):
-
-        results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
-
-                self.search_params.update({'q': search_string.strip()})
-
                 if mode != 'RSS':
-                    logger.log(u"Search string: " + search_string, logger.DEBUG)
+                    logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls[('search', 'rss')[mode == 'RSS']] + '?' + urlencode(self.search_params)
+                search_params['q'] = search_string.strip()
+
+                search_url = self.urls[('search', 'rss')[mode == 'RSS']] + '?' + urlencode(search_params)
                 if self.custom_url:
-                    searchURL = posixpath.join(self.custom_url, searchURL.split(self.url)[1].lstrip('/'))  # Must use posixpath
+                    search_url = posixpath.join(self.custom_url, search_url.split(self.url)[1].lstrip('/'))  # Must use posixpath
+
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     logger.log(u'URL did not return data, maybe try a custom url, or a different one', logger.DEBUG)
                     continue
 
-                matches = re.compile(self.re_title_url, re.DOTALL).finditer(data)
-                for torrent in matches:
-                    title = torrent.group('title')
-                    download_url = torrent.group('url')
-                    # id = int(torrent.group('id'))
-                    size = self._convertSize(torrent.group('size'))
-                    seeders = int(torrent.group('seeders'))
-                    leechers = int(torrent.group('leechers'))
-
-                    if not all([title, download_url]):
-                        continue
-
-                    # Filter unseeded torrent
-                    if seeders < self.minseed or leechers < self.minleech:
-                        if mode != 'RSS':
-                            logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                        continue
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('table', id='searchResult')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
 
-                    # Accept Torrent only from Good People for every Episode Search
-                    if self.confirmed and re.search(r'(VIP|Trusted|Helper|Moderator)', torrent.group(0)) is None:
-                        if mode != 'RSS':
-                            logger.log(u"Found result %s but that doesn't seem like a trusted result so I'm ignoring it" % title, logger.DEBUG)
+                    # Continue only if one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
                         continue
 
-                    item = title, download_url, size, seeders, leechers
-                    if mode != 'RSS':
-                        logger.log(u"Found result: %s " % title, logger.DEBUG)
-
-                    items[mode].append(item)
+                    def process_column_header(th):
+                        result = ''
+                        if th.a:
+                            result = th.a.get_text(strip=True)
+                        if not result:
+                            result = th.get_text(strip=True)
+                        return result
+
+                    labels = [process_column_header(label) for label in torrent_rows[0].find_all('th')]
+                    for result in torrent_rows[1:]:
+                        try:
+                            cells = result.find_all('td')
+
+                            title = result.find(class_='detName').get_text(strip=True)
+                            download_url = result.find(title="Download this torrent using magnet")['href']
+                            if not all([title, download_url]):
+                                continue
+
+                            seeders = try_int(cells[labels.index('SE')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('LE')].get_text(strip=True))
+                            if seeders < self.minseed or leechers < self.minleech:
+                                if mode != 'RSS':
+                                    logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                                continue
+
+                            # Accept Torrent only from Good People for every Episode Search
+                            if self.confirmed and result.find(alt=re.compile(r'(VIP|Trusted|Helper|Moderator)')):
+                                if mode != 'RSS':
+                                    logger.log(u"Found result %s but that doesn't seem like a trusted result so I'm ignoring it" % title, logger.DEBUG)
+                                continue
+
+                            # Convert size after all possible skip scenarios
+                            torrent_size = cells[labels.index('Name')].find(class_='detDesc').get_text(strip=True).split(', ')[1]
+                            torrent_size = re.sub(r'Size ([\d.]+).+([KMGT]iB)', r'\1 \2', torrent_size)
+                            size = convert_size(torrent_size) or -1
+
+                            item = title, download_url, size, seeders, leechers
+                            if mode != 'RSS':
+                                logger.log(u"Found result: %s " % title, logger.DEBUG)
+
+                            items.append(item)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
-    def _convertSize(self, size):
-        size, modifier = size.split('&nbsp;')
-        size = float(size)
-        if modifier in 'KiB':
-            size *= 1024 ** 1
-        elif modifier in 'MiB':
-            size *= 1024 ** 2
-        elif modifier in 'GiB':
-            size *= 1024 ** 3
-        elif modifier in 'TiB':
-            size *= 1024 ** 4
-        return long(size)
-
     def seed_ratio(self):
         return self.ratio
 
@@ -152,7 +156,7 @@ class ThePirateBayCache(tvcache.TVCache):
         self.minTime = 30
 
     def _getRSSData(self):
-        search_params = {'RSS': ['']}
-        return {'entries': self.provider.search(search_params)}
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
 
 provider = ThePirateBayProvider()
diff --git a/sickbeard/providers/titansoftv.py b/sickbeard/providers/titansoftv.py
index 87820802af9a3542ad10fac7f2cbb92feb27c589..7cb72144bdb47f318b19041ef6ac827343614cf4 100644
--- a/sickbeard/providers/titansoftv.py
+++ b/sickbeard/providers/titansoftv.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 
@@ -64,11 +64,11 @@ class TitansOfTVProvider(TorrentProvider):
         if search_params:
             params.update(search_params)
 
-        searchURL = self.url + '?' + urllib.urlencode(params)
+        search_url = self.url + '?' + urllib.urlencode(params)
         logger.log(u"Search string: %s " % search_params, logger.DEBUG)
-        logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+        logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-        parsedJSON = self.get_url(searchURL, json=True)  # do search
+        parsedJSON = self.get_url(search_url, json=True)  # do search
 
         if not parsedJSON:
             logger.log(u"No data returned from provider", logger.DEBUG)
diff --git a/sickbeard/providers/tntvillage.py b/sickbeard/providers/tntvillage.py
index 430467a283a93cefd7809c77fe45a1350ed5d8ca..e79044502998071b6fbe73567167a36fd14288bb 100644
--- a/sickbeard/providers/tntvillage.py
+++ b/sickbeard/providers/tntvillage.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import traceback
@@ -26,6 +26,7 @@ from sickbeard import db
 
 from sickbeard.bs4_parser import BS4Parser
 from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
+from sickrage.helper.common import convert_size
 from sickrage.helper.exceptions import AuthException
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
@@ -56,7 +57,7 @@ category_excluded = {'Sport': 22,
                      'Mobile': 37}
 
 
-class TNTVillageProvider(TorrentProvider):
+class TNTVillageProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, "TNTVillage")
 
@@ -136,7 +137,8 @@ class TNTVillageProvider(TorrentProvider):
 
         return True
 
-    def _reverseQuality(self, quality):
+    @staticmethod
+    def _reverseQuality(quality):
 
         quality_string = ''
 
@@ -161,7 +163,8 @@ class TNTVillageProvider(TorrentProvider):
 
         return quality_string
 
-    def _episodeQuality(self, torrent_rows):
+    @staticmethod
+    def _episodeQuality(torrent_rows):  # pylint: disable=too-many-return-statements, too-many-branches
         """
             Return The quality from the scene episode HTML row.
         """
@@ -237,7 +240,8 @@ class TNTVillageProvider(TorrentProvider):
 
         return italian
 
-    def _is_english(self, torrent_rows):
+    @staticmethod
+    def _is_english(torrent_rows):
 
         name = str(torrent_rows.find_all('td')[1].find('b').find('span'))
         if not name or name == 'None':
@@ -250,7 +254,8 @@ class TNTVillageProvider(TorrentProvider):
 
         return english
 
-    def _is_season_pack(self, name):
+    @staticmethod
+    def _is_season_pack(name):
 
         try:
             myParser = NameParser(tryIndexers=True)
@@ -268,17 +273,15 @@ class TNTVillageProvider(TorrentProvider):
         if int(episodes[0]['count']) == len(parse_result.episode_numbers):
             return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        self.categories = "cat=" + str(self.cat)
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        self.categories = "cat=" + str(self.cat)
+
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
@@ -299,15 +302,15 @@ class TNTVillageProvider(TorrentProvider):
                         break
 
                     if mode != 'RSS':
-                        searchURL = (self.urls['search_page'] + '&filter={2}').format(z, self.categories, search_string)
+                        search_url = (self.urls['search_page'] + '&filter={2}').format(z, self.categories, search_string)
                     else:
-                        searchURL = self.urls['search_page'].format(z, self.categories)
+                        search_url = self.urls['search_page'].format(z, self.categories)
 
                     if mode != 'RSS':
                         logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                    logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                    data = self.get_url(searchURL)
+                    logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                    data = self.get_url(search_url)
                     if not data:
                         logger.log(u"No data returned from provider", logger.DEBUG)
                         continue
@@ -336,8 +339,8 @@ class TNTVillageProvider(TorrentProvider):
                                     leechers = int(leechers.strip('[]'))
                                     seeders = result.find_all('td')[3].find_all('td')[2].text
                                     seeders = int(seeders.strip('[]'))
-                                    # FIXME
-                                    size = -1
+                                    torrent_size = result.find_all('td')[3].find_all('td')[3].text.strip('[]') + " GB"
+                                    size = convert_size(torrent_size) or -1
                                 except (AttributeError, TypeError):
                                     continue
 
@@ -385,15 +388,15 @@ class TNTVillageProvider(TorrentProvider):
                                 if mode != 'RSS':
                                     logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                                items[mode].append(item)
+                                items.append(item)
 
                     except Exception:
                         logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
                 # For each search mode sort all the items by seeders if available if available
-                items[mode].sort(key=lambda tup: tup[3], reverse=True)
+                items.sort(key=lambda tup: tup[3], reverse=True)
 
-                results += items[mode]
+                results += items
 
         return results
 
diff --git a/sickbeard/providers/tokyotoshokan.py b/sickbeard/providers/tokyotoshokan.py
index 9c8c06fba80cb6ad56e804d4dd31544735ec3e58..49de713ce5e8b132d753abd4658dca9b59721630 100644
--- a/sickbeard/providers/tokyotoshokan.py
+++ b/sickbeard/providers/tokyotoshokan.py
@@ -11,23 +11,24 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
+import re
 import urllib
-import traceback
 
 from sickbeard import logger
 from sickbeard import tvcache
-from sickbeard import show_name_helpers
 from sickbeard.bs4_parser import BS4Parser
+
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TokyoToshokanProvider(TorrentProvider):
+class TokyoToshokanProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "TokyoToshokan")
@@ -37,76 +38,87 @@ class TokyoToshokanProvider(TorrentProvider):
         self.anime_only = True
         self.ratio = None
 
-        self.cache = TokyoToshokanCache(self)
+        self.minseed = None
+        self.minleech = None
 
-        self.urls = {'base_url': 'http://tokyotosho.info/'}
-        self.url = self.urls['base_url']
+        self.url = 'http://tokyotosho.info/'
+        self.urls = {
+            'search': self.url + 'search.php',
+            'rss': self.url + 'rss.php'
+        }
+        self.cache = TokyoToshokanCache(self)
 
     def seed_ratio(self):
         return self.ratio
 
-    def _get_season_search_strings(self, ep_obj):
-        return [x.replace('.', ' ') for x in show_name_helpers.makeSceneSeasonSearchString(self.show, ep_obj)]
-
-    def _get_episode_search_strings(self, ep_obj, add_string=''):
-        return [x.replace('.', ' ') for x in show_name_helpers.makeSceneSearchString(self.show, ep_obj)]
-
-    def search(self, search_string, age=0, ep_obj=None):
-        # FIXME ADD MODE
-        if self.show and not self.show.is_anime:
-            return []
-
-        logger.log(u"Search string: %s " % search_string, logger.DEBUG)
-
-        params = {
-            "terms": search_string.encode('utf-8'),
-            "type": 1,  # get anime types
-        }
-
-        searchURL = self.url + 'search.php?' + urllib.urlencode(params)
-        logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-        data = self.get_url(searchURL)
-
-        if not data:
-            return []
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        try:
-            with BS4Parser(data, 'html5lib') as soup:
-                torrent_table = soup.find('table', attrs={'class': 'listing'})
-                torrent_rows = torrent_table.find_all('tr') if torrent_table else []
-                if torrent_rows:
-                    if torrent_rows[0].find('td', attrs={'class': 'centertext'}):
-                        a = 1
-                    else:
-                        a = 0
-
-                    for top, bottom in zip(torrent_rows[a::2], torrent_rows[a::2]):
-                        title = top.find('td', attrs={'class': 'desc-top'}).text
-                        title.lstrip()
-                        download_url = top.find('td', attrs={'class': 'desc-top'}).find('a')['href']
-                        # FIXME
-                        size = -1
-                        seeders = 1
-                        leechers = 0
+        if not self.show or not self.show.is_anime:
+            return results
+
+        for mode in search_strings:
+            items = []
+            logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
+            for search_string in search_strings[mode]:
+                if mode != 'RSS':
+                    logger.log(u"Search string: %s " % search_string, logger.DEBUG)
+
+                search_params = {
+                    "terms": search_string.encode('utf-8'),
+                    "type": 1,  # get anime types
+                }
+
+                logger.log(u"Search URL: %s" % self.urls['search'] + '?' + urllib.urlencode(search_params), logger.DEBUG)
+                data = self.get_url(self.urls['search'], params=search_params)
+                if not data:
+                    continue
+
+                with BS4Parser(data, 'html5lib') as soup:
+                    torrent_table = soup.find('table', class_='listing')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
+
+                    # Continue only if one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                        continue
+
+                    a = 1 if len(torrent_rows[0].find_all('td')) < 2 else 0
+
+                    for top, bot in zip(torrent_rows[a::2], torrent_rows[a+1::2]):
+                        try:
+                            desc_top = top.find('td', class_='desc-top')
+                            title = desc_top.get_text(strip=True)
+                            download_url = desc_top.find('a')['href']
+
+                            desc_bottom = bot.find('td', class_='desc-bot').get_text(strip=True)
+                            size = convert_size(desc_bottom.split('|')[1].strip('Size: ')) or -1
+
+                            stats = bot.find('td', class_='stats').get_text(strip=True)
+                            sl = re.match(r'S:(?P<seeders>\d+)L:(?P<leechers>\d+)C:(?:\d+)ID:(?:\d+)', stats.replace(' ', ''))
+                            seeders = try_int(sl.group('seeders')) if sl else 0
+                            leechers = try_int(sl.group('leechers')) if sl else 0
+                        except StandardError:
+                            continue
 
                         if not all([title, download_url]):
                             continue
 
                         # Filter unseeded torrent
-                        # if seeders < self.minseed or leechers < self.minleech:
-                        #    if mode != 'RSS':
-                        #        logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                        #    continue
+                        if seeders < self.minseed or leechers < self.minleech:
+                            if mode != 'RSS':
+                                logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                            continue
 
                         item = title, download_url, size, seeders, leechers
+                        if mode != 'RSS':
+                            logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        results.append(item)
+                        items.append(item)
 
-        except Exception as e:
-            logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+            # For each search mode sort all the items by seeders if available
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
-        # FIXME SORTING
         return results
 
 
@@ -114,19 +126,22 @@ class TokyoToshokanCache(tvcache.TVCache):
     def __init__(self, provider_obj):
         tvcache.TVCache.__init__(self, provider_obj)
 
-        # only poll NyaaTorrents every 15 minutes max
+        # only poll TokyoToshokan every 15 minutes max
         self.minTime = 15
 
-    def _getRSSData(self):
-        params = {
-            "filter": '1',
-        }
-
-        url = self.provider.url + 'rss.php?' + urllib.urlencode(params)
-
-        logger.log(u"Cache update URL: %s" % url, logger.DEBUG)
-
-        return self.getRSSFeed(url)
+    # def _getRSSData(self):
+    #     params = {
+    #         "filter": '1',
+    #     }
+    #
+    #     url = self.provider.urls['rss'] + '?' + urllib.urlencode(params)
+    #
+    #     logger.log(u"Cache update URL: %s" % url, logger.DEBUG)
+    #
+    #     return self.getRSSFeed(url)
 
+    def _getRSSData(self):
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
 
 provider = TokyoToshokanProvider()
diff --git a/sickbeard/providers/torrentbytes.py b/sickbeard/providers/torrentbytes.py
index e22c5eb300f10783ee3bbd232426596813a0e9b9..08e9cf3ecca9f3da7791c8a42fd9a28172da96b2 100644
--- a/sickbeard/providers/torrentbytes.py
+++ b/sickbeard/providers/torrentbytes.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import urllib
@@ -24,10 +24,11 @@ import traceback
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TorrentBytesProvider(TorrentProvider):
+class TorrentBytesProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -40,11 +41,13 @@ class TorrentBytesProvider(TorrentProvider):
         self.minleech = None
         self.freeleech = False
 
-        self.urls = {'base_url': 'https://www.torrentbytes.net',
-                     'login': 'https://www.torrentbytes.net/takelogin.php',
-                     'detail': 'https://www.torrentbytes.net/details.php?id=%s',
-                     'search': 'https://www.torrentbytes.net/browse.php?search=%s%s',
-                     'download': 'https://www.torrentbytes.net/download.php?id=%s&name=%s'}
+        self.urls = {
+            'base_url': 'https://www.torrentbytes.net',
+            'login': 'https://www.torrentbytes.net/takelogin.php',
+            'detail': 'https://www.torrentbytes.net/details.php?id=%s',
+            'search': 'https://www.torrentbytes.net/browse.php?search=%s%s',
+            'download': 'https://www.torrentbytes.net/download.php?id=%s&name=%s'
+        }
 
         self.url = self.urls['base_url']
 
@@ -71,25 +74,23 @@ class TorrentBytesProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['search'] % (urllib.quote(search_string.encode('utf-8')), self.categories)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
+                search_url = self.urls['search'] % (urllib.quote(search_string.encode('utf-8')), self.categories)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                data = self.get_url(searchURL)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
@@ -106,7 +107,7 @@ class TorrentBytesProvider(TorrentProvider):
 
                         for result in torrent_rows[1:]:
                             cells = result.find_all('td')
-                            size = None
+                            torrent_size = None
                             link = cells[1].find('a', attrs={'class': 'index'})
 
                             full_id = link['href'].replace('details.php?id=', '')
@@ -132,11 +133,7 @@ class TorrentBytesProvider(TorrentProvider):
                                 leechers = int(cells[9].find('span').contents[0])
 
                                 # Need size for failed downloads handling
-                                if size is None:
-                                    if re.match(r'[0-9]+,?\.?[0-9]*[KkMmGg]+[Bb]+', cells[6].text):
-                                        size = self._convertSize(cells[6].text)
-                                        if not size:
-                                            size = -1
+                                torrent_size = cells[6].text if torrent_size is None else torrent_size
 
                             except (AttributeError, TypeError):
                                 continue
@@ -150,39 +147,27 @@ class TorrentBytesProvider(TorrentProvider):
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
+                            size = convert_size(torrent_size) or -1
+
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
-                except Exception as e:
+                except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, sizeString):
-        size = sizeString[:-2]
-        modifier = sizeString[-2:]
-        size = float(size)
-        if modifier in 'KB':
-            size *= 1024 ** 1
-        elif modifier in 'MB':
-            size *= 1024 ** 2
-        elif modifier in 'GB':
-            size *= 1024 ** 3
-        elif modifier in 'TB':
-            size *= 1024 ** 4
-        return long(size)
-
 
 class TorrentBytesCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/torrentday.py b/sickbeard/providers/torrentday.py
index 9c79bbd6b0f9f2eb435452af6603dc67ab9d2e0f..0e9e2e6113fe7a3444bb35e4a99d32e436fa9a34 100644
--- a/sickbeard/providers/torrentday.py
+++ b/sickbeard/providers/torrentday.py
@@ -10,20 +10,21 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import requests
 from sickbeard import logger
 from sickbeard import tvcache
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TorrentDayProvider(TorrentProvider):
+class TorrentDayProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -93,15 +94,13 @@ class TorrentDayProvider(TorrentProvider):
             logger.log(u"Unable to obtain cookie", logger.WARNING)
             return False
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_params, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        for mode in search_params:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_params[mode]:
 
@@ -129,12 +128,12 @@ class TorrentDayProvider(TorrentProvider):
 
                 for torrent in torrents:
 
-                    title = re.sub(r"\[.*\=.*\].*\[/.*\]", "", torrent['name'])
-                    download_url = self.urls['download'] % (torrent['id'], torrent['fname'])
-                    seeders = int(torrent['seed'])
-                    leechers = int(torrent['leech'])
-                    # FIXME
-                    size = -1
+                    title = re.sub(r"\[.*\=.*\].*\[/.*\]", "", torrent['name']) if torrent['name'] else None
+                    download_url = self.urls['download'] % (torrent['id'], torrent['fname']) if torrent['id'] and torrent['fname'] else None
+                    seeders = int(torrent['seed']) if torrent['seed'] else 1
+                    leechers = int(torrent['leech']) if torrent['leech'] else 0
+                    torrent_size = torrent['size']
+                    size = convert_size(torrent_size) or -1
 
                     if not all([title, download_url]):
                         continue
@@ -149,12 +148,12 @@ class TorrentDayProvider(TorrentProvider):
                     if mode != 'RSS':
                         logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                    items[mode].append(item)
+                    items.append(item)
 
             # For each search mode sort all the items by seeders if available if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/torrentleech.py b/sickbeard/providers/torrentleech.py
index 5b05cd8b760906ee455c19313edb966b5bd8265d..3e1fdf902bffe1e1857fe8acdb56c1184d0d4f45 100644
--- a/sickbeard/providers/torrentleech.py
+++ b/sickbeard/providers/torrentleech.py
@@ -1,6 +1,6 @@
 # coding=utf-8
-# Author: Idan Gutman
-# URL: http://code.google.com/p/sickbeard/
+# Author: Dustyn Gibson <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,23 +11,24 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
-import traceback
-import urllib
+from urllib import urlencode
+from requests.utils import dict_from_cookiejar
 
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TorrentLeechProvider(TorrentProvider):
+class TorrentLeechProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -39,27 +40,26 @@ class TorrentLeechProvider(TorrentProvider):
         self.minseed = None
         self.minleech = None
 
-        self.urls = {'base_url': 'https://torrentleech.org/',
-                     'login': 'https://torrentleech.org/user/account/login/',
-                     'detail': 'https://torrentleech.org/torrent/%s',
-                     'search': 'https://torrentleech.org/torrents/browse/index/query/%s/categories/%s',
-                     'download': 'https://torrentleech.org%s',
-                     'index': 'https://torrentleech.org/torrents/browse/index/categories/%s'}
-
-        self.url = self.urls['base_url']
-
-        self.categories = "2,7,26,27,32,34,35"
+        self.url = 'https://torrentleech.org'
+        self.urls = {
+            'login': self.url + '/user/account/login/',
+            'search': self.url + '/torrents/browse',
+        }
 
         self.proper_strings = ['PROPER', 'REPACK']
 
         self.cache = TorrentLeechCache(self)
 
     def login(self):
+        if any(dict_from_cookiejar(self.session.cookies).values()):
+            return True
 
-        login_params = {'username': self.username,
-                        'password': self.password,
-                        'remember_me': 'on',
-                        'login': 'submit'}
+        login_params = {
+            'username': self.username.encode('utf-8'),
+            'password': self.password.encode('utf-8'),
+            'remember_me': 'on',
+            'login': 'submit'
+        }
 
         response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
         if not response:
@@ -72,75 +72,89 @@ class TorrentLeechProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_params.keys():
-            logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
+        # TV, Episodes, BoxSets, Episodes HD, Animation, Anime, Cartoons
+        # 2,26,27,32,7,34,35
 
-                if mode == 'RSS':
-                    searchURL = self.urls['index'] % self.categories
-                else:
-                    searchURL = self.urls['search'] % (urllib.quote_plus(search_string.encode('utf-8')), self.categories)
+        for mode in search_strings:
+            items = []
+            logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
+            for search_string in search_strings[mode]:
+                if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                data = self.get_url(searchURL)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                if not data:
-                    continue
+                    categories = ['2', '7', '35']
+                    categories += ['26', '32'] if mode == 'Episode' else ['27']
+                    if self.show and self.show.is_anime:
+                        categories += ['34']
+                else:
+                    categories = ['2', '26', '27', '32', '7', '34', '35']
 
-                try:
-                    with BS4Parser(data, 'html5lib') as html:
-                        torrent_table = html.find('table', attrs={'id': 'torrenttable'})
-                        torrent_rows = torrent_table.find_all('tr') if torrent_table else []
+                search_params = {
+                    'categories': ','.join(categories),
+                    'query': search_string
+                }
 
-                        # Continue only if one Release is found
-                        if len(torrent_rows) < 2:
-                            logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
-                            continue
+                search_url = "%s?%s" % (self.urls['search'], urlencode(search_params))
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
 
-                        for result in torrent_table.find_all('tr')[1:]:
-
-                            try:
-                                link = result.find('td', attrs={'class': 'name'}).find('a')
-                                url = result.find('td', attrs={'class': 'quickdownload'}).find('a')
-                                title = link.string
-                                download_url = self.urls['download'] % url['href']
-                                seeders = int(result.find('td', attrs={'class': 'seeders'}).string)
-                                leechers = int(result.find('td', attrs={'class': 'leechers'}).string)
-                                # FIXME
-                                size = -1
-                            except (AttributeError, TypeError):
-                                continue
+                # returns top 15 results by default, expandable in user profile to 100
+                data = self.get_url(search_url)
+                if not data:
+                    continue
 
+                with BS4Parser(data, 'html5lib') as html:
+                    torrent_table = html.find('table', id='torrenttable')
+                    torrent_rows = torrent_table.find_all('tr') if torrent_table else []
+
+                    # Continue only if at least one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
+                        continue
+
+                    def process_column_header(td):
+                        result = ''
+                        if td.a:
+                            result = td.a.get('title')
+                        if not result:
+                            result = td.get_text(strip=True)
+                        return result
+
+                    labels = [process_column_header(label) for label in torrent_rows[0].find_all('th')]
+
+                    for result in torrent_rows[1:]:
+                        try:
+                            title = result.find('td', class_='name').find('a').get_text(strip=True)
+                            download_url = self.url + result.find('td', class_='quickdownload').find('a')['href']
                             if not all([title, download_url]):
                                 continue
 
-                            # Filter unseeded torrent
+                            seeders = try_int(result.find('td', class_='seeders').get_text(strip=True))
+                            leechers = try_int(result.find('td', class_='leechers').get_text(strip=True))
                             if seeders < self.minseed or leechers < self.minleech:
                                 if mode != 'RSS':
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
+                            torrent_size = result.find_all('td')[labels.index('Size')].get_text()
+                            size = convert_size(torrent_size) or -1
+
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
-
-                except Exception as e:
-                    logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
+                            items.append(item)
+                        except StandardError:
+                            continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -157,8 +171,8 @@ class TorrentLeechCache(tvcache.TVCache):
         self.minTime = 20
 
     def _getRSSData(self):
-        search_params = {'RSS': ['']}
-        return {'entries': self.provider.search(search_params)}
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
 
 
 provider = TorrentLeechProvider()
diff --git a/sickbeard/providers/torrentproject.py b/sickbeard/providers/torrentproject.py
index eedb52d6d7a23ef456417ed65d54aeba1d9f2488..b5b15844762d80f47ec971c1b7d78a11581270fe 100644
--- a/sickbeard/providers/torrentproject.py
+++ b/sickbeard/providers/torrentproject.py
@@ -11,22 +11,22 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import posixpath # Must use posixpath
 from urllib import quote_plus
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.common import USER_AGENT
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TORRENTPROJECTProvider(TorrentProvider):
+class TorrentProjectProvider(TorrentProvider):
     def __init__(self):
         TorrentProvider.__init__(self, "TorrentProject")
 
@@ -38,25 +38,23 @@ class TORRENTPROJECTProvider(TorrentProvider):
         self.headers.update({'User-Agent': USER_AGENT})
         self.minseed = None
         self.minleech = None
-        self.cache = TORRENTPROJECTCache(self)
+        self.cache = TorrentProjectCache(self)
 
     def search(self, search_strings, age=0, ep_obj=None):
-
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        for mode in search_strings.keys():  # Mode = RSS, Season, Episode
+        for mode in search_strings:  # Mode = RSS, Season, Episode
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urls['api'] + "?s=%s&out=json&filter=2101&num=150" % quote_plus(search_string.encode('utf-8'))
+                search_url = self.urls['api'] + "?s=%s&out=json&filter=2101&num=150" % quote_plus(search_string.encode('utf-8'))
                 if self.custom_url:
-                    searchURL = posixpath.join(self.custom_url, searchURL.split(self.url)[1].lstrip('/')) # Must use posixpath
+                    search_url = posixpath.join(self.custom_url, search_url.split(self.url)[1].lstrip('/')) # Must use posixpath
 
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                torrents = self.get_url(searchURL, json=True)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                torrents = self.get_url(search_url, json=True)
                 if not (torrents and "total_found" in torrents and int(torrents["total_found"]) > 0):
                     logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
                     continue
@@ -74,7 +72,8 @@ class TORRENTPROJECTProvider(TorrentProvider):
                         continue
 
                     t_hash = torrents[i]["torrent_hash"]
-                    size = int(torrents[i]["torrent_size"])
+                    torrent_size = torrents[i]["torrent_size"]
+                    size = convert_size(torrent_size) or -1
 
                     try:
                         assert seeders < 10
@@ -82,7 +81,7 @@ class TORRENTPROJECTProvider(TorrentProvider):
                         logger.log(u"Torrent has less than 10 seeds getting dyn trackers: " + title, logger.DEBUG)
                         trackerUrl = self.urls['api'] + "" + t_hash + "/trackers_json"
                         if self.custom_url:
-                            searchURL = posixpath.join(self.custom_url, searchURL.split(self.url)[1].lstrip('/')) # Must use posixpath
+                            search_url = posixpath.join(self.custom_url, search_url.split(self.url)[1].lstrip('/')) # Must use posixpath
                         jdata = self.get_url(trackerUrl, json=True)
                         assert jdata != "maintenance"
                         download_url = "magnet:?xt=urn:btih:" + t_hash + "&dn=" + title + "".join(["&tr=" + s for s in jdata])
@@ -97,12 +96,12 @@ class TORRENTPROJECTProvider(TorrentProvider):
                     if mode != 'RSS':
                         logger.log(u"Found result: %s" % title, logger.DEBUG)
 
-                    items[mode].append(item)
+                    items.append(item)
 
             # For each search mode sort all the items by seeders
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
@@ -110,7 +109,7 @@ class TORRENTPROJECTProvider(TorrentProvider):
         return self.ratio
 
 
-class TORRENTPROJECTCache(tvcache.TVCache):
+class TorrentProjectCache(tvcache.TVCache):
     def __init__(self, provider_obj):
 
         tvcache.TVCache.__init__(self, provider_obj)
@@ -122,4 +121,4 @@ class TORRENTPROJECTCache(tvcache.TVCache):
         search_params = {'RSS': ['0day']}
         return {'entries': self.provider.search(search_params)}
 
-provider = TORRENTPROJECTProvider()
+provider = TorrentProjectProvider()
diff --git a/sickbeard/providers/torrentz.py b/sickbeard/providers/torrentz.py
index 3916ccdc0a4ddc8febdb45df5b5f78c8caca946f..02060f299a983b9921538a5e38614de114793b16 100644
--- a/sickbeard/providers/torrentz.py
+++ b/sickbeard/providers/torrentz.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import traceback
@@ -24,10 +24,11 @@ from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.common import USER_AGENT
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TORRENTZProvider(TorrentProvider):
+class TorrentzProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -37,7 +38,7 @@ class TORRENTZProvider(TorrentProvider):
         self.ratio = None
         self.minseed = None
         self.minleech = None
-        self.cache = TORRENTZCache(self)
+        self.cache = TorrentzCache(self)
         self.headers.update({'User-Agent': USER_AGENT})
         self.urls = {'verified': 'https://torrentz.eu/feed_verified',
                      'feed': 'https://torrentz.eu/feed',
@@ -52,11 +53,11 @@ class TORRENTZProvider(TorrentProvider):
         match = re.findall(r'[0-9]+', description)
         return int(match[0]) * 1024 ** 2, int(match[1]), int(match[2])
 
-    def search(self, search_strings, age=0, ep_obj=None):
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
 
         for mode in search_strings:
+            items = []
             for search_string in search_strings[mode]:
                 search_url = self.urls['verified'] if self.confirmed else self.urls['feed']
                 if mode != 'RSS':
@@ -83,9 +84,9 @@ class TORRENTZProvider(TorrentProvider):
                             if not all([title, t_hash]):
                                 continue
 
-                            # TODO: Add method to generic provider for building magnet from hash.
                             download_url = "magnet:?xt=urn:btih:" + t_hash + "&dn=" + title + self._custom_trackers
-                            size, seeders, leechers = self._split_description(item.find('description').text)
+                            torrent_size, seeders, leechers = self._split_description(item.find('description').text)
+                            size = convert_size(torrent_size) or -1
 
                             # Filter unseeded torrent
                             if seeders < self.minseed or leechers < self.minleech:
@@ -93,19 +94,19 @@ class TORRENTZProvider(TorrentProvider):
                                     logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
                                 continue
 
-                            items[mode].append((title, download_url, size, seeders, leechers))
+                            items.append((title, download_url, size, seeders, leechers))
 
                 except (AttributeError, TypeError, KeyError, ValueError):
                     logger.log(u"Failed parsing provider. Traceback: %r" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
-            results += items[mode]
+            items.sort(key=lambda tup: tup[3], reverse=True)
+            results += items
 
         return results
 
 
-class TORRENTZCache(tvcache.TVCache):
+class TorrentzCache(tvcache.TVCache):
 
     def __init__(self, provider_obj):
 
@@ -117,4 +118,4 @@ class TORRENTZCache(tvcache.TVCache):
     def _getRSSData(self):
         return {'entries': self.provider.search({'RSS': ['']})}
 
-provider = TORRENTZProvider()
+provider = TorrentzProvider()
diff --git a/sickbeard/providers/transmitthenet.py b/sickbeard/providers/transmitthenet.py
index 928ed49db5e625cce5b71c4c50fa9153efa8d49a..55c0845c2fddee727113b0177ab72330d40706b2 100644
--- a/sickbeard/providers/transmitthenet.py
+++ b/sickbeard/providers/transmitthenet.py
@@ -8,11 +8,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import traceback
@@ -22,11 +22,11 @@ from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
 from sickrage.helper.exceptions import AuthException
-from sickrage.helper.common import try_int
+from sickrage.helper.common import try_int, convert_size
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TransmitTheNetProvider(TorrentProvider):
+class TransmitTheNetProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
 
         TorrentProvider.__init__(self, "TransmitTheNet")
@@ -75,15 +75,13 @@ class TransmitTheNetProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-branches, too-many-locals, too-many-statements
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             for search_string in search_strings[mode]:
 
                 if mode != 'RSS':
@@ -136,7 +134,9 @@ class TransmitTheNetProvider(TorrentProvider):
                             if not title:
                                 title = torrent_row.find('a', onmouseout='return nd();').string
                                 title = title.replace("[", "").replace("]", "").replace("/ ", "")
-                            size = try_int(temp_anchor['data-filesize'])
+
+                            torrent_size = temp_anchor['data-filesize']
+                            size = convert_size(torrent_size) or -1
 
                             temp_anchor = torrent_row.find('span', class_='time').parent.find_next_sibling()
                             seeders = try_int(temp_anchor.text.strip())
@@ -155,15 +155,15 @@ class TransmitTheNetProvider(TorrentProvider):
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                 except Exception:
                     logger.log(u"Failed parsing provider. Traceback: %s" % traceback.format_exc(), logger.ERROR)
 
             # For each search mode sort all the items by seeders
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
diff --git a/sickbeard/providers/tvchaosuk.py b/sickbeard/providers/tvchaosuk.py
index 874f4761a1df8bef587e1a31602c71053968d306..65d18be459bfd03c27ec7dc7e17facc0afe04f51 100644
--- a/sickbeard/providers/tvchaosuk.py
+++ b/sickbeard/providers/tvchaosuk.py
@@ -8,11 +8,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 # from urllib import urlencode
@@ -23,11 +23,12 @@ from sickbeard import tvcache
 from sickbeard import show_name_helpers
 from sickbeard.helpers import sanitizeSceneName
 from sickbeard.bs4_parser import BS4Parser
+from sickrage.helper.common import convert_size
 from sickrage.helper.exceptions import AuthException
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
 
-class TVChaosUKProvider(TorrentProvider):
+class TVChaosUKProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
     def __init__(self):
         TorrentProvider.__init__(self, 'TvChaosUK')
 
@@ -119,15 +120,13 @@ class TVChaosUKProvider(TorrentProvider):
 
         return True
 
-    def search(self, search_strings, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
         if not self.login():
             return results
 
-        for mode in search_strings.keys():
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
             for search_string in search_strings[mode]:
 
@@ -180,46 +179,27 @@ class TVChaosUKProvider(TorrentProvider):
 
                             # Strip year from the end or we can't parse it!
                             title = re.sub(r'[\. ]?\(\d{4}\)', '', title)
-                            torrent_size = cells[4].getText().strip()
-                            size = -1
-                            if re.match(r"\d+([,\.]\d+)?\s*[KkMmGgTt]?[Bb]", torrent_size):
-                                size = self._convertSize(torrent_size.rstrip())
+                            torrent_size = cells[4].getText()
+                            size = convert_size(torrent_size) or -1
                             item = title, download_url, size, seeders, leechers
                             if mode != 'RSS':
                                 logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                            items[mode].append(item)
+                            items.append(item)
 
                         except Exception:
                             continue
 
             # For each search mode sort all the items by seeders if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
-    def _convertSize(self, sizeString):
-        size = sizeString[:-2].strip()
-        modifier = sizeString[-2:].upper()
-        try:
-            size = float(size)
-            if modifier in 'KB':
-                size *= 1024 ** 1
-            elif modifier in 'MB':
-                size *= 1024 ** 2
-            elif modifier in 'GB':
-                size *= 1024 ** 3
-            elif modifier in 'TB':
-                size *= 1024 ** 4
-        except Exception:
-            size = -1
-        return long(size)
-
 
 class TVChaosUKCache(tvcache.TVCache):
     def __init__(self, provider_obj):
diff --git a/sickbeard/providers/womble.py b/sickbeard/providers/womble.py
index 5a003863467a81064d75c801f2b589d1aafe2754..b21d3fbd3045fe75210aeda7639bc3392c60a0bc 100644
--- a/sickbeard/providers/womble.py
+++ b/sickbeard/providers/womble.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard import logger
 from sickbeard import tvcache
diff --git a/sickbeard/providers/xthor.py b/sickbeard/providers/xthor.py
index 83b596a7e5e8109aca2e259e702fd8f81314e449..c5b479fa0b4ea6de4b2e28c9cf201118431c690e 100644
--- a/sickbeard/providers/xthor.py
+++ b/sickbeard/providers/xthor.py
@@ -1,6 +1,7 @@
 # -*- coding: latin-1 -*-
 # Author: adaur <adaur.underground@gmail.com>
-# URL: http://code.google.com/p/sickbeard/
+# Rewrite: Dustyn Gibson (miigotu) <miigotu@gmail.com>
+# URL: https://sickrage.github.io
 #
 # This file is part of SickRage.
 #
@@ -11,23 +12,26 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
-import cookielib
-import urllib
 import requests
+import cookielib
+from urllib import urlencode
 
 from sickbeard import logger
+from sickbeard import tvcache
 from sickbeard.bs4_parser import BS4Parser
 from sickrage.providers.torrent.TorrentProvider import TorrentProvider
 
+from sickrage.helper.common import try_int, convert_size
+
 
-class XthorProvider(TorrentProvider):
+class XthorProvider(TorrentProvider):  # pylint: disable=too-many-instance-attributes
 
     def __init__(self):
 
@@ -35,13 +39,20 @@ class XthorProvider(TorrentProvider):
 
         self.cj = cookielib.CookieJar()
 
-        self.url = "https://xthor.bz"
-        self.urlsearch = "https://xthor.bz/browse.php?search=\"%s\"%s"
-        self.categories = "&searchin=title&incldead=0"
+        self.url = 'https://xthor.bz'
+        self.urls = {
+            'login': self.url + '/takelogin.php',
+            'search': self.url + '/browse.php?'
+        }
 
+        self.ratio = None
+        self.minseed = None
+        self.minleech = None
         self.username = None
         self.password = None
-        self.ratio = None
+        self.freeleech = None
+        self.proper_strings = ['PROPER']
+        self.cache = XthorCache(self)
 
     def login(self):
 
@@ -52,7 +63,7 @@ class XthorProvider(TorrentProvider):
                         'password': self.password,
                         'submitme': 'X'}
 
-        response = self.get_url(self.url + '/takelogin.php', post_data=login_params, timeout=30)
+        response = self.get_url(self.urls['login'], post_data=login_params, timeout=30)
         if not response:
             logger.log(u"Unable to connect to provider", logger.WARNING)
             return False
@@ -63,75 +74,107 @@ class XthorProvider(TorrentProvider):
             logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
             return False
 
-    def search(self, search_params, age=0, ep_obj=None):
-
+    def search(self, search_strings, age=0, ep_obj=None):  # pylint: disable=too-many-locals, too-many-branches
         results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
-
-        # check for auth
         if not self.login():
             return results
 
-        for mode in search_params.keys():
+        """
+            Séries / Pack TV 13
+            Séries / TV FR 14
+            Séries / HD FR 15
+            Séries / TV VOSTFR 16
+            Séries / HD VOSTFR 17
+            Mangas (Anime) 32
+            Sport 34
+        """
+        search_params = {
+            'only_free': try_int(self.freeleech),
+            'searchin': 'title',
+            'incldead': 0,
+            'type': 'desc',
+            'c13': 1, 'c14': 1, 'c15': 1,
+            'c16': 1, 'c17': 1, 'c32': 1
+        }
+
+        for mode in search_strings:
+            items = []
             logger.log(u"Search Mode: %s" % mode, logger.DEBUG)
-            for search_string in search_params[mode]:
 
+            # Sorting: 1: Name, 3: Comments, 5: Size, 6: Completed, 7: Seeders, 8: Leechers (4: Time ?)
+            search_params['sort'] = (7, 4)[mode == 'RSS']
+            for search_string in search_strings[mode]:
                 if mode != 'RSS':
                     logger.log(u"Search string: %s " % search_string, logger.DEBUG)
 
-                searchURL = self.urlsearch % (urllib.quote(search_string), self.categories)
-                logger.log(u"Search URL: %s" % searchURL, logger.DEBUG)
-                data = self.get_url(searchURL)
-
+                search_params['search'] = search_string
+                search_url = self.urls['search'] + urlencode(search_params)
+                logger.log(u"Search URL: %s" % search_url, logger.DEBUG)
+                data = self.get_url(search_url)
                 if not data:
                     continue
 
                 with BS4Parser(data, 'html5lib') as html:
-                    resultsTable = html.find("table", {"class": "table2 table-bordered2"})
-                    if not resultsTable:
+                    torrent_table = html.find("table", class_="table2 table-bordered2")
+                    torrent_rows = []
+                    if torrent_table:
+                        torrent_rows = torrent_table.find_all("tr")
+
+                    # Continue only if at least one Release is found
+                    if len(torrent_rows) < 2:
+                        logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
                         continue
 
-                    rows = resultsTable.findAll("tr")
-                    for row in rows:
-                        link = row.find("a", href=re.compile("details.php"))
-                        if not link:
-                            continue
-
-                        title = link.text
-                        download_item = row.find("a", href=re.compile("download.php"))
-                        if not download_item:
+                    # Catégorie, Nom du Torrent, (Download), (Bookmark), Com., Taille, Complété, Seeders, Leechers
+                    labels = [label.get_text(strip=True) for label in torrent_rows[0].find_all('td')]
+
+                    for row in torrent_rows[1:]:
+                        try:
+                            cells = row.find_all('td')
+                            title = cells[labels.index('Nom du Torrent')].get_text(strip=True)
+                            download_url = self.url + '/' + row.find("a", href=re.compile("download.php"))['href']
+                            size = convert_size(cells[labels.index('Taille')].get_text(strip=True))
+                            seeders = try_int(cells[labels.index('Seeders')].get_text(strip=True))
+                            leechers = try_int(cells[labels.index('Leechers')].get_text(strip=True))
+                        except (AttributeError, TypeError, KeyError, ValueError):
                             continue
 
-                        download_url = self.url + '/' + download_item['href']
-
-                        # FIXME
-                        size = -1
-                        seeders = 1
-                        leechers = 0
-
                         if not all([title, download_url]):
                             continue
 
                         # Filter unseeded torrent
-                        # if seeders < self.minseed or leechers < self.minleech:
-                        #    if mode != 'RSS':
-                        #        logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
-                        #    continue
+                        if seeders < self.minseed or leechers < self.minleech:
+                            if mode != 'RSS':
+                                logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(title, seeders, leechers), logger.DEBUG)
+                            continue
 
                         item = title, download_url, size, seeders, leechers
                         if mode != 'RSS':
                             logger.log(u"Found result: %s " % title, logger.DEBUG)
 
-                        items[mode].append(item)
+                        items.append(item)
 
             # For each search mode sort all the items by seeders if available if available
-            items[mode].sort(key=lambda tup: tup[3], reverse=True)
+            items.sort(key=lambda tup: tup[3], reverse=True)
 
-            results += items[mode]
+            results += items
 
         return results
 
     def seed_ratio(self):
         return self.ratio
 
+
+class XthorCache(tvcache.TVCache):
+    def __init__(self, provider_obj):
+
+        tvcache.TVCache.__init__(self, provider_obj)
+
+        self.minTime = 30
+
+    def _getRSSData(self):
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider.search(search_strings)}
+
+
 provider = XthorProvider()
diff --git a/sickbeard/sab.py b/sickbeard/sab.py
index bf4a0583ca45206fdcab7c8f2507367bc141ff88..ee053533401aa8233e749d10ae9e022a19237e58 100644
--- a/sickbeard/sab.py
+++ b/sickbeard/sab.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import urllib
 import httplib
diff --git a/sickbeard/sbdatetime.py b/sickbeard/sbdatetime.py
index f61d5ecd3b75444a78cf433b185a1f1dc26ae623..03bb4b325912c336e76a4f7f01e89087a5ec8573 100644
--- a/sickbeard/sbdatetime.py
+++ b/sickbeard/sbdatetime.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import locale
diff --git a/sickbeard/scene_exceptions.py b/sickbeard/scene_exceptions.py
index 0598ee4fbf8ab5b83c830edbef8576e6dd66ee94..ceb15b3ccaf69f3e73ba4afd34bfce746fb74bce 100644
--- a/sickbeard/scene_exceptions.py
+++ b/sickbeard/scene_exceptions.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import time
diff --git a/sickbeard/scene_numbering.py b/sickbeard/scene_numbering.py
index b1a19387be1d2c65e5b8f1dc7ac9180e94f8e706..4316347063269796f459c1c7615c993ea8404873 100644
--- a/sickbeard/scene_numbering.py
+++ b/sickbeard/scene_numbering.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 #
 # Created on Sep 20, 2012
 # @author: Dermot Buckley <dermot@buckley.ie>
diff --git a/sickbeard/scheduler.py b/sickbeard/scheduler.py
index a4690cf5dda6c7727261dd6376b0622a27fd876b..cdf3171c895ef53083d3c9be7b95f68501b3be49 100644
--- a/sickbeard/scheduler.py
+++ b/sickbeard/scheduler.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import time
diff --git a/sickbeard/search.py b/sickbeard/search.py
index 58145a60e973d7dbcd4b0cdaebd7ffd3078d30f0..541bff2cdf8c68d601404b5ee13777da054103b5 100644
--- a/sickbeard/search.py
+++ b/sickbeard/search.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import re
diff --git a/sickbeard/searchBacklog.py b/sickbeard/searchBacklog.py
index efd21b5d517742b8c39b1e99905b30be70698eab..a16552e597407af300a28f509d0ecfb9f675ca5d 100644
--- a/sickbeard/searchBacklog.py
+++ b/sickbeard/searchBacklog.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 
 import datetime
diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py
index 4b8fccb4dca3208ad96b1fb67ecc11e5dd8f5a99..b70c9278b342b4d3f2934048a72c6131e987de09 100644
--- a/sickbeard/search_queue.py
+++ b/sickbeard/search_queue.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 
 import time
diff --git a/sickbeard/showUpdater.py b/sickbeard/showUpdater.py
index f995d45174593692b573230c8b9a773bb8852450..929e276fe61d88fc327c2eb598df9b074eb9f20e 100644
--- a/sickbeard/showUpdater.py
+++ b/sickbeard/showUpdater.py
@@ -11,11 +11,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import xml.etree.ElementTree as ET
 import requests
@@ -35,14 +35,14 @@ from sickbeard.indexers.indexer_config import INDEXER_TVRAGE
 from sickbeard.indexers.indexer_config import INDEXER_TVDB
 
 
-class ShowUpdater(object):
+class ShowUpdater(object):  # pylint: disable=too-few-public-methods
     def __init__(self):
         self.lock = threading.Lock()
         self.amActive = False
 
         self.session = requests.Session()
 
-    def run(self, force=False):  # pylint: disable=unused-parameter
+    def run(self, force=False):  # pylint: disable=unused-argument, too-many-locals, too-many-branches, too-many-statements
 
         self.amActive = True
 
@@ -79,13 +79,16 @@ class ShowUpdater(object):
         # url = 'http://thetvdb.com/api/Updates.php?type=series&time=%s' % last_update
         url = 'http://thetvdb.com/api/%s/updates/%s' % (sickbeard.indexerApi(INDEXER_TVDB).api_params['apikey'], update_file)
         data = helpers.getURL(url, session=self.session)
+        if not data:
+            logger.log(u"Could not get the recently updated show data from %s. Retrying later. Url was: %s" % (sickbeard.indexerApi(INDEXER_TVDB).name, url))
+            self.amActive = False
+            return
 
         updated_shows = []
         try:
             tree = ET.fromstring(data)
             for show in tree.findall("Series"):
                 updated_shows.append(int(show.find('id').text))
-
         except SyntaxError:
             pass
 
diff --git a/sickbeard/show_name_helpers.py b/sickbeard/show_name_helpers.py
index f161b0569c67dcd64e910395a8dce8d969b716b9..299d7a7a7990118ebc638f83f4b46b56e08668f5 100644
--- a/sickbeard/show_name_helpers.py
+++ b/sickbeard/show_name_helpers.py
@@ -11,27 +11,23 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import fnmatch
 import os
 
 import re
-import datetime
-from functools import partial
 
 import sickbeard
 from sickbeard import common
-from sickbeard.helpers import sanitizeSceneName
 from sickbeard.scene_exceptions import get_scene_exceptions
 from sickbeard import logger
-from sickbeard import db
-from sickrage.helper.encoding import ek, ss
-from name_parser.parser import NameParser, InvalidNameException, InvalidShowException
+from sickrage.helper.encoding import ek
+from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
 
 resultFilters = [
     "sub(bed|ed|pack|s)",
@@ -56,7 +52,7 @@ def containsAtLeastOneWord(name, words):
     """
     if isinstance(words, basestring):
         words = words.split(',')
-    items = [(re.compile('(^|[\W_])%s($|[\W_])' % re.escape(word.strip()), re.I), word.strip()) for word in words]
+    items = [(re.compile(r'(^|[\W_])%s($|[\W_])' % re.escape(word.strip()), re.I), word.strip()) for word in words]
     for regexp, word in items:
         if regexp.search(name):
             return word
@@ -104,195 +100,6 @@ def filterBadReleases(name, parse=True):
     return True
 
 
-def sceneToNormalShowNames(name):
-    """
-        Takes a show name from a scene dirname and converts it to a more "human-readable" format.
-
-    name: The show name to convert
-
-    Returns: a list of all the possible "normal" names
-    """
-
-    if not name:
-        return []
-
-    name_list = [name]
-
-    # use both and and &
-    new_name = re.sub('(?i)([\. ])and([\. ])', '\\1&\\2', name, re.I)
-    if new_name not in name_list:
-        name_list.append(new_name)
-
-    results = []
-
-    for cur_name in name_list:
-        # add brackets around the year
-        results.append(re.sub('(\D)(\d{4})$', '\\1(\\2)', cur_name))
-
-        # add brackets around the country
-        country_match_str = '|'.join(common.countryList.values())
-        results.append(re.sub('(?i)([. _-])(' + country_match_str + ')$', '\\1(\\2)', cur_name))
-
-    results += name_list
-
-    return list(set(results))
-
-
-def makeSceneShowSearchStrings(show, season=-1, anime=False):
-    showNames = allPossibleShowNames(show, season=season)
-
-    # scenify the names
-    if anime:
-        sanitizeSceneNameAnime = partial(sanitizeSceneName, anime=True)
-        return map(sanitizeSceneNameAnime, showNames)
-    else:
-        return map(sanitizeSceneName, showNames)
-
-
-def makeSceneSeasonSearchString(show, ep_obj, extraSearchType=None):
-
-    if show.air_by_date or show.sports:
-        numseasons = 0
-
-        # the search string for air by date shows is just
-        seasonStrings = [str(ep_obj.airdate).split('-')[0]]
-    elif show.is_anime:
-        numseasons = 0
-        seasonEps = show.getAllEpisodes(ep_obj.season)
-
-        # get show qualities
-        anyQualities, bestQualities = common.Quality.splitQuality(show.quality)
-
-        # compile a list of all the episode numbers we need in this 'season'
-        seasonStrings = []
-        for episode in seasonEps:
-
-            # get quality of the episode
-            curCompositeStatus = episode.status
-            curStatus, curQuality = common.Quality.splitCompositeStatus(curCompositeStatus)
-
-            if bestQualities:
-                highestBestQuality = max(bestQualities)
-            else:
-                highestBestQuality = 0
-
-            # if we need a better one then add it to the list of episodes to fetch
-            if (curStatus in (
-                    common.DOWNLOADED,
-                    common.SNATCHED) and curQuality < highestBestQuality) or curStatus == common.WANTED:
-                ab_number = episode.scene_absolute_number
-                if ab_number > 0:
-                    seasonStrings.append("%02d" % ab_number)
-
-    else:
-        myDB = db.DBConnection()
-        numseasonsSQlResult = myDB.select(
-            "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0",
-            [show.indexerid])
-
-        numseasons = int(numseasonsSQlResult[0][0])
-        seasonStrings = ["S%02d" % int(ep_obj.scene_season)]
-
-    showNames = set(makeSceneShowSearchStrings(show, ep_obj.scene_season))
-
-    toReturn = []
-
-    # search each show name
-    for curShow in showNames:
-        # most providers all work the same way
-        if not extraSearchType:
-            # if there's only one season then we can just use the show name straight up
-            if numseasons == 1:
-                toReturn.append(curShow)
-            # for providers that don't allow multiple searches in one request we only search for Sxx style stuff
-            else:
-                for cur_season in seasonStrings:
-                    if ep_obj.show.is_anime:
-                        if ep_obj.show.release_groups is not None:
-                            if len(show.release_groups.whitelist) > 0:
-                                for keyword in show.release_groups.whitelist:
-                                    toReturn.append(keyword + '.' + curShow + "." + cur_season)
-                    else:
-                        toReturn.append(curShow + "." + cur_season)
-
-    return toReturn
-
-
-def makeSceneSearchString(show, ep_obj):
-    myDB = db.DBConnection()
-    numseasonsSQlResult = myDB.select(
-        "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0",
-        [show.indexerid])
-    numseasons = int(numseasonsSQlResult[0][0])
-
-    # see if we should use dates instead of episodes
-    if (show.air_by_date or show.sports) and ep_obj.airdate != datetime.date.fromordinal(1):
-        epStrings = [str(ep_obj.airdate)]
-    elif show.is_anime:
-        epStrings = ["%02i" % int(ep_obj.scene_absolute_number if ep_obj.scene_absolute_number > 0 else ep_obj.scene_episode)]
-    else:
-        epStrings = ["S%02iE%02i" % (int(ep_obj.scene_season), int(ep_obj.scene_episode)),
-                     "%ix%02i" % (int(ep_obj.scene_season), int(ep_obj.scene_episode))]
-
-    # for single-season shows just search for the show name -- if total ep count (exclude s0) is less than 11
-    # due to the amount of qualities and releases, it is easy to go over the 50 result limit on rss feeds otherwise
-    if numseasons == 1 and not ep_obj.show.is_anime:
-        epStrings = ['']
-
-    showNames = set(makeSceneShowSearchStrings(show, ep_obj.scene_season))
-
-    toReturn = []
-
-    for curShow in showNames:
-        for curEpString in epStrings:
-            if ep_obj.show.is_anime:
-                if ep_obj.show.release_groups is not None:
-                    if len(ep_obj.show.release_groups.whitelist) > 0:
-                        for keyword in ep_obj.show.release_groups.whitelist:
-                            toReturn.append(keyword + '.' + curShow + '.' + curEpString)
-                    elif len(ep_obj.show.release_groups.blacklist) == 0:
-                        # If we have neither whitelist or blacklist we just append what we have
-                        toReturn.append(curShow + '.' + curEpString)
-            else:
-                toReturn.append(curShow + '.' + curEpString)
-
-    return toReturn
-
-
-def isGoodResult(name, show, log=True, season=-1):
-    """
-    Use an automatically-created regex to make sure the result actually is the show it claims to be
-    """
-
-    all_show_names = allPossibleShowNames(show, season=season)
-    showNames = map(sanitizeSceneName, all_show_names) + all_show_names
-    showNames += map(ss, all_show_names)
-
-    for curName in set(showNames):
-        if not show.is_anime:
-            escaped_name = re.sub('\\\\[\\s.-]', '\W+', re.escape(curName))
-            if show.startyear:
-                escaped_name += "(?:\W+" + str(show.startyear) + ")?"
-            curRegex = '^' + escaped_name + '\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}.+))'
-        else:
-            escaped_name = re.sub('\\\\[\\s.-]', '[\W_]+', re.escape(curName))
-            # FIXME: find a "automatically-created" regex for anime releases # test at http://regexr.com?2uon3
-            curRegex = '^((\[.*?\])|(\d+[\.-]))*[ _\.]*' + escaped_name + '(([ ._-]+\d+)|([ ._-]+s\d{2})).*'
-
-        if log:
-            logger.log(u"Checking if show " + name + " matches " + curRegex, logger.DEBUG)
-
-        match = re.search(curRegex, name, re.I)
-        if match:
-            logger.log(u"Matched " + curRegex + " to " + name, logger.DEBUG)
-            return True
-
-    if log:
-        logger.log(
-            u"Provider gave result " + name + " but that doesn't seem like a valid result for " + show.name + " so I'm ignoring it")
-    return False
-
-
 def allPossibleShowNames(show, season=-1):
     """
     Figures out every possible variation of the name for a particular show. Includes TVDB name, TVRage name,
@@ -354,7 +161,8 @@ def determineReleaseName(dir_name=None, nzb_name=None):
         reg_expr = re.compile(fnmatch.translate(search), re.IGNORECASE)
         files = [file_name for file_name in ek(os.listdir, dir_name) if
                  ek(os.path.isfile, ek(os.path.join, dir_name, file_name))]
-        results = filter(reg_expr.search, files)
+
+        results = [f for f in files if reg_expr.search(f)]
 
         if len(results) == 1:
             found_file = ek(os.path.basename, results[0])
diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py
index e9bfcf309325d8a71cf3949aedaa7a785e39ec2c..4d868108cbaf08ec5e704aec54aa3e6c40004f59 100644
--- a/sickbeard/show_queue.py
+++ b/sickbeard/show_queue.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 
 import traceback
@@ -432,7 +432,7 @@ class QueueItemAdd(ShowQueueItem):
             logger.log(traceback.format_exc(), logger.DEBUG)
 
         # update internal name cache
-        name_cache.buildNameCache()
+        name_cache.buildNameCache(self.show)
 
         try:
             self.show.loadEpisodesFromDir()
diff --git a/sickbeard/subtitles.py b/sickbeard/subtitles.py
index 7b20b57330223bc0ed47829f0ca785c6e0539bc9..15f1a56e00c17218033461978e05d9328a6e673c 100644
--- a/sickbeard/subtitles.py
+++ b/sickbeard/subtitles.py
@@ -13,11 +13,11 @@
 #
 # 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.
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import re
@@ -25,10 +25,9 @@ import datetime
 import traceback
 import subliminal
 import subprocess
-import pkg_resources
 import sickbeard
-from subliminal.api import provider_manager
 from babelfish import Language, language_converters
+from subliminal import ProviderPool, provider_manager
 from sickbeard import logger
 from sickbeard import history
 from sickbeard import db
@@ -40,32 +39,8 @@ from sickrage.helper.encoding import ek
 from sickrage.helper.exceptions import ex
 from sickrage.show.Show import Show
 
-DISTRIBUTION = pkg_resources.Distribution(location=os.path.dirname(os.path.dirname(__file__)),
-                                          project_name='fake_entry_points', version='1.0.0')
-
-ENTRY_POINTS = {
-    'subliminal.providers': [
-        'addic7ed = subliminal.providers.addic7ed:Addic7edProvider',
-        'legendastv = subliminal.providers.legendastv:LegendasTvProvider',
-        'napiprojekt = subliminal.providers.napiprojekt:NapiProjektProvider',
-        'opensubtitles = subliminal.providers.opensubtitles:OpenSubtitlesProvider',
-        'podnapisi = subliminal.providers.podnapisi:PodnapisiProvider',
-        'subscenter = subliminal.providers.subscenter:SubsCenterProvider',
-        'thesubdb = subliminal.providers.thesubdb:TheSubDBProvider',
-        'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider'
-    ],
-    'babelfish.language_converters': [
-        'addic7ed = subliminal.converters.addic7ed:Addic7edConverter',
-        'legendastv = subliminal.converters.legendastv:LegendasTvConverter',
-        'thesubdb = subliminal.converters.thesubdb:TheSubDBConverter',
-        'tvsubtitles = subliminal.converters.tvsubtitles:TVsubtitlesConverter'
-    ]
-}
-
-DISTRIBUTION._ep_map = pkg_resources.EntryPoint.parse_map(ENTRY_POINTS, DISTRIBUTION)  # pylint: disable=protected-access
-pkg_resources.working_set.add(DISTRIBUTION)
-
-provider_manager.ENTRY_POINT_CACHE.pop('subliminal.providers')
+provider_manager.register('legendastv = subliminal.providers.legendastv:LegendasTvProvider')
+provider_manager.register('napiprojekt = subliminal.providers.napiprojekt:NapiProjektProvider')
 
 subliminal.region.configure('dogpile.cache.memory')
 
@@ -87,14 +62,14 @@ def sorted_service_list():
 
     current_index = 0
     for current_service in sickbeard.SUBTITLES_SERVICES_LIST:
-        if current_service in subliminal.provider_manager.names():
+        if current_service in provider_manager.names():
             new_list.append({'name': current_service,
                              'url': PROVIDER_URLS[current_service] if current_service in PROVIDER_URLS else lmgtfy % current_service,
                              'image': current_service + '.png',
                              'enabled': sickbeard.SUBTITLES_SERVICES_ENABLED[current_index] == 1})
         current_index += 1
 
-    for current_service in subliminal.provider_manager.names():
+    for current_service in provider_manager.names():
         if current_service not in [service['name'] for service in new_list]:
             new_list.append({'name': current_service,
                              'url': PROVIDER_URLS[current_service] if current_service in PROVIDER_URLS else lmgtfy % current_service,
@@ -187,7 +162,7 @@ def download_subtitles(subtitles_info):  # pylint: disable=too-many-locals, too-
                         'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                           'password': sickbeard.OPENSUBTITLES_PASS}}
 
-    pool = subliminal.api.ProviderPool(providers=providers, provider_configs=provider_configs)
+    pool = ProviderPool(providers=providers, provider_configs=provider_configs)
 
     try:
         subtitles_list = pool.list_subtitles(video, languages)
@@ -333,7 +308,7 @@ class SubtitlesFinder(object):
                             'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                               'password': sickbeard.OPENSUBTITLES_PASS}}
 
-        pool = subliminal.api.ProviderPool(providers=providers, provider_configs=provider_configs)
+        pool = ProviderPool(providers=providers, provider_configs=provider_configs)
 
         # Search for all wanted languages
         languages = {from_code(language) for language in wanted_languages()}
diff --git a/sickbeard/traktChecker.py b/sickbeard/traktChecker.py
index 14d3b92e7aa00fe97f5c7a058005c7609f74db26..07c4f5a69f22062b0b320b13c40e38e71e25262a 100644
--- a/sickbeard/traktChecker.py
+++ b/sickbeard/traktChecker.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import traceback
diff --git a/sickbeard/tv.py b/sickbeard/tv.py
index f9d0a51bb2bc2f702023c258a807bc48b41d53b6..640511e4b8fe1c9fc9c2e85ac7fee540bf02c24e 100644
--- a/sickbeard/tv.py
+++ b/sickbeard/tv.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 # pylint: disable=too-many-lines
 
 import os.path
@@ -629,30 +629,46 @@ class TVShow(object):  # pylint: disable=too-many-instance-attributes, too-many-
             logger.log(u"Unable to parse the filename " + file + " into a valid show", logger.DEBUG)
             return None
 
-        if not len(parse_result.episode_numbers):
+        # for now lets assume that any episode in the show dir belongs to that show
+        season = parse_result.season_number
+        episodes = [ep for ep in parse_result.episode_numbers if ep is not None]
+        absolute_numbers = [ep for ep in parse_result.ab_episode_numbers if ep is not None]
+
+        is_absolute = len(absolute_numbers) > 0
+
+        if season is None and not is_absolute:
+            season = 1
+
+        if not episodes + absolute_numbers:
             logger.log(u"parse_result: " + str(parse_result))
             logger.log(u"No episode number found in " + file + ", ignoring it", logger.WARNING)
             return None
 
-        # for now lets assume that any episode in the show dir belongs to that show
-        season = parse_result.season_number if parse_result.season_number is not None else 1
-        episodes = parse_result.episode_numbers
         rootEp = None
 
         sql_l = []
-        for curEpNum in episodes:
-
-            episode = int(curEpNum)
+        for current_ep in episodes if not is_absolute else absolute_numbers:
 
-            logger.log(u"%s: %s parsed to %s S%02dE%02d" % (self.indexerid, file, self.name, season or 0, episode or 0), logger.DEBUG)
+            if is_absolute:
+                logger.log(u"%s: %s parsed to %s with absolute number %d" % (self.indexerid, file, self.name, current_ep), logger.DEBUG)
+            else:
+                logger.log(u"%s: %s parsed to %s S%02dE%02d" % (self.indexerid, file, self.name, season, current_ep), logger.DEBUG)
 
             checkQualityAgain = False
             same_file = False
 
-            curEp = self.getEpisode(season, episode)
+            if is_absolute:
+                curEp = self.getEpisode(absolute_number=current_ep)
+            else:
+                curEp = self.getEpisode(season, current_ep)
+
             if not curEp:
                 try:
-                    curEp = self.getEpisode(season, episode, file)
+                    if is_absolute:
+                        curEp = self.getEpisode(absolute_number=current_ep, file=file)
+                    else:
+                        curEp = self.getEpisode(season, current_ep, file)
+
                     if not curEp:
                         raise EpisodeNotFoundException
                 except EpisodeNotFoundException:
@@ -2187,7 +2203,7 @@ class TVEpisode(object):  # pylint: disable=too-many-instance-attributes, too-ma
         result_name = pattern
 
         # if there's no release group in the db, let the user know we replaced it
-        if replace_map['%RG'] and replace_map['%RG'] != 'SiCKRAGE':
+        if replace_map['%RG'] and replace_map['%RG'] != 'SickRage':
             if not hasattr(self, '_release_group'):
                 logger.log(u"Episode has no release group, replacing it with '" + replace_map['%RG'] + "'", logger.DEBUG)
                 self._release_group = replace_map['%RG']  # if release_group is not in the db, put it there
diff --git a/sickbeard/tvcache.py b/sickbeard/tvcache.py
index 17b8c6e799d889ab24a2e01aa0c72923fbd4d8ae..417e64fae259969019057161cebd7723cb31a9af 100644
--- a/sickbeard/tvcache.py
+++ b/sickbeard/tvcache.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import time
 import datetime
diff --git a/sickbeard/ui.py b/sickbeard/ui.py
index 60c9273df0698ab3918f15fb63d3c7420634e88c..4946f71b267993ae24934cd4638531c26f231d27 100644
--- a/sickbeard/ui.py
+++ b/sickbeard/ui.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import datetime
 import sickbeard
diff --git a/sickbeard/versionChecker.py b/sickbeard/versionChecker.py
index dfa6815474ed94e3a3997aeeed879282a39d69c7..82598358f0a0bcf8414497cbb30cf12538387fb0 100644
--- a/sickbeard/versionChecker.py
+++ b/sickbeard/versionChecker.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import platform
diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py
index be38f1b8eba78fed7b918daef3300e3d43be4aaa..8954fdf5c91713e8f32a35e86b3038b7220589a1 100644
--- a/sickbeard/webapi.py
+++ b/sickbeard/webapi.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # TODO: break this up into separate files
 # pylint: disable=line-too-long,too-many-lines,abstract-method
@@ -1197,11 +1197,11 @@ class CMD_Logs(ApiCall):
     def run(self):
         """ Get the logs """
         # 10 = Debug / 20 = Info / 30 = Warning / 40 = Error
-        min_level = logger.reverseNames[str(self.min_level).upper()]
+        min_level = logger.LOGGING_LEVELS[str(self.min_level).upper()]
 
         data = []
-        if ek(os.path.isfile, logger.logFile):
-            with io.open(logger.logFile, 'r', encoding='utf-8') as f:
+        if ek(os.path.isfile, logger.log_file):
+            with io.open(logger.log_file, 'r', encoding='utf-8') as f:
                 data = f.readlines()
 
         regex = r"^(\d\d\d\d)\-(\d\d)\-(\d\d)\s*(\d\d)\:(\d\d):(\d\d)\s*([A-Z]+)\s*(.+?)\s*\:\:\s*(.*)$"
@@ -1218,11 +1218,11 @@ class CMD_Logs(ApiCall):
 
             if match:
                 level = match.group(7)
-                if level not in logger.reverseNames:
+                if level not in logger.LOGGING_LEVELS:
                     last_line = False
                     continue
 
-                if logger.reverseNames[level] >= min_level:
+                if logger.LOGGING_LEVELS[level] >= min_level:
                     last_line = True
                     final_data.append(x.rstrip("\n"))
                 else:
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index fd4f08c47685fd1906dfdf8813777fb82efa25f0..986e7b2a84c8cc6ba635831b0d4b878b3c628ebb 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 # pylint: disable=abstract-method,too-many-lines
 
 import io
@@ -81,6 +81,7 @@ except ImportError:
 
 from mako.template import Template as MakoTemplate
 from mako.lookup import TemplateLookup
+from mako.exceptions import RichTraceback
 
 from tornado.routes import route
 from tornado.web import RequestHandler, HTTPError, authenticated
@@ -106,7 +107,11 @@ def get_lookup():
         mako_cache = ek(os.path.join, sickbeard.CACHE_DIR, 'mako')
     if mako_lookup is None:
         use_strict = sickbeard.BRANCH and sickbeard.BRANCH != 'master'
-        mako_lookup = TemplateLookup(directories=[mako_path], module_directory=mako_cache, format_exceptions=True, strict_undefined=use_strict)
+        mako_lookup = TemplateLookup(directories=[mako_path],
+                                     module_directory=mako_cache,
+                                    #  format_exceptions=True,
+                                     strict_undefined=use_strict,
+                                     filesystem_checks=True)
     return mako_lookup
 
 
@@ -158,9 +163,13 @@ class PageTemplate(MakoTemplate):
                 kwargs[key] = self.arguments[key]
 
         kwargs['makoStartTime'] = time.time()
-
-        return self.template.render_unicode(*args, **kwargs)
-
+        try:
+            return self.template.render_unicode(*args, **kwargs)
+        except Exception:
+            kwargs['title'] = '500'
+            kwargs['header'] = 'Mako Error'
+            kwargs['backtrace'] = RichTraceback()
+            return get_lookup().get_template('500.mako').render_unicode(*args, **kwargs)
 
 class BaseHandler(RequestHandler):
     startTime = 0.
@@ -181,7 +190,8 @@ class BaseHandler(RequestHandler):
                 url = url[len(sickbeard.WEB_ROOT) + 1:]
 
             if url[:3] != 'api':
-                return self.redirect('/')
+                t = PageTemplate(rh=self, filename="404.mako")
+                return self.finish(t.render(title='404', header='Oops'))
             else:
                 self.finish('Wrong API key used')
 
@@ -802,6 +812,15 @@ class Home(WebRoot):
         else:
             return "Problem sending SMS: " + message
 
+    @staticmethod
+    def testTelegram(telegram_id=None, telegram_apikey=None):
+
+        result, message = notifiers.telegram_notifier.test_notify(telegram_id, telegram_apikey)
+        if result:
+            return "Telegram notification succeeded. Check your Telegram clients to make sure it worked"
+        else:
+            return "Error sending Telegram notification: " + message
+
     @staticmethod
     def testGrowl(host=None, password=None):
         # self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@@ -1211,9 +1230,11 @@ class Home(WebRoot):
             [showObj.indexerid]
         )
 
+        min_season = 0 if sickbeard.DISPLAY_SHOW_SPECIALS else 1
+
         sqlResults = myDB.select(
-            "SELECT * FROM tv_episodes WHERE showid = ? ORDER BY season DESC, episode DESC",
-            [showObj.indexerid]
+            "SELECT * FROM tv_episodes WHERE showid = ? and season >= ? ORDER BY season DESC, episode DESC",
+            [showObj.indexerid, min_season]
         )
 
         t = PageTemplate(rh=self, filename="displayShow.mako")
@@ -4750,6 +4771,8 @@ class ConfigNotifications(Config):
                           growl_notify_onsubtitledownload=None, growl_host=None, growl_password=None,
                           use_freemobile=None, freemobile_notify_onsnatch=None, freemobile_notify_ondownload=None,
                           freemobile_notify_onsubtitledownload=None, freemobile_id=None, freemobile_apikey=None,
+                          use_telegram=None, telegram_notify_onsnatch=None, telegram_notify_ondownload=None,
+                          telegram_notify_onsubtitledownload=None, telegram_id=None, telegram_apikey=None,
                           use_prowl=None, prowl_notify_onsnatch=None, prowl_notify_ondownload=None,
                           prowl_notify_onsubtitledownload=None, prowl_api=None, prowl_priority=0,
                           prowl_show_list=None, prowl_show=None, prowl_message_title=None,
@@ -4831,6 +4854,13 @@ class ConfigNotifications(Config):
         sickbeard.FREEMOBILE_ID = freemobile_id
         sickbeard.FREEMOBILE_APIKEY = freemobile_apikey
 
+        sickbeard.USE_TELEGRAM = config.checkbox_to_value(use_telegram)
+        sickbeard.TELEGRAM_NOTIFY_ONSNATCH = config.checkbox_to_value(telegram_notify_onsnatch)
+        sickbeard.TELEGRAM_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(telegram_notify_ondownload)
+        sickbeard.TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = config.checkbox_to_value(telegram_notify_onsubtitledownload)
+        sickbeard.TELEGRAM_ID = telegram_id
+        sickbeard.TELEGRAM_APIKEY = telegram_apikey
+
         sickbeard.USE_PROWL = config.checkbox_to_value(use_prowl)
         sickbeard.PROWL_NOTIFY_ONSNATCH = config.checkbox_to_value(prowl_notify_onsnatch)
         sickbeard.PROWL_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(prowl_notify_ondownload)
@@ -5115,7 +5145,7 @@ class ErrorLogs(WebRoot):
                     logName = match.group(8)
                     if not sickbeard.DEBUG and (level == 'DEBUG' or level == 'DB'):
                         continue
-                    if level not in logger.reverseNames:
+                    if level not in logger.LOGGING_LEVELS:
                         lastLine = False
                         continue
 
@@ -5123,7 +5153,7 @@ class ErrorLogs(WebRoot):
                         lastLine = True
                         finalData.append(x)
                         numLines += 1
-                    elif not logSearch and logger.reverseNames[level] >= minLevel and (logFilter == '<NONE>' or logName.startswith(logFilter)):
+                    elif not logSearch and logger.LOGGING_LEVELS[level] >= minLevel and (logFilter == '<NONE>' or logName.startswith(logFilter)):
                         lastLine = True
                         finalData.append(x)
                         numLines += 1
@@ -5175,13 +5205,13 @@ class ErrorLogs(WebRoot):
 
         data = []
 
-        if ek(os.path.isfile, logger.logFile):
-            with io.open(logger.logFile, 'r', encoding='utf-8') as f:
+        if ek(os.path.isfile, logger.log_file):
+            with io.open(logger.log_file, 'r', encoding='utf-8') as f:
                 data = Get_Data(minLevel, f.readlines(), 0, regex, logFilter, logSearch, maxLines)
 
         for i in range(1, int(sickbeard.LOG_NR)):
-            if ek(os.path.isfile, logger.logFile + "." + str(i)) and (len(data) <= maxLines):
-                with io.open(logger.logFile + "." + str(i), 'r', encoding='utf-8') as f:
+            if ek(os.path.isfile, logger.log_file + "." + str(i)) and (len(data) <= maxLines):
+                with io.open(logger.log_file + "." + str(i), 'r', encoding='utf-8') as f:
                     data += Get_Data(minLevel, f.readlines(), len(data), regex, logFilter, logSearch, maxLines)
 
         return t.render(
diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py
index fcfa1ff7ff515c209c13cab3793e54dda54b2aeb..433fac267e5014f7783431f708116a9ec970cfb6 100644
--- a/sickbeard/webserveInit.py
+++ b/sickbeard/webserveInit.py
@@ -15,15 +15,15 @@ from tornado.ioloop import IOLoop
 from tornado.routes import route
 
 
-class SRWebServer(threading.Thread):
-    def __init__(self, options={}, io_loop=None):
+class SRWebServer(threading.Thread):  # pylint: disable=too-many-instance-attributes
+    def __init__(self, options=None, io_loop=None):
         threading.Thread.__init__(self)
         self.daemon = True
         self.alive = True
         self.name = "TORNADO"
         self.io_loop = io_loop or IOLoop.current()
 
-        self.options = options
+        self.options = options or {}
         self.options.setdefault('port', 8081)
         self.options.setdefault('host', '0.0.0.0')
         self.options.setdefault('log_dir', None)
@@ -33,6 +33,8 @@ class SRWebServer(threading.Thread):
         assert isinstance(self.options['port'], int)
         assert 'data_root' in self.options
 
+        self.server = None
+
         # video root
         if sickbeard.ROOT_DIRS:
             root_dirs = sickbeard.ROOT_DIRS.split('|')
@@ -94,14 +96,12 @@ class SRWebServer(threading.Thread):
             (r'%s/login(/?)' % self.options['web_root'], LoginHandler),
             (r'%s/logout(/?)' % self.options['web_root'], LogoutHandler),
 
+            # Web calendar handler (Needed because option Unprotected calendar)
+            (r'%s/calendar' % self.options['web_root'], CalendarHandler),
+
             # webui handlers
         ] + route.get_routes(self.options['web_root']))
 
-        # Web calendar handler (Needed because option Unprotected calendar)
-        self.app.add_handlers('.*$', [
-            (r'%s/calendar' % self.options['web_root'], CalendarHandler),
-        ])
-
         # Static File Handlers
         self.app.add_handlers(".*$", [
             # favicon
@@ -124,9 +124,14 @@ class SRWebServer(threading.Thread):
             (r'%s/js/(.*)' % self.options['web_root'], StaticFileHandler,
              {"path": ek(os.path.join, self.options['data_root'], 'js')}),
 
+            # fonts
+            (r'%s/fonts/(.*)' % self.options['web_root'], StaticFileHandler,
+             {"path": ek(os.path.join, self.options['data_root'], 'fonts')}),
+
             # videos
-        ] + [(r'%s/videos/(.*)' % self.options['web_root'], StaticFileHandler,
-              {"path": self.video_root})])
+            (r'%s/videos/(.*)' % self.options['web_root'], StaticFileHandler,
+             {"path": self.video_root})
+        ])
 
     def run(self):
         if self.enable_https:
@@ -141,12 +146,12 @@ class SRWebServer(threading.Thread):
 
         try:
             self.server.listen(self.options['port'], self.options['host'])
-        except:
+        except Exception:
             if sickbeard.LAUNCH_BROWSER and not self.daemon:
                 sickbeard.launchBrowser('https' if sickbeard.ENABLE_HTTPS else 'http', self.options['port'], sickbeard.WEB_ROOT)
                 logger.log(u"Launching browser and exiting")
             logger.log(u"Could not start webserver on port %s, already in use!" % self.options['port'])
-            os._exit(1)
+            os._exit(1)  # pylint: disable=protected-access
 
         try:
             self.io_loop.start()
diff --git a/sickrage/helper/common.py b/sickrage/helper/common.py
index 5fad42bfd4a434c039076ea04a5d31e225c1d0a0..5def83b5184e37189827b7446f9899b0892b48ff 100644
--- a/sickrage/helper/common.py
+++ b/sickrage/helper/common.py
@@ -11,11 +11,13 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import unicode_literals
 
 import re
 import sickbeard
@@ -90,13 +92,13 @@ http_status_code = {
     509: 'Bandwidth Limit Exceeded',
     510: 'Not Extended',
     511: 'Network Authentication Required',
-    520: 'Cloudfare - Web server is returning an unknown error',
-    521: 'Cloudfare - Web server is down',
-    522: 'Cloudfare - Connection timed out',
-    523: 'Cloudfare - Origin is unreachable',
-    524: 'Cloudfare - A timeout occurred',
-    525: 'Cloudfare - SSL handshake failed',
-    526: 'Cloudfare - Invalid SSL certificate',
+    520: 'CloudFlare - Web server is returning an unknown error',
+    521: 'CloudFlare - Web server is down',
+    522: 'CloudFlare - Connection timed out',
+    523: 'CloudFlare - Origin is unreachable',
+    524: 'CloudFlare - A timeout occurred',
+    525: 'CloudFlare - SSL handshake failed',
+    526: 'CloudFlare - Invalid SSL certificate',
     598: 'Network read timeout error',
     599: 'Network connect timeout error',
 }
@@ -124,7 +126,7 @@ def http_code_description(http_code):
         return description
 
     # TODO Restore logger import
-    # logger.log(u'Unknown HTTP status code %s. Please submit an issue' % http_code, logger.ERROR)
+    # logger.log('Unknown HTTP status code %s. Please submit an issue' % http_code, logger.ERROR)
 
     return None
 
@@ -157,10 +159,15 @@ def is_torrent_or_nzb_file(filename):
     return filename.rpartition('.')[2].lower() in ['nzb', 'torrent']
 
 
-def pretty_file_size(size):
+def pretty_file_size(size, use_decimal=False, **kwargs):
     """
     Return a human readable representation of the provided ``size``.
+
     :param size: The size to convert
+    :param use_decimal: use decimal instead of binary prefixes (e.g. kilo = 1000 instead of 1024)
+
+    :keyword units: A list of unit names in ascending order. Default units: ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
+
     :return: The converted size
     """
     try:
@@ -169,13 +176,68 @@ def pretty_file_size(size):
         size = 0.
 
     remaining_size = size
-    for unit in ['B', 'KB', 'MB', 'GB', 'TB', 'PB']:
-        if remaining_size < 1024.:
+    units = kwargs.pop('units', ['B', 'KB', 'MB', 'GB', 'TB', 'PB'])
+    block = 1024. if not use_decimal else 1000.
+    for unit in units:
+        if remaining_size < block:
             return '%3.2f %s' % (remaining_size, unit)
-        remaining_size /= 1024.
+        remaining_size /= block
     return size
 
 
+def convert_size(size, default=None, use_decimal=False, **kwargs):
+    """
+    Convert a file size into the number of bytes
+
+    :param size: to be converted
+    :param default: value to return if conversion fails
+    :param use_decimal: use decimal instead of binary prefixes (e.g. kilo = 1000 instead of 1024)
+
+    :keyword sep: Separator between size and units, default is space
+    :keyword units: A list of (uppercase) unit names in ascending order. Default units: ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
+    :keyword default_units: Default unit if none is given, default is lowest unit in the scale, e.g. bytes
+
+    :returns: the number of bytes, the default value, or 0
+    """
+    result = None
+
+    try:
+        sep = kwargs.pop('sep', ' ')
+        scale = kwargs.pop('units', ['B', 'KB', 'MB', 'GB', 'TB', 'PB'])
+        default_units = kwargs.pop('default_units', scale[0])
+
+        if sep:
+            size_tuple = size.strip().split(sep)
+            scalar, units = size_tuple[0], size_tuple[1:]
+            units = units[0].upper() if units else default_units
+        else:
+            regex_units = re.search(r'(\w+)', size, re.IGNORECASE)
+            units = regex_units.group() if regex_units else default_units
+            scalar = size.strip(units)
+
+        scalar = float(scalar)
+        scalar *= (1024 if not use_decimal else 1000) ** scale.index(units)
+
+        result = scalar
+
+    # TODO: Make sure fallback methods obey default units
+    except AttributeError:
+        result = size if size is not None else default
+
+    except ValueError:
+        result = default
+
+    finally:
+        try:
+            if result != default:
+                result = long(result)
+                result = max(result, 0)
+        except (TypeError, ValueError):
+            pass
+
+    return result
+
+
 def remove_extension(filename):
     """
     Remove the extension of the provided ``filename``.
@@ -220,7 +282,7 @@ def sanitize_filename(filename):
     if isinstance(filename, (str, unicode)):
         filename = re.sub(r'[\\/\*]', '-', filename)
         filename = re.sub(r'[:"<>|?]', '', filename)
-        filename = re.sub(ur'\u2122', '', filename)  # Trade Mark Sign
+        filename = re.sub(r'™', '', filename)  # Trade Mark Sign unicode: \u2122
         filename = filename.strip(' .')
 
         return filename
@@ -238,5 +300,5 @@ def try_int(candidate, default_value=0):
 
     try:
         return int(candidate)
-    except Exception:
+    except (ValueError, TypeError):
         return default_value
diff --git a/sickrage/helper/encoding.py b/sickrage/helper/encoding.py
index e199b3d61157ff9873c4e5b77643c73bad34ee52..97dbde1d56df43cd663cfbeb79242f9b2378d3f9 100644
--- a/sickrage/helper/encoding.py
+++ b/sickrage/helper/encoding.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/helper/exceptions.py b/sickrage/helper/exceptions.py
index 560e27af7ad1c8a4e425bcf7d2e559bf3e08928b..a6b1026c9b68fe3a89ad73bcb05fd4886372b244 100644
--- a/sickrage/helper/exceptions.py
+++ b/sickrage/helper/exceptions.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickrage.helper.encoding import ss
 
diff --git a/sickrage/helper/quality.py b/sickrage/helper/quality.py
index 85002db566f4370486d61ab821da6faa6c4bac08..49b1fce186801b7babf2632988162bd93c10835e 100644
--- a/sickrage/helper/quality.py
+++ b/sickrage/helper/quality.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard.common import Quality, qualityPresetStrings
 
diff --git a/sickrage/media/GenericMedia.py b/sickrage/media/GenericMedia.py
index b3d56e2ac7fb11a70ae4a8c0563f59843c74dbf1..955c30c2d0b950a51cb371bb6eaabe8581a27f61 100644
--- a/sickrage/media/GenericMedia.py
+++ b/sickrage/media/GenericMedia.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/media/ShowBanner.py b/sickrage/media/ShowBanner.py
index ac0427514819bc73046a1d8b3cb281065f91a80e..fccf7d888e454dec12d314401b94adc4c0bb0115 100644
--- a/sickrage/media/ShowBanner.py
+++ b/sickrage/media/ShowBanner.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard.image_cache import ImageCache
 from sickrage.media.GenericMedia import GenericMedia
diff --git a/sickrage/media/ShowFanArt.py b/sickrage/media/ShowFanArt.py
index 36e0b1cc5ab68db5304b42f1b9850e4908c3ca17..4376f1ddd49e3fb59965f2196b5e223739fd798d 100644
--- a/sickrage/media/ShowFanArt.py
+++ b/sickrage/media/ShowFanArt.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard.image_cache import ImageCache
 from sickrage.media.GenericMedia import GenericMedia
diff --git a/sickrage/media/ShowNetworkLogo.py b/sickrage/media/ShowNetworkLogo.py
index 59910b32051f5ec8a02ee24e686a4e460fd7d7ac..58034e2dd1251cefc8fd50da44981b99bbaf3891 100644
--- a/sickrage/media/ShowNetworkLogo.py
+++ b/sickrage/media/ShowNetworkLogo.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from os.path import join
 from sickrage.helper.encoding import ek
diff --git a/sickrage/media/ShowPoster.py b/sickrage/media/ShowPoster.py
index 86629649140b0760616a47e83577cecffc61da07..2b6b01c9e0ae9fe6a3ad7c085d29a8f81c527de6 100644
--- a/sickrage/media/ShowPoster.py
+++ b/sickrage/media/ShowPoster.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from sickbeard.image_cache import ImageCache
 from sickrage.media.GenericMedia import GenericMedia
diff --git a/sickrage/providers/GenericProvider.py b/sickrage/providers/GenericProvider.py
index 669b51398c1e4bab159945f6948469e559f9e148..f8bba141cb3caf84501fb737b32e2fc0df2c82b6 100644
--- a/sickrage/providers/GenericProvider.py
+++ b/sickrage/providers/GenericProvider.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import sickbeard
diff --git a/sickrage/providers/nzb/NZBProvider.py b/sickrage/providers/nzb/NZBProvider.py
index 89d3f15d0942bd08df69eab1345f4d9300428290..3a7a6dcf2251b4fae2c71804432743cf7f46c1c8 100644
--- a/sickrage/providers/nzb/NZBProvider.py
+++ b/sickrage/providers/nzb/NZBProvider.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/providers/torrent/TorrentProvider.py b/sickrage/providers/torrent/TorrentProvider.py
index e0b91945b7076427d7c201d006713306c57ea699..51b03fd2c69eb901d0e52ae2d2271d842e68ec50 100644
--- a/sickrage/providers/torrent/TorrentProvider.py
+++ b/sickrage/providers/torrent/TorrentProvider.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/show/ComingEpisodes.py b/sickrage/show/ComingEpisodes.py
index 976fc780467324b361c9d79230b4ef89213546f6..e19511f8c265a5b90eed4e49b222d990d6030a36 100644
--- a/sickrage/show/ComingEpisodes.py
+++ b/sickrage/show/ComingEpisodes.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/show/History.py b/sickrage/show/History.py
index 35a372f848dc3fecd27d77ba8d54eb9f597b0264..4d9099a2497ccc582cfc827854faf114354bcb2c 100644
--- a/sickrage/show/History.py
+++ b/sickrage/show/History.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 from datetime import datetime
 from datetime import timedelta
diff --git a/sickrage/show/Show.py b/sickrage/show/Show.py
index 034269475e28baad0a74c26e098bca4c1d74ca22..2e66067d4967931a537f50189b15e17c4b55f5cd 100644
--- a/sickrage/show/Show.py
+++ b/sickrage/show/Show.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/system/Restart.py b/sickrage/system/Restart.py
index 48056638b228c68dc1f696590accf150afff7e13..399e909535fd64f79dc4533ffef34d2b2ccbc6a7 100644
--- a/sickrage/system/Restart.py
+++ b/sickrage/system/Restart.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/sickrage/system/Shutdown.py b/sickrage/system/Shutdown.py
index ca4501eb3d244e6cfe6a75ab30a2e8cdddf3bcb1..813bea5a582daf4b494948baa3b29aa124fa9b81 100644
--- a/sickrage/system/Shutdown.py
+++ b/sickrage/system/Shutdown.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 import sickbeard
 
diff --git a/tests/all_tests.py b/tests/all_tests.py
index 47aea896f0f49e69e44dfb3cf51770a417364551..b0d4312dda2aaa0eaa2df78ea64e327d2bd7917c 100755
--- a/tests/all_tests.py
+++ b/tests/all_tests.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Perform all tests in tests/
diff --git a/tests/db_tests.py b/tests/db_tests.py
index 6088dc342ed987a1c75f344b353a5267c80aa02c..0c0ce59bd7731235de925cd82c336cde3d3b41ba 100644
--- a/tests/db_tests.py
+++ b/tests/db_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test show database functionality.
diff --git a/tests/helpers_tests.py b/tests/helpers_tests.py
index 1ec1cb4605e726317f0c03b068c1dc6b1846f8a0..bc997e2e029dcbd415dd4a64f11ead79028b422a 100755
--- a/tests/helpers_tests.py
+++ b/tests/helpers_tests.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test sickbeard.helpers
diff --git a/tests/issue_submitter_tests.py b/tests/issue_submitter_tests.py
index c929ee284587eae0e1d75a51c9cfacbeff794631..283584d8c8ed44c799bdc5a068160702e1258d05 100644
--- a/tests/issue_submitter_tests.py
+++ b/tests/issue_submitter_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test exception logging
diff --git a/tests/notifier_tests.py b/tests/notifier_tests.py
index 6b4decb3b3f80340575fe39e8d8125f83d94cc66..5a176f13fbb7bf564c7cdec6e8cc8a192b362349 100644
--- a/tests/notifier_tests.py
+++ b/tests/notifier_tests.py
@@ -10,11 +10,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
 
diff --git a/tests/pp_tests.py b/tests/pp_tests.py
index 30ecdc4750928f9d253f526fca0e0708a17aac96..f5cadaca0505797b94af536698486e093835e0bd 100644
--- a/tests/pp_tests.py
+++ b/tests/pp_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test post processing
diff --git a/tests/scene_helpers_tests.py b/tests/scene_helpers_tests.py
index 9241c69fa22de4eb087c89b0370173a40decd4bd..4a357fa7fad86c0cbdfd8739b8347ef8fbe4665d 100644
--- a/tests/scene_helpers_tests.py
+++ b/tests/scene_helpers_tests.py
@@ -21,21 +21,6 @@ class SceneTests(test.SickbeardTestDBCase):
     """
     Test Scene
     """
-    def _test_scene_to_norm_show_name(self, name, expected):
-        """
-        Test scene to normal show names
-
-        :param name:
-        :param expected:
-        :return:
-        """
-        result = show_name_helpers.sceneToNormalShowNames(name)
-        self.assertTrue(len(set(expected).intersection(set(result))) == len(expected))
-
-        dot_result = show_name_helpers.sceneToNormalShowNames(name.replace(' ', '.'))
-        dot_expected = [x.replace(' ', '.') for x in expected]
-        self.assertTrue(len(set(dot_expected).intersection(set(dot_result))) == len(dot_expected))
-
     def _test_all_possible_show_names(self, name, indexerid=0, expected=None):
         """
         Test all possible show names
@@ -63,51 +48,6 @@ class SceneTests(test.SickbeardTestDBCase):
         result = show_name_helpers.filterBadReleases(name)
         self.assertEqual(result, expected)
 
-    def _test_is_good_name(self, name, show):
-        """
-        Test if name is good
-
-        :param name:
-        :param show:
-        :return:
-        """
-        self.assertTrue(show_name_helpers.isGoodResult(name, show))
-
-    def test_is_good_name(self):
-        """
-        Perform good name tests
-        """
-        list_of_cases = [('Show.Name.S01E02.Test-Test', 'Show/Name'),
-                         ('Show.Name.S01E02.Test-Test', 'Show. Name'),
-                         ('Show.Name.S01E02.Test-Test', 'Show- Name'),
-                         ('Show.Name.Part.IV.Test-Test', 'Show Name'),
-                         ('Show.Name.S01.Test-Test', 'Show Name'),
-                         ('Show.Name.E02.Test-Test', 'Show: Name'),
-                         ('Show Name Season 2 Test', 'Show: Name'), ]
-
-        for test_case in list_of_cases:
-            scene_name, show_name = test_case
-            show = Show(1, 0)
-            show.name = show_name
-            self._test_is_good_name(scene_name, show)
-
-    def test_scene_to_norm_show_names(self):
-        """
-        Test scene to normal show names
-        """
-        self._test_scene_to_norm_show_name('Show Name 2010', ['Show Name 2010', 'Show Name (2010)'])
-        self._test_scene_to_norm_show_name('Show Name US', ['Show Name US', 'Show Name (US)'])
-        self._test_scene_to_norm_show_name('Show Name AU', ['Show Name AU', 'Show Name (AU)'])
-        self._test_scene_to_norm_show_name('Show Name CA', ['Show Name CA', 'Show Name (CA)'])
-        self._test_scene_to_norm_show_name('Show and Name', ['Show and Name', 'Show & Name'])
-        self._test_scene_to_norm_show_name('Show and Name 2010', ['Show and Name 2010', 'Show & Name 2010', 'Show and Name (2010)', 'Show & Name (2010)'])
-        self._test_scene_to_norm_show_name('show name us', ['show name us', 'show name (us)'])
-        self._test_scene_to_norm_show_name('Show And Name', ['Show And Name', 'Show & Name'])
-
-        # failure cases
-        self._test_scene_to_norm_show_name('Show Name 90210', ['Show Name 90210'])
-        self._test_scene_to_norm_show_name('Show Name YA', ['Show Name YA'])
-
     def test_all_possible_show_names(self):
         """
         Test all possible show names
diff --git a/tests/search_tests.py b/tests/search_tests.py
index 326a4f2f2388c010eeba5bbbf16b26c17c2d5003..3a50d95d209589130fe88526e14f731bb4dc4ca9 100644
--- a/tests/search_tests.py
+++ b/tests/search_tests.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # pylint: disable=line-too-long
 
@@ -64,7 +64,7 @@ def test_generator(cur_data, cur_name, cur_provider):
     :return:
     """
 
-    def do_test():
+    def do_test(self):
         """
         Test to perform
         """
diff --git a/tests/sickrage_tests/__init__.py b/tests/sickrage_tests/__init__.py
index a504b8b1db037eb7bf86e88cc8aa2ef29110a251..b873eb3c1037554b77c80aaeacad9cf84b10a041 100644
--- a/tests/sickrage_tests/__init__.py
+++ b/tests/sickrage_tests/__init__.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Tests for SickRage
diff --git a/tests/sickrage_tests/helper/common_tests.py b/tests/sickrage_tests/helper/common_tests.py
index 766084ea5404d297b8d1bd9a4ca5d30112cdb0db..ffdd05bb873746af82379ae09b703a7143cfdcb9 100644
--- a/tests/sickrage_tests/helper/common_tests.py
+++ b/tests/sickrage_tests/helper/common_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # pylint: disable=line-too-long
 
@@ -34,7 +34,7 @@ sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), '../.
 
 import sickbeard
 from sickrage.helper.common import http_code_description, is_sync_file, is_torrent_or_nzb_file, pretty_file_size
-from sickrage.helper.common import remove_extension, replace_extension, sanitize_filename, try_int
+from sickrage.helper.common import remove_extension, replace_extension, sanitize_filename, try_int, convert_size
 
 
 class CommonTests(unittest.TestCase):
@@ -397,6 +397,47 @@ class CommonTests(unittest.TestCase):
             for (candidate, result) in test.iteritems():
                 self.assertEqual(try_int(candidate, default_value), result)
 
+    def test_convert_size(self):
+        # converts pretty file sizes to integers
+        self.assertEqual(convert_size('1 B'), 1)
+        self.assertEqual(convert_size('1 KB'), 1024)
+        self.assertEqual(convert_size('1 kb', use_decimal=True), 1000)  # can use decimal units (e.g. KB = 1000 bytes instead of 1024)
+
+        # returns integer sizes for integers
+        self.assertEqual(convert_size(0, -1), 0)
+        self.assertEqual(convert_size(100, -1), 100)
+        self.assertEqual(convert_size(1.312, -1), 1)  # returns integer sizes for floats too
+
+        # without a default value, failures return None
+        self.assertEqual(convert_size('pancakes'), None)
+
+        # default value can be anything
+        self.assertEqual(convert_size(None, -1), -1)
+        self.assertEqual(convert_size('', 3.14), 3.14)
+        self.assertEqual(convert_size('elephant', 'frog'), 'frog')
+
+        # negative sizes return 0
+        self.assertEqual(convert_size(-1024, -1), 0)
+        self.assertEqual(convert_size('-1 GB', -1), 0)
+
+        # can also use `or` for a default value
+        self.assertEqual(convert_size(None) or 100, 100)
+        self.assertEqual(convert_size(None) or 1.61803, 1.61803)  # default doesn't have to be integer
+        self.assertEqual(convert_size(None) or '100', '100')  # default doesn't have to be numeric either
+        self.assertEqual(convert_size('-1 GB') or -1, -1)  # can use `or` to provide a default when size evaluates to 0
+
+        # can use custom dictionary to support internationalization
+        french = ['O', 'KO', 'MO', 'GO', 'TO', 'PO']
+        self.assertEqual(convert_size('1 o', units=french), 1)
+        self.assertEqual(convert_size('1 go', use_decimal=True, units=french), 1000000000)
+        self.assertEqual(convert_size('1 o'), None)  # Wrong units so result is None
+
+        # custom units need to be uppercase or they won't match
+        oops = ['b', 'kb', 'Mb', 'Gb', 'tB', 'Pb']
+        self.assertEqual(convert_size('1 b', units=oops), None)
+        self.assertEqual(convert_size('1 B', units=oops), None)
+        self.assertEqual(convert_size('1 Mb', units=oops), None)
+        self.assertEqual(convert_size('1 MB', units=oops), None)
 
 if __name__ == '__main__':
     print('=====> Testing %s' % __file__)
diff --git a/tests/sickrage_tests/helper/quality_tests.py b/tests/sickrage_tests/helper/quality_tests.py
index be0021fadabd078fac6f21b8a46a0a1af93a5278..9c802fa4a4196e2d1fa6617802ace55468fd2961 100644
--- a/tests/sickrage_tests/helper/quality_tests.py
+++ b/tests/sickrage_tests/helper/quality_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test qualities
diff --git a/tests/sickrage_tests/media/generic_media_tests.py b/tests/sickrage_tests/media/generic_media_tests.py
index b7079bd67a40223ff19565d22dc11c548c50350b..124691bc40b55955af59e5beb835faeeb1b2b955 100644
--- a/tests/sickrage_tests/media/generic_media_tests.py
+++ b/tests/sickrage_tests/media/generic_media_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test GenericMedia
diff --git a/tests/sickrage_tests/media/show_banner_tests.py b/tests/sickrage_tests/media/show_banner_tests.py
index 68233b51e015edd236746bfbfba8f2d920739f70..f61379eb1dc9323e753f48c9512feda5e3b225c5 100644
--- a/tests/sickrage_tests/media/show_banner_tests.py
+++ b/tests/sickrage_tests/media/show_banner_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test ShowBanner
diff --git a/tests/sickrage_tests/media/show_fan_art_tests.py b/tests/sickrage_tests/media/show_fan_art_tests.py
index 6e5be0582097ab9f9a9711894ceedd86d0e2053c..e82e9250a2fac5d28804b0a995451c9f73b467ba 100644
--- a/tests/sickrage_tests/media/show_fan_art_tests.py
+++ b/tests/sickrage_tests/media/show_fan_art_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test ShowFanArt
diff --git a/tests/sickrage_tests/media/show_network_logo_tests.py b/tests/sickrage_tests/media/show_network_logo_tests.py
index 3bce111d5b77f3c18c1e3b0595512f68bcfe712f..a98b7e5fa57871f073ae1e4b6b24b16631fd4de5 100644
--- a/tests/sickrage_tests/media/show_network_logo_tests.py
+++ b/tests/sickrage_tests/media/show_network_logo_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test ShowNetworkLogo
diff --git a/tests/sickrage_tests/media/show_poster_tests.py b/tests/sickrage_tests/media/show_poster_tests.py
index 16a8a8bc21eb7e2d24760c5d7a1603d9496f56d7..248b5e135b8af88279cee0f38101786cf59d191b 100644
--- a/tests/sickrage_tests/media/show_poster_tests.py
+++ b/tests/sickrage_tests/media/show_poster_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test ShowPoster
diff --git a/tests/sickrage_tests/providers/generic_provider_tests.py b/tests/sickrage_tests/providers/generic_provider_tests.py
index 335491dad6e396b753e2c53868921124318dac42..cfb078a21930e6d11d850827419e4c9965322656 100644
--- a/tests/sickrage_tests/providers/generic_provider_tests.py
+++ b/tests/sickrage_tests/providers/generic_provider_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test GenericProvider
diff --git a/tests/sickrage_tests/providers/nzb_provider_tests.py b/tests/sickrage_tests/providers/nzb_provider_tests.py
index 2cafcdb54e953595d2aade8dba02633fdc3a31cc..d11064459f95c20eefb8b7754fa64c426d208512 100644
--- a/tests/sickrage_tests/providers/nzb_provider_tests.py
+++ b/tests/sickrage_tests/providers/nzb_provider_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test NZBProvider
diff --git a/tests/sickrage_tests/providers/torrent_provider_tests.py b/tests/sickrage_tests/providers/torrent_provider_tests.py
index 48e772144d168a288cf9f2e7e3ea4eb543845bf1..83e77c7fbafacd6d59638730d4617fa98ae57457 100644
--- a/tests/sickrage_tests/providers/torrent_provider_tests.py
+++ b/tests/sickrage_tests/providers/torrent_provider_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test TorrentProvider
diff --git a/tests/sickrage_tests/show/coming_episodes_tests.py b/tests/sickrage_tests/show/coming_episodes_tests.py
index 387f90839a1c9b6b65ee36a5594a8ced99ea5a3b..b24a33f3eaa0ac109fc3af297e7ab4f82e377ab2 100644
--- a/tests/sickrage_tests/show/coming_episodes_tests.py
+++ b/tests/sickrage_tests/show/coming_episodes_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test coming episodes
diff --git a/tests/sickrage_tests/show/history_tests.py b/tests/sickrage_tests/show/history_tests.py
index 74aac381b2ffbfe2398e934325d66549d383bb41..a671a5f11006bbc3d8b3f6dc7e75eca741b0a9e6 100644
--- a/tests/sickrage_tests/show/history_tests.py
+++ b/tests/sickrage_tests/show/history_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test history
diff --git a/tests/sickrage_tests/show/show_tests.py b/tests/sickrage_tests/show/show_tests.py
index f28ec0c6b71a3d9297166abb8dcee4bfcd571b81..ff353a3f639068fbfb50ea0edd6e2a53a9ad8062 100644
--- a/tests/sickrage_tests/show/show_tests.py
+++ b/tests/sickrage_tests/show/show_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test shows
diff --git a/tests/sickrage_tests/system/restart_tests.py b/tests/sickrage_tests/system/restart_tests.py
index e0b6b6c47cf4e80a0c1ebf8824d7d73d250dfe29..fdfe6f17523fc9b84b90d20b22cb14caede90c45 100644
--- a/tests/sickrage_tests/system/restart_tests.py
+++ b/tests/sickrage_tests/system/restart_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test restart
diff --git a/tests/sickrage_tests/system/shutdown_tests.py b/tests/sickrage_tests/system/shutdown_tests.py
index 7b425c0d4669104fe86c66de23018064f4b721d7..7ee0b294d57a78099cac27ea5c3c8429b3461615 100644
--- a/tests/sickrage_tests/system/shutdown_tests.py
+++ b/tests/sickrage_tests/system/shutdown_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test shutdown
diff --git a/tests/snatch_tests.py b/tests/snatch_tests.py
index c629f5f66bbf614b432a13d273a1c44d4ae0dd0e..fdab792bd99ce56c5320f41e4903c34f299d0a52 100644
--- a/tests/snatch_tests.py
+++ b/tests/snatch_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # pylint: disable=line-too-long
 
diff --git a/tests/ssl_sni_tests.py b/tests/ssl_sni_tests.py
index f69618501ac8d39b9ade1ba47a5e8b34e879be11..d60ff29f0c17edbc75d5667ecb5fc0e786678a29 100644
--- a/tests/ssl_sni_tests.py
+++ b/tests/ssl_sni_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # pylint: disable=line-too-long
 
diff --git a/tests/test_lib.py b/tests/test_lib.py
index a3381ae84e23f85e5f5b1767d8df1868d8f4b49d..7e8a7545726bc3b1d8b72bebdfc90295ad2ef92b 100644
--- a/tests/test_lib.py
+++ b/tests/test_lib.py
@@ -12,11 +12,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 # pylint: disable=line-too-long
 
@@ -126,14 +126,14 @@ sickbeard.GIT_USERNAME = sickbeard.config.check_setting_str(sickbeard.CFG, 'Gene
 sickbeard.GIT_PASSWORD = sickbeard.config.check_setting_str(sickbeard.CFG, 'General', 'git_password', '', censor_log=True)
 
 sickbeard.LOG_DIR = os.path.join(TEST_DIR, 'Logs')
-sickbeard.logger.logFile = os.path.join(sickbeard.LOG_DIR, 'test_sickbeard.log')
+sickbeard.logger.log_file = os.path.join(sickbeard.LOG_DIR, 'test_sickbeard.log')
 create_test_log_folder()
 
 sickbeard.CACHE_DIR = os.path.join(TEST_DIR, 'cache')
 create_test_cache_folder()
 
 # pylint: disable=no-member
-sickbeard.logger.initLogging(False, True)
+sickbeard.logger.init_logging(False, True)
 
 
 # =================
diff --git a/tests/torrent_tests.py b/tests/torrent_tests.py
index 665be92ed4083a3243507f76984a4f4a31475804..3f3974205ae0cc91de0c8ae4fe086deb2fe1ae4a 100644
--- a/tests/torrent_tests.py
+++ b/tests/torrent_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test torrents
diff --git a/tests/tv_tests.py b/tests/tv_tests.py
index 1b02e70940040affdf6db4977df94336d4a78a01..c76cb96af429dc59b96d7b5d7f5e04abfeebb80e 100644
--- a/tests/tv_tests.py
+++ b/tests/tv_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test tv
diff --git a/tests/xem_tests.py b/tests/xem_tests.py
index 4341c6625bf49cbedf285643a8e0028e03c13b9c..a9e5596c669bf53c5c841d2d8bee8e104e238d99 100644
--- a/tests/xem_tests.py
+++ b/tests/xem_tests.py
@@ -11,11 +11,11 @@
 #
 # 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
+# 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 <http://www.gnu.org/licenses/>.
+# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
 
 """
 Test XEM