#!/usr/bin/env python
import errno
import os
import re
import shutil
import string
import sys
import tvdb_api
from tvdb_exceptions import tvdb_error, tvdb_shownotfound


CONFIG_FILE = '/etc/sabnzbd/scripts.conf'
EXTENSIONS = ['avi', 'm4v', 'mkv', 'mp4']
PATTERN = re.compile('^(.*)[\._]s(\d+)e(\d+)(.*)', re.I)


def get_config(cfgfile):
    config = {}
    with open(cfgfile) as fh:
        for line in fh:
            k, v = re.split('\s+=\s+', line, 1)
            config[k] = v.strip()
    return config


def get_canonical_name(name):
    """
    Translates a dotted filename into the real name with spaces while
    preserving acronyms.
    """
    if not name.endswith('.'):
        name += '.'

    regex = '((?:[A-Z]\.)+)'
    acronyms = re.findall(regex, name)
    parts = re.split(regex, name)

    if not parts:
        return name

    canonical_name = []
    for part in parts:
        if part in acronyms:
            part = re.sub('\.$', '', part)
        else:
            part = part.replace('.', ' ')
        canonical_name.append(part.strip())
    canonical_name = ' '.join(canonical_name)

    # look up TheTVDB for the show name
    canonical_name = get_tvdb_name(canonical_name)

    # replace trailing dots
    canonical_name = re.sub('\.+$', '', canonical_name)

    return canonical_name


def get_tvdb_name(show):
    tvdb = tvdb_api.Tvdb()
    try:
        return tvdb[show]['seriesname']
    except (tvdb_error, tvdb_shownotfound):
        return show



def mkdirp(path, mode=0755):
    try:
        os.makedirs(path, mode=mode)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

    # os.makedirs seems to randomly ignore the mode argument
    # so we have to manually set the mode on each directory
    for r, _, _ in os.walk(path):
        os.chmod(os.path.join(path, r), mode)



def main(job_dir, nzb, clean, index_num, category, group, status):
    config = get_config(CONFIG_FILE)

    # Loop through the files in ``job_dir``, trying to find one which
    # matches PATTERN. Also build a list of files and their sizes.
    #
    # If no files match PATTERN but we do find one or more files with
    # a suitable extension we assume the largest file is the one we
    # want. We take this file use the ``job_dir`` as the base for the
    # new file name.
    match = None
    files_by_size = []
    for fn in os.listdir(job_dir):
        ext = fn.rsplit('.', 1)[-1]
        if ext not in EXTENSIONS:
            continue

        abs = os.path.abspath(os.path.join(job_dir, fn))
        files_by_size.append((fn, os.path.getsize(abs)))
        match = PATTERN.match(fn)
        if match:
            break

    files_by_size = sorted(files_by_size, key=lambda x: x[1])
    original_name = None

    if not match:
        # no files at all? just exit
        if not files_by_size:
            print("No suitable files found")
            sys.exit()

        # found a potential match
        fn = files_by_size[0][0]
        match = PATTERN.match(os.path.basename(job_dir))
        if not match:
            print("No suitable files found")
            sys.exit()


    original_name = fn
    fn = os.path.join(job_dir, fn)
    dotted_name = string.capwords(match.group(1), '.').replace('_', '.')
    canonical_name = get_canonical_name(dotted_name)
    show_dir = os.path.join(config['tv_directory'], canonical_name)
    season_dir = os.path.join(show_dir, 'Season %s' % int(match.group(2)))

    filename = "%s.s%se%s.%s" % (dotted_name, match.group(2), match.group(3), ext)
    final_name = os.path.join(season_dir, filename)
    if os.path.isfile(final_name):
        print("File already exists: %s" % final_name)
        sys.exit(1)

    # create the full path to the new location, move the file over
    # and remove the old directory
    mkdirp(show_dir)
    mkdirp(season_dir)
    shutil.move(fn, final_name)
    shutil.rmtree(job_dir)

    msg = "New file: %s" % final_name
    if original_name is not None:
        msg = "%s (renamed from %s)" % (msg, original_name)
    print(msg)

    # try to remove the empty category directories
    parent_dirname = os.path.dirname(os.path.abspath(job_dir))
    parent_basename = os.path.basename(parent_dirname)
    if parent_basename.lower() == category.lower():
        try:
            os.rmdir(parent_dirname)
            print("Removed empty directory: %s" % parent_dirname)
        except OSError:
            print("Skipped non-empty directory: %s" % parent_dirname)
            pass


if __name__ == '__main__':
    main(*sys.argv[1:])

@@ -1476,17 +1476,16 @@
  show%0A%0A%0A
-%0A
 def mkdi
@@ -1694,211 +1694,8 @@
 se%0A%0A
-    # os.makedirs seems to randomly ignore the mode argument%0A    # so we have to manually set the mode on each directory%0A    for r, _, _ in os.walk(path):%0A        os.chmod(os.path.join(path, r), mode)%0A%0A%0A
 %0Adef
@@ -2107,16 +2107,20 @@
 is file 
+and 
 use the 
@@ -2150,18 +2150,18 @@
  for
- the
 %0A    #
+ the
  new
@@ -2589,33 +2589,8 @@
 %5B1%5D)
-%0A    original_name = None
 %0A%0A  
@@ -2960,32 +2960,8 @@
 ()%0A%0A
-%0A    original_name = fn%0A
     
@@ -3265,24 +3265,21 @@
 ))%0A%0A    
+v
 file
-name
  = %22%25s.s
@@ -3383,24 +3383,21 @@
 on_dir, 
+v
 file
-name
 )%0A    if
@@ -3606,29 +3606,8 @@
 ory%0A
-    mkdirp(show_dir)%0A
     
@@ -3641,18 +3641,41 @@
 il.move(
+os.path.join(job_dir, 
 fn
+)
 , final_
@@ -3712,22 +3712,22 @@
 r)%0A%0A    
-msg = 
+print(
 %22New fil
@@ -3727,28 +3727,34 @@
 New file: %25s
+ (%25s)
 %22 %25 
+(
 final_name%0A 
@@ -3755,116 +3755,31 @@
 name
-%0A    if original_name is not None:%0A        msg = %22%25s (renamed from %25s)%22 %25 (msg, original_name)%0A    print(msg
+, os.path.basename(fn))
 )%0A%0A 

Improve tv-mover.py.