diff --git a/autoProcessTV/autoProcessTV.py b/autoProcessTV/autoProcessTV.py
index 5d2c817c8a58ec8c616c9b7b8ab7ed824a49717e..25630b213c2e4fa89689a438254fc9892a0eb15b 100755
--- a/autoProcessTV/autoProcessTV.py
+++ b/autoProcessTV/autoProcessTV.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2.7
 
 # Author: Nic Wolfe <nic@wolfeden.ca>
 # URL: http://code.google.com/p/sickbeard/
@@ -7,7 +7,7 @@
 # DEPRECATION NOTICE: autoProcessTV is deprecated and will be removed
 # from SickRage at 31-10-2015.
 #
-# Please switch to nzbToMedia from Clinton Hall, which is included in 
+# Please switch to nzbToMedia from Clinton Hall, which is included in
 # the contrib folder
 #
 # SickRage is free software: you can redistribute it and/or modify
diff --git a/autoProcessTV/hellaToSickBeard.py b/autoProcessTV/hellaToSickBeard.py
index b57ddef1cdaedc1c1ca45399b9d7995d61f34d98..333ff63cd7397635a1299c6e7ef23730ec6aa54a 100755
--- a/autoProcessTV/hellaToSickBeard.py
+++ b/autoProcessTV/hellaToSickBeard.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python2.7
 
 # Author: Nic Wolfe <nic@wolfeden.ca>
 # URL: http://code.google.com/p/sickbeard/
@@ -19,7 +19,7 @@
 # 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/>.
 
diff --git a/autoProcessTV/mediaToSickbeard.py b/autoProcessTV/mediaToSickbeard.py
index a24ffaf657a2561b0c20aa1c4627dc8d4b866e8c..21ff9b931251efb5d4b598a526b539cc741b8784 100755
--- a/autoProcessTV/mediaToSickbeard.py
+++ b/autoProcessTV/mediaToSickbeard.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python2.7
 # DEPRECATION NOTICE: autoProcessTV is deprecated and will be removed
 # from SickRage at 31-10-2015.
 #
@@ -61,16 +61,16 @@ def utorrent():
 
     dirName = sys.argv[1]
     nzbName = sys.argv[2]
-    
+
     return (dirName, nzbName)
-    
+
 def transmission():
-    
+
     dirName = os.getenv('TR_TORRENT_DIR')
     nzbName = os.getenv('TR_TORRENT_NAME')
-    
+
     return (dirName, nzbName)
-    
+
 def deluge():
 
     if len(sys.argv) < 4:
@@ -78,10 +78,10 @@ def deluge():
         print "No folder supplied - is this being called from Deluge?"
         time.sleep(3)
         sys.exit()
-    
+
     dirName = sys.argv[3]
     nzbName = sys.argv[2]
-    
+
     return (dirName, nzbName)
 
 def deluged() :
@@ -128,10 +128,10 @@ def blackhole():
 #        nzbName = sys.argv[2]
 #    else:
 #        dirName = sys.argv[1]
-#        
-#    return (dirName, nzbName)    
 #
-#def hella():        
+#    return (dirName, nzbName)
+#
+#def hella():
 #    if len(sys.argv) < 4:
 #        scriptlogger.error('No folder supplied - is this being called from HellaVCR?')
 #        print "No folder supplied - is this being called from HellaVCR?"
@@ -139,8 +139,8 @@ def blackhole():
 #    else:
 #        dirName = sys.argv[3]
 #        nzbName = sys.argv[2]
-#        
-#    return (dirName, nzbName)    
+#
+#    return (dirName, nzbName)
 
 def main():
     scriptlogger.info(u'Starting external PostProcess script ' + __file__)
@@ -156,28 +156,28 @@ def main():
         ssl = int(config.get("General", "enable_https"))
     except (ConfigParser.NoOptionError, ValueError):
         ssl = 0
-        
+
     try:
         web_root = config.get("General", "web_root")
     except ConfigParser.NoOptionError:
         web_root = ""
-    
+
     tv_dir = config.get("General", "tv_download_dir")
     use_torrents = int(config.get("General", "use_torrents"))
     torrent_method = config.get("General", "torrent_method")
-    
+
     if not use_torrents:
         scriptlogger.error(u'Enable Use Torrent on Sickbeard to use this Script. Aborting!')
         print u'Enable Use Torrent on Sickbeard to use this Script. Aborting!'
         time.sleep(3)
         sys.exit()
-        
+
     if not torrent_method in ['utorrent', 'transmission', 'deluge', 'deluged', 'blackhole']:
         scriptlogger.error(u'Unknown Torrent Method. Aborting!')
         print u'Unknown Torrent Method. Aborting!'
         time.sleep(3)
         sys.exit()
-    
+
     dirName, nzbName = eval(locals()['torrent_method'])()
 
     if dirName is None:
@@ -194,29 +194,29 @@ def main():
 
     if nzbName and os.path.isdir(os.path.join(dirName, nzbName)):
         dirName = os.path.join(dirName, nzbName)
-        
+
     params = {}
-        
+
     params['quiet'] = 1
-    
+
     params['dir'] = dirName
     if nzbName != None:
         params['nzbName'] = nzbName
-    
+
     if ssl:
         protocol = "https://"
     else:
         protocol = "http://"
-    
+
     if host == '0.0.0.0':
         host = 'localhost'
-    
+
     url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode"
     login_url = protocol + host + ":" + port + web_root + "/login"
-    
-    scriptlogger.debug("Opening URL: " + url + ' with params=' + str(params))   
+
+    scriptlogger.debug("Opening URL: " + url + ' with params=' + str(params))
     print "Opening URL: " + url + ' with params=' + str(params)
-    
+
     try:
         sess = requests.Session()
         sess.post(login_url, data={'username': username, 'password': password}, stream=True, verify=False)
@@ -225,18 +225,18 @@ def main():
         scriptlogger.error(u': Unknown exception raised when opening url: ' + str(e))
         time.sleep(3)
         sys.exit()
-    
+
     if response.status_code == 302:
         scriptlogger.error(u'Invalid Sickbeard Username or Password, check your config')
         print 'Invalid Sickbeard Username or Password, check your config'
         time.sleep(3)
         sys.exit()
-    
+
     if response.status_code == 200:
         scriptlogger.info(u'Script ' + __file__ + ' Succesfull')
         print 'Script ' + __file__ + ' Succesfull'
         time.sleep(3)
         sys.exit()
-        
+
 if __name__ == '__main__':
     main()
diff --git a/autoProcessTV/sabToSickBeard.py b/autoProcessTV/sabToSickBeard.py
index 6419bb9a56050b2e281bc0cc0c0382c36b8894bb..2fe414d8ba3fa11a0b29e517ec62aa8245d074cc 100755
--- a/autoProcessTV/sabToSickBeard.py
+++ b/autoProcessTV/sabToSickBeard.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python2.7
 
 # Author: Nic Wolfe <nic@wolfeden.ca>
 # URL: http://code.google.com/p/sickbeard/
@@ -19,7 +19,7 @@
 # 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/>.
 
diff --git a/contributing.md b/contributing.md
index 4ca2dc5ed4e75b5f418b9f03b94ff12c3a687a42..90ede8c6f461f6d9d144f1936275b05e5fb4c0af 100644
--- a/contributing.md
+++ b/contributing.md
@@ -51,14 +51,14 @@ Please follow these guidelines before reporting a bug:
 
 1. **Update to the latest version** &mdash; Check if you can reproduce the issue with the latest version from the `develop` branch.
 
-2. **Use the SickRage Forums search** &mdash; check if the issue has already been reported. If it has been, please comment on the existing issue.
+2. **Use the search on sickrage-issues** &mdash; check if the issue has already been reported. If it has been, please comment on the existing issue.
 
 3. **Provide a means to reproduce the problem** &mdash; Please provide as much details as possible, e.g. SickRage log files (obfuscate apikey/passwords), browser and operating system versions, how you started SickRage, and of course the steps to reproduce the problem. Bugs are always reported in the forums.
 
 
 ### Feature requests
