diff --git a/data/css/config.css b/data/css/config.css
index 4412896544e18e0878095a54db0bf8419edc6266..a32d1a22a8e16f9ad8fcfdb4783f482478f1fd2a 100644
--- a/data/css/config.css
+++ b/data/css/config.css
@@ -24,8 +24,8 @@
 #config div.field-pair{margin:.9em 0 1.4em;}
 #config div.field-pair input{float:left;margin-right:6px;}
 #config label.nocheck,#config div.providerDiv,#config div #customQuality{padding-left:20px;}
-#config label span.component-title{font-size:1.2em;font-weight:700;float:left;width:160px;margin-right:10px;}
-#config label span.component-desc{font-size:1.1em;}
+#config span.component-title{font-size:1.2em;font-weight:700;float:left;width:160px;margin-right:10px;}
+#config span.component-desc{font-size:1.1em;}
 #config div.field-pair select{font-size:1.1em;border:1px solid #d4d0c8;}
 #config div.field-pair select option{line-height:1.4;padding:0 10px; border-bottom: 1px dotted #D7D7D7;}
 #config-settings{float:right;width:200px;background:#fffae5;border-bottom:1px dotted #666;border-top:1px solid #999;margin-right:20px;padding:20px 0 30px;}
diff --git a/data/interfaces/default/config_postProcessing.tmpl b/data/interfaces/default/config_postProcessing.tmpl
index d8d0e211182ea84c5d25df1352a1fd604ee896ae..6c785a636ecb9e6e56f823d35fecfda1599aec6c 100644
--- a/data/interfaces/default/config_postProcessing.tmpl
+++ b/data/interfaces/default/config_postProcessing.tmpl
@@ -4,6 +4,8 @@
 #from sickbeard import config
 #from sickbeard import metadata
 #from sickbeard.metadata.generic import GenericMetadata
+#from sickbeard import naming
+
 #set global $title  = "Config - Post Processing"
 #set global $header = "Post Processing Configuration"
 
@@ -19,10 +21,235 @@
 <div id="config-content">
 <h5>All non-absolute folder locations are relative to " <span class="path">$sickbeard.DATA_DIR</span> "</h5>
 
-<form id="configForm" action="savePostProcessing" method="post">
+<form id="configForms" action="savePostProcessing" method="post">
 
             <div id="config-components">
                 
+                <div id="core-component-group3" class="component-group clearfix">
+                    <div class="component-group-desc">
+                        <h3>Naming</h3>
+                        <p>How Sick Beard will name and sort your episodes.</p>
+                    </div>
+
+                    <fieldset class="component-group-list">
+
+                        <div>
+
+                            <div class="clearfix">
+                                <span class="component-title">File Name</span>
+                                <span class="component-desc">
+                                    <select id="name_presets" class="naming_preset_select">
+                                    #set $is_custom = True
+                                    #for $cur_preset in $naming.name_presets:
+                                        #set $tmp = $naming.test_name($cur_preset)
+                                        #if $cur_preset == $sickbeard.NAMING_NAME_PATTERN:
+                                            #set $is_custom = False
+                                        #end if
+                                        <option id="$cur_preset" #if $cur_preset == $sickbeard.NAMING_NAME_PATTERN then "selected" else ""#>$tmp['name']</option>
+                                    #end for
+                                    <option id="custom" #if $is_custom then "selected" else ""#>Custom...</option>
+                                    </select><br />
+                                    <br />
+                                </span>
+                                <div class="clearfix"></div>
+                                <span class="naming_custom_span">
+                                    <span class="component-title">&nbsp;</span>
+                                    <span id="naming_name_custom" class="component-desc">
+                                        <input type="text" size="60" name="naming_name_pattern" id="naming_name_pattern" class="naming_pattern" value="$sickbeard.NAMING_NAME_PATTERN" /><br />
+                                        <br />
+                                    </span>
+                                </span>
+                            </div>
+
+                        </div>
+                        
+                        <div>
+
+                            <div class="clearfix">
+                                <span class="component-title">Folder Name</span>
+                                <span class="component-desc">
+                                    <select id="dir_presets" class="naming_preset_select">
+                                    <option id="none" #if not $sickbeard.NAMING_DIR_PATTERN then "selected" else ""#>None</option>
+                                    #set $is_custom = True
+                                    #for $cur_preset in $naming.dir_presets:
+                                        #set $tmp = $naming.test_name($cur_preset)
+                                        #if $cur_preset == $sickbeard.NAMING_DIR_PATTERN:
+                                            #set $is_custom = False
+                                        #end if
+                                        <option id="$cur_preset" #if $cur_preset == $sickbeard.NAMING_DIR_PATTERN then "selected" else ""#>$tmp['name']</option>
+                                    #end for
+                                    <option id="custom" #if $is_custom and $sickbeard.NAMING_DIR_PATTERN then "selected" else ""#>Custom...</option>
+                                    </select><br />
+                                    <br />
+                                </span>
+                                <div class="clearfix"></div>
+                                <span class="naming_custom_span">
+                                    <span class="component-title">&nbsp;</span>
+                                    <span id="naming_dir_custom" class="component-desc">
+                                        <input type="text" size="60" name="naming_dir_pattern" id="naming_dir_pattern" class="naming_pattern" value="$sickbeard.NAMING_DIR_PATTERN" /><br />
+                                        <br />
+                                    </span>
+                                </span>
+                            </div>
+                            
+                        </div>
+
+                        <div style="padding:10px; background: #efefef;">
+                            <label class="clearfix">
+                                <span class="component-title jumbo" style="padding-bottom: 5px;"><b>Example:</b></span>
+                                <span class="component-desc jumbo" id="naming_example"></span>
+                            </label>
+                        </div>
+                    
+                        <div class="field-pair">
+                            <label class="nocheck clearfix" for="naming_multi_ep">
+                                <span class="component-title">Multi-episode Style</span>
+                                <span class="component-desc">
+                                    <select id="naming_multi_ep" name="naming_multi_ep">
+                                    #for $cur_multi_ep in $multiEpStrings:
+                                        <option value="$cur_multi_ep">$multiEpStrings[$cur_multi_ep]</option>
+                                    #end for
+                                    </select>
+                                </span>
+                            </label>
+                        </div>
+
+                        <div style="padding:10px; background: #efefef;">
+                            <label class="clearfix">
+                                <span class="component-title jumbo" style="padding-bottom: 5px;"><b>Multi-Ep Example:</b></span>
+                                <span class="component-desc jumbo" id="naming_example_multi"></span>
+                            </label>
+                        </div>
+                        
+                        <br />
+                        
+                        <div id="naming_custom_help">
+<b>Help</b><br />
+<br />
+<table width="100%" cellpadding="3" cellspacing="0">
+ <tr style="background: #efefef;">
+  <td><b>Show Name</b></td>
+  <td>%SN</td>
+  <td>Show Name</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td>&nbsp;</td>
+  <td>%S.N</td>
+  <td>Show.Name</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td>&nbsp;</td>
+  <td>%S_N</td>
+  <td>Show_Name</td>
+ </tr>
+ <tr>
+  <td>Episode Name</td>
+  <td>%EN</td>
+  <td>Episode Name</td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td>%E.N</td>
+  <td>Episode.Name</td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td>%E_N</td>
+  <td>Episode_Name</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td><b>Season Number</b></td>
+  <td>%S</td>
+  <td>1</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td>&nbsp;</td>
+  <td>%0S</td>
+  <td>01</td>
+ </tr>
+ <tr>
+  <td><b>Episode Number</b></td>
+  <td>%E</td>
+  <td>5</td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td>%0E</td>
+  <td>05</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td><b>Quality</b></td>
+  <td>%EQ</td>
+  <td>720p BluRay</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td>&nbsp;</td>
+  <td>%E.Q</td>
+  <td>720p.BluRay</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td>&nbsp;</td>
+  <td>%E_Q</td>
+  <td>720p_BluRay</td>
+ </tr>
+ <tr>
+  <td><b>Date</b></td>
+  <td>%AD</td>
+  <td>2010 03 22</td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td>%A_D</td>
+  <td>2010_03_22</td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td>%A.D</td>
+  <td>2010.03.22</td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td>%A-D</td>
+  <td>2010-03-22</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td><b>Year</b></td>
+  <td>%Y</td>
+  <td>2010</td>
+ </tr>
+ <tr>
+  <td><b>Month</b></td>
+  <td>%M</td>
+  <td>03</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td><b>Day</b></td>
+  <td>%D</td>
+  <td>22</td>
+ </tr>
+ <tr>
+  <td><b>Release Name</b></td>
+  <td>%RN</td>
+  <td>Show.Name.S02E03.HDTV.XviD-GROUP</td>
+ </tr>
+ <tr style="background: #efefef;">
+  <td><b>Release Group</b></td>
+  <td>%RG</td>
+  <td>GROUP</td>
+ </tr>
+</table>
+
+<br />
+Use lower case if you want lower case names (eg. %sn, %e.n, %q etc)<br />
+<br />
+                        </div>                        
+
+                        <div class="clearfix"></div>
+                        <input type="submit" class="config_submitter" value="Save Changes" /><br/>
+
+                    </fieldset>
+                </div><!-- /component-group3 //-->
+
                 <div id="core-component-group3" class="component-group clearfix">
 
                     <div class="component-group-desc">
@@ -165,132 +392,6 @@
                     </fieldset>
                 </div><!-- /component-group2 //-->
 
-                <div id="core-component-group4" class="component-group clearfix">
-
-                    <div class="component-group-desc">
-                        <h3>Episode Naming</h3>
-                        <p>If post-processing 'Rename episodes' is enabled then use these settings.</p>
-                    </div>
-
-                    #set $naming_ep_type_text = ("1x02", "s01e02", "S01E02")
-                    #set $naming_multi_ep_type_text = ("extend", "duplicate", "repeat")
-                    
-                    <fieldset class="component-group-list">
-                        <div class="field-pair">
-                            <input type="checkbox" name="naming_show_name" id="naming_show_name" #if $sickbeard.NAMING_SHOW_NAME then "checked=\"checked\"" else ""#/>
-                            <label class="clearfix" for="naming_show_name">
-                                <span class="component-title">Show Name</span>
-                                <span class="component-desc">Include the TV show's name when renaming the file?</span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <input type="checkbox" name="naming_ep_name" id="naming_ep_name" #if $sickbeard.NAMING_EP_NAME then "checked=\"checked\"" else ""#/>
-                            <label class="clearfix" for="naming_ep_name">
-                                <span class="component-title">Episode Name</span>
-                                <span class="component-desc">Include the TV show's episode title when renaming the file?</span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <input type="checkbox" name="naming_use_periods" id="naming_use_periods" #if $sickbeard.NAMING_USE_PERIODS then "checked=\"checked\"" else ""#/>
-                            <label class="clearfix" for="naming_use_periods">
-                                <span class="component-title">Use Periods</span>
-                                <span class="component-desc">Replace the spaces with periods in the filename instead?</span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <input type="checkbox" name="naming_quality" id="naming_quality" #if $sickbeard.NAMING_QUALITY then "checked=\"checked\"" else ""#/>
-                            <label class="clearfix" for="naming_quality">
-                                <span class="component-title">Quality</span>
-                                <span class="component-desc">Append the show quality to the end of the filename?</span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <input type="checkbox" name="naming_dates" id="naming_dates" #if $sickbeard.NAMING_DATES then "checked=\"checked\"" else ""#/>
-                            <label class="clearfix" for="naming_dates">
-                                <span class="component-title">Air-By-Date Format</span>
-                                <span class="component-desc">Use the date instead of the season/episode format?</span>
-                            </label>
-                            <label class="nocheck clearfix">
-                                <span class="component-title">&nbsp;</span>
-                                <span class="component-desc">Only applies to air-by-date shows. (eg. 2010-02-15 vs S12E23)</span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <label class="nocheck clearfix" for="naming_sep_type">
-                                <span class="component-title">Separator Style</span>
-                                <span class="component-desc">
-                                    <select name="naming_sep_type" id="naming_sep_type">
-                                    #for ($i, $ex) in enumerate($config.naming_sep_type_text):
-                                    <option value="$i" #if $i == int($sickbeard.NAMING_SEP_TYPE) then "selected=\"selected\"" else ""#>$ex</option>
-                                    #end for
-                                    </select>
-                                </span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <label class="nocheck clearfix" for="naming_ep_type">
-                                <span class="component-title">Number Style</span>
-                                <span class="component-desc">
-                                    <select name="naming_ep_type" id="naming_ep_type">
-                                    #for ($i, $ex) in enumerate($config.naming_ep_type_text):
-                                    <option value="$i" #if $i == int($sickbeard.NAMING_EP_TYPE) then "selected=\"selected\"" else ""#>$ex</option>
-                                    #end for
-                                    </select>
-                                </span>
-                            </label>
-                        </div>
-                        
-                        <div class="field-pair" style="padding:10px; background: #efefef;">
-                            <label class="clearfix" for="naming_ep_type">
-                                <span class="component-title jumbo">Single-Ep Example:</span>
-                                <span class="component-desc jumbo" id="normalExampleText"></span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair">
-                            <label class="nocheck clearfix" for="naming_multi_ep_type">
-                                <span class="component-title">Multi-episode Style</span>
-                                <span class="component-desc">
-                                    <select name="naming_multi_ep_type" id="naming_multi_ep_type">
-                                    #for ($i, $ex) in enumerate($config.naming_multi_ep_type_text):
-                                    <option value="$i" #if $i == int($sickbeard.NAMING_MULTI_EP_TYPE) then "selected=\"selected\"" else ""#>$ex</option>
-                                    #end for
-                                    </select>
-                                </span>
-                            </label>
-                        </div>
-
-                        <div class="field-pair" style="padding:10px; background: #efefef;">
-                            <label class="clearfix" for="naming_multi_ep_type">
-                                <span class="component-title jumbo">Multi-Ep Example:</span>
-                                <span class="component-desc jumbo" id="multiExampleText"></span>
-                            </label>
-                        </div>
-                        
-                        <div class="field-pair">
-                            <label class="nocheck clearfix">
-                                <span class="component-title">Season Folder Format</span>
-                                <input type="text" id="season_folders_format" name="season_folders_format" value="$sickbeard.SEASON_FOLDERS_FORMAT" size="15" />
-                            </label>
-                            <label class="nocheck clearfix">
-                                <span class="component-title">&nbsp;</span>
-                                <span class="component-desc">Format to use when creating season folders.</span>
-                            </label>
-                            <label class="nocheck clearfix">
-                                <span class="component-title">&nbsp;</span>
-                                <span class="component-desc">(eg. 'Season %0d' or 'season%02d')</span>
-                            </label>
-                        </div>
-
-                        <input type="submit" class="config_submitter" value="Save Changes" />
-                    </fieldset>
-                </div><!-- /component-group4 //-->
 
             <br/><input type="submit" class="config_submitter" value="Save Changes" /><br/>
             </div><!-- /config-components -->
diff --git a/data/js/configPostProcessing.js b/data/js/configPostProcessing.js
index b23562daf508ce2a1dd4fb20a1e67939f49f24bc..a17e3116177b4659ace9a63a37293afd6de831e3 100644
--- a/data/js/configPostProcessing.js
+++ b/data/js/configPostProcessing.js
@@ -1,61 +1,72 @@
 $(document).ready(function(){
 
-    $.fn.setExampleText = function() { 
-
-        params = {'show_name': $('#naming_show_name').prop('checked')?"1":"0",
-                  'ep_type': $('#naming_ep_type :selected').val(),
-                  'multi_ep_type': $('#naming_multi_ep_type :selected').val(),
-                  'ep_name': $('#naming_ep_name').prop('checked')?"1":"0",
-                  'use_periods': $('#naming_use_periods').prop('checked')?"1":"0",
-                  'quality': $('#naming_quality').prop('checked')?"1":"0",
-                  'sep_type': $('#naming_sep_type :selected').val(),
-                  'whichTest': 'single'
-                  }
-        
-        $.get(sbRoot+"/config/postProcessing/testNaming", params,
-              function(data){
-                  $('#normalExampleText').text(data);
-        });
-
-        params['whichTest'] = 'multi'
-        $.get(sbRoot+"/config/postProcessing/testNaming", params,
-              function(data){
-                  $('#multiExampleText').text(data);
-        });
-
-        return
-
-    };
-
-  $(this).setExampleText();
-
-  $('#naming_ep_name').click(function(){
-        $(this).setExampleText();
-    });  
-
-  $('#naming_show_name').click(function(){
-        $(this).setExampleText();
-    });  
-
-  $('#naming_use_periods').click(function(){
-        $(this).setExampleText();
-    });  
-
-  $('#naming_quality').click(function(){
-        $(this).setExampleText();
-    });  
-
-  $('#naming_multi_ep_type').change(function(){
-        $(this).setExampleText();
-    });  
-
-  $('#naming_ep_type').change(function(){
-        $(this).setExampleText();
-    });  
-
-  $('#naming_sep_type').change(function(){
-        $(this).setExampleText();
-    });  
+	function fill_examples() {
+
+		var dir_pattern = $('#naming_dir_pattern').val();
+		var name_pattern = $('#naming_name_pattern').val();
+		
+		var pattern = dir_pattern + '/' + name_pattern;
+		var multi = $('#naming_multi_ep :selected').val();
+		
+		$.get(sbRoot+'/config/postProcessing/testNaming', {pattern: pattern},
+			function(data){
+				$('#naming_example').text(data+'.ext');
+		});
+
+		$.get(sbRoot+'/config/postProcessing/testNaming', {pattern: pattern, multi: multi},
+			function(data){
+				$('#naming_example_multi').text(data+'.ext');
+		});
+	}
+	
+	function do_custom_help() {
+		var show_help = false;
+		$('.naming_custom_span').each(function(){
+			if ($(this).is(':visible')) {
+				show_help = true;
+				return false;
+			}
+		});
+
+		if (show_help)
+			$('#naming_custom_help').show();
+		else
+			$('#naming_custom_help').hide();
+	}
+	
+	function do_preset(me) {
+		
+		var preset = $(me+' :selected').attr('id');
+
+		if (preset == 'none')
+			preset = '';
+		
+		if (preset == 'custom')
+			$(me).parent().siblings('.naming_custom_span').show();
+		else
+			$(me).parent().siblings('.naming_custom_span').hide();
+
+		if (preset != 'custom')
+			$(me).parent().siblings('.naming_custom_span').children('.component-desc').children('.naming_pattern').val(preset);
+
+		fill_examples();
+		
+		do_custom_help();
+	}
+
+	// initialize the presets
+	do_preset('#dir_presets');
+	do_preset('#name_presets');
+	
+	$('.naming_preset_select').change(function(){
+		var me = '#'+$(this).attr('id');
+		do_preset(me);
+	});
+	
+	$('#naming_multi_ep').change(fill_examples);
+	$('.naming_pattern').change(fill_examples);
+
+	
 
     // -- start of metadata options div toggle code --
     $('#metadataType').change(function(){
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index c20fc5f8d075fbb9a1e46e5be53a4303493dcc8e..10fe0e6636438cc96c21c34152b3b6fe118beba5 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -36,7 +36,7 @@ from sickbeard import searchCurrent, searchBacklog, showUpdater, versionChecker,
 from sickbeard import helpers, db, exceptions, show_queue, search_queue, scheduler
 from sickbeard import logger
 
-from sickbeard.common import *
+from common import SD, SKIPPED, NAMING_REPEAT
 
 from sickbeard.databases import mainDB, cache_db
 
@@ -117,20 +117,18 @@ METADATA_PS3 = None
 METADATA_WDTV = None
 METADATA_TIVO = None
 
+MULTI_FORMAT = NAMING_REPEAT
+NAME_FORMATTING = r'%RN/%0Sx%0E - %E.N (%RG)'
+
 QUALITY_DEFAULT = None
 STATUS_DEFAULT = None
 SEASON_FOLDERS_FORMAT = None
 SEASON_FOLDERS_DEFAULT = None
 PROVIDER_ORDER = []
 
-NAMING_SHOW_NAME = None
-NAMING_EP_NAME = None
-NAMING_EP_TYPE = None
-NAMING_MULTI_EP_TYPE = None
-NAMING_SEP_TYPE = None
-NAMING_USE_PERIODS = None
-NAMING_QUALITY = None
-NAMING_DATES = None
+NAMING_MULTI_EP = None
+NAMING_DIR_PATTERN = None
+NAMING_NAME_PATTERN = None
 
 TVDB_API_KEY = '9DAF49C96CBF8DAC'
 TVDB_BASE_URL = None
@@ -386,11 +384,10 @@ def initialize(consoleLogging=True):
                 NZBMATRIX_APIKEY, versionCheckScheduler, VERSION_NOTIFY, PROCESS_AUTOMATICALLY, \
                 KEEP_PROCESSED_DIR, TV_DOWNLOAD_DIR, TVDB_BASE_URL, MIN_SEARCH_FREQUENCY, \
                 showQueueScheduler, searchQueueScheduler, ROOT_DIRS, \
-                NAMING_SHOW_NAME, NAMING_EP_TYPE, NAMING_MULTI_EP_TYPE, CACHE_DIR, ACTUAL_CACHE_DIR, TVDB_API_PARMS, \
+                NAMING_DIR_PATTERN, NAMING_NAME_PATTERN, NAMING_MULTI_EP, CACHE_DIR, ACTUAL_CACHE_DIR, TVDB_API_PARMS, \
                 RENAME_EPISODES, properFinderScheduler, PROVIDER_ORDER, autoPostProcesserScheduler, \
-                NAMING_EP_NAME, NAMING_SEP_TYPE, NAMING_USE_PERIODS, WOMBLE, \
-                NZBSRUS, NZBSRUS_UID, NZBSRUS_HASH, NAMING_QUALITY, providerList, newznabProviderList, \
-                NAMING_DATES, EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \
+                NZBSRUS, NZBSRUS_UID, NZBSRUS_HASH, WOMBLE, providerList, newznabProviderList, \
+                EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \
                 USE_NOTIFO, NOTIFO_USERNAME, NOTIFO_APISECRET, NOTIFO_NOTIFY_ONDOWNLOAD, NOTIFO_NOTIFY_ONSNATCH, \
                 USE_BOXCAR, BOXCAR_USERNAME, BOXCAR_PASSWORD, BOXCAR_NOTIFY_ONDOWNLOAD, BOXCAR_NOTIFY_ONSNATCH, \
                 USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_SYNOINDEX, \
@@ -498,14 +495,9 @@ def initialize(consoleLogging=True):
 
         PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split()
 
-        NAMING_SHOW_NAME = bool(check_setting_int(CFG, 'General', 'naming_show_name', 1))
-        NAMING_EP_NAME = bool(check_setting_int(CFG, 'General', 'naming_ep_name', 1))
-        NAMING_EP_TYPE = check_setting_int(CFG, 'General', 'naming_ep_type', 0)
-        NAMING_MULTI_EP_TYPE = check_setting_int(CFG, 'General', 'naming_multi_ep_type', 0)
-        NAMING_SEP_TYPE = check_setting_int(CFG, 'General', 'naming_sep_type', 0)
-        NAMING_USE_PERIODS = bool(check_setting_int(CFG, 'General', 'naming_use_periods', 0))
-        NAMING_QUALITY = bool(check_setting_int(CFG, 'General', 'naming_quality', 0))
-        NAMING_DATES = bool(check_setting_int(CFG, 'General', 'naming_dates', 1))
+        NAMING_DIR_PATTERN = check_setting_str(CFG, 'General', 'naming_dir_pattern', '')
+        NAMING_NAME_PATTERN = check_setting_str(CFG, 'General', 'naming_ep_name', '')
+        NAMING_MULTI_EP = check_setting_int(CFG, 'General', 'naming_multi_ep', 1)
 
         TVDB_BASE_URL = 'http://www.thetvdb.com/api/' + TVDB_API_KEY
 
@@ -1005,14 +997,9 @@ def save_config():
     new_config['General']['season_folders_default'] = int(SEASON_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_ep_name'] = int(NAMING_EP_NAME)
-    new_config['General']['naming_show_name'] = int(NAMING_SHOW_NAME)
-    new_config['General']['naming_ep_type'] = int(NAMING_EP_TYPE)
-    new_config['General']['naming_multi_ep_type'] = int(NAMING_MULTI_EP_TYPE)
-    new_config['General']['naming_sep_type'] = int(NAMING_SEP_TYPE)
-    new_config['General']['naming_use_periods'] = int(NAMING_USE_PERIODS)
-    new_config['General']['naming_quality'] = int(NAMING_QUALITY)
-    new_config['General']['naming_dates'] = int(NAMING_DATES)
+    new_config['General']['naming_ep_name'] = NAMING_DIR_PATTERN
+    new_config['General']['naming_show_name'] = NAMING_NAME_PATTERN
+    new_config['General']['naming_multi_ep_type'] = int(NAMING_MULTI_EP)
     new_config['General']['launch_browser'] = int(LAUNCH_BROWSER)
 
     new_config['General']['use_banner'] = int(USE_BANNER)
diff --git a/sickbeard/common.py b/sickbeard/common.py
index 51f2bf86c98cd94292a711e0d67349be73c19be0..f3ddb43d7ac8f453c2d85ad703c386490f385a46 100644
--- a/sickbeard/common.py
+++ b/sickbeard/common.py
@@ -53,6 +53,15 @@ ARCHIVED = 6 # episodes that you don't have locally (counts toward download comp
 IGNORED = 7 # episodes that you don't want included in your download stats
 SNATCHED_PROPER = 9 # qualified with quality
 
+NAMING_REPEAT = 1
+NAMING_EXTEND = 2
+NAMING_DUPLICATE = 4
+
+multiEpStrings = {}
+multiEpStrings[NAMING_REPEAT] = "Repeat"
+multiEpStrings[NAMING_DUPLICATE] = "Duplicate"
+multiEpStrings[NAMING_EXTEND] = "Extend"
+
 class Quality:
 
     NONE = 0
diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py
index 05b70cf7c749e8f84a1cfb00795c85480c60349b..1edad2f320d9e96a70cfff467cee4a6a6cb4f687 100644
--- a/sickbeard/databases/mainDB.py
+++ b/sickbeard/databases/mainDB.py
@@ -356,10 +356,53 @@ class PopulateRootDirs (AddLang):
         
         self.incDBVersion()
         
-class AddSizeAndSceneNameFields(SetNzbTorrentSettings):
+class SetNzbTorrentSettings(PopulateRootDirs):
 
+    def test(self):
+        return self.checkDBVersion() >= 8
+    
+    def execute(self):
+
+        use_torrents = False
+        use_nzbs = False
+
+        for cur_provider in sickbeard.providers.sortedProviderList():
+            if cur_provider.isEnabled():
+                if cur_provider.providerType == GenericProvider.NZB:
+                    use_nzbs = True
+                    logger.log(u"Provider "+cur_provider.name+" is enabled, enabling NZBs in the upgrade")
+                    break
+                elif cur_provider.providerType == GenericProvider.TORRENT:
+                    use_torrents = True
+                    logger.log(u"Provider "+cur_provider.name+" is enabled, enabling Torrents in the upgrade")
+                    break
+
+        sickbeard.USE_TORRENTS = use_torrents
+        sickbeard.USE_NZBS = use_nzbs
+        
+        sickbeard.save_config()
+        
+        self.incDBVersion()
+
+class FixAirByDateSetting(SetNzbTorrentSettings):
+    
     def test(self):
         return self.checkDBVersion() >= 9
+
+    def execute(self):
+        
+        shows = self.connection.select("SELECT * FROM tv_shows")
+        
+        for cur_show in shows:
+            if cur_show["genre"] and "talk show" in cur_show["genre"].lower():
+                self.connection.action("UPDATE tv_shows SET air_by_date = ? WHERE tvdb_id = ?", [1, cur_show["tvdb_id"]])
+        
+        self.incDBVersion()
+
+class AddSizeAndSceneNameFields(FixAirByDateSetting):
+
+    def test(self):
+        return self.checkDBVersion() >= 10
     
     def execute(self):
 
@@ -425,45 +468,4 @@ class AddSizeAndSceneNameFields(SetNzbTorrentSettings):
                     break
 
         self.incDBVersion()
-        class SetNzbTorrentSettings(PopulateRootDirs):
 
-    def test(self):
-        return self.checkDBVersion() >= 8
-    
-    def execute(self):
-
-        use_torrents = False
-        use_nzbs = False
-
-        for cur_provider in sickbeard.providers.sortedProviderList():
-            if cur_provider.isEnabled():
-                if cur_provider.providerType == GenericProvider.NZB:
-                    use_nzbs = True
-                    logger.log(u"Provider "+cur_provider.name+" is enabled, enabling NZBs in the upgrade")
-                    break
-                elif cur_provider.providerType == GenericProvider.TORRENT:
-                    use_torrents = True
-                    logger.log(u"Provider "+cur_provider.name+" is enabled, enabling Torrents in the upgrade")
-                    break
-
-        sickbeard.USE_TORRENTS = use_torrents
-        sickbeard.USE_NZBS = use_nzbs
-        
-        sickbeard.save_config()
-        
-        self.incDBVersion()
-
-class FixAirByDateSetting(SetNzbTorrentSettings):
-    
-    def test(self):
-        return self.checkDBVersion() >= 9
-
-    def execute(self):
-        
-        shows = self.connection.select("SELECT * FROM tv_shows")
-        
-        for cur_show in shows:
-            if cur_show["genre"] and "talk show" in cur_show["genre"].lower():
-                self.connection.action("UPDATE tv_shows SET air_by_date = ? WHERE tvdb_id = ?", [1, cur_show["tvdb_id"]])
-        
-        self.incDBVersion()
diff --git a/sickbeard/tv.py b/sickbeard/tv.py
index a2f08116f64dc4a2d5397631135717cc90fbc5b3..fb6f4e4b8e73ee7f8b93b1cd45412e386f15f606 100644
--- a/sickbeard/tv.py
+++ b/sickbeard/tv.py
@@ -44,6 +44,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
 
 class TVShow(object):
 
@@ -1480,3 +1481,143 @@ class TVEpisode(object):
 
         return finalName
 
+    def _replace_map(self):
+        def dot(name):
+            return name.replace(' ','.')
+        
+        def us(name):
+            return name.replace(' ','_')
+        
+        def release_group(name):
+            if not name or '-' not in name:
+                return ''
+            return name.split('-')[-1]
+
+        epStatus, epQual = Quality.splitCompositeStatus(self.status) #@UnusedVariable
+        
+        return {
+                       '%SN': self.show.name,
+                       '%S.N': dot(self.show.name),
+                       '%S_N': us(self.show.name),
+                       '%EN': self.name,
+                       '%E.N': dot(self.name),
+                       '%E_N': us(self.name),
+                       '%QN': Quality.qualityStrings[epQual],
+                       '%Q.N': dot(Quality.qualityStrings[epQual]),
+                       '%Q_N': us(Quality.qualityStrings[epQual]),
+                       '%S': str(self.season),
+                       '%0S': '%02d' % self.season,
+                       '%E': str(self.episode),
+                       '%0E': '%02d' % self.episode,
+                       '%RN': self.release_name,
+                       '%RG': release_group(self.release_name),
+                       }
+
+    def _formatted_string(self, pattern=None, multi=None):
+        
+        replace_map = self._replace_map()
+        
+        if pattern == None:
+            pattern = sickbeard.NAME_FORMATTING
+        
+        if multi == None:
+            multi = sickbeard.MULTI_FORMAT
+        
+        # split off ep name part only
+        name_groups = re.split(r'[\\/]', pattern)
+        
+        result_name = pattern
+        
+        # figure out the double-ep naming style for each group, if applicable
+        for cur_name_group in name_groups:
+        
+            season_format = sep = ep_sep = ep_format = None
+        
+            season_ep_regex = '''
+                                (?P<pre_sep>[ _.-]*)
+                                ((?:s(?:eason|eries)?\s*)?%0?S(?![._]?N))
+                                (.*?)
+                                (%0?E(?![._]?N))
+                                (?P<post_sep>[ _.-]*)
+                              '''
+            ep_only_regex = '(%0?E(?![._]?N))'
+        
+            # try the normal way
+            season_ep_match = re.search(season_ep_regex, cur_name_group, re.I|re.X)
+            ep_only_match = re.search(ep_only_regex, cur_name_group, re.I|re.X)
+            
+            # if we have a season and episode then collect the necessary data
+            if season_ep_match:
+                season_format = season_ep_match.group(2)
+                ep_sep = season_ep_match.group(3)
+                ep_format = season_ep_match.group(4)
+                sep = season_ep_match.group('pre_sep')
+                if not sep:
+                    sep = season_ep_match.group('post_sep')
+                if not sep:
+                    sep = ' '
+
+                # force 2-3-4 format if they chose to extend
+                if multi == NAMING_EXTEND:
+                    ep_sep = '-'
+
+            # if there's no season then there's not much choice so we'll just force them to use 03-04-05 style
+            elif ep_only_match:
+                season_format = ''
+                ep_sep = '-'
+                ep_format = ep_only_match.group(1)
+                sep = ''
+
+            # we need at least this much info to continue
+            if not ep_sep or not ep_format:
+                continue
+            
+            # start with the ep string, eg. E03
+            ep_string = replace_map[ep_format.upper()]
+            for other_eps in self.relatedEps:
+                if multi == NAMING_DUPLICATE:
+                    # add " - S01"
+                    ep_string += sep + season_format
+                # add "E04"
+                ep_string += ep_sep
+                ep_string += other_eps._replace_map()[ep_format.upper()]
+
+            # fill out the template for this piece and then insert this piece into the actual pattern
+            cur_name_group_result = cur_name_group.replace(ep_format, ep_string)
+            result_name = result_name.replace(cur_name_group, cur_name_group_result)
+        
+        # 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())
+        
+        return result_name
+
+    def formatted_dir(self, pattern=None, multi=None):
+        """
+        Just the folder name of the episode
+        """
+        
+        if pattern == None:
+            pattern = sickbeard.NAME_FORMATTING
+        
+        # split off the dirs only, if they exist
+        name_groups = re.split(r'[\\/]', pattern)
+        
+        if len(name_groups) == 1:
+            return ''
+        else:
+            return self._formatted_string(os.sep.join(name_groups[:-1]), multi)
+
+    def formatted_filename(self, pattern=None, multi=None):
+        """
+        Just the filename of the episode, formatted based on the naming settings
+        """
+        
+        if pattern == None:
+            pattern = sickbeard.NAME_FORMATTING
+        
+        # split off the filename only, if they exist
+        name_groups = re.split(r'[\\/]', pattern)
+
+        return self._formatted_string(name_groups[-1], multi)
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index fb65fa17d5691801aeba4ca10064c6e9373c57f8..12428aff872dfbeb384f6c75699575d00e0bc2c5 100755
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -39,6 +39,7 @@ from sickbeard import logger, helpers, exceptions, classes, db
 from sickbeard import encodingKludge as ek
 from sickbeard import search_queue
 from sickbeard import image_cache
+from sickbeard import naming
 
 from sickbeard.providers import newznab
 from sickbeard.common import Quality, Overview, statusStrings
@@ -823,9 +824,7 @@ class ConfigPostProcessing:
         return _munge(t)
 
     @cherrypy.expose
-    def savePostProcessing(self, season_folders_format=None, naming_show_name=None, naming_ep_type=None,
-                    naming_multi_ep_type=None, naming_ep_name=None, naming_use_periods=None,
-                    naming_sep_type=None, naming_quality=None, naming_dates=None,
+    def savePostProcessing(self, season_folders_format=None, naming_dir_pattern=None, naming_name_pattern=None, naming_multi_ep=None,
                     xbmc_data=None, mediabrowser_data=None, sony_ps3_data=None, wdtv_data=None, tivo_data=None,
                     use_banner=None, keep_processed_dir=None, process_automatically=None, rename_episodes=None,
                     move_associated_files=None, tv_download_dir=None):
@@ -835,31 +834,6 @@ class ConfigPostProcessing:
         if not config.change_TV_DOWNLOAD_DIR(tv_download_dir):
             results += ["Unable to create directory " + os.path.normpath(tv_download_dir) + ", dir not changed."]
 
-        if naming_show_name == "on":
-            naming_show_name = 1
-        else:
-            naming_show_name = 0
-
-        if naming_ep_name == "on":
-            naming_ep_name = 1
-        else:
-            naming_ep_name = 0
-
-        if naming_use_periods == "on":
-            naming_use_periods = 1
-        else:
-            naming_use_periods = 0
-
-        if naming_quality == "on":
-            naming_quality = 1
-        else:
-            naming_quality = 0
-
-        if naming_dates == "on":
-            naming_dates = 1
-        else:
-            naming_dates = 0
-
         if use_banner == "on":
             use_banner = 1
         else:
@@ -898,14 +872,9 @@ class ConfigPostProcessing:
         
         sickbeard.SEASON_FOLDERS_FORMAT = season_folders_format
 
-        sickbeard.NAMING_SHOW_NAME = naming_show_name
-        sickbeard.NAMING_EP_NAME = naming_ep_name
-        sickbeard.NAMING_USE_PERIODS = naming_use_periods
-        sickbeard.NAMING_QUALITY = naming_quality
-        sickbeard.NAMING_DATES = naming_dates
-        sickbeard.NAMING_EP_TYPE = int(naming_ep_type)
-        sickbeard.NAMING_MULTI_EP_TYPE = int(naming_multi_ep_type)
-        sickbeard.NAMING_SEP_TYPE = int(naming_sep_type)
+        sickbeard.NAMING_DIR_PATTERN = naming_dir_pattern
+        sickbeard.NAMING_NAME_PATTERN = naming_name_pattern
+        sickbeard.NAMING_MULTI_EP = int(naming_multi_ep)
 
         sickbeard.USE_BANNER = use_banner
 
@@ -922,86 +891,18 @@ class ConfigPostProcessing:
         redirect("/config/postProcessing/")
 
     @cherrypy.expose
-    def testNaming(self, show_name=None, ep_type=None, multi_ep_type=None, ep_name=None,
-                   sep_type=None, use_periods=None, quality=None, whichTest="single"):
-
-        if show_name == None:
-            show_name = sickbeard.NAMING_SHOW_NAME
-        else:
-            if show_name == "0":
-                show_name = False
-            else:
-                show_name = True
-
-        if ep_name == None:
-            ep_name = sickbeard.NAMING_EP_NAME
-        else:
-            if ep_name == "0":
-                ep_name = False
-            else:
-                ep_name = True
-
-        if use_periods == None:
-            use_periods = sickbeard.NAMING_USE_PERIODS
-        else:
-            if use_periods == "0":
-                use_periods = False
-            else:
-                use_periods = True
-
-        if quality == None:
-            quality = sickbeard.NAMING_QUALITY
-        else:
-            if quality == "0":
-                quality = False
-            else:
-                quality = True
-
-        if ep_type == None:
-            ep_type = sickbeard.NAMING_EP_TYPE
-        else:
-            ep_type = int(ep_type)
-
-        if multi_ep_type == None:
-            multi_ep_type = sickbeard.NAMING_MULTI_EP_TYPE
-        else:
-            multi_ep_type = int(multi_ep_type)
-
-        if sep_type == None:
-            sep_type = sickbeard.NAMING_SEP_TYPE
-        else:
-            sep_type = int(sep_type)
-
-        class TVShow():
-            def __init__(self):
-                self.name = "Show Name"
-                self.genre = "Comedy"
-                self.air_by_date = 0
-
-        # fake a TVShow (hack since new TVShow is coming anyway)
-        class TVEpisode(tv.TVEpisode):
-            def __init__(self, season, episode, name):
-                self.relatedEps = []
-                self._name = name
-                self._season = season
-                self._episode = episode
-                self.show = TVShow()
-
-
-        # make a fake episode object
-        ep = TVEpisode(1,2,"Ep Name")
-        ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV)
+    def testNaming(self, pattern=None, multi=False):
 
-        if whichTest == "multi":
-            ep._name = "Ep Name (1)"
-            secondEp = TVEpisode(1,3,"Ep Name (2)")
-            ep.relatedEps.append(secondEp)
+        if multi != False:
+            multi = int(multi)
 
-        # get the name
-        name = ep.prettyName(show_name, ep_type, multi_ep_type, ep_name, sep_type, use_periods, quality)
-
-        return name
+        result = naming.test_name(pattern, multi)
+        
+        result = ek.ek(os.path.join, result['dir'], result['name']) 
 
+        return result
+        
+        
 class ConfigProviders:
 
     @cherrypy.expose