diff --git a/ythdd_globals.py b/ythdd_globals.py index d44c6ff..c212315 100644 --- a/ythdd_globals.py +++ b/ythdd_globals.py @@ -84,26 +84,64 @@ def getHeaders(caller="proxy"): return headers -def translateLinks(link): +def translateLinks(link: str, remove_params: bool = True): link = link.replace("https://i.ytimg.com/", config['general']['public_facing_url']) link = link.replace("https://yt3.ggpht.com/", config['general']['public_facing_url'] + "ggpht/") link = link.replace("https://yt3.googleusercontent.com/", config['general']['public_facing_url'] + "guc/") + # try to remove tracking params + if remove_params and "?" in link: + link = link[:link.find("?")] + return link def getUptime(): return int(time.time()) - starttime def safeTraverse(obj: dict, path: list, default=None, quiet: bool = False): + """ + Traverse dynamic objects with fallback to default values + + This function can take an Ellipsis as part of traversal path, + meaning that it will return the object from the list + that contains the next key. This has been introduced + so that no matter which object in a list holds the relevant + model, it will find it (meaning no assumptions are necessary). + Kepp in mind that only one ellipsis at a time is supported, + thus ["some_key", ..., ..., "some_other_key"] won't work. + + :param obj: Traversed object + :type obj: dict + :param path: Path which shall be traversed + :type path: list + :param default: Default value returned on failure + :type default: any, None by default + :param quiet: Quiet flag + :type quiet: bool + """ result = obj try: - for x in path: - #print(f"traversing {result} with respect to {x}") - result = result[x] + # for every item in path and its position + for pos, iterable_key in enumerate(path): + # if the key is not an ellipsis, traverse it + if iterable_key is not Ellipsis: + result = result[iterable_key] + # if it is an ellipsis, and there is another key beside it + elif pos < len(path) - 1: + # then iterate through all of the list contents + for list_content in result: + # in search of the next traversal key + if path[pos + 1] in list_content: + result = list_content + # show an error message if ellipsis is used incorrectly + else: + print("error(safeTraverse): Traversal path can't end with an Ellipsis!") + raise TypeError() + # handle exceptions except (KeyError, TypeError, IndexError): result = default - if not quiet: print(f"error reading: {' -> '.join(path)} - returning: {default}") + if not quiet: print(f"error reading: {' -> '.join([str(x) for x in path])} - returning: {default}") finally: return result