-
-Please follow the bug guidelines above for feature requests, i.e. update to the latest version and search for existing issues before posting a new request. You can submit Feature Requests in the [SickRage Forum](http://sickrage.tv/) as well.
+Please follow the bug guidelines above for feature requests, i.e. update to the latest version and search for existing requests on [FeatHub](http://feathub.com/SiCKRAGETV/SickRage) before posting a new request..
+[![Feature Requests](https://cloud.githubusercontent.com/assets/390379/10127973/045b3a96-6560-11e5-9b20-31a2032956b2.png)](http://feathub.com/SiCKRAGETV/SickRage)
 
 ### Pull requests
 
@@ -102,7 +102,7 @@ Please follow this process; it's the best way to get your work included in the p
    # merge upstream changes
    git merge upstream/master
    ```
-   
+
 - Make sure that your develop branch is up to date:
 
    ```bash
@@ -131,4 +131,3 @@ Please follow this process; it's the best way to get your work included in the p
 
 - [Open a Pull Request](https://help.github.com/articles/using-pull-requests) with a
     clear title and description.
-
diff --git a/gui/slick/images/providers/extratorrent.png b/gui/slick/images/providers/extratorrent.png
new file mode 100644
index 0000000000000000000000000000000000000000..f0d5f822f8e178a031f3ebc1485d970a77e21199
Binary files /dev/null and b/gui/slick/images/providers/extratorrent.png differ
diff --git a/gui/slick/js/config.js b/gui/slick/js/config.js
deleted file mode 100644
index 7c852360b89e1f1ea408996f73d007bc5d69b81d..0000000000000000000000000000000000000000
--- a/gui/slick/js/config.js
+++ /dev/null
@@ -1,115 +0,0 @@
-$(document).ready(function(){
-    $(".enabler").each(function(){
-        if (!$(this).prop('checked')) $('#content_'+$(this).attr('id')).hide();
-    });
-
-    $(".enabler").click(function() {
-        if ($(this).prop('checked')){
-            $('#content_'+$(this).attr('id')).fadeIn("fast", "linear");
-        } else {
-            $('#content_'+$(this).attr('id')).fadeOut("fast", "linear");
-        }
-    });
-
-    $(".viewIf").click(function() {
-        if ($(this).prop('checked')) {
-            $('.hide_if_'+$(this).attr('id')).css('display','none');
-            $('.show_if_'+$(this).attr('id')).fadeIn("fast", "linear");
-        } else {
-            $('.show_if_'+$(this).attr('id')).css('display','none');
-            $('.hide_if_'+$(this).attr('id')).fadeIn("fast", "linear");
-        }
-    });
-
-    $(".datePresets").click(function() {
-        var def = $('#date_presets').val();
-        if ($(this).prop('checked') && '%x' == def) {
-            def = '%a, %b %d, %Y';
-            $('#date_use_system_default').html('1');
-        } else if (!$(this).prop('checked') && '1' == $('#date_use_system_default').html()){
-            def = '%x';
-        }
-
-        $('#date_presets').attr('name', 'date_preset_old');
-        $('#date_presets').attr('id', 'date_presets_old');
-
-        $('#date_presets_na').attr('name', 'date_preset');
-        $('#date_presets_na').attr('id', 'date_presets');
-
-        $('#date_presets_old').attr('name', 'date_preset_na');
-        $('#date_presets_old').attr('id', 'date_presets_na');
-
-        if (def) $('#date_presets').val(def);
-    });
-
-    // bind 'myForm' and provide a simple callback function
-    $('#configForm').ajaxForm({
-        beforeSubmit: function(){
-            $('.config_submitter .config_submitter_refresh').each(function(){
-                $(this).attr("disabled", "disabled");
-                $(this).after('<span><img src="' + srRoot + '/images/loading16' + themeSpinner + '.gif"> Saving...</span>');
-                $(this).hide();
-            });
-        },
-        success: function(){
-            setTimeout(function () {
-                "use strict";
-                config_success();
-            }, 2000);
-        }
-    });
-
-    $('#api_key').click(function(){
-        $('#api_key').select();
-    });
-
-    $("#generate_new_apikey").click(function(){
-        $.get(srRoot + '/config/general/generateApiKey',
-            function(data){
-                if (data.error !== undefined) {
-                    alert(data.error);
-                    return;
-                }
-                $('#api_key').val(data);
-        });
-    });
-
-    $('#branchCheckout').click(function() {
-        var url = srRoot+'/home/branchCheckout?branch='+$("#branchVersion").val();
-        var  checkDBversion = srRoot + "/home/getDBcompare";
-        $.getJSON(checkDBversion, function(data){
-            if (data.status == "success") {
-                if (data.message == "equal") {
-                    //Checkout Branch
-                    window.location.href = url;
-                }
-                if (data.message == "upgrade") {
-                    if ( confirm("Changing branch will upgrade your database.\nYou won't be able to downgrade afterward.\nDo you want to continue?") ) {
-                        //Checkout Branch
-                        window.location.href = url;
-                    }
-                }
-                if (data.message == "downgrade") {
-                    alert("Can't switch branch as this will result in a database downgrade.");
-                }
-            }
-        });
-    });
-
-});
-
-function config_success(){
-    $('.config_submitter').each(function(){
-        $(this).removeAttr("disabled");
-        $(this).next().remove();
-        $(this).show();
-    });
-    $('.config_submitter_refresh').each(function(){
-        $(this).removeAttr("disabled");
-        $(this).next().remove();
-        $(this).show();
-        url = srRoot+'/config/providers/';
-        window.location.href = url;
-    });
-    $('#email_show').trigger('notify');
-}
diff --git a/gui/slick/js/new/config_backuprestore.js b/gui/slick/js/new/config_backuprestore.js
index 774e7e39dda07a91c29487ea9768e0c3037fb740..143464c6165e53740b51b7875fa9510a5ba5590f 100644
--- a/gui/slick/js/new/config_backuprestore.js
+++ b/gui/slick/js/new/config_backuprestore.js
@@ -1,5 +1,119 @@
-$(document).load(function(){
+$(document).ready(function(){
     $('#backupDir').fileBrowser({ title: 'Select backup folder to save to', key: 'backupPath' });
     $('#backupFile').fileBrowser({ title: 'Select backup files to restore', key: 'backupFile', includeFiles: 1 });
     $('#config-components').tabs();
+    
+    $(".enabler").each(function(){
+        if (!$(this).prop('checked')) $('#content_'+$(this).attr('id')).hide();
+    });
+
+    $(".enabler").click(function() {
+        if ($(this).prop('checked')){
+            $('#content_'+$(this).attr('id')).fadeIn("fast", "linear");
+        } else {
+            $('#content_'+$(this).attr('id')).fadeOut("fast", "linear");
+        }
+    });
+
+    $(".viewIf").click(function() {
+        if ($(this).prop('checked')) {
+            $('.hide_if_'+$(this).attr('id')).css('display','none');
+            $('.show_if_'+$(this).attr('id')).fadeIn("fast", "linear");
+        } else {
+            $('.show_if_'+$(this).attr('id')).css('display','none');
+            $('.hide_if_'+$(this).attr('id')).fadeIn("fast", "linear");
+        }
+    });
+
+    $(".datePresets").click(function() {
+        var def = $('#date_presets').val();
+        if ($(this).prop('checked') && '%x' == def) {
+            def = '%a, %b %d, %Y';
+            $('#date_use_system_default').html('1');
+        } else if (!$(this).prop('checked') && '1' == $('#date_use_system_default').html()){
+            def = '%x';
+        }
+
+        $('#date_presets').attr('name', 'date_preset_old');
+        $('#date_presets').attr('id', 'date_presets_old');
+
+        $('#date_presets_na').attr('name', 'date_preset');
+        $('#date_presets_na').attr('id', 'date_presets');
+
+        $('#date_presets_old').attr('name', 'date_preset_na');
+        $('#date_presets_old').attr('id', 'date_presets_na');
+
+        if (def) $('#date_presets').val(def);
+    });
+
+    // bind 'myForm' and provide a simple callback function
+    $('#configForm').ajaxForm({
+        beforeSubmit: function(){
+            $('.config_submitter .config_submitter_refresh').each(function(){
+                $(this).attr("disabled", "disabled");
+                $(this).after('<span><img src="' + srRoot + '/images/loading16' + themeSpinner + '.gif"> Saving...</span>');
+                $(this).hide();
+            });
+        },
+        success: function(){
+            setTimeout(function () {
+                "use strict";
+                config_success();
+            }, 2000);
+        }
+    });
+
+    $('#api_key').click(function(){
+        $('#api_key').select();
+    });
+
+    $("#generate_new_apikey").click(function(){
+        $.get(srRoot + '/config/general/generateApiKey',
+            function(data){
+                if (data.error !== undefined) {
+                    alert(data.error);
+                    return;
+                }
+                $('#api_key').val(data);
+        });
+    });
+
+    $('#branchCheckout').click(function() {
+        var url = srRoot+'/home/branchCheckout?branch='+$("#branchVersion").val();
+        var  checkDBversion = srRoot + "/home/getDBcompare";
+        $.getJSON(checkDBversion, function(data){
+            if (data.status == "success") {
+                if (data.message == "equal") {
+                    //Checkout Branch
+                    window.location.href = url;
+                }
+                if (data.message == "upgrade") {
+                    if ( confirm("Changing branch will upgrade your database.\nYou won't be able to downgrade afterward.\nDo you want to continue?") ) {
+                        //Checkout Branch
+                        window.location.href = url;
+                    }
+                }
+                if (data.message == "downgrade") {
+                    alert("Can't switch branch as this will result in a database downgrade.");
+                }
+            }
+        });
+    });
+
 });
+
+function config_success(){
+    $('.config_submitter').each(function(){
+        $(this).removeAttr("disabled");
+        $(this).next().remove();
+        $(this).show();
+    });
+    $('.config_submitter_refresh').each(function(){
+        $(this).removeAttr("disabled");
+        $(this).next().remove();
+        $(this).show();
+        url = srRoot+'/config/providers/';
+        window.location.href = url;
+    });
+    $('#email_show').trigger('notify');
+}
diff --git a/gui/slick/views/config_backuprestore.mako b/gui/slick/views/config_backuprestore.mako
index 3f7cffa618816a038f5ae67b93dff2a0c0dd97d6..51293caf1ab33a839a27d10255c9ebb49b76ec9c 100644
--- a/gui/slick/views/config_backuprestore.mako
+++ b/gui/slick/views/config_backuprestore.mako
@@ -25,9 +25,6 @@
 % if sickbeard.INDEXER_DEFAULT:
     <% indexer = sickbeard.INDEXER_DEFAULT %>
 % endif
-
-<script type="text/javascript" src="${srRoot}/js/config.js?${sbPID}"></script>
-
 <div id="config">
     <div id="config-content">
 
diff --git a/gui/slick/views/displayShow.mako b/gui/slick/views/displayShow.mako
index b1914a82307c2e9b22b04462189397a350ead244..fc25ef1c33104794cc78263cd3fd15ce384b8341 100644
--- a/gui/slick/views/displayShow.mako
+++ b/gui/slick/views/displayShow.mako
@@ -494,7 +494,7 @@
             <% date = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(epResult['airdate'], show.airs, show.network)) %>
             <td class="col-airdate">
                 % if int(epResult['airdate']) != 1:
-                    <time datetime="${date.isoformat('T')}" class="date">${date}</time>
+                    <time datetime="${date.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdate(date)}</time>
                 % else:
                     Never
                 % endif
diff --git a/readme.md b/readme.md
index 3c6d1fdb3f2de833a16e9905cc14aa407d32652f..bf321572f0471ce0a4adefbf54fdaa0868803a20 100644
--- a/readme.md
+++ b/readme.md
@@ -32,6 +32,9 @@ Automatic Video Library Manager for TV Shows. It watches for new episodes of you
 ## Dependencies
  To run SickRage from source you will need Python 2.7.x, Mako, and PyOpenSSL
 
+## Feature Requests
+[![Feature Requests](https://cloud.githubusercontent.com/assets/390379/10127973/045b3a96-6560-11e5-9b20-31a2032956b2.png)](http://feathub.com/SiCKRAGETV/SickRage)
+
 ## Forums
  Any questions or setup info your looking for can be found at out forums https://www.sickrage.tv
 
diff --git a/runscripts/init.debian b/runscripts/init.debian
index 6d4b2e97a494f62d1d653c1eee204957e5d2a56c..1682dc0bfaf217eb6af035ebdff9f50484d29113 100755
--- a/runscripts/init.debian
+++ b/runscripts/init.debian
@@ -35,7 +35,7 @@ fi
 ## SR_HOME=         #$APP_PATH, the location of SickBeard.py, the default is /opt/sickrage
 ## SR_DATA=         #$DATA_DIR, the location of sickbeard.db, cache, logs, the default is /opt/sickrage
 ## SR_PIDFILE=      #$PID_FILE, the location of sickrage.pid, the default is /var/run/sickrage/sickrage.pid
-## PYTHON_BIN=      #$DAEMON, the location of the python binary, the default is /usr/bin/python
+## PYTHON_BIN=      #$DAEMON, the location of the python binary, the default is /usr/bin/python2.7
 ## SR_OPTS=         #$EXTRA_DAEMON_OPTS, extra cli option for sickrage, i.e. " --config=/home/sickrage/config.ini"
 ## SSD_OPTS=        #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users"
 ##
@@ -50,7 +50,7 @@ NAME=$(basename "$0")
 DESC=SickRage
 
 ## The defaults
-# Run as username 
+# Run as username
 RUN_AS=${SR_USER-sickrage}
 
 # Run as group
@@ -66,7 +66,7 @@ DATA_DIR=${SR_DATA-/opt/sickrage}
 PID_FILE=${SR_PIDFILE-/var/run/sickrage/sickrage.pid}
 
 # path to python bin
-DAEMON=${PYTHON_BIN-/usr/bin/python}
+DAEMON=${PYTHON_BIN-/usr/bin/python2.7}
 
 # Extra daemon option like: SR_OPTS=" --config=/home/sickrage/config.ini"
 EXTRA_DAEMON_OPTS=${SR_OPTS-}
@@ -103,7 +103,7 @@ fi
 
 start_sickrage() {
     [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
-    start-stop-daemon -d $APP_PATH -c $RUN_AS --group=${RUN_GROUP} $EXTRA_SSD_OPTS --start --quiet --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS 
+    start-stop-daemon -d $APP_PATH -c $RUN_AS --group=${RUN_GROUP} $EXTRA_SSD_OPTS --start --quiet --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
     RETVAL="$?"
     case "${RETVAL}" in
         # Service was started or was running already
@@ -127,7 +127,7 @@ stop_sickrage() {
     esac
     [ "${RETVAL}" = 2 ] && return 2
     [ -f "${PID_FILE}" ] && rm -f ${PID_FILE}
-    return 0 
+    return 0
 }
 
 case "$1" in
diff --git a/runscripts/init.fedora b/runscripts/init.fedora
index 792f9d5c8ade1c338148126d31edb3d489c2f507..ecb40d23c4b05890b7ccbc3f9228f04b56fcf6ca 100755
--- a/runscripts/init.fedora
+++ b/runscripts/init.fedora
@@ -28,7 +28,7 @@ homedir=${SR_HOME-/opt/sickrage}
 datadir=${SR_DATA-/opt/sickrage}
 pidfile=${SR_PIDFILE-/var/run/sickrage/sickrage.pid}
 nice=${SR_NICE-}
-python_bin=${PYTHON_BIN-/usr/bin/python}
+python_bin=${PYTHON_BIN-/usr/bin/python2.7}
 ##
 
 pidpath=`dirname ${pidfile}`
diff --git a/runscripts/init.gentoo b/runscripts/init.gentoo
index 43147d9b8a28642d9314abe02980f161b3049aa5..2a0a3f5f2c3084f61d702892199a6fa3ec09d163 100755
--- a/runscripts/init.gentoo
+++ b/runscripts/init.gentoo
@@ -12,7 +12,7 @@
 # SICKRAGE_USER=<user you want sickrage to run under>
 # SICKRAGE_GROUP=<group you want sickrage to run under>
 # SICKRAGE_DIR=<path to Sickbeard.py>
-# PATH_TO_PYTHON_2=/usr/bin/python2
+# PATH_TO_PYTHON_2=/usr/bin/python2.7
 # SICKRAGE_DATADIR=<directory that contains sickbeard.db file>
 # SICKRAGE_CONFDIR=<directory that contains Sickrage's config.ini file>
 #
diff --git a/runscripts/init.systemd b/runscripts/init.systemd
index 44d4990eaa4aa25892bb6d92f56c83563b9852f0..c73087c41712685fc702d64f31dbb3ffad6f8a44 100755
--- a/runscripts/init.systemd
+++ b/runscripts/init.systemd
@@ -24,21 +24,21 @@
 ### Example Using SickRage as daemon with pid file
 # Type=forking
 # PIDFile=/var/run/sickrage/sickrage.pid
-# ExecStart=/usr/bin/python /opt/sickrage/SickBeard.py -q --daemon --nolaunch --pidfile=/var/run/sickrage/sickrage.pid --datadir=/opt/sickrage
+# ExecStart=/usr/bin/python2.7 /opt/sickrage/SickBeard.py -q --daemon --nolaunch --pidfile=/var/run/sickrage/sickrage.pid --datadir=/opt/sickrage
 
 ## Example Using SickRage as daemon without pid file
 # Type=forking
 # GuessMainPID=no
-# ExecStart=/usr/bin/python /opt/sickrage/SickBeard.py -q --daemon --nolaunch --datadir=/opt/sickrage
+# ExecStart=/usr/bin/python2.7 /opt/sickrage/SickBeard.py -q --daemon --nolaunch --datadir=/opt/sickrage
 
 ### Example Using simple
 # Type=simple
-# ExecStart=/usr/bin/python /opt/sickrage/SickBeard.py -q --nolaunch
+# ExecStart=/usr/bin/python2.7 /opt/sickrage/SickBeard.py -q --nolaunch
 
 ### Example Using simple with EnvironmentFile where SR_DATA=/home/sickrage/.sickrage in /etc/sickrage.conf
 # Type=simple
 # EnvironmentFile=/etc/sickrage.conf
-# ExecStart=/usr/bin/python /opt/sickrage/SickBeard.py -q --nolaunch --datadir=${SR_DATA}
+# ExecStart=/usr/bin/python2.7 /opt/sickrage/SickBeard.py -q --nolaunch --datadir=${SR_DATA}
 
 ### Configuration
 
@@ -51,7 +51,7 @@ Group=sickrage
 
 Type=forking
 GuessMainPID=no
-ExecStart=/usr/bin/python /opt/sickrage/SickBeard.py -q --daemon --nolaunch --datadir=/opt/sickrage
+ExecStart=/usr/bin/python2.7 /opt/sickrage/SickBeard.py -q --daemon --nolaunch --datadir=/opt/sickrage
 
 [Install]
 WantedBy=multi-user.target
diff --git a/runscripts/init.ubuntu b/runscripts/init.ubuntu
index fd50edee5e0345ca467ac91406ab46d1d1be03e7..97543d77cc748bb8094248a6c1024e575e6fdda4 100755
--- a/runscripts/init.ubuntu
+++ b/runscripts/init.ubuntu
@@ -35,7 +35,7 @@ DESC=SickRage
 ## SR_HOME=         #$APP_PATH, the location of SickBeard.py, the default is /opt/sickrage
 ## SR_DATA=         #$DATA_DIR, the location of sickbeard.db, cache, logs, the default is /opt/sickrage
 ## SR_PIDFILE=      #$PID_FILE, the location of sickrage.pid, the default is /var/run/sickrage/sickrage.pid
-## PYTHON_BIN=      #$DAEMON, the location of the python binary, the default is /usr/bin/python
+## PYTHON_BIN=      #$DAEMON, the location of the python binary, the default is /usr/bin/python2.7
 ## SR_OPTS=         #$EXTRA_DAEMON_OPTS, extra cli option for sickrage, i.e. " --config=/home/sickrage/config.ini"
 ## SSD_OPTS=        #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users"
 ##
@@ -44,7 +44,7 @@ DESC=SickRage
 ## otherwise default sickrage is used
 
 ## The defaults
-# Run as username 
+# Run as username
 RUN_AS=${SR_USER-sickrage}
 
 # Path to app SR_HOME=path_to_app_SickBeard.py
@@ -57,7 +57,7 @@ DATA_DIR=${SR_DATA-/opt/sickrage}
 PID_FILE=${SR_PIDFILE-/var/run/sickrage/sickrage.pid}
 
 # path to python bin
-DAEMON=${PYTHON_BIN-/usr/bin/python}
+DAEMON=${PYTHON_BIN-/usr/bin/python2.7}
 
 # Extra daemon option like: SR_OPTS=" --config=/home/sickrage/config.ini"
 EXTRA_DAEMON_OPTS=${SR_OPTS-}
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 4124b784b1cf139484292645af7dd01af07824be..52ac11ecfc209ad6431e5b6c526c6816c125f0a4 100644
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -39,7 +39,7 @@ from sickbeard import providers
 from sickbeard.providers.generic import GenericProvider
 from sickbeard.providers import btn, newznab, womble, thepiratebay, torrentleech, kat, iptorrents, \
     omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, hounddawgs, nextgen, speedcd, nyaatorrents, animenzb, bluetigers, cpasbien, fnt, xthor, torrentbytes, \
-    frenchtorrentdb, freshontv, titansoftv, libertalia, morethantv, bitsoup, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, \
+    frenchtorrentdb, freshontv, titansoftv, libertalia, morethantv, bitsoup, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, extratorrent, \
     scenetime, btdigg, strike, transmitthenet, tvchaosuk
 from sickbeard.config import CheckSection, check_setting_int, check_setting_str, check_setting_float, ConfigMigrator, \
     naming_ep_type
diff --git a/sickbeard/indexers/indexer_exceptions.py b/sickbeard/indexers/indexer_exceptions.py
index 221f529661f32dcadc798725956de5bf23873b97..f8bd2221808289df3fd1eccae37c14081d6e947f 100644
--- a/sickbeard/indexers/indexer_exceptions.py
+++ b/sickbeard/indexers/indexer_exceptions.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python2.7
 # encoding:utf-8
 #author:echel0n
 #project:indexer_api
diff --git a/sickbeard/processTV.py b/sickbeard/processTV.py
index 1c41988a9a3b8d9fe334c55aecd599905c9e117b..9058b0275668363f2ad97fa7eb7a825901ea6e5c 100644
--- a/sickbeard/processTV.py
+++ b/sickbeard/processTV.py
@@ -311,16 +311,21 @@ def validateDir(path, dirName, nzbNameOriginal, failed, result):
     :return: True if dir is valid for processing, False if not
     """
 
+    IGNORED_FOLDERS = ['.@__thumb', '@eaDir']
+    folder_name = ek(os.path.basename, dirName)
+    if folder_name in IGNORED_FOLDERS:
+        return False
+
     result.output += logHelper(u"Processing folder " + dirName, logger.DEBUG)
 
-    if ek(os.path.basename, dirName).startswith('_FAILED_'):
+    if folder_name.startswith('_FAILED_'):
         result.output += logHelper(u"The directory name indicates it failed to extract.", logger.DEBUG)
         failed = True
-    elif ek(os.path.basename, dirName).startswith('_UNDERSIZED_'):
+    elif folder_name.startswith('_UNDERSIZED_'):
         result.output += logHelper(u"The directory name indicates that it was previously rejected for being undersized.",
                                logger.DEBUG)
         failed = True
-    elif ek(os.path.basename, dirName).upper().startswith('_UNPACK'):
+    elif folder_name.upper().startswith('_UNPACK'):
         result.output += logHelper(u"The directory name indicates that this release is in the process of being unpacked.",
                                logger.DEBUG)
         result.missedfiles.append(dirName + " : Being unpacked")
diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py
index 40bc790c8b38d1e6c0509edbc6a6a6dbee330ba7..86588c6cca6cbe5532365954400ef89251bb2c60 100644
--- a/sickbeard/providers/__init__.py
+++ b/sickbeard/providers/__init__.py
@@ -55,7 +55,8 @@ __all__ = ['womble',
            'strike',
            'transmitthenet',
            'tvchaosuk',
-           'torrentproject'
+           'torrentproject',
+           'extratorrent'
 ]
 
 import sickbeard
diff --git a/sickbeard/providers/extratorrent.py b/sickbeard/providers/extratorrent.py
new file mode 100644
index 0000000000000000000000000000000000000000..585a8e13f04e1b81b6bc9c2b2229322b020c4bf6
--- /dev/null
+++ b/sickbeard/providers/extratorrent.py
@@ -0,0 +1,197 @@
+# Author: duramato <matigonkas@outlook.com>
+# Author: miigotu
+# URL: https://github.com/SiCKRAGETV/sickrage
+# 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 re
+import traceback
+import datetime
+import sickbeard
+import xmltodict
+
+from sickbeard.providers import generic
+from sickbeard.common import Quality
+from sickbeard import logger
+from sickbeard import tvcache
+from sickbeard import db
+from sickbeard import classes
+from sickbeard import helpers
+from sickbeard import show_name_helpers
+from sickbeard.helpers import sanitizeSceneName
+
+
+class ExtraTorrentProvider(generic.TorrentProvider):
+    def __init__(self):
+        generic.TorrentProvider.__init__(self, "ExtraTorrent")
+
+        self.urls = {
+            'index': 'http://extratorrent.cc',
+            'rss': 'http://extratorrent.cc/rss.xml',
+            }
+
+        self.url = self.urls['index']
+
+        self.supportsBacklog = True
+        self.public = True
+        self.enabled = False
+        self.ratio = None
+        self.minseed = None
+        self.minleech = None
+
+        self.cache = ExtraTorrentCache(self)
+
+        self.search_params = {'cid': 8}
+
+    def isEnabled(self):
+        return self.enabled
+
+    def _get_season_search_strings(self, ep_obj):
+
+        search_string = {'Season': []}
+        for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
+            if ep_obj.show.air_by_date or ep_obj.show.sports:
+                ep_string = show_name + ' ' + str(ep_obj.airdate).split('-')[0]
+            elif ep_obj.show.anime:
+                ep_string = show_name + ' ' + "%d" % ep_obj.scene_absolute_number
+            else:
+                ep_string = show_name + ' S%02d' % int(ep_obj.scene_season)  #1) showName SXX
+
+            search_string['Season'].append(ep_string.strip())
+
+        return [search_string]
+
+    def _get_episode_search_strings(self, ep_obj, add_string=''):
+
+        search_strings = {'Episode': []}
+
+        if not ep_obj:
+            return []
+
+        for show_name in set(show_name_helpers.allPossibleShowNames(ep_obj.show)):
+            if ep_obj.show.air_by_date:
+                ep_string = sanitizeSceneName(show_name) + ' ' + \
+                                str(ep_obj.airdate).replace('-', '|')
+            elif ep_obj.show.sports:
+                ep_string = sanitizeSceneName(show_name) + ' ' + \
+                                str(ep_obj.airdate).replace('-', '|') + '|' + \
+                                ep_obj.airdate.strftime('%b')
+            elif ep_obj.show.anime:
+                ep_string = sanitizeSceneName(show_name) + ' ' + \
+                                "%i" % int(ep_obj.scene_absolute_number)
+            else:
+                ep_string = sanitizeSceneName(show_name) + ' ' + \
+                            sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
+                                                                  'episodenumber': ep_obj.scene_episode}
+
+            if add_string:
+                ep_string += ' %s' % add_string
+
+            search_strings['Episode'].append(re.sub(r'\s+', ' ', ep_string))
+
+        return [search_strings]
+
+
+    def _doSearch(self, search_strings, search_mode='eponly', epcount=0, age=0, epObj=None):
+
+        results = []
+        items = {'Season': [], 'Episode': [], 'RSS': []}
+
+        for mode in search_strings.keys():
+            for search_string in search_strings[mode]:
+                try:
+                    self.search_params.update({'type': ('search', 'rss')[mode == 'RSS'], 'search': search_string.strip()})
+                    data = self.getURL(self.urls['rss'], params=self.search_params)
+                    if not data:
+                        continue
+
+                    data = xmltodict.parse(data)
+                    for item in data['rss']['channel']['item']:
+                        title = item['title']
+                        info_hash = item['info_hash']
+                        url = item['enclosure']['@url']
+                        size = int(item['enclosure']['@length'] or item['size'])
+                        seeders = int(item['seeders'])
+                        leechers = int(item['leechers'])
+
+                        if not seeders or seeders < self.minseed or leechers < self.minleech:
+                            continue
+
+                        items[mode].append((title, url, seeders, leechers, size, info_hash))
+
+                except Exception:
+                    logger.log(u"Failed parsing " + self.name + " Traceback: " + traceback.format_exc(), logger.ERROR)
+
+            results += items[mode]
+
+        return results
+
+    def _get_title_and_url(self, item):
+        #pylint: disable=W0612
+        title, url, seeders, leechers, size, info_hash = item
+
+        if title:
+            title = self._clean_title_from_provider(title)
+
+        if url:
+            url = url.replace('&amp;', '&')
+
+        return (title, url)
+
+
+    def _get_size(self, item):
+        #pylint: disable=W0612
+        title, url, seeders, leechers, size, info_hash = item
+        return size
+
+    def findPropers(self, search_date=datetime.datetime.today()-datetime.timedelta(days=1)):
+        results = []
+        myDB = db.DBConnection()
+        sqlResults = myDB.select(
+            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' +
+            ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' +
+            ' WHERE e.airdate >= ' + str(search_date.toordinal()) +
+            ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' +
+            ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))'
+        )
+
+        for sqlshow in sqlResults or []:
+            show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"]))
+            if show:
+                curEp = show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"]))
+                searchStrings = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
+                for item in self._doSearch(searchStrings):
+                    title, url = self._get_title_and_url(item)
+                    results.append(classes.Proper(title, url, datetime.datetime.today(), show))
+
+        return results
+
+    def seedRatio(self):
+        return self.ratio
+
+
+class ExtraTorrentCache(tvcache.TVCache):
+    def __init__(self, _provider):
+
+        tvcache.TVCache.__init__(self, _provider)
+
+        self.minTime = 30
+
+    def _getRSSData(self):
+        search_strings = {'RSS': ['']}
+        return {'entries': self.provider._doSearch(search_strings)}
+
+
+provider = ExtraTorrentProvider()
diff --git a/sickbeard/providers/fnt.py b/sickbeard/providers/fnt.py
index b94e2b82398ec77a8d6dc54b03a1f78270c08468..ecb9a54ee94d095d2af43485bac74f32f874857f 100644
--- a/sickbeard/providers/fnt.py
+++ b/sickbeard/providers/fnt.py
@@ -152,6 +152,10 @@ class FNTProvider(generic.TorrentProvider):
         results = []
         items = {'Season': [], 'Episode': [], 'RSS': []}
 
+        # check for auth
+        if not self._doLogin():
+            return results
+
         for mode in search_strings.keys():
             for search_string in search_strings[mode]:
                 logger.log(u"Search string: " + search_string, logger.DEBUG)
diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py
index f8ee86b45edf0ae5085f90195466a65acb60c566..10009610fc83db8b413f92b7ff7dcdfe69ce0246 100644
--- a/sickbeard/providers/generic.py
+++ b/sickbeard/providers/generic.py
@@ -92,7 +92,7 @@ class GenericProvider:
 
     @staticmethod
     def makeID(name):
-        return re.sub("[^\w\d_]", "_", name.strip().lower())
+        return re.sub(r"[^\w\d_]", "_", name.strip().lower())
 
     def imageName(self):
         return self.getID() + '.png'
@@ -156,7 +156,7 @@ class GenericProvider:
         filename = u''
         if result.url.startswith('magnet'):
             try:
-                torrent_hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0].upper()
+                torrent_hash = re.findall(r'urn:btih:([\w]{32,40})', result.url)[0].upper()
 
                 try:
                     torrent_name = re.findall('dn=([^&]+)', result.url)[0]
diff --git a/sickbeard/providers/kat.py b/sickbeard/providers/kat.py
index 0f142b056037a45255b05ccc1395b59ae5d55f6a..b82c8d1e09c83970c8e751e5926781b6aea1a664 100644
--- a/sickbeard/providers/kat.py
+++ b/sickbeard/providers/kat.py
@@ -20,13 +20,12 @@
 from __future__ import with_statement
 
 import traceback
-import urllib
 import re
 import datetime
+import xmltodict
 
 import sickbeard
-import generic
-
+from sickbeard.providers import generic
 from sickbeard.common import Quality
 from sickbeard import logger
 from sickbeard import tvcache
@@ -34,7 +33,6 @@ from sickbeard import helpers
 from sickbeard import db
 from sickbeard import classes
 from sickbeard.show_name_helpers import allPossibleShowNames, sanitizeSceneName
-from unidecode import unidecode
 
 
 class KATProvider(generic.TorrentProvider):
@@ -46,17 +44,29 @@ class KATProvider(generic.TorrentProvider):
         self.public = True
 
         self.enabled = False
-        self.confirmed = False
+        self.confirmed = True
         self.ratio = None
         self.minseed = None
         self.minleech = None
 
         self.cache = KATCache(self)
 
-        self.urls = {'base_url': 'https://kat.cr/'}
+        self.urls = {
+            'base_url': 'https://kat.cr/',
+            'search': 'https://kat.cr/usearch/',
+            'rss': 'https://kat.cr/tv/',
+        }
 
         self.url = self.urls['base_url']
 
+        self.search_params = {
+            'q': '',
+            'field': 'seeders',
+            'sorder': 'desc',
+            'rss': 1,
+            'category': 'tv'
+        }
+
     def isEnabled(self):
         return self.enabled
 
@@ -66,81 +76,92 @@ class KATProvider(generic.TorrentProvider):
     def _get_season_search_strings(self, ep_obj):
         search_string = {'Season': []}
 
-        for show_name in set(allPossibleShowNames(self.show)):
+        for show_name in set(allPossibleShowNames(ep_obj.show)):
             ep_string = sanitizeSceneName(show_name) + ' '
             if ep_obj.show.air_by_date or ep_obj.show.sports:
                 ep_string += str(ep_obj.airdate).split('-')[0]
-                search_string['Season'].append(ep_string)
             elif ep_obj.show.anime:
                 ep_string += "%02d" % ep_obj.scene_absolute_number
-                search_string['Season'].append(ep_string)
             else:
                 ep_string = '%s S%02d -S%02dE category:tv' % (sanitizeSceneName(show_name), ep_obj.scene_season, ep_obj.scene_season) #1) showName SXX -SXXE
                 search_string['Season'].append(ep_string)
                 ep_string = '%s "Season %d" -Ep* category:tv' % (sanitizeSceneName(show_name), ep_obj.scene_season) # 2) showName "Season X"
-                search_string['Season'].append(ep_string)
+
+            search_string['Season'].append(ep_string)
 
         return [search_string]
 
     def _get_episode_search_strings(self, ep_obj, add_string=''):
         search_string = {'Episode': []}
 
-        for show_name in set(allPossibleShowNames(self.show)):
+        for show_name in set(allPossibleShowNames(ep_obj.show)):
             ep_string = sanitizeSceneName(show_name) + ' '
-            if self.show.air_by_date:
+            if ep_obj.show.air_by_date:
                 ep_string += str(ep_obj.airdate).replace('-', ' ')
-            elif self.show.sports:
+            elif ep_obj.show.sports:
                 ep_string += str(ep_obj.airdate).replace('-', ' ') + '|' + ep_obj.airdate.strftime('%b')
-            elif self.show.anime:
+            elif ep_obj.show.anime:
                 ep_string += "%02d" % ep_obj.scene_absolute_number
             else:
                 ep_string += sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
                                                                    'episodenumber': ep_obj.scene_episode} + '|' + \
                              sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
-                                                                   'episodenumber': ep_obj.scene_episode} + ' category:tv'
+                                                                   'episodenumber': ep_obj.scene_episode}
             if add_string:
                 ep_string += ' ' + add_string
 
-            search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
+            search_string['Episode'].append(re.sub(r'\s+', ' ', ep_string.strip()))
 
         return [search_string]
 
     def _get_size(self, item):
-        title, url, id, seeders, leechers, size, pubdate = item
+        #pylint: disable=W0612
+        title, url, info_hash, seeders, leechers, size, pubdate = item
         return size or -1
 
-    def _doSearch(self, search_params, search_mode='eponly', epcount=0, age=0, epObj=None):
+    def _doSearch(self, search_strings, search_mode='eponly', epcount=0, age=0, epObj=None):
         results = []
         items = {'Season': [], 'Episode': [], 'RSS': []}
 
-        for mode in search_params.keys():
-            for search_string in search_params[mode]:
-                if isinstance(search_string, unicode):
-                    search_string = unidecode(search_string)
+        for mode in search_strings.keys():
+            for search_string in search_strings[mode]:
+                self.search_params.update({'q': search_string, 'field': ('seeders', 'time_add')[mode == 'RSS']})
+                logger.log(u"Search string: %s" % unicode(self.search_params), logger.DEBUG)
 
-                if mode != 'RSS':
-                    searchURL = self.url + 'usearch/%s/?field=seeders&sorder=desc&rss=1' % urllib.quote_plus(search_string)
-                else:
-                    searchURL = self.url + 'tv/?field=time_add&sorder=desc&rss=1'
+                try:
+                    data = self.getURL(self.urls[('search', 'rss')[mode == 'RSS']], params=self.search_params)
+                    if not data:
+                        continue
 
-                logger.log(u"Search string: " + searchURL, logger.DEBUG)
+                    entries = xmltodict.parse(data)
+                    if not all([entries, 'rss' in entries, 'channel' in entries['rss'], 'item' in entries['rss']['channel']]):
+                        continue
 
-                try:
-                    entries = self.cache.getRSSFeed(searchURL)['entries']
-                    for item in entries or []:
+                    for item in entries['rss']['channel']['item']:
                         try:
-                            link = item['link']
-                            id = item['guid']
                             title = item['title']
-                            url = item['torrent_magneturi']
-                            verified = bool(int(item['torrent_verified']) or 0)
-                            seeders = int(item['torrent_seeds'])
-                            leechers = int(item['torrent_peers'])
-                            size = int(item['torrent_contentlength'])
+
+                            # Use the torcache link kat provides,
+                            # unless it is not torcache or we are not using blackhole
+                            # because we want to use magnets if connecting direct to client
+                            # so that proxies work.
+                            url = item['enclosure']['@url']
+                            if sickbeard.TORRENT_METHOD != "blackhole" or 'torcache' not in url:
+                                url = item['torrent:magnetURI']
+
+                            seeders = int(item['torrent:seeds'])
+                            leechers = int(item['torrent:peers'])
+                            verified = bool(int(item['torrent:verified']) or 0)
+                            size = int(item['torrent:contentLength'])
+
+                            info_hash = item['torrent:infoHash']
+                            #link = item['link']
+
                         except (AttributeError, TypeError, KeyError):
                             continue
 
-                        if mode != 'RSS' and (seeders < self.minseed or leechers < self.minleech):
+                        # Dont let RSS add items with no seeders either -.-
+                        if not seeders or seeders < self.minseed or leechers < self.minleech:
                             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
 
@@ -152,26 +173,17 @@ class KATProvider(generic.TorrentProvider):
                             continue
 
                         try:
-                            pubdate = datetime.datetime(*item['published_parsed'][0:6])
-                        except AttributeError:
-                            try:
-                                pubdate = datetime.datetime(*item['updated_parsed'][0:6])
-                            except AttributeError:
-                                try:
-                                    pubdate = datetime.datetime(*item['created_parsed'][0:6])
-                                except AttributeError:
-                                    try:
-                                        pubdate = datetime.datetime(*item['date'][0:6])
-                                    except AttributeError:
-                                        pubdate = datetime.datetime.today()
-
-                        item = title, url, id, seeders, leechers, size, pubdate
+                            pubdate = datetime.datetime.strptime(item['pubDate'], '%a, %d %b %Y %H:%M:%S +0000')
+                        except Exception:
+                            pubdate = datetime.datetime.today()
+
+                        item = title, url, info_hash, seeders, leechers, size, pubdate
 
                         items[mode].append(item)
 
-                except Exception, e:
+                except Exception:
                     logger.log(u"Failed to parsing " + self.name + " Traceback: " + traceback.format_exc(),
-                               logger.ERROR)
+                               logger.WARNING)
 
             #For each search mode sort all the items by seeders
             items[mode].sort(key=lambda tup: tup[3], reverse=True)
@@ -181,7 +193,8 @@ class KATProvider(generic.TorrentProvider):
         return results
 
     def _get_title_and_url(self, item):
-        title, url, id, seeders, leechers, size, pubdate = item
+        #pylint: disable=W0612
+        title, url, info_hash, seeders, leechers, size, pubdate = item
 
         if title:
             title = self._clean_title_from_provider(title)
@@ -191,7 +204,7 @@ class KATProvider(generic.TorrentProvider):
 
         return (title, url)
 
-    def findPropers(self, search_date=datetime.datetime.today()):
+    def findPropers(self, search_date=datetime.datetime.today()-datetime.timedelta(days=1)):
         results = []
 
         myDB = db.DBConnection()
@@ -203,21 +216,18 @@ class KATProvider(generic.TorrentProvider):
             ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))'
         )
 
-        if not sqlResults:
-            return []
-
-        for sqlshow in sqlResults:
-            self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"]))
-            if self.show:
-                curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"]))
+        for sqlshow in sqlResults or []:
+            show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"]))
+            if show:
+                curEp = show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"]))
 
-                searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
+                searchStrings = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
 
-                for item in self._doSearch(searchString[0]):
+                for item in self._doSearch(searchStrings):
                     title, url = self._get_title_and_url(item)
                     pubdate = item[6]
 
-                    results.append(classes.Proper(title, url, pubdate, self.show))
+                    results.append(classes.Proper(title, url, pubdate, show))
 
         return results
 
@@ -226,15 +236,15 @@ class KATProvider(generic.TorrentProvider):
 
 
 class KATCache(tvcache.TVCache):
-    def __init__(self, provider):
+    def __init__(self, provider_obj):
 
-        tvcache.TVCache.__init__(self, provider)
+        tvcache.TVCache.__init__(self, provider_obj)
 
         # only poll KickAss every 10 minutes max
         self.minTime = 20
 
     def _getRSSData(self):
-        search_params = {'RSS': ['rss']}
+        search_params = {'RSS': ['']}
         return {'entries': self.provider._doSearch(search_params)}
 
 provider = KATProvider()
diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py
index 682994d3061237df87f5a65cd232121b7a9d2714..a4f14bcd7c0815307c99e6f0b17d99dfce2299bf 100644
--- a/sickbeard/providers/thepiratebay.py
+++ b/sickbeard/providers/thepiratebay.py
@@ -19,19 +19,18 @@
 from __future__ import with_statement
 
 import re
-import urllib
 import datetime
 
 import sickbeard
-import generic
+from sickbeard.providers import generic
 from sickbeard.common import Quality
+from sickbeard.common import USER_AGENT
 from sickbeard import db
 from sickbeard import classes
 from sickbeard import logger
 from sickbeard import tvcache
 from sickbeard import helpers
 from sickbeard.show_name_helpers import allPossibleShowNames, sanitizeSceneName
-from unidecode import unidecode
 
 
 class ThePirateBayProvider(generic.TorrentProvider):
@@ -44,124 +43,121 @@ class ThePirateBayProvider(generic.TorrentProvider):
 
         self.enabled = False
         self.ratio = None
-        self.confirmed = False
+        self.confirmed = True
         self.minseed = None
         self.minleech = None
 
         self.cache = ThePirateBayCache(self)
 
-        self.urls = {'base_url': 'https://thepiratebay.gd/'}
+        self.urls = {
+            'base_url': 'https://thepiratebay.gd/',
+            'search': 'https://thepiratebay.gd/s/',
+            'rss': 'https://thepiratebay.gd/tv/latest'
+        }
 
         self.url = self.urls['base_url']
-
-        self.searchurl = self.url + 'search/%s/0/7/200' # order by seed
-
-        self.re_title_url = '/torrent/(?P<id>\d+)/(?P<title>.*?)//1".+?(?P<url>magnet.*?)//1".+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>'
+        self.headers.update({'User-Agent': USER_AGENT})
+
+        """
+        205 = SD, 208 = HD, 200 = All Videos
+        https://thepiratebay.gd/s/?q=Game of Thrones&type=search&orderby=7&page=0&category=200
+        """
+        self.search_params = {
+            'q': '',
+            'type': 'search',
+            'orderby': 7,
+            'page': 0,
+            'category': 200
+        }
+
+        self.re_title_url = r'/torrent/(?P<id>\d+)/(?P<title>.*?)//1".+?(?P<url>magnet.*?)//1".+?Size (?P<size>[\d\.]*&nbsp;[TGKMiB]{2,3}).+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>'
 
     def isEnabled(self):
         return self.enabled
 
-    def imageName(self):
-        return 'thepiratebay.png'
-
     def _get_season_search_strings(self, ep_obj):
 
-        search_string = {'Season': []}
-        for show_name in set(allPossibleShowNames(self.show)):
+        search_strings = {'Season': []}
+        for show_name in set(allPossibleShowNames(ep_obj.show)):
             if ep_obj.show.air_by_date or ep_obj.show.sports:
                 ep_string = show_name + ' ' + str(ep_obj.airdate).split('-')[0]
-                search_string['Season'].append(ep_string)
+                search_strings['Season'].append(ep_string)
                 ep_string = show_name + ' Season ' + str(ep_obj.airdate).split('-')[0]
-                search_string['Season'].append(ep_string)
             elif ep_obj.show.anime:
-                ep_string = show_name + ' ' + "%02d" % ep_obj.scene_absolute_number
-                search_string['Season'].append(ep_string)
+                ep_string = show_name + ' %02d' % ep_obj.scene_absolute_number
             else:
                 ep_string = show_name + ' S%02d' % int(ep_obj.scene_season)
-                search_string['Season'].append(ep_string)
+                search_strings['Season'].append(ep_string)
                 ep_string = show_name + ' Season ' + str(ep_obj.scene_season) + ' -Ep*'
-                search_string['Season'].append(ep_string)
 
-            search_string['Season'].append(ep_string)
+            search_strings['Season'].append(ep_string)
 
-        return [search_string]
+        return [search_strings]
 
     def _get_episode_search_strings(self, ep_obj, add_string=''):
 
-        search_string = {'Episode': []}
-
-        if self.show.air_by_date:
-            for show_name in set(allPossibleShowNames(self.show)):
-                ep_string = sanitizeSceneName(show_name) + ' ' + \
-                            str(ep_obj.airdate).replace('-', ' ')
-                search_string['Episode'].append(ep_string)
-        elif self.show.sports:
-            for show_name in set(allPossibleShowNames(self.show)):
-                ep_string = sanitizeSceneName(show_name) + ' ' + \
-                            str(ep_obj.airdate).replace('-', '|') + '|' + \
-                            ep_obj.airdate.strftime('%b')
-                search_string['Episode'].append(ep_string)
-        elif self.show.anime:
-            for show_name in set(allPossibleShowNames(self.show)):
-                ep_string = sanitizeSceneName(show_name) + ' ' + \
-                            "%02i" % int(ep_obj.scene_absolute_number)
-                search_string['Episode'].append(ep_string)
-        else:
-            for show_name in set(allPossibleShowNames(self.show)):
-                ep_string = sanitizeSceneName(show_name) + ' ' + \
-                            sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
-                                                                  'episodenumber': ep_obj.scene_episode} + '|' + \
-                            sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
-                                                                  'episodenumber': ep_obj.scene_episode} + ' %s' % add_string
-                search_string['Episode'].append(re.sub('\s+', ' ', ep_string))
-
-        return [search_string]
-
-    def _doSearch(self, search_params, search_mode='eponly', epcount=0, age=0, epObj=None):
+        search_strings = {'Episode': []}
+        for show_name in set(allPossibleShowNames(ep_obj.show)):
+            ep_string = sanitizeSceneName(show_name) + ' '
+            if ep_obj.show.air_by_date:
+                ep_string += str(ep_obj.airdate).replace('-', ' ')
+            elif ep_obj.show.sports:
+                ep_string += str(ep_obj.airdate).replace('-', '|') + '|' + ep_obj.airdate.strftime('%b')
+            elif ep_obj.show.anime:
+                ep_string += "%02i" % int(ep_obj.scene_absolute_number)
+            else:
+                ep_string += sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season,
+                                                                   'episodenumber': ep_obj.scene_episode} + '|' + \
+                sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season,
+                                                      'episodenumber': ep_obj.scene_episode}
 
-        results = []
-        items = {'Season': [], 'Episode': [], 'RSS': []}
+            if add_string:
+                ep_string += ' %s' % add_string
+
+            search_strings['Episode'].append(re.sub(r'\s+', ' ', ep_string).strip())
+
+        return [search_strings]
 
-        for mode in search_params.keys():
-            for search_string in search_params[mode]:
-                if isinstance(search_string, unicode):
-                    search_string = unidecode(search_string)
+    def _doSearch(self, search_strings, search_mode='eponly', epcount=0, age=0, epObj=None):
 
-                if mode != 'RSS':
-                    searchURL = self.searchurl % (urllib.quote(search_string))
-                else:
-                    searchURL = self.url + 'tv/latest/'
+        results = []
+        items = {'Season': [], 'Episode': [], 'RSS': []}
 
-                logger.log(u"Search string: " + searchURL, logger.DEBUG)
+        for mode in search_strings.keys():
+            for search_string in search_strings[mode]:
+                self.search_params.update({'q': search_string.strip()})
+                logger.log(u"Search string: " + search_string.strip(), logger.DEBUG)
 
-                data = self.getURL(searchURL)
+                data = self.getURL(self.urls[('search', 'rss')[mode == 'RSS']], params=self.search_params)
                 if not data:
                     continue
 
                 re_title_url = self.proxy._buildRE(self.re_title_url).replace('&amp;f=norefer', '')
-                matches = re.compile(re_title_url, re.DOTALL).finditer(urllib.unquote(data))
+                matches = re.compile(re_title_url, re.DOTALL).finditer(data)
                 for torrent in matches:
                     title = torrent.group('title')
                     url = torrent.group('url')
-                    id = int(torrent.group('id'))
+                    #id = int(torrent.group('id'))
+                    size = self._convertSize(torrent.group('size'))
                     seeders = int(torrent.group('seeders'))
                     leechers = int(torrent.group('leechers'))
 
-                    #Filter unseeded torrent
-                    if mode != 'RSS' and (seeders < self.minseed or leechers < self.minleech):
-                        logger.log(u"Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format(name, seeders, leechers), logger.DEBUG)
+                    # Continue before we check if we need to log anything,
+                    # if there is no url or title.
+                    if not title or not url:
                         continue
 
-                    #Accept Torrent only from Good People for every Episode Search
-                    if self.confirmed and re.search('(VIP|Trusted|Helper|Moderator)', torrent.group(0)) is None:
-                        logger.log(u"ThePirateBay Provider found result " + torrent.group(
-                            'title') + " but that doesn't seem like a trusted result so I'm ignoring it", logger.DEBUG)
+                    #Filter unseeded torrent
+                    if not seeders or seeders < self.minseed or leechers < self.minleech:
+                        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 title or not url:
+                    #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:
+                        logger.log(u"ThePirateBay Provider found result " + title + " but that doesn't seem like a trusted result so I'm ignoring it", logger.DEBUG)
                         continue
 
-                    item = title, url, id, seeders, leechers
+                    item = title, url, size, seeders, leechers
 
                     items[mode].append(item)
 
@@ -172,9 +168,27 @@ class ThePirateBayProvider(generic.TorrentProvider):
 
         return results
 
-    def _get_title_and_url(self, item):
+    def _convertSize(self, size):
+        size, modifier = size.split('&nbsp;')
+        size = float(size)
+        if modifier in 'KiB':
+            size = size * 1024
+        elif modifier in 'MiB':
+            size = size * 1024**2
+        elif modifier in 'GiB':
+            size = size * 1024**3
+        elif modifier in 'TiB':
+            size = size * 1024**4
+        return size
+
+    def _get_size(self, item):
+        # pylint: disable=W0612
+        title, url, size, seeders, leechers = item
+        return size
 
-        title, url, id, seeders, leechers = item
+    def _get_title_and_url(self, item):
+        # pylint: disable=W0612
+        title, url, size, seeders, leechers = item
 
         if title:
             title = self._clean_title_from_provider(title)
@@ -184,7 +198,7 @@ class ThePirateBayProvider(generic.TorrentProvider):
 
         return (title, url)
 
-    def findPropers(self, search_date=datetime.datetime.today()):
+    def findPropers(self, search_date=datetime.datetime.today()-datetime.timedelta(days=1)):
 
         results = []
 
@@ -197,20 +211,14 @@ class ThePirateBayProvider(generic.TorrentProvider):
             ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))'
         )
 
-        if not sqlResults:
-            return []
-
-        for sqlshow in sqlResults:
-            self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"]))
-
-            if self.show:
-                curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"]))
-
-                searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
-
-                for item in self._doSearch(searchString[0]):
+        for sqlshow in sqlResults or []:
+            show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"]))
+            if show:
+                curEp = show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"]))
+                searchStrings = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
+                for item in self._doSearch(searchStrings):
                     title, url = self._get_title_and_url(item)
-                    results.append(classes.Proper(title, url, search_date, self.show))
+                    results.append(classes.Proper(title, url, search_date, show))
 
         return results
 
@@ -219,15 +227,15 @@ class ThePirateBayProvider(generic.TorrentProvider):
 
 
 class ThePirateBayCache(tvcache.TVCache):
-    def __init__(self, provider):
+    def __init__(self, provider_obj):
 
-        tvcache.TVCache.__init__(self, provider)
+        tvcache.TVCache.__init__(self, provider_obj)
 
-        # only poll ThePirateBay every 10 minutes max
-        self.minTime = 20
+        # only poll ThePirateBay every 30 minutes max
+        self.minTime = 30
 
     def _getRSSData(self):
-        search_params = {'RSS': ['rss']}
+        search_params = {'RSS': ['']}
         return {'entries': self.provider._doSearch(search_params)}
 
 provider = ThePirateBayProvider()
diff --git a/sickbeard/providers/torrentproject.py b/sickbeard/providers/torrentproject.py
index e1a6958040f6a144074c4074ab9472039408da49..dc81feeb531b5eac3cb4aacbbcd3863da9d4fd1b 100644
--- a/sickbeard/providers/torrentproject.py
+++ b/sickbeard/providers/torrentproject.py
@@ -148,9 +148,11 @@ class TORRENTPROJECTProvider(generic.TorrentProvider):
                 continue
             hash = torrents[i]["torrent_hash"]
             size = torrents[i]["torrent_size"]
-			
-            magnet = "magnet:?xt=urn:btih:" + hash + "&tr=udp://open.demonii.com:1337/announce&tr=udp://tracker.openbittorrent.com:80/announce&tr=udp://tracker.leechers-paradise.org:6969/announce&tr=http://tracker.dler.org:6969/announce&tr=http://bt.careland.com.cn:6969/announce&tr=http://tracker.tfile.me/announce&tr=http://mgtracker.org:2710/announce&tr=http://tracker1.wasabii.com.tw:6969/announce"
-            #logger.log(u'magnet : ' + magnet, logger.DEBUG)
+            trackerUrl = self.urls['api'] + "" + hash + "/trackers_json"
+            logger.log(u'The tracker list is: ' + trackerUrl, logger.DEBUG)
+            jdata = self.getURL(trackerUrl, json=True)
+            magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + name + "".join(["&tr=" + s for s in jdata])
+            logger.log(u'Magnet URL is: ' + magnet, logger.DEBUG)
             results.append((name, magnet, size))
 
         logger.log("URL to be parsed: " + searchUrl, logger.DEBUG)
diff --git a/sickbeard/providers/xthor.py b/sickbeard/providers/xthor.py
index 350b5c98011086636be3df6e21fb46b480882d6f..bdb587eece5cc5759162f44f540805e8e09d1f8e 100644
--- a/sickbeard/providers/xthor.py
+++ b/sickbeard/providers/xthor.py
@@ -47,7 +47,7 @@ class XthorProvider(generic.TorrentProvider):
         self.cj = cookielib.CookieJar()
 
         self.url = "https://xthor.bz"
-        self.urlsearch = "https://xthor.bz/browse.php?search=\"%s%s\""
+        self.urlsearch = "https://xthor.bz/browse.php?search=\"%s\"%s"
         self.categories = "&searchin=title&incldead=0"
 
         self.enabled = False
diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py
index 5b867723d914f575e2b644954fa5d835b8fc6df8..b1200db7ae98f5e39fb930749998799fb8b62b4f 100644
--- a/sickbeard/webapi.py
+++ b/sickbeard/webapi.py
@@ -2706,7 +2706,7 @@ class CMD_ShowStats(ApiCall):
         # the outgoing container
         episodes_stats = {}
         episodes_stats["downloaded"] = {}
-        # truning codes into strings
+        # turning codes into strings
         for statusCode in episode_qualities_counts_download:
             if statusCode == "total":
                 episodes_stats["downloaded"]["total"] = episode_qualities_counts_download[statusCode]
diff --git a/tests/all_tests.py b/tests/all_tests.py
index 4f0c9e46008ff1057b77eaab7b20a4f8525738f8..5351032c1ca3b7a25adf9b4461e56bd61863dab2 100755
--- a/tests/all_tests.py
+++ b/tests/all_tests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python2.7
 # coding=UTF-8
 # Author: Dennis Lutter <lad1337@gmail.com>
 # URL: http://code.google.com/p/sickbeard/