Example #1
0
def files_unrar(abs_path, ext=None):
    """ Unzip rar files

    Arguments:
        abs_path {string} -- Path to the directory containg rar files
    """

    stderr = ""
    exts = ext if isinstance(ext, str) else tuple(ext)
    for rar_file in files_find_ext(abs_path, "rar"):
        files = []
        if (exts):
            process = Popen(["unrar", "lb", rar_file],
                            stdout=PIPE,
                            stderr=PIPE)
            stdout, stderr = process.communicate()
            if len(stderr) > 1: break
            files = stdout.decode("UTF-8").split("\n")
            files = [f for f in files if f.endswith(exts)]
        if (files or exts == None):
            infomsg("Found RAR archive in source directory, extract it",
                    "Postprocessing", (rar_file, ))
            process = Popen(["unrar", "x", "-o+", rar_file, abs_path],
                            stdout=PIPE,
                            stderr=PIPE)
            stderr = process.communicate()[1]
            if len(stderr) > 1: break

    if len(stderr) > 1:
        errmsg("Unrar archive failed with the following error message")
        print(stderr)
        exit()
Example #2
0
def client(scope,
           port,
           source_host,
           output_host=None,
           original_host=None,
           original_mode=0):

    ## Get the URL to the Syno-Index server and add the arguments
    url = client_get_url(scope, port)
    if not output_host:
        query_vars = {'source_host': source_host}
    else:
        query_vars = {
            "source_host": source_host,
            "output_host": output_host,
            "original_host": original_host
        }
    query_vars["original_mode"] = original_mode

    ## Call the url and get the answer of the server
    url = url + urlencode(query_vars)
    infomsg("  Source", "SynoClient", (source_host, ))
    infomsg("  Handbrake Output", "SynoClient", (output_host, ))
    infomsg("  Original", "SynoClient", (original_host, ))
    infomsg("  Original mode", "SynoClient", (original_mode, ))
    try:
        contents = urlopen(url).read()
        debugmsg("SynoIndex-Server answered with", "SynoClient",
                 (contents.decode("UTF-8"), ))
    except urllib.error.URLError:
        errmsg(
            "Server is not started yet, start the Triggered Task with the right mode"
        )
        exit()
Example #3
0
def main():
    """ Name:    VS-Handbrake (Part of the VS-Package)
        Summary: After handbrake finished the convertion process, the script is called and
                 handles the right naming for the video file and relocates it according to
                 its video type (episode or movie).
    """

    ## Get the shell arguments
    args = argparse.Namespace()
    parser = argparse.ArgumentParser(description='Naming and locate script for Handbrake docker container')
    parser.add_argument('-f','--file', help='Path to the video file', required=True)
    args = parser.parse_args()
    args.script_dir = cur_dir
    args.scope = scope_get()

    ## Check whether the file exists
    if not os.path.isfile(args.file):
        errmsg("File does not exist, check the path", "Postprocessing")

    ## Parse the config
    config_file = os.path.join(cur_dir, "config.txt")
    cfg = parse_cfg(config_file, "vs-handbrake", "docker")

    ## Initialize the logging
    init_logging(args, cfg)

    ## Print the date and the file
    infomsg("-" * 35, "Postprocessing")
    infomsg("Handbrake finished converting file", "Postprocessing", (args.file,))

    ## Check for the source file, continue if convert file doesnt exist
    args = get_convert_source_path(args)

    ## Check which media type it is and process it accordingly
    processing_file(cfg, args)
Example #4
0
def parse_cfg_transmission(cfg, scope):

    mapping, host_admin, host_watch_dir = (None for _ in range(3))

    ## Parse the config in case the script is running within a docker container
    if (scope == "docker"):
        mapping = parse_docker_mappings()
        handbrake = [m[0] for m in mapping if "handbrake" in m[0]]
        if (len(handbrake) > 0):
            handbrake = handbrake[0]
        else:
            errmsg("Define the handbrake mount in the container settings")
            exit()

    ## [Hostsystem] Parse the config in case the script is running in host system
    else:
        handbrake = parse_strlist(cfg.get("Host", "host_handbrake"), True)[0]
        host_watch_dir = parse_strlist(cfg.get("Host", "host_watch_dir"), True)
        host_admin = parse_hostadmin(cfg.get("Host", "host_admin"))

    codecs = enum(cfg.get("Transmission", "codecs"))
    extensions = enum(cfg.get("Transmission", "extensions"))
    port = parse_dig(cfg.get("SynoIndex", "synoindex_port"), 1, 65535)
    handbrake_exclude = parse_strlist(cfg.get("Handbrake",
                                              "handbrake_exclude"))
    handbrake_4k = parse_dig(cfg.get("Handbrake", "handbrake_4k"), 1, 2)
    log_level = parse_loglevel(cfg.get("Logging", "log_level"))
    log_dir = parse_strlist(cfg.get("Logging", "log_dir"))[0]

    return (mapping, codecs, extensions, port, handbrake, host_watch_dir,
            host_admin, handbrake_exclude, handbrake_4k, log_level, log_dir)
Example #5
0
def get_resolution(file_name):

    ## Call mediainfo via command line
    cmds = ['mediainfo', file_name]
    p = subprocess.Popen(cmds,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    (stdout, stderr) = p.communicate()
    if (len(stderr) > 1): errmsg(stderr)

    ## Parse the mediainfo output as dictionary
    mediainfo_output = stdout.decode("UTF-8").split("\n")
    mediainfo_output = [
        ' '.join(m.split()).split(" : ") for m in mediainfo_output
    ]
    mediainfo_output = dict([tuple(m) for m in mediainfo_output if len(m) > 1])

    ## Parse the height of the video resolution
    res = mediainfo_output["Height"]
    res = int(res.replace(" ", "").replace("pixels", ""))

    ## Round the real resolution of the video file to the common resolution
    if (res == 0): return -1
    if (0 < res and res <= 360): return "360p"
    elif (360 < res and res <= 480): return "480p"
    elif (480 < res and res <= 720): return "720p"
    elif (720 < res and res <= 1080): return "1080p"
    elif (1080 < res and res <= 2160): return "2160p"
    else: return -1
Example #6
0
def processing_file(cfg, args):

    ## Check the file type
    file_dst = None
    if any(file_type in args.root_host.split(os.sep) for file_type in cfg.series):
        infomsg("Type: Episode", "Postprocessing")
        file_dst = naming_episode(args, cfg)

    elif any(file_type in args.root_host.split(os.sep) for file_type in cfg.movies):
        infomsg("Type: Movie", "Postprocessing")
        file_dst = naming_movie(args)
    else:
        exit("Error: Unsupported type of converted file")

    ## Delete the corresponding convert and watch file and add to synoindex
    if file_dst:
        msg = "Add converted file to synoindex and {} original file".format(switch_original(cfg.original))
        infomsg(msg, "Postprocessing")
        client(args.scope, cfg.port, file_dst, args.output_host, args.source_host, cfg.original)

        watch_file = scope_reverse_map_path(cfg, args, args.watch_host)
        debugmsg("Delete watch file", "Postprocessing", (watch_file,))
        try:
            os.remove(watch_file)
        except FileNotFoundError:
            errmsg("Could not find watch file at", "Postprocessing", (watch_file,)); exit()

        debugmsg("Delete convert file", "Postprocessing", (args.convert_path,))
        os.remove(args.convert_path)
Example #7
0
def get_convert_source_path(args):
    """ Get the convert file path and the source path inside it.

    Arguments:
        args {Namespace} -- Namespace containing the shell arguments.

    Returns:
        tuple -- (convert file path, source file path)
    """

    ## check whether the convert directory exists
    file_name = os.path.basename(args.file)
    convert_file = "%s.txt" % os.path.splitext(file_name)[0]
    convert_path = os.path.join(os.sep, "convert")
    if not os.path.isdir(convert_path):
        errmsg("Seems like the data mount does not exist, [VS-Handbrake] -> /convert", "Postprocessing"); exit()

    ## check whether the convert file exists
    args.convert_path = os.path.join(convert_path, convert_file)
    if not os.path.isfile(args.convert_path):
        errmsg("Convert file does not exist"); exit()

    ## Get the source path
    with open(args.convert_path, "r") as f: lines = f.readlines()
    convert_args = [l.replace("\n", "").split(":")[1] for l in lines]
    args.root_host, args.source_host, args.output_host, args.watch_host = convert_args
    return args
Example #8
0
def get_season_desc(cfg):
    if (cfg.language == "DE"):
        return "Staffel"
    elif (cfg.language == "EN"):
        return "Season"
    else:
        errmsg("Invalid language in configuration", "Naming")
        exit()
Example #9
0
def connect():
    try:
        conn = psycopg2.connect("dbname='video_metadata' user='******'")
    except:
        errmsg("Could not connect to the database, try to run as follows: sudo -u postgres python")
        return (None,None)

    cur = conn.cursor()
    return (conn, cur)
Example #10
0
def parse_hostadmin(username):
    ''' Parse the host admin username from config '''
    try:
        gid = pwd.getpwnam(username).pw_gid
        uid = pwd.getpwnam(username).pw_uid
    except KeyError:
        errmsg("Configured host admin does not exist", "Parsing", (username, ))
        exit()
    return (uid, gid)
Example #11
0
def parse_loglevel(log_level):
    allowed = [10, 20, 40]
    log_level = enum(log_level)[0]
    try:
        if int(log_level) in allowed: return int(log_level)
        else:
            errmsg("Invalid log level in config")
            exit()
    except ValueError:
        errmsg("Invalid log level in config")
        exit()
Example #12
0
def parse_language(language):
    allowed = ["DE", "EN"]
    language = enum(language)[0]
    try:
        if language in allowed: return language
        else:
            errmsg("Invalid language in config")
            exit()
    except ValueError:
        errmsg("Invalid language in config")
        exit()
Example #13
0
def daemon_items_same(conn, cur, user_collection, admin_collection):

    ## Get all items of the collection
    user_items = get_all_items_of_collection(cur, user_collection)
    admin_items = get_all_items_of_collection(cur, admin_collection)
    if (user_items == None or admin_items == None):
        errmsg("Could not get items of admin collection")
        close_connection(conn, cur)
        exit(-1)
    if (set([u[0] for u in user_items]) == set([u[0] for u in admin_items])):
        return True
    return False
Example #14
0
def daemon_mode(args):

    debugmsg("Started execution", "Daemon mode")

    ## Connect to Video Station database
    conn, cur = connect()
    if (conn == None):
        errmsg("Could not connect to database")
        exit(-1)
    debugmsg("Connected successfully to Synology Video Station database",
             "Daemon mode")

    ## Get the admin ID
    users, admin = users_get_selection(1)

    ## Get all collection information of the admin
    admin_collections = get_collections_of_user(cur, admin[1])
    if (admin_collections == None):
        close_connection(conn, cur)
        exit(-1)

    changes = False
    for user in users:
        ## Check whether user has all admin collections
        user_collections = get_collections_of_user(cur, user[1])
        new_collections = daemon_collections_same(user_collections,
                                                  admin_collections)
        for collection_info in new_collections:
            daemon_collection_add_to_user(conn, cur, collection_info, user)
            debugmsg("Add another playlist to the user", "Daemon mode",
                     (user[0], collection_info[2]))
            changes = True

        ## Check whether all items in every collection is synced
        for collection_info in admin_collections:
            user_collection = [
                uc for uc in user_collections if uc[2] == collection_info[2]
            ]
            if user_collection:
                user_collection = user_collection[0]
                if not daemon_items_same(conn, cur, user_collection,
                                         collection_info):
                    delete_all_items_of_collection(conn, cur, user_collection)
                    delete_collection(conn, cur, user_collection)
                    daemon_collection_add_to_user(conn, cur, collection_info,
                                                  user)
                    debugmsg(
                        "Renew playlist due to admin's playlist was updated",
                        "Daemon mode", (user[0], collection_info[2]))
                    changes = True
    if not changes:
        debugmsg("Finish daemon mode without any changes", "Daemon mode")
    return
Example #15
0
def parse_dig(dig, imin, imax):
    ''' Parse a digit '''

    dig = enum(dig)[0]
    try:
        if imin <= int(dig) <= imax: return int(dig)
        else:
            errmsg("Invalid digit in config")
            exit()
    except ValueError:
        errmsg("Invalid digit in config")
        exit()
Example #16
0
def mail_get_addresses(args):
    """ Get all users and mail address of the current system

    Arguments:
        args {Namespace} -- Namespace containing all arguments.

    Returns:
        string -- List of tuples with users and mail addresses
    """

    ## Get the username, real name and the mail address of each user
    admin = getpass.getuser()
    user_file = os.path.join(os.sep, "volume1", "homes", admin, "users.csv")
    user_mails = os.path.join(args.scriptdir, "user_mails.sh")
    p = Popen(["/bin/bash", user_mails, admin], stdout=PIPE, stderr=PIPE)
    stderr = p.communicate()[1]
    if p.returncode != 0:
        errmsg("Could not get user mail addresses", (stderr, ))
        exit()
    try:
        with open(user_file, 'r', encoding='utf-8', errors='replace') as f:
            users = f.read()
    except EnvironmentError:
        errmsg("Could not read the user mail addresses file", (user_file, ))
        exit()
    os.remove(user_file)

    ## Parse user names and separate the admin
    users = ("".join(i for i in users if ord(i) < 128)).split("\n")
    users = [u.replace("\n", "").replace("\"", "") for u in users]
    users = [u.replace(" (user)", "").replace(" (admin)", "") for u in users]
    users = list(filter(None, users))
    fs_admin = users_get_selection(2, False)
    admin = [u for u in users if u.split(',')[0] == fs_admin]
    users = list(set(users) - set(admin))

    ## Get the mail tuples
    fs_admin = users_get_selection(2, False)
    user_mails = [
        "{} <{}>".format(u.split(",")[1],
                         u.split(",")[2]) for u in users
    ]
    admin_mails = [
        "{} <{}>".format(a.split(",")[1],
                         a.split(",")[2]) for a in admin
    ]
    mails = admin_mails if args.receivers == "admin" else user_mails

    if args.receivers == "all": mails = admin_mails + user_mails
    infomsg("Selected list of mail addresses by receivers argument", "Mail",
            (",".join(mails), ))
    return mails
Example #17
0
def parse_cfg(config_file, config_type, scope):
    ''' Parse all configuration options of the config file. '''

    ## Read the config file
    config = ConfigParser()
    config.read(config_file)

    ## VS-Handbrake
    if (config_type == "vs-handbrake"):
        sections = ["Handbrake", "SynoIndex", "Logging"]
        fields = [
            "mapping", "movies", "series", "original", "language", "port",
            "log_level", "log_dir"
        ]

    ## VS-Transmission
    elif (config_type == "vs-transmission"):
        sections = [
            "Transmission", "SynoIndex", "Handbrake", "Host", "Logging"
        ]
        fields = [
            "mapping", "codecs", "extensions", "port", "handbrake",
            "watch_directories", "host_admin", "exclude", "hb_4k", "log_level",
            "log_dir"
        ]
    else:
        errmsg("Config type not supported")
        exit()

    ## Check whether all sections are present and initialize config Namespace
    _ = [
        exit('Error: Section (%s) missing' % s) for s in sections
        if not config.has_section(s)
    ]
    cfg = namedtuple('cfg', " ".join(fields))
    cfg.__new__.__defaults__ = (None, ) * len(cfg._fields)

    ## VS-Handbrake
    if (config_type == "vs-handbrake"):
        (mpg, movies, series, original, lang, port, level,
         log) = parse_cfg_handbrake(config, scope)
        parsed_cfg = cfg(mpg, movies, series, original, lang, port, level, log)

    ## VS-Transmission
    elif (config_type == "vs-transmission"):
        (mpg, cds, exts, port, hb, dirs, had, excls, h4k, lvl,
         log) = parse_cfg_transmission(config, scope)
        parsed_cfg = cfg(mpg, cds, exts, port, hb, dirs, had, excls, h4k, lvl,
                         log)

    return parsed_cfg
Example #18
0
def add_all_items_to_collection(conn, cur, items, new_collection_id):

    items = [(mapper_id, new_collection_id)
             for mapper_id, collection_id in items]
    try:
        values = ', '.join(map(str, items))
        sql_query = (
            "INSERT INTO collection_map (mapper_id, collection_id) VALUES {}"
        ).format(values)
        cur.execute(sql.SQL(sql_query))
        conn.commit()
    except psycopg2.IntegrityError:
        errmsg("Could not insert the items to the new playlist")
        return None
Example #19
0
def get_all_items_of_collection(cur, collection_info):
    collection_id = collection_info[0]

    ## Get all items
    cur.execute(
        sql.SQL("SELECT * FROM collection_map WHERE collection_id = %s;"),
        [collection_id])
    result = cur.fetchall()

    ## Parse the mapper_id and collection_id
    result = [r[1:3] for r in result]
    if (result == None or len(result) == 0):
        errmsg("The playlist is empty")
        return None
    return (result)
Example #20
0
def main():
    ## Parse the shell arguments
    args = parse_arguments()

    ## Parse the config
    config_file = os.path.join(cur_dir, "config.txt")
    cfg = parse_cfg(config_file, "vs-transmission", args.scope)

    ## Check for userid and groupid in docker scope
    if (args.scope == "docker" and (args.userid == 0 or args.groupid == 0)):
        errmsg("Docker scope requires userid and groupid", "Post-Processing")
    elif (args.scope == "host"):
        args.userid, args.groupid = cfg.host_admin

    ## Post Processing
    post_processing(args, cfg)
Example #21
0
def get_collections_of_user(cur, user):
    if (user == None):
        errmsg("get_collections_of_user() failed - User missing")
        exit()
    else:
        cur.execute(
            sql.SQL(
                "SELECT * FROM collection WHERE uid = %s AND (title != %s AND title != %s AND title != %s);"
            ), [
                str(user), "syno_watchlist", "syno_favorite",
                "syno_default_shared"
            ])
        result = cur.fetchall()
    if (result == None):
        errmsg("User does not have any playlist information")
        return None
    return (result)
Example #22
0
def get_collection(cur, playlist, user=None):
    if (user == None):
        cur.execute(
            sql.SQL(
                "SELECT * FROM collection WHERE title = %s AND (title != %s AND title != %s);"
            ), [playlist, "syno_watchlist", "syno_favorite"])
        result = cur.fetchall()
    else:
        cur.execute(
            sql.SQL(
                "SELECT * FROM collection WHERE title = %s AND uid = %s AND (title != %s AND title != %s);"
            ),
            [playlist, str(user), "syno_watchlist", "syno_favorite"])
        result = cur.fetchone()
    if (result == None):
        errmsg("Could not find the playlist")
        return None
    return (result)
Example #23
0
def parse_arguments():
    """ Parse the shell arguments

    Returns:
        Namespace -- Namespace containing all arguments
    """

    args = argparse.Namespace()
    parser = argparse.ArgumentParser(
        description='Post Processing of torrents via transmission')
    parser.add_argument('-n',
                        '--name',
                        help='Name of the torrent',
                        required=True)
    parser.add_argument('-d',
                        '--directory',
                        help='Directory of the torrent',
                        required=True)
    parser.add_argument('-u',
                        '--userid',
                        help='ID of the user (PUID)',
                        default=0,
                        type=int,
                        nargs='?')
    parser.add_argument('-g',
                        '--groupid',
                        help='ID of the group (PGID)',
                        default=0,
                        type=int,
                        nargs='?')
    args = parser.parse_args()
    args.script_dir = cur_dir
    args.scope = scope_get()

    ## Check whether the passed name and directory are valid
    if not os.path.isdir(args.directory):
        errmsg("Passed torrent directory does not exist", "Parsing",
               (args.directory, ))
        exit()
    full_path = os.path.join(args.directory, args.name)
    if (not os.path.isdir(full_path)) and (not os.path.isfile(full_path)):
        errmsg("Passed torrent does not exist", "Parsing", (full_path, ))
        exit()
    return args
Example #24
0
def create_new_collection(conn, cur, collection_info, userid):
    if (int(userid) == int(collection_info[1])):
        errmsg("The ownerID and the userID are equal")
        return None

    ## Insert the collection
    collection_name = collection_info[2]
    try:
        cur.execute(
            sql.SQL("INSERT INTO collection (uid,title) VALUES (%s,%s);"),
            [userid, collection_name])
        conn.commit()

    except psycopg2.IntegrityError:
        errmsg(
            "Could not insert the new playlist, the playlist already exists (%s)",
            userid)
        return None

    ## Get the ID of the new created collection
    cur.execute(
        sql.SQL("SELECT * FROM collection WHERE uid = %s AND title = %s;"),
        [userid, collection_name])
    result = cur.fetchone()
    if (result == None):
        errmsg(
            "Could not insert the new playlist, the playlist already exists")
        return None
    return result[0]
Example #25
0
def parse_strlist(strlist, paths=False):
    ''' Parse a stringlist which may be a list of paths '''
    try:
        strlist = list(filter(None, strlist.split(',')))
        strlist = [s.strip() for s in strlist]
    except ValueError:
        errmsg("Invalid string list in config")
        exit()
    if not strlist:
        errmsg("Invalid string list in config")
        exit()
    if paths:
        paths = [p.rstrip(os.sep).lstrip() for p in strlist]
        non_paths = [p for p in paths if not os.path.isdir(p)]
        paths = [p for p in paths if os.path.isdir(p)]
        if not paths:
            infomsg("Config contains list of non-existent file paths",
                    "Parsing", (paths, ))
        if non_paths:
            infomsg("Config contains path which does not exist", "Parsing",
                    (non_paths, ))
        return paths
    return strlist
Example #26
0
def analyze_movie(movie):

    ## Get the extensions of the season
    movie.extension = os.path.splitext(movie.file)[1]

    ## Analyze resolution of the season
    movie.resolution = get_resolution(movie.file)
    if (movie.resolution == -1):
        errmsg("The resolution of the movie was invalid", "Naming")
        exit()

    ## Get the real movie name of the file
    movie.name_bk = movie.original.replace(movie.movies_path,
                                           "").split(os.sep)[1]
    movie.name = []
    for token in movie.name_bk.split(movie.delim):
        if (token.isdigit() and int(token) > 1925 and int(token) < 2050):
            break
        movie.name.append(token)
    movie.name = " ".join(movie.name)

    ## Get the destination directory
    movie.dst = os.path.join(movie.movies_path, movie.name_bk)
    return movie
Example #27
0
def daemon_collection_add_to_user(conn, cur, collection_info, user):
    new_collection_id = create_new_collection(conn, cur, collection_info,
                                              str(user[1]))
    if (new_collection_id == None):
        errmsg("Could not find collection of admin")
        close_connection(conn, cur)
        exit(-1)

    ## Get all items of the collection
    items = get_all_items_of_collection(cur, collection_info)
    if (items == None):
        errmsg("Could not get items of admin collection")
        close_connection(conn, cur)
        exit(-1)

    ## Add all items to the new collection
    add_all_items_to_collection(conn, cur, items, new_collection_id)
    if (items == None):
        close_connection(conn, cur)
        errmsg("Could not add items to user collection")
        exit(-1)
Example #28
0
def analyze_series(cfg, series):

    ## Get the extensions of the season
    series.file_base, series.extension = os.path.splitext(series.file)

    ## Analyze resolution of the season
    series.resolution = get_resolution(series.file)
    if (series.resolution == -1):
        errmsg("The resolution of the series episode was invalid", "Naming")
        exit()

    ## Analyze the current season number
    splitted = series.file_base.split(series.delim)
    try:
        debugmsg("Check for regular naming scheme (s01e01)", "Naming")
        season_ep = [
            f for f in splitted if "s0" in f.lower() or "s1" in f.lower()
        ][0]
        series.season = "{}".format(re.split('s|e', season_ep.lower())[1])
        series.episode = "S%sE%s" % (series.season,
                                     re.split('s|e', season_ep.lower())[2])
        series.season = "%s %s" % (get_season_desc(cfg), series.season)
    except IndexError:
        debugmsg(
            "Regular naming scheme not found, check for alternative naming scheme (101|1201|122324)",
            "Naming")
        season_ep = splitted[-1]
        if (season_ep.isdigit()):
            if (int(season_ep) > 100 and int(season_ep) < 400000):
                ## Single episode - 101, 923
                if (int(season_ep) > 100 and int(season_ep) < 1000):
                    series.season = "{:02d}".format(int(season_ep[0]))
                    series.episode = "S{}E{}".format(series.season,
                                                     season_ep[1:])
                ## Single episode - 1001,9023
                elif (int(season_ep) > 1000 and int(season_ep) < 4000):
                    series.season = "{:02d}".format(int(season_ep[:2]))
                    series.episode = "S{}E{}".format(series.season,
                                                     season_ep[-2:])
                ## Double episode - 100102, 12324, 92324
                elif (int(season_ep) > 10000 and int(season_ep) < 40000):
                    series.season = "{:02d}".format(int(season_ep[0]))
                    series.episode = "S{}E{}".format(series.season,
                                                     season_ep[1:3])
                ## Double episode - 122324
                elif (int(season_ep) > 100000 and int(season_ep) < 400000):
                    series.season = "{:02d}".format(int(season_ep[:2]))
                    series.episode = "S{}E{}".format(series.season,
                                                     season_ep[2:4])
                else:
                    errmsg("Undefined naming scheme for episode", "Naming",
                           (series.file, ))
                    exit()
                series.season = "{} {}".format(get_season_desc(cfg),
                                               series.season)
                debugmsg("Alternative naming scheme found", "Naming")
            else:
                errmsg("Undefined naming scheme for episode", "Naming",
                       (series.file, ))
                exit()
        else:
            debugmsg(
                "Alternative naming scheme not found, check for unusual naming scheme (Ep 01)",
                "Naming")
            season = None
            for part in splitted:
                if (part.isdigit()):
                    season = series.original.replace(
                        series.series_path, "").split(os.sep)[2].split()[1]
                    series.season = "{:02d}".format(int(season))
                    series.episode = "S{}E{}".format(series.season, part)
                    series.season = "{} {}".format(get_season_desc(cfg),
                                                   series.season)
                    debugmsg("Unusual naming scheme found", "Naming")
                    break
            if not season:
                errmsg("Undefined naming scheme for episode", "Naming",
                       (series.file, ))
                exit()

    ## Get the series name of the file
    series.name_bk = series.original.replace(series.series_path,
                                             "").split(os.sep)[1]
    series.name = series.name_bk.replace(" ", "-")

    ## Get the destination directory
    series.dst = os.path.join(series.series_path, series.name_bk,
                              series.season)
    return series
Example #29
0
def copy_file_to_handbrake(args, cfg, source, source_host, root_host):
    """ Copy file to the handbrake watch directory and change owner.

    Arguments:
        args {Namespace}     -- Namespace containing all shell arguments.
        cfg {Namespace}      -- Namespace containing all configurations.
        source {string}      -- Path to the source within docker container.
        source_host {string} -- Path to the source file on the host system.
        root_host {string}   -- Path to the top mount containing the file.
    """

    ## Get all media info about the file
    video_info = ffprobe_file(source)
    codec = video_info["video_codec"]
    resolution = video_info["resolutionY"]
    debugmsg("Analyse the video file for codec and resolution", "Mediainfo",
             (resolution, codec))

    ## Check whether it is one codec of the config is present
    if codec not in cfg.codecs:
        infomsg("Codec is not watched in file", "Postprocessing",
                (source, codec))
        return

    ## Only copy files which match no exclude string
    if any(exclude in source for exclude in cfg.exclude):
        infomsg("Source file excluded for handbrake by config",
                "Postprocessing", (source, ))
        return

    ## Switch the watch directory depending on the 4K mode and the resolution
    watch_host = os.path.join(cfg.handbrake, "watch")
    if (cfg.hb_4k == 1 and int(resolution) > 2000):
        infomsg("4K mode enabled - file is copied to separate watch directory",
                "Postprocessing", (watch_host, ))
        watch_host = os.path.join(cfg.handbrake, "watch2")
    if not os.path.isdir(watch_host):
        create_path_directories(watch_host)
        os.chown(watch_host, cfg.host_admin[0], cfg.host_admin[1])

    ## Copy the video file to the handbrake watch directory
    infomsg("Copying file to handbrake watch directory", "Postprocessing",
            (watch_host, ))
    watch_file = file_copy(source, watch_host, args)
    if not watch_file:
        errmsg("Could not copy file to handbrake watch directory",
               "Postprocessing", (watch_host, ))
        return
    infomsg("Finished copying file", "Postprocessing", (watch_file, ))

    ## Convert the output file into host system path
    output_file = os.path.join(cfg.handbrake, "output",
                               os.path.basename(watch_file))
    output_host = scope_map_path(cfg, args, output_file)[0]
    if output_host == -1:
        errmsg("Could not get the host path of file", "Postprocessing",
               (output_file))
        return

    ## Convert the watch file into host system path
    watch_file = os.path.join(watch_host, os.path.basename(watch_file))
    watch_host = scope_map_path(cfg, args, watch_file)[0]
    if watch_host == -1:
        errmsg("Could not get the host path of watch file", "Postprocessing",
               (watch_file))
        return

    ## Write the convert file with all necessary information
    write_convert_file(cfg, source, source_host, root_host, output_host,
                       watch_host)