diff --git a/data/interfaces/default/displayShow.tmpl b/data/interfaces/default/displayShow.tmpl
index 1d451a8de176b7bf7bbde1e4ee9b7026bbfae195..5ae71359bd6f245ff592fe258c41c0932e2f9b42 100644
--- a/data/interfaces/default/displayShow.tmpl
+++ b/data/interfaces/default/displayShow.tmpl
@@ -84,7 +84,7 @@ replace with: <b><%=", ".join([Quality.qualityStrings[x] for x in bestQualities]
 #end if
     </td></tr>
     <tr><td class="showLegend">Language:</td><td><img src="$sbRoot/images/flags/${show.lang}.png" width="16" height="11" alt="" /> $show.lang</td></tr>
-    <tr><td class="showLegend">Flatten files (no folders): </td><td><img src="$sbRoot/images/#if $show.seasonfolders == 0 or not $sickbeard.NAMING_FORCE_FOLDERS then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr>
+    <tr><td class="showLegend">Flatten files (no folders): </td><td><img src="$sbRoot/images/#if $show.flatten_folders == 1 or $sickbeard.NAMING_FORCE_FOLDERS then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr>
     <tr><td class="showLegend">Paused: </td><td><img src="$sbRoot/images/#if int($show.paused) == 1 then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr>
     <tr><td class="showLegend">Air-by-Date: </td><td><img src="$sbRoot/images/#if int($show.air_by_date) == 1 then "yes16.png\" alt=\"Y" else "no16.png\" alt=\"N"#" width="16" height="16" /></td></tr>
 </table>
diff --git a/data/interfaces/default/editShow.tmpl b/data/interfaces/default/editShow.tmpl
index 478a5167eecd19fb9d52ec20deb05b88e8f0209b..57a9f15d448553fe69518bde8b780e0299d74c9b 100644
--- a/data/interfaces/default/editShow.tmpl
+++ b/data/interfaces/default/editShow.tmpl
@@ -65,7 +65,7 @@ Note: This will only affect the language of the retrieved metadata file contents
 This <b>DOES NOT</b> allow Sick Beard to download non-english TV episodes!<br />
 <br />
 <br />
-Flatten files (no folders): <input type="checkbox" name="flatten_folders" #if $show.seasonfolders == 0 or not $sickbeard.NAMING_FORCE_FOLDERS then "checked=\"checked\"" else ""# #if $sickbeard.NAMING_FORCE_FOLDERS then "disabled=\"disabled\"" else ""#/><br /><br />
+Flatten files (no folders): <input type="checkbox" name="flatten_folders" #if $show.flatten_folders == 1 and not $sickbeard.NAMING_FORCE_FOLDERS then "checked=\"checked\"" else ""# #if $sickbeard.NAMING_FORCE_FOLDERS then "disabled=\"disabled\"" else ""#/><br /><br />
 Paused: <input type="checkbox" name="paused" #if $show.paused == 1 then "checked=\"checked\"" else ""# /><br /><br />
 
 Air by date: 
diff --git a/data/interfaces/default/inc_addShowOptions.tmpl b/data/interfaces/default/inc_addShowOptions.tmpl
index bd0905bbcd1fb2802689be490259a2e504459d29..c568b042665b26a1eaead91f9dfc72eb8150e89d 100644
--- a/data/interfaces/default/inc_addShowOptions.tmpl
+++ b/data/interfaces/default/inc_addShowOptions.tmpl
@@ -14,10 +14,10 @@
         </div>
 
         <div class="field-pair alt">
-            <input type="checkbox" name="seasonFolders" id="seasonFolders" #if $sickbeard.SEASON_FOLDERS_DEFAULT then "checked=\"checked\"" else ""# />
-            <label for="seasonFolders" class="clearfix">
-                <span class="component-title">Season Folders</span>
-                <span class="component-desc">Store episodes in season folders?</span>
+            <input type="checkbox" name="flatten_folders" id="flatten_folders" #if $sickbeard.FLATTEN_FOLDERS_DEFAULT then "checked=\"checked\"" else ""# />
+            <label for="flatten_folders" class="clearfix">
+                <span class="component-title">Flatten Folders</span>
+                <span class="component-desc">Disregard sub-folders?</span>
             </label>
         </div>
 
diff --git a/data/interfaces/default/manage.tmpl b/data/interfaces/default/manage.tmpl
index 7bd6f6336c46893ecc2cd32bb952db6d066c2cd4..36598c9092a78076f155605325df4f70f1362be7 100644
--- a/data/interfaces/default/manage.tmpl
+++ b/data/interfaces/default/manage.tmpl
@@ -123,7 +123,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
 #else:
     <td align="center"><span class="quality Custom">Custom</span></td>
 #end if 
-    <td align="center"><img src="$sbRoot/images/#if int($curShow.seasonfolders) == 1 then "yes16.png\" alt=\"Y\"" else "no16.png\" alt=\"N\""# width="16" height="16" /></td>
+    <td align="center"><img src="$sbRoot/images/#if int($curShow.flatten_folders) == 1 then "yes16.png\" alt=\"Y\"" else "no16.png\" alt=\"N\""# width="16" height="16" /></td>
     <td align="center"><img src="$sbRoot/images/#if int($curShow.paused) == 1 then "yes16.png\" alt=\"Y\"" else "no16.png\" alt=\"N\""# width="16" height="16" /></td>
     <td align="center">$curShow.status</td>
     <td align="center">$curUpdate</td>
diff --git a/data/interfaces/default/manage_massEdit.tmpl b/data/interfaces/default/manage_massEdit.tmpl
index 492f4e89c60fe0089e928f15e597a5acb414be3c..fe2408c6eaa2ded966ed208e7d37120662a7bbf5 100644
--- a/data/interfaces/default/manage_massEdit.tmpl
+++ b/data/interfaces/default/manage_massEdit.tmpl
@@ -72,12 +72,12 @@
 </div>
 
 <div class="optionWrapper">
-<span class="selectTitle">Season Folders <span class="separator">*</span></span>
+<span class="selectTitle">Flatten Folders <span class="separator">*</span></span>
     <div class="selectChoices">
-        <select id="edit_season_folders" name="season_folders">
+        <select id="edit_flatten_folders" name="flatten_folders">
             <option value="keep">&lt; keep &gt;</option>
-            <option value="enable" #if $season_folders_value then "selected=\"selected\"" else ""#>enable</option>
-            <option value="disable" #if $season_folders_value == False then "selected=\"selected\"" else ""#>disable</option>
+            <option value="enable" #if $flatten_folders_value then "selected=\"selected\"" else ""#>enable</option>
+            <option value="disable" #if $flatten_folders_value == False then "selected=\"selected\"" else ""#>disable</option>
         </select>
     </div><br />
 </div>
diff --git a/data/interfaces/default/testRename.tmpl b/data/interfaces/default/testRename.tmpl
index 67b1f06de4a4f0e32bceb6b985960faae28a0a48..eeab672a46b020021526a73fe6b5c143d30f81c0 100644
--- a/data/interfaces/default/testRename.tmpl
+++ b/data/interfaces/default/testRename.tmpl
@@ -40,7 +40,7 @@
     <td width="1%">
       <input type="checkbox" class="epCheck" id="<%=str(cur_ep_obj.season)+'x'+str(cur_ep_obj.episode)%>" name="<%=str(cur_ep_obj.season) +"x"+str(cur_ep_obj.episode) %>" />
     </td>
-    <td align="center">$cur_ep_obj.episode</td>
+    <td align="center"><%= " / ".join([str(cur_ep_obj.episode)] + [str(x.episode) for x in cur_ep_obj.relatedEps]) %></td>
     <td width="50%">$curLoc</td>
     <td width="50%">$cur_ep_obj.proper_path().$curExt</td>
     </td>
diff --git a/data/js/addShowOptions.js b/data/js/addShowOptions.js
index eaa830a93af38a20a5486f9710bf5e7314b52212..5f2f2c9e9c3da78a9d2c7968a9b98d0a6f44a51c 100644
--- a/data/js/addShowOptions.js
+++ b/data/js/addShowOptions.js
@@ -9,7 +9,7 @@ $(document).ready(function(){
         $.get(sbRoot+'/config/general/saveAddShowDefaults', {defaultStatus: $('#statusSelect').val(),
                                                              anyQualities: anyQualArray.join(','),
                                                              bestQualities: bestQualArray.join(','),
-                                                             defaultSeasonFolders: $('#seasonFolders').prop('checked')} );
+                                                             defaultFlattenFolders: $('#flatten_folders').prop('checked')} );
         $(this).attr('disabled', true);
         $.pnotify({
             pnotify_title: 'Saved Defaults',
@@ -17,7 +17,7 @@ $(document).ready(function(){
         });
     });
 
-    $('#statusSelect, #qualityPreset, #seasonFolders, #anyQualities, #bestQualities').change(function(){
+    $('#statusSelect, #qualityPreset, #flatten_folders, #anyQualities, #bestQualities').change(function(){
         $('#saveDefaultsButton').attr('disabled', false);
     });
 
diff --git a/data/js/testRename.js b/data/js/testRename.js
index 549667166c93da24fb8406e8b5754755bc762679..658ee484273cb6213816cce245864203fa508c0e 100644
--- a/data/js/testRename.js
+++ b/data/js/testRename.js
@@ -25,8 +25,7 @@ $(document).ready(function(){
             return false
 
         url = sbRoot+'/home/doRename?show='+$('#showID').attr('value')+'&eps='+epArr.join('|')
-        //window.location.href = url
-        alert(url)
+        window.location.href = url
     });
     
 });
\ No newline at end of file
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 89263c29ce6196a428c75b75349d4dc6ea8c7cb7..aebf5f9d819ae95a544511af501327d8bde47e9b 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -123,8 +123,7 @@ NAME_FORMATTING = r'%RN/%0Sx%0E - %E.N (%RG)'
 
 QUALITY_DEFAULT = None
 STATUS_DEFAULT = None
-SEASON_FOLDERS_FORMAT = None
-SEASON_FOLDERS_DEFAULT = None
+FLATTEN_FOLDERS_DEFAULT = None
 PROVIDER_ORDER = []
 
 NAMING_MULTI_EP = None
@@ -378,7 +377,7 @@ def initialize(consoleLogging=True):
                 showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, showList, loadingShowList, \
                 NZBS, NZBS_UID, NZBS_HASH, EZRSS, TVTORRENTS, TVTORRENTS_DIGEST, TVTORRENTS_HASH, TORRENT_DIR, USENET_RETENTION, SOCKET_TIMEOUT, \
                 SEARCH_FREQUENCY, DEFAULT_SEARCH_FREQUENCY, BACKLOG_SEARCH_FREQUENCY, \
-                QUALITY_DEFAULT, SEASON_FOLDERS_FORMAT, SEASON_FOLDERS_DEFAULT, STATUS_DEFAULT, \
+                QUALITY_DEFAULT, FLATTEN_FOLDERS_DEFAULT, STATUS_DEFAULT, \
                 GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, \
                 USE_GROWL, GROWL_HOST, GROWL_PASSWORD, USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_API, PROWL_PRIORITY, PROG_DIR, NZBMATRIX, NZBMATRIX_USERNAME, \
                 USE_PYTIVO, PYTIVO_NOTIFY_ONSNATCH, PYTIVO_NOTIFY_ONDOWNLOAD, PYTIVO_UPDATE_LIBRARY, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME, \
@@ -491,8 +490,7 @@ def initialize(consoleLogging=True):
         QUALITY_DEFAULT = check_setting_int(CFG, 'General', 'quality_default', SD)
         STATUS_DEFAULT = check_setting_int(CFG, 'General', 'status_default', SKIPPED)
         VERSION_NOTIFY = check_setting_int(CFG, 'General', 'version_notify', 1)
-        SEASON_FOLDERS_FORMAT = check_setting_str(CFG, 'General', 'season_folders_format', 'Season %02d')
-        SEASON_FOLDERS_DEFAULT = bool(check_setting_int(CFG, 'General', 'season_folders_default', 0))
+        FLATTEN_FOLDERS_DEFAULT = bool(check_setting_int(CFG, 'General', 'flatten_folders_default', 0))
 
         PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split()
 
@@ -994,8 +992,7 @@ def save_config():
     new_config['General']['download_propers'] = int(DOWNLOAD_PROPERS)
     new_config['General']['quality_default'] = int(QUALITY_DEFAULT)
     new_config['General']['status_default'] = int(STATUS_DEFAULT)
-    new_config['General']['season_folders_format'] = SEASON_FOLDERS_FORMAT
-    new_config['General']['season_folders_default'] = int(SEASON_FOLDERS_DEFAULT)
+    new_config['General']['flatten_folders_default'] = int(FLATTEN_FOLDERS_DEFAULT)
     new_config['General']['provider_order'] = ' '.join([x.getID() for x in providers.sortedProviderList()])
     new_config['General']['version_notify'] = int(VERSION_NOTIFY)
     new_config['General']['naming_pattern'] = NAMING_PATTERN
diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py
index 1edad2f320d9e96a70cfff467cee4a6a6cb4f687..4ce58461cf28761b198f7119bc6982fa961eb09f 100644
--- a/sickbeard/databases/mainDB.py
+++ b/sickbeard/databases/mainDB.py
@@ -469,3 +469,23 @@ class AddSizeAndSceneNameFields(FixAirByDateSetting):
 
         self.incDBVersion()
 
+class RenameSeasonFolders(AddSizeAndSceneNameFields):
+
+    def test(self):
+        return self.checkDBVersion() >= 11
+    
+    def execute(self):
+        
+        self.connection.action("ALTER TABLE tv_shows RENAME TO tmp_tv_shows")
+        
+        self.connection.action("CREATE TABLE tv_shows (show_id INTEGER PRIMARY KEY, location TEXT, show_name TEXT, tvdb_id NUMERIC, network TEXT, genre TEXT, runtime NUMERIC, quality NUMERIC, airs TEXT, status TEXT, flatten_folders NUMERIC, paused NUMERIC, startyear NUMERIC, tvr_id NUMERIC, tvr_name TEXT, air_by_date NUMERIC, lang TEXT)")
+
+        sql = "INSERT INTO tv_shows(show_id, location, show_name, tvdb_id, network, genre, runtime, quality, airs, status, flatten_folders, paused, startyear, tvr_id, tvr_name, air_by_date, lang) SELECT show_id, location, show_name, tvdb_id, network, genre, runtime, quality, airs, status, seasonfolders, paused, startyear, tvr_id, tvr_name, air_by_date, lang FROM tmp_tv_shows"
+        self.connection.action(sql)
+        
+        self.connection.action("UPDATE tv_shows SET flatten_folders = 2 WHERE flatten_folders = 1")
+        self.connection.action("UPDATE tv_shows SET flatten_folders = 1 WHERE flatten_folders = 0")
+        self.connection.action("UPDATE tv_shows SET flatten_folders = 0 WHERE flatten_folders = 2")
+        self.connection.action("DROP TABLE tmp_tv_shows")
+
+        self.incDBVersion()
diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py
index a0c6d47335053f22376c4f57535fdaed34ad4a46..6b4c4f428b7d958b20d7f3f13c918b28d64ebd0b 100644
--- a/sickbeard/helpers.py
+++ b/sickbeard/helpers.py
@@ -406,22 +406,72 @@ def moveFile(srcFile, destFile):
         copyFile(srcFile, destFile)
         ek.ek(os.unlink, srcFile)
 
-def rename_file(old_path, new_name):
+def make_dirs(path):
+    """
+    Creates any folders that are missing and assigns them the permissions of their
+    parents
+    """
+
+    # strip off the file name if there is one
+    path = os.path.dirname(path)
 
-    old_path_list = ek.ek(os.path.split, old_path)
-    old_file_ext = os.path.splitext(old_path_list[1])[1]
+    sofar = ''
+    folder_list = path.split(os.path.sep)
 
-    new_path = ek.ek(os.path.join, old_path_list[0], sanitizeFileName(new_name) + old_file_ext)
+    # look through each subfolder and make sure they all exist
+    for cur_folder in folder_list:
+        sofar += cur_folder + os.path.sep;
 
-    logger.log(u"Renaming from " + old_path + " to " + new_path)
+        # if it exists then just keep walking down the line
+        if ek.ek(os.path.isdir, sofar):
+            continue
 
+        try:
+            ek.ek(os.mkdir, sofar)
+            chmodAsParent(sofar)
+        except OSError, IOError:
+            return False
+    
+    return True
+
+def rename_ep_file(cur_path, new_path):
+    """
+    Creates all folders needed to move a file to its new location, renames it, then cleans up any folders
+    left that are now empty.
+    
+    cur_path: The absolute path to the file you want to move/rename
+    new_path: The absolute path to the destination for the file WITHOUT THE EXTENSION
+    """
+    
+    logger.log(u"Renaming file from "+cur_path+" to "+new_path)
+    
+    new_dest_dir, new_dest_name = os.path.split(new_path) #@UnusedVariable
+    cur_file_name, cur_file_ext = os.path.splitext(cur_path) #@UnusedVariable
+    
+    # put the extension on the incoming file
+    new_path += cur_file_ext
+    
+    make_dirs(new_path)
+    
+    # move the file
     try:
-        ek.ek(os.rename, old_path, new_path)
+        ek.ek(os.rename, cur_path, new_path)
     except (OSError, IOError), e:
-        logger.log(u"Failed renaming " + old_path + " to " + new_path + ": " + ex(e), logger.ERROR)
+        logger.log(u"Failed renaming " + cur_path + " to " + new_path + ": " + ex(e), logger.ERROR)
         return False
-
-    return new_path
+    
+    # clean up any old folders that are empty
+    check_empty_dir = ek.ek(os.path.dirname, cur_path)
+    while not os.listdir(check_empty_dir):
+        logger.log(u"Deleting empty folder: "+check_empty_dir)
+        try:
+            os.remove(check_empty_dir)
+        except (WindowsError, OSError):
+            logger.log(u"Unable to delete "+check_empty_dir, logger.WARNING)
+            break
+        check_empty_dir = os.path.basename(check_empty_dir)
+    
+    return True
 
 def chmodAsParent(childPath):
     if os.name == 'nt' or os.name == 'ce':
diff --git a/sickbeard/naming.py b/sickbeard/naming.py
index 8b5c3fbc052989958c6ef239449697fcbc6610c8..45b63b7e9bac18672788d8151c4497fd982ae9c2 100644
--- a/sickbeard/naming.py
+++ b/sickbeard/naming.py
@@ -126,4 +126,4 @@ def test_name(pattern, multi=None):
 
     ep = _generate_sample_ep(multi)
 
-    return {'name': ep.formatted_filename(pattern, multi), 'dir': ep.formatted_dir(pattern, multi)}
+    return {'name': ep.formatted_filename(pattern, multi), 'dir': ep.formatted_dir(pattern, multi)}
\ No newline at end of file
diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py
index 855f7e8afd0ed87416938834bc2b0d0ffce5f325..1b99f5692e7b959cb168bb62531a4bfba9a3b03b 100755
--- a/sickbeard/postProcessor.py
+++ b/sickbeard/postProcessor.py
@@ -112,6 +112,9 @@ class PostProcessor(object):
             return PostProcessor.DOESNT_EXIST
 
     def _list_associated_files(self, file_path):
+        """
+        Returns the absolute path to all files that share the same name but different extension with the given file
+        """
     
         if not file_path:
             return []
@@ -120,6 +123,10 @@ class PostProcessor(object):
     
         base_name = file_path.rpartition('.')[0]+'.'
         
+        # don't strip it all and use cwd by accident
+        if not base_name:
+            return []
+        
         # don't confuse glob with chars we didn't mean to use
         base_name = re.sub(r'[\[\]\*\?]', r'[\g<0>]', base_name)
     
@@ -235,41 +242,6 @@ class PostProcessor(object):
 
         self._combined_file_operation(file_path, new_path, new_base_name, associated_files, action=_int_copy)
 
-    def _find_ep_destination_folder(self, ep_obj):
-        
-        # if we're supposed to put it in a season folder then figure out what folder to use
-        season_folder = ''
-        if ep_obj.show.seasonfolders:
-    
-            # search the show dir for season folders
-            for curDir in ek.ek(os.listdir, ep_obj.show.location):
-    
-                if not ek.ek(os.path.isdir, ek.ek(os.path.join, ep_obj.show.location, curDir)):
-                    continue
-    
-                # if it's a season folder, check if it's the one we want
-                match = re.match(".*season\s*(\d+)", curDir, re.IGNORECASE)
-                if match:
-                    # if it's the correct season folder then stop looking
-                    if int(match.group(1)) == int(ep_obj.season):
-                        season_folder = curDir
-                        break
-    
-            # if we couldn't find the right one then just use the season folder defaut format
-            if season_folder == '':
-                # for air-by-date shows use the year as the season folder
-                if ep_obj.show.air_by_date:
-                    season_folder = str(ep_obj.airdate.year)
-                else:
-                    try:
-                        season_folder = sickbeard.SEASON_FOLDERS_FORMAT % (ep_obj.season)
-                    except TypeError:
-                        logger.log(u"Error: Your season folder format is incorrect, try setting it back to the default")
-        
-        dest_folder = ek.ek(os.path.join, ep_obj.show.location, season_folder)
-        
-        return dest_folder
-
     def _history_lookup(self):
         """
         Look up the NZB name in the history and see if it contains a record for self.nzb_name
@@ -670,20 +642,17 @@ class PostProcessor(object):
         
         # find the destination folder
         try:
-            dest_path = self._find_ep_destination_folder(ep_obj)
+            proper_path = ep_obj.proper_path()
+            proper_absolute_path = ek.ek(os.path.join, ep_obj.show.location, proper_path)
+            
+            dest_path = ek.ek(os.path.dirname, proper_absolute_path)
         except exceptions.ShowDirNotFoundException:
             raise exceptions.PostProcessingFailed(u"Unable to post-process an episode if the show dir doesn't exist, quitting")
             
         self._log(u"Destination folder for this episode: "+dest_path, logger.DEBUG)
-        
-        # if the dir doesn't exist (new season folder) then make it
-        if not ek.ek(os.path.isdir, dest_path):
-            self._log(u"Season folder didn't exist, creating it", logger.DEBUG)
-            try:
-                ek.ek(os.mkdir, dest_path)
-                helpers.chmodAsParent(dest_path)
-            except OSError, IOError:
-                raise exceptions.PostProcessingFailed("Unable to create the episode's destination folder: "+dest_path)
+
+        # create any folders we need
+        helpers.make_dirs(dest_path)
 
         # update the statuses before we rename so the quality goes into the name properly
         for cur_ep in [ep_obj] + ep_obj.relatedEps:
@@ -694,7 +663,7 @@ class PostProcessor(object):
         # figure out the base name of the resulting episode file
         if sickbeard.RENAME_EPISODES:
             orig_extension = self.file_name.rpartition('.')[-1]
-            new_base_name = helpers.sanitizeFileName(ep_obj.prettyName())
+            new_base_name = ek.ek(os.path.basename, ep_obj.proper_path)
             new_file_name = new_base_name + '.' + orig_extension
 
         else:
diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py
index cbfa169fda94374bc1a16d305525d420bd979b30..039b2227de3f3ab79f11abf05ca79009845891c6 100644
--- a/sickbeard/show_queue.py
+++ b/sickbeard/show_queue.py
@@ -115,8 +115,8 @@ class ShowQueue(generic_queue.GenericQueue):
 
         return queueItemObj
 
-    def addShow(self, tvdb_id, showDir, default_status=None, quality=None, season_folders=None, lang="en"):
-        queueItemObj = QueueItemAdd(tvdb_id, showDir, default_status, quality, season_folders, lang)
+    def addShow(self, tvdb_id, showDir, default_status=None, quality=None, flatten_folders=None, lang="en"):
+        queueItemObj = QueueItemAdd(tvdb_id, showDir, default_status, quality, flatten_folders, lang)
         
         self.add_item(queueItemObj)
 
@@ -165,13 +165,13 @@ class ShowQueueItem(generic_queue.QueueItem):
 
 
 class QueueItemAdd(ShowQueueItem):
-    def __init__(self, tvdb_id, showDir, default_status, quality, season_folders, lang):
+    def __init__(self, tvdb_id, showDir, default_status, quality, flatten_folders, lang):
 
         self.tvdb_id = tvdb_id
         self.showDir = showDir
         self.default_status = default_status
         self.quality = quality
-        self.season_folders = season_folders
+        self.flatten_folders = flatten_folders
         self.lang = lang
 
         self.show = None
@@ -242,7 +242,7 @@ class QueueItemAdd(ShowQueueItem):
             # set up initial values
             self.show.location = self.showDir
             self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT
-            self.show.seasonfolders = self.season_folders if self.season_folders != None else sickbeard.SEASON_FOLDERS_DEFAULT
+            self.show.flatten_folders = self.flatten_folders if self.flatten_folders != None else sickbeard.FLATTEN_FOLDERS_DEFAULT
             self.show.paused = False
             
             # be smartish about this
@@ -347,7 +347,8 @@ class QueueItemRename(ShowQueueItem):
 
         logger.log(u"Performing rename on "+self.show.name)
 
-        self.show.fixEpisodeNames()
+        for cur_ep_obj in self.show.loadEpisodesFromDir():
+            cur_ep_obj.rename()
 
         self.inProgress = False
 
diff --git a/sickbeard/tv.py b/sickbeard/tv.py
index 6e139909b2b988880cef4e4d3062df62ba091636..1d8bfa09620366a05f0da880d73a4ef7a8a462a0 100644
--- a/sickbeard/tv.py
+++ b/sickbeard/tv.py
@@ -43,7 +43,7 @@ from sickbeard import encodingKludge as ek
 
 from common import Quality, Overview
 from common import DOWNLOADED, SNATCHED, SNATCHED_PROPER, ARCHIVED, IGNORED, UNAIRED, WANTED, SKIPPED, UNKNOWN
-from common import NAMING_DUPLICATE, NAMING_EXTEND, NAMING_REPEAT
+from common import NAMING_DUPLICATE, NAMING_EXTEND
 
 class TVShow(object):
 
@@ -59,7 +59,7 @@ class TVShow(object):
         self.genre = ""
         self.runtime = 0
         self.quality = int(sickbeard.QUALITY_DEFAULT)
-        self.seasonfolders = int(sickbeard.SEASON_FOLDERS_DEFAULT)
+        self.flatten_folders = int(sickbeard.FLATTEN_FOLDERS_DEFAULT)
 
         self.status = ""
         self.airs = ""
@@ -463,7 +463,8 @@ class TVShow(object):
             if rootEp == None:
                 rootEp = curEp
             else:
-                rootEp.relatedEps.append(curEp)
+                if curEp not in rootEp.relatedEps:
+                    rootEp.relatedEps.append(curEp)
 
             # if it's a new file then 
             if not same_file:
@@ -555,7 +556,7 @@ class TVShow(object):
                 self.air_by_date = 0
 
             self.quality = int(sqlResults[0]["quality"])
-            self.seasonfolders = int(sqlResults[0]["seasonfolders"])
+            self.flatten_folders = int(sqlResults[0]["flatten_folders"])
             self.paused = int(sqlResults[0]["paused"])
 
             self._location = sqlResults[0]["location"]
@@ -754,80 +755,6 @@ class TVShow(object):
                     curEp.hastbn = False
                     curEp.saveToDB()
 
-
-
-    def fixEpisodeNames(self):
-
-        if not os.path.isdir(self._location):
-            logger.log(str(self.tvdbid) + ": Show dir doesn't exist, can't rename episodes")
-            return
-
-        # load episodes from my folder
-        self.loadEpisodesFromDir()
-
-        logger.log(str(self.tvdbid) + ": Loading all episodes with a location from the database")
-
-        myDB = db.DBConnection()
-        sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND location != ''", [self.tvdbid])
-
-        # build list of locations
-        fileLocations = {}
-        for epResult in sqlResults:
-            goodLoc = os.path.normpath(epResult["location"])
-            goodSeason = int(epResult["season"])
-            goodEpisode = int(epResult["episode"])
-            if fileLocations.has_key(goodLoc):
-                fileLocations[goodLoc].append((goodSeason, goodEpisode))
-            else:
-                fileLocations[goodLoc] = [(goodSeason, goodEpisode)]
-
-        logger.log(u"File results: " + str(fileLocations), logger.DEBUG)
-
-        for curLocation in fileLocations:
-
-            epList = fileLocations[curLocation]
-
-            # get the root episode and add all related episodes to it
-            rootEp = None
-            for myEp in epList:
-                curEp = self.getEpisode(myEp[0], myEp[1])
-                if rootEp == None:
-                    rootEp = curEp
-                    rootEp.relatedEps = []
-                else:
-                    rootEp.relatedEps.append(curEp)
-
-            goodName = rootEp.prettyName()
-            actualName = os.path.splitext(os.path.basename(curLocation))
-
-            if goodName == actualName[0]:
-                logger.log(str(self.tvdbid) + ": File " + rootEp.location + " is already named correctly, skipping", logger.DEBUG)
-                continue
-
-            with rootEp.lock:
-                result = helpers.rename_file(rootEp.location, rootEp.prettyName())
-                if result != False:
-                    rootEp.location = result
-                    for relEp in rootEp.relatedEps:
-                        relEp.location = result
-
-            fileList = postProcessor.PostProcessor(curLocation)._list_associated_files(curLocation)
-            logger.log(u"Files associated to "+curLocation+": "+str(fileList), logger.DEBUG)
-
-            for file in fileList:
-                result = helpers.rename_file(file, rootEp.prettyName())
-                if result == False:
-                    logger.log(str(self.tvdbid) + ": Unable to rename file "+file, logger.ERROR)
-
-            for curEp in [rootEp]+rootEp.relatedEps:
-                curEp.checkForMetaFiles()
-
-            with rootEp.lock:
-                rootEp.saveToDB()
-                for relEp in rootEp.relatedEps:
-                    relEp.saveToDB()
-
-
     def saveToDB(self):
 
         logger.log(str(self.tvdbid) + ": Saving show info to database", logger.DEBUG)
@@ -844,7 +771,7 @@ class TVShow(object):
                         "quality": self.quality,
                         "airs": self.airs,
                         "status": self.status,
-                        "seasonfolders": self.seasonfolders,
+                        "flatten_folders": self.flatten_folders,
                         "paused": self.paused,
                         "air_by_date": self.air_by_date,
                         "startyear": self.startyear,
@@ -1405,7 +1332,7 @@ class TVEpisode(object):
     def prettyName (self, naming_show_name=None, naming_ep_type=None, naming_multi_ep_type=None,
                     naming_ep_name=None, naming_sep_type=None, naming_use_periods=None, naming_quality=None):
 
-        return self._formatted_string('%SN - %Sx%0E - %EN')
+        return self._format_string('%SN - %Sx%0E - %EN')
 
     def _ep_name(self):
         """
@@ -1454,7 +1381,7 @@ class TVEpisode(object):
         ep_name = self._ep_name()
         
         def dot(name):
-            return re.sub('[_ -]','.', name)
+            return helpers.sanitizeSceneName(name)
         
         def us(name):
             return re.sub('[ -]','_', name)
@@ -1580,20 +1507,20 @@ class TVEpisode(object):
         
         # do the replacements
         for cur_replacement in sorted(replace_map.keys(), reverse=True):
-            result_name = result_name.replace(cur_replacement, replace_map[cur_replacement])
-            result_name = result_name.replace(cur_replacement.lower(), replace_map[cur_replacement].lower())
+            result_name = result_name.replace(cur_replacement, helpers.sanitizeFileName(replace_map[cur_replacement]))
+            result_name = result_name.replace(cur_replacement.lower(), helpers.sanitizeFileName(replace_map[cur_replacement].lower()))
         
         return result_name
 
     def proper_path(self):
         """
-        Figures out where this episode SHOULD live according to the renaming rules
+        Figures out the path where this episode SHOULD live according to the renaming rules, relative from the show dir
         """
         
         result = self.formatted_filename()
         
         # as long as they don't want us to flatten it and we're not FORCED to flatten it then append the dir
-        if self.show.seasonfolders or sickbeard.NAMING_FORCE_FOLDERS:
+        if not self.show.flatten_folders or sickbeard.NAMING_FORCE_FOLDERS:
             result = ek.ek(os.path.join, self.formatted_dir(), result)
         
         return result
@@ -1628,3 +1555,50 @@ class TVEpisode(object):
         name_groups = re.split(r'[\\/]', pattern)
         
         return self._format_string(name_groups[-1], multi)
+
+    def rename(self):
+        
+        proper_path = self.proper_path()
+        absolute_proper_path = ek.ek(os.path.join, self.show.location, proper_path)
+        absolute_current_path_no_ext, file_ext = os.path.splitext(self.location)
+
+        current_path = absolute_current_path_no_ext
+
+        if absolute_current_path_no_ext.startswith(self.show.location):
+            current_path = absolute_current_path_no_ext[len(self.show.location):]
+
+        logger.log(u"Renaming/moving episode from the base path "+self.location+" to "+absolute_proper_path, logger.DEBUG)
+
+        # if it's already named correctly then don't do anything
+        if proper_path == current_path:
+            logger.log(str(self.tvdbid) + ": File " + self.location + " is already named correctly, skipping", logger.DEBUG)
+            return
+
+        related_files = postProcessor.PostProcessor(self.location)._list_associated_files(self.location)
+        logger.log(u"Files associated to "+self.location+": "+str(related_files), logger.DEBUG)
+
+        # move the ep file
+        result = helpers.rename_ep_file(self.location, absolute_proper_path)
+        
+        # move related files
+        for cur_related_file in related_files:
+            cur_result = helpers.rename_ep_file(cur_related_file, absolute_proper_path)
+            if cur_result == False:
+                logger.log(str(self.tvdbid) + ": Unable to rename file "+cur_related_file, logger.ERROR)
+
+        # save the ep
+        with self.lock:
+            if result != False:
+                self.location = absolute_proper_path + file_ext
+                for relEp in self.relatedEps:
+                    relEp.location = absolute_proper_path + file_ext
+
+        # in case something changed with the metadata just do a quick check
+        for curEp in [self]+self.relatedEps:
+            curEp.checkForMetaFiles()
+
+        # save any changes to the database
+        with self.lock:
+            self.saveToDB()
+            for relEp in self.relatedEps:
+                relEp.saveToDB()
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 5de587dbb8f2a7b6e9dde055c1067cb967ebc853..b24efa72f87439295c4e5316aef2e9d5f3498343 100755
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -352,8 +352,8 @@ class Manage:
             if showObj:
                 showList.append(showObj)
 
-        season_folders_all_same = True
-        last_season_folders = None
+        flatten_folders_all_same = True
+        last_flatten_folders = None
 
         paused_all_same = True
         last_paused = None
@@ -377,11 +377,11 @@ class Manage:
                 else:
                     last_paused = curShow.paused
 
-            if season_folders_all_same:
-                if last_season_folders not in (None, curShow.seasonfolders):
-                    season_folders_all_same = False
+            if flatten_folders_all_same:
+                if last_flatten_folders not in (None, curShow.flatten_folders):
+                    flatten_folders_all_same = False
                 else:
-                    last_season_folders = curShow.seasonfolders
+                    last_flatten_folders = curShow.flatten_folders
 
             if quality_all_same:
                 if last_quality not in (None, curShow.quality):
@@ -391,14 +391,14 @@ class Manage:
 
         t.showList = toEdit
         t.paused_value = last_paused if paused_all_same else None
-        t.season_folders_value = last_season_folders if season_folders_all_same else None
+        t.flatten_folders_value = last_flatten_folders if flatten_folders_all_same else None
         t.quality_value = last_quality if quality_all_same else None
         t.root_dir_list = root_dir_list
 
         return _munge(t)
 
     @cherrypy.expose
-    def massEditSubmit(self, paused=None, season_folders=None, quality_preset=False,
+    def massEditSubmit(self, paused=None, flatten_folders=None, quality_preset=False,
                        anyQualities=[], bestQualities=[], toEdit=None, *args, **kwargs):
 
         dir_map = {}
@@ -431,16 +431,16 @@ class Manage:
                 new_paused = True if paused == 'enable' else False
             new_paused = 'on' if new_paused else 'off'
 
-            if season_folders == 'keep':
-                new_season_folders = showObj.seasonfolders
+            if flatten_folders == 'keep':
+                new_flatten_folders = showObj.flatten_folders
             else:
-                new_season_folders = True if season_folders == 'enable' else False
-            new_season_folders = 'on' if new_season_folders else 'off'
+                new_flatten_folders = True if flatten_folders == 'enable' else False
+            new_flatten_folders = 'on' if new_flatten_folders else 'off'
 
             if quality_preset == 'keep':
                 anyQualities, bestQualities = Quality.splitQuality(showObj.quality)
             
-            curErrors += Home().editShow(curShow, new_show_dir, anyQualities, bestQualities, new_season_folders, new_paused, directCall=True)
+            curErrors += Home().editShow(curShow, new_show_dir, anyQualities, bestQualities, new_flatten_folders, new_paused, directCall=True)
 
             if curErrors:
                 logger.log(u"Errors: "+str(curErrors), logger.ERROR)
@@ -611,7 +611,7 @@ class ConfigGeneral:
         sickbeard.ROOT_DIRS = rootDirString
     
     @cherrypy.expose
-    def saveAddShowDefaults(self, defaultSeasonFolders, defaultStatus, anyQualities, bestQualities):
+    def saveAddShowDefaults(self, defaultFlattenFolders, defaultStatus, anyQualities, bestQualities):
 
         if anyQualities:
             anyQualities = anyQualities.split(',')
@@ -628,12 +628,12 @@ class ConfigGeneral:
         sickbeard.STATUS_DEFAULT = int(defaultStatus)
         sickbeard.QUALITY_DEFAULT = int(newQuality)
 
-        if defaultSeasonFolders == "true":
-            defaultSeasonFolders = 1
+        if defaultFlattenFolders == "true":
+            defaultFlattenFolders = 1
         else:
-            defaultSeasonFolders = 0
+            defaultFlattenFolders = 0
 
-        sickbeard.SEASON_FOLDERS_DEFAULT = int(defaultSeasonFolders)
+        sickbeard.FLATTEN_FOLDERS_DEFAULT = int(defaultFlattenFolders)
 
     @cherrypy.expose
     def generateKey(self):
@@ -1576,7 +1576,7 @@ class NewHomeAddShows:
 
     @cherrypy.expose
     def addNewShow(self, whichSeries=None, tvdbLang="en", rootDir=None, defaultStatus=None,
-                   anyQualities=None, bestQualities=None, seasonFolders=None, fullShowPath=None,
+                   anyQualities=None, bestQualities=None, flatten_folders=None, fullShowPath=None,
                    other_shows=None, skipShow=None):
         """
         Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are
@@ -1638,10 +1638,10 @@ class NewHomeAddShows:
             helpers.chmodAsParent(show_dir)
 
         # prepare the inputs for passing along
-        if seasonFolders == "on":
-            seasonFolders = 1
+        if flatten_folders == "on":
+            flatten_folders = 1
         else:
-            seasonFolders = 0
+            flatten_folders = 0
         
         if not anyQualities:
             anyQualities = []
@@ -1654,7 +1654,7 @@ class NewHomeAddShows:
         newQuality = Quality.combineQualities(map(int, anyQualities), map(int, bestQualities))
         
         # add the show
-        sickbeard.showQueueScheduler.action.addShow(tvdb_id, show_dir, int(defaultStatus), newQuality, seasonFolders, tvdbLang) #@UndefinedVariable
+        sickbeard.showQueueScheduler.action.addShow(tvdb_id, show_dir, int(defaultStatus), newQuality, flatten_folders, tvdbLang) #@UndefinedVariable
         ui.notifications.message('Show added', 'Adding the specified show into '+show_dir)
 
         return finishAddShow()
@@ -1725,7 +1725,7 @@ class NewHomeAddShows:
             show_dir, tvdb_id, show_name = cur_show
 
             # add the show
-            sickbeard.showQueueScheduler.action.addShow(tvdb_id, show_dir, SKIPPED, sickbeard.QUALITY_DEFAULT, sickbeard.SEASON_FOLDERS_DEFAULT) #@UndefinedVariable
+            sickbeard.showQueueScheduler.action.addShow(tvdb_id, show_dir, SKIPPED, sickbeard.QUALITY_DEFAULT, sickbeard.FLATTEN_FOLDERS_DEFAULT) #@UndefinedVariable
             num_added += 1
          
         if num_added:
@@ -2152,9 +2152,11 @@ class Home:
             return _munge(t)
 
         if flatten_folders == "on":
-            flatten_folders = 0
-        else:
             flatten_folders = 1
+        else:
+            flatten_folders = 0
+
+        logger.log(u"flatten folders: "+str(flatten_folders))
 
         if paused == "on":
             paused = 1
@@ -2188,8 +2190,9 @@ class Home:
             newQuality = Quality.combineQualities(map(int, anyQualities), map(int, bestQualities))
             showObj.quality = newQuality
 
-            if bool(showObj.seasonfolders) != bool(flatten_folders):
-                showObj.seasonfolders = flatten_folders
+            # reversed for now
+            if bool(showObj.flatten_folders) != bool(flatten_folders):
+                showObj.flatten_folders = flatten_folders
                 try:
                     sickbeard.showQueueScheduler.action.refreshShow(showObj) #@UndefinedVariable
                 except exceptions.CantRefreshException, e:
@@ -2327,25 +2330,6 @@ class Home:
             logger.log(u"Plex library update failed for host " + sickbeard.PLEX_HOST, logger.ERROR)
         redirect('/home')
 
-
-    @cherrypy.expose
-    def fixEpisodeNames(self, show=None):
-
-        if show == None:
-            return _genericMessage("Error", "Invalid show ID")
-
-        showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
-
-        if showObj == None:
-            return _genericMessage("Error", "Unable to find the specified show")
-
-        if sickbeard.showQueueScheduler.action.isBeingAdded(showObj): #@UndefinedVariable
-            return _genericMessage("Error", "Show is still being added, wait until it is finished before you rename files")
-
-        showObj.fixEpisodeNames()
-
-        redirect("/home/displayShow?show=" + show)
-
     @cherrypy.expose
     def setStatus(self, show=None, eps=None, status=None, direct=False):
 
@@ -2444,10 +2428,15 @@ class Home:
 
         ep_obj_list = []
 
-        for cur_ep_obj in showObj.getAllEpisodes():
-            if not cur_ep_obj.location:
-                continue
+        myDB = db.DBConnection()
+        ep_list = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND location != '' GROUP BY location ORDER BY season*1000+episode", [show])
+
+        for cur_ep in ep_list:
+
+            # get the episode object
+            cur_ep_obj = showObj.makeEpFromFile(cur_ep["location"])
             
+            # figure out the path vars
             cur_path = cur_ep_obj.location[len(showObj.location)+1:]
             cur_ext = cur_path.rsplit('.')[-1]
             
@@ -2460,6 +2449,45 @@ class Home:
 
         return _munge(t)
 
+    @cherrypy.expose
+    def doRename(self, show=None, eps=None):
+
+        if show == None or eps == None:
+            errMsg = "You must specify a show and at least one episode"
+            return _genericMessage("Error", errMsg)
+
+        show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
+
+        if show_obj == None:
+            errMsg = "Error", "Show not in show list"
+            return _genericMessage("Error", errMsg)
+
+        myDB = db.DBConnection()
+
+        if eps == None:
+            redirect("/home/displayShow?show=" + show)
+            
+        for curEp in eps.split('|'):
+
+            epInfo = curEp.split('x')
+            
+            # this is probably the worst possible way to deal with double eps but I've kinda painted myself into a corner here with this stupid database
+            ep_result = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ? AND 5=5", [show, epInfo[0], epInfo[1]])
+            if not ep_result:
+                logger.log(u"Unable to find an episode for "+curEp+", skipping", logger.WARNING)
+                continue
+            related_eps_result = myDB.select("SELECT * FROM tv_episodes WHERE location = ? AND episode != ?", [ep_result[0]["location"], epInfo[1]])
+            
+            root_ep_obj = show_obj.getEpisode(int(epInfo[0]), int(epInfo[1]))
+            for cur_related_ep in related_eps_result:
+                related_ep_obj = show_obj.getEpisode(int(cur_related_ep["season"]), int(cur_related_ep["episode"]))
+                if related_ep_obj not in root_ep_obj.relatedEps:
+                    root_ep_obj.relatedEps.append(related_ep_obj)
+
+            root_ep_obj.rename()
+
+        redirect("/home/displayShow?show=" + show)
+
     @cherrypy.expose
     def searchEpisode(self, show=None, season=None, episode=None):