#!/usr/bin/env python

# Author: Shannon Brooks <http://www.brooksworks.com>

# Version: 1.2 beta

#

# This file is supplementary to SickBeard.

#

# This file will allow you to set season modifiers as custom categories

# in SABnzbd, which will then be used to modify the Season and/or Episode

# numbers before submitting the files to SickBeard.

#

# Also fixes issues with releases using the s00e00a format that some

# release groups use for split episodes, but that SickBeard doesn't

# recognize.

#

# To use:

# 1. Place this script into your autoProcessTV scripts directory

# 2. Create a custom category that includes a modifier (below)

# 3. Assign the category to show downloads where the season/episode

# is incorrect and set the proccessing for those episodes to use

# FixSeasons.py

# (I use RSS to accomplish this)

#

# Alternative Instructions: http://imgur.com/a/KkbEB

#

#

# Modifier Format:

#

# [+|-][integer][S|E|s|e]

#

# Category Name Examples:

# "+1S" S05E05 -> S06E05

# "-1S" S05E05 -> S04E05

# "+1E" S05E05 -> S05E06

# "-1E" S05E05 -> S05E04

# "+1S -1E" S05E05 -> S06E04

# "TV +1s" S05E05 -> S06E05

#

#

# Issues:

# - SABnzbd on Windows doesn't recognize *.py files if Python

# installed from zip; fix by creating a bootstrap file:

# http://pastebin.com/5DiTecWg

#

# Change Log:

# 1.2 beta

# - handle error conditions from SABnzbd

# 1.1 beta

# - made rename function recursive for bundled downloads

# - added extra verbosity for tracking changes

# - added checks to see if directory or file already exists

# 1.0 beta

# - initial release

import sys

import autoProcessTV

import glob , os , re

def getSeasonOffset ( category ) :

match = re . search ( r "(?ix)([+-] \d +)s" , category )

if match:

return eval ( "0" +match. group ( 1 ) )

else :

return 0

def getEpisodeOffset ( category ) :

match = re . search ( r "(?ix)([+-] \d +)e" , category )

if match:

return eval ( "0" +match. group ( 1 ) )

else :

return 0

def getPatterns ( string , season , episode ) :

# matches s00e00

match = re . search ( r "(?ix) \b (s0*( \d +)e0*( \d +)) \b " , string )

if match:

se = eval ( "0+" +match. group ( 2 ) ) + season

ep = eval ( "0+" +match. group ( 3 ) ) + episode

search = match. group ( 1 )

replace = "S%02dE%02d" % ( se , ep )

return { 'search' :search , 'replace' :replace }

# matches and fixes s00e00a

match = re . search ( r "(?ix) \b (s0*( \d +)e0*( \d +)([ab])) \b " , string )

if match:

se = eval ( "0+" +match. group ( 2 ) ) + season

ep = eval ( "0+" +match. group ( 3 ) )

if match. group ( 4 ) . lower ( ) == "a" :

ep = ( ep * 2 ) - 1 + episode

else :

ep = ( ep * 2 ) + episode

search = match. group ( 1 )

replace = "S%02dE%02d" % ( se , ep )

return { 'search' :search , 'replace' :replace }

# matches 0x00

match = re . search ( r "(?ix) \b (0*( \d +)x0*( \d +)) \b " , string )

if match:

se = eval ( "0+" +match. group ( 2 ) ) + season

ep = eval ( "0+" +match. group ( 3 ) ) + episode

search = match. group ( 1 )

replace = "S%02dE%02d" % ( se , ep )

return { 'search' :search , 'replace' :replace }

# no match, return false

return False

def replaceSeasonInString ( strInput , intSeasonOffset , intEpisodeOffset ) :

pattern = getPatterns ( strInput , intSeasonOffset , intEpisodeOffset )

if not pattern:

return strInput

else :

return re . sub ( pattern [ 'search' ] , pattern [ 'replace' ] , strInput )

def renameDownload ( strBasePathname , intSeasonOffset , intEpisodeOffset ) :

# rename base directory

strDirectory = os . path . basename ( strBasePathname )

strNewDirectory = replaceSeasonInString ( strDirectory , intSeasonOffset , intEpisodeOffset )

if strNewDirectory != strDirectory:

strNewBasePathname = os . path . join ( os . path . dirname ( strBasePathname ) , strNewDirectory )

if os . path . exists ( strNewBasePathname ) :

print "ERROR: Renamed download already exists, you will have to manually clean up your download folder."

sys . exit ( )

else :

os . rename ( strBasePathname , strNewBasePathname )

print " Original: " , strBasePathname

print " Updated: " , strNewBasePathname

print ""

strBasePathname = strNewBasePathname

# rename files in base directory

strFilepath = strBasePathname + "/*"

for strPathname in glob . glob ( strFilepath ) :

if os . path . isdir ( strPathname ) :

renameDownload ( strPathname , intSeasonOffset , intEpisodeOffset )

else :

strFilename = os . path . basename ( strPathname )

strNewFilename = replaceSeasonInString ( strFilename , intSeasonOffset , intEpisodeOffset )

if strNewFilename != strFilename:

strNewPathname = os . path . join ( os . path . dirname ( strPathname ) , strNewFilename )

if os . path . exists ( strNewPathname ) :

print "WARNING: Renamed file \" " +strNewPathname+ " \" already exists in directory, skipping."

else :

print " Original: " , strPathname

print " Updated: " , strNewPathname

print ""

os . rename ( strPathname , strNewPathname )

# return new directory name

return strBasePathname

if len ( sys . argv ) < 8 :

print "Missing nessesary info! - Is this being called from SABnzbd?"

sys . exit ( 99 )

elif eval ( sys . argv [ 7 ] ) > 0 :

print "Download appears not to have completed successfully, please check and process manually."

sys . exit ( eval ( sys . argv [ 7 ] ) )

else :

print "Renaming download...



"

intSeasonOffset = getSeasonOffset ( sys . argv [ 5 ] )

intEpisodeOffset = getEpisodeOffset ( sys . argv [ 5 ] )

strEpisodeDirectory = renameDownload ( sys . argv [ 1 ] , intSeasonOffset , intEpisodeOffset )

strNZBFileName = replaceSeasonInString ( sys . argv [ 2 ] , intSeasonOffset , intEpisodeOffset )

print ""

print "-- SENT TO SICKBEARD --"

print ""

print "Episode Directory"

print " Original: " , sys . argv [ 1 ]

print " Updated: " , strEpisodeDirectory

print ""

print "NZB File Name"

print " Original: " , sys . argv [ 2 ]

print " Updated: " , strNZBFileName

print ""

print "-- SENT TO SICKBEARD --"

print ""