def add_to_collection(config_path, plex, method, value, c, subfilters=None):
    movies = []
    shows = []
    items = []
    if method in Movie.__doc__ or hasattr(Movie, method):
        try:
            movies = plex.Library.search(**{method: value})
        except PlexExceptions.BadRequest:
            # If last character is "s" remove it and try again
            if method[-1:] == "s":
                movies = plex.Library.search(**{method[:-1]: value})
                movies = [m.ratingKey for m in movies if movies]
    elif method in Show.__doc__ or hasattr(Show, method):
        try:
            shows = plex.Library.search(**{method: value})
        except PlexExceptions.BadRequest as e:
            print(e)
    else:
        if isinstance(plex.Library, MovieSection):
            if method == "imdb-list":
                movies, missing = imdb_tools.imdb_get_movies(
                    config_path, plex, value)
            elif method == "tmdb-list":
                movies, missing = imdb_tools.tmdb_get_movies(
                    config_path, plex, value)
            elif method == "trakt-list":
                movies, missing = trakt_tools.trakt_get_movies(
                    config_path, plex, value)
        elif isinstance(plex.Library, ShowSection):
            if method == "trakt-list":
                shows, missing = trakt_tools.trakt_get_shows(
                    config_path, plex, value)
    if movies:
        # Check if already in collection
        cols = plex.Library.search(title=c, libtype="collection")
        try:
            fs = cols[0].children
        except IndexError:
            fs = []
        for rk in movies:
            current_m = get_movie(plex, rk)
            current_m.reload()
            if current_m in fs:
                print("{} is already in collection: {}".format(
                    current_m.title, c))
            elif subfilters:
                match = True
                for sf in subfilters:
                    method = sf[0]
                    terms = str(sf[1]).split(", ")
                    try:
                        mv_attrs = getattr(current_m, method)
                        # If it returns a list, get the 'tag' attribute
                        # Otherwise, it's a string. Make it a list.
                        if isinstance(mv_attrs, list) and "-" not in method:
                            mv_attrs = [getattr(x, 'tag') for x in mv_attrs]
                        else:
                            mv_attrs = [str(mv_attrs)]
                    except AttributeError:
                        for media in current_m.media:
                            if method == "video-resolution":
                                mv_attrs = [media.videoResolution]
                            for part in media.parts:
                                if method == "audio-language":
                                    mv_attrs = ([
                                        audio_stream.language for audio_stream
                                        in part.audioStreams()
                                    ])
                                if method == "subtitle-language":
                                    mv_attrs = ([
                                        subtitle_stream.language
                                        for subtitle_stream in
                                        part.subtitleStreams()
                                    ])

                    # Get the intersection of the user's terms and movie's terms
                    # If it's empty, it's not a match
                    if not list(set(terms) & set(mv_attrs)):
                        match = False
                        break
                if match:
                    print("+++ Adding {} to collection {}".format(
                        current_m.title, c))
                    current_m.addCollection(c)
            elif not subfilters:
                print("+++ Adding {} to collection: {}".format(
                    current_m.title, c))
                current_m.addCollection(c)
    if shows:
        # Check if already in collection
        cols = plex.Library.search(title=c, libtype="collection")
        try:
            fs = cols[0].children
        except IndexError:
            fs = []
        for rk in shows:
            current_s = get_item(plex, rk)
            current_s.reload()
            if current_s in fs:
                print("{} is already in collection: {}".format(
                    current_s.title, c))
            elif subfilters:
                match = True
                for sf in subfilters:
                    method = sf[0]
                    terms = str(sf[1]).split(", ")
                    try:
                        show_attrs = getattr(current_s, method)
                        # If it returns a list, get the 'tag' attribute
                        # Otherwise, it's a string. Make it a list.
                        if isinstance(show_attrs, list) and "-" not in method:
                            show_attrs = [
                                getattr(x, 'tag') for x in show_attrs
                            ]
                        else:
                            show_attrs = [str(show_attrs)]
                    except AttributeError as e:
                        print(e)
                        # for media in current_s.media:
                        #     if method == "video-resolution":
                        #         show_attrs = [media.videoResolution]
                        #     for part in media.parts:
                        #         if method == "audio-language":
                        #             show_attrs = ([audio_stream.language for audio_stream in part.audioStreams()])
                        #         if method == "subtitle-language":
                        #             show_attrs = ([subtitle_stream.language for subtitle_stream in part.subtitleStreams()])

                    # Get the intersection of the user's terms and movie's terms
                    # If it's empty, it's not a match
                    if not list(set(terms) & set(show_attrs)):
                        match = False
                        break
                if match:
                    print("+++ Adding {} to collection {}".format(
                        current_s.title, c))
                    current_s.addCollection(c)
            elif not subfilters:
                print("+++ Adding {} to collection: {}".format(
                    current_s.title, c))
                current_s.addCollection(c)
    try:
        missing
    except UnboundLocalError:
        return
    else:
        return missing
def add_to_collection(config_path,
                      plex,
                      method,
                      value,
                      c,
                      plex_map=None,
                      map=None,
                      filters=None):
    if plex_map is None and ("imdb" in method or "tvdb" in method
                             or "tmdb" in method or "trakt" in method):
        plex_map = get_map(config_path, plex)
    if map is None:
        map = {}
    items = []
    missing = []

    if method == "all":
        items = plex.Library.all()
    elif method == "plex_collection":
        items = value.children
    elif method == "plex_search":
        search_terms = {}
        output = ""
        for attr_pair in value:
            if attr_pair[0] == "actor":
                search_list = []
                for actor in attr_pair[1]:
                    search_list.append(get_actor_rkey(plex, actor))
            else:
                search_list = attr_pair[1]
            final_method = attr_pair[0][:-4] + "!" if attr_pair[0][
                -4:] == ".not" else attr_pair[0]
            if plex.library_type == "show":
                final_method = "show." + final_method
            search_terms[final_method] = search_list
            ors = ""
            for param in attr_pair[1]:
                ors = ors + (" OR " if len(ors) > 0 else attr_pair[0] +
                             "(") + str(param)
            output = output + ("\n|\t\t      AND " if len(output) > 0 else
                               "| Processing Plex Search: ") + ors + ")"
        print(output)
        items = plex.Library.search(**search_terms)
    elif method == "tvdb_show" and plex.library_type == "show":
        items, missing = imdb_tools.tvdb_get_shows(config_path, plex, plex_map,
                                                   value)
    elif "imdb" in method or "tmdb" in method:
        if not TMDB.valid:
            raise KeyError("| tmdb connection required for {}", format(method))
        elif method == "imdb_list" and plex.library_type == "movie":
            items, missing = imdb_tools.imdb_get_movies(
                config_path, plex, plex_map, value)
        elif "tmdb" in method and plex.library_type == "movie":
            items, missing = imdb_tools.tmdb_get_movies(
                config_path, plex, plex_map, value, method)
        elif "tmdb" in method and plex.library_type == "show":
            items, missing = imdb_tools.tmdb_get_shows(config_path, plex,
                                                       plex_map, value, method)
    elif "trakt" in method:
        if not TraktClient.valid:
            raise KeyError("| trakt connection required for {}",
                           format(method))
        elif plex.library_type == "movie":
            items, missing = trakt_tools.trakt_get_movies(
                config_path, plex, plex_map, value, method)
        elif plex.library_type == "show":
            items, missing = trakt_tools.trakt_get_shows(
                config_path, plex, plex_map, value, method)
    elif method == "tautulli":
        if not Tautulli.valid:
            raise KeyError("| tautulli connection required for {}",
                           format(method))
        else:
            items, missing = imdb_tools.get_tautulli(config_path, plex, value)
    else:
        print("| Config Error: {} method not supported".format(method))

    filter_alias = {
        "actor": "actors",
        "content_rating": "contentRating",
        "country": "countries",
        "director": "directors",
        "genre": "genres",
        "studio": "studio",
        "year": "year",
        "writer": "writers",
        "rating": "rating",
        "max_age": "max_age",
        "originally_available": "originallyAvailableAt",
        "video_resolution": "video_resolution",
        "audio_language": "audio_language",
        "subtitle_language": "subtitle_language",
        "plex_collection": "collections",
    }

    if items:
        # Check if already in collection
        cols = plex.Library.search(title=c, libtype="collection")
        try:
            fs = cols[0].children
        except IndexError:
            fs = []
        item_count = 0
        item_max = len(items)
        max_str_len = len(str(item_max))
        current_length = 0
        for rk in items:
            current_item = get_item(plex, rk)
            item_count += 1
            match = True
            if filters:
                display_count = (
                    " " *
                    (max_str_len - len(str(item_count)))) + str(item_count)
                print_display = "| Filtering {}/{} {}".format(
                    display_count, item_max, current_item.title)
                print(adjust_space(current_length, print_display), end="\r")
                current_length = len(print_display)
                for f in filters:
                    modifier = f[0][-4:]
                    method = filter_alias[f[0][:-4]] if modifier in [
                        ".not", ".lte", ".gte"
                    ] else filter_alias[f[0]]
                    if method == "max_age":
                        threshold_date = datetime.now() - timedelta(days=f[1])
                        attr = getattr(current_item, "originallyAvailableAt")
                        if attr is None or attr < threshold_date:
                            match = False
                            break
                    elif modifier in [".gte", ".lte"]:
                        if method == "originallyAvailableAt":
                            threshold_date = datetime.strptime(
                                f[1], "%m/%d/%y")
                            attr = getattr(current_item,
                                           "originallyAvailableAt")
                            if (modifier == ".lte" and attr > threshold_date
                                ) or (modifier == ".gte"
                                      and attr < threshold_date):
                                match = False
                                break
                        elif method in ["year", "rating"]:
                            attr = getattr(current_item, method)
                            if (modifier == ".lte"
                                    and attr > f[1]) or (modifier == ".gte"
                                                         and attr < f[1]):
                                match = False
                                break
                    else:
                        terms = f[1] if isinstance(f[1], list) else str(
                            f[1]).split(", ")
                        if method in [
                                "video_resolution", "audio_language",
                                "subtitle_language"
                        ]:
                            for media in current_item.media:
                                if method == "video_resolution":
                                    attrs = [media.videoResolution]
                                for part in media.parts:
                                    if method == "audio_language":
                                        attrs = ([
                                            audio_stream.language
                                            for audio_stream in
                                            part.audioStreams()
                                        ])
                                    if method == "subtitle_language":
                                        attrs = ([
                                            subtitle_stream.language
                                            for subtitle_stream in
                                            part.subtitleStreams()
                                        ])
                        elif method in [
                                "contentRating", "studio", "year", "rating",
                                "originallyAvailableAt"
                        ]:  # Otherwise, it's a string. Make it a list.
                            attrs = [str(getattr(current_item, method))]
                        elif method in [
                                "actors", "countries", "directors", "genres",
                                "writers", "collections"
                        ]:
                            attrs = [
                                getattr(x, 'tag')
                                for x in getattr(current_item, method)
                            ]

                        # Get the intersection of the user's terms and item's terms
                        # If it's empty and modifier is not .not, it's not a match
                        # If it's not empty and modifier is .not, it's not a match
                        if (not list(set(terms) & set(attrs)) and modifier !=
                                ".not") or (list(set(terms) & set(attrs))
                                            and modifier == ".not"):
                            match = False
                            break
            if match:
                if current_item in fs:
                    map[current_item.ratingKey] = None
                else:
                    current_item.addCollection(c)
                print(
                    adjust_space(
                        current_length, "| {} Collection | {} | {}".format(
                            c, "=" if current_item in fs else "+",
                            current_item.title)))
        print(
            adjust_space(
                current_length, "| Processed {} {}".format(
                    item_max,
                    "Movies" if plex.library_type == "movie" else "Shows")))
    else:
        print("| No {} Found".format("Movies" if plex.library_type ==
                                     "movie" else "Shows"))

    return missing, map