Search code examples
pythonpython-3.6

how can i list the contents of a mega public folder by it's shared url using mega api in python


i want to iterate over a public folder contents using it's shared link in python and to extract it's information using mega api the only available method is for getting the files list that only available in a specific account only

 def get_files_in_node(self, target):
    """
    Get all files in a given target, e.g. 4=trash
    """
    if type(target) == int:
        # convert special nodes (e.g. trash)
        node_id = self.get_node_by_type(target)
    else:
        node_id = [target]

    files = self._api_request({'a': 'f', 'c': 1})
    files_dict = {}
    shared_keys = {}
    self._init_shared_keys(files, shared_keys)
    for file in files['f']:
        processed_file = self._process_file(file, shared_keys)
        if processed_file['a'] and processed_file['p'] == node_id[0]:
            files_dict[file['h']] = processed_file
    return files_dict

can anyone please tell me how to do this?


Solution

  • Retrieving a list of nodes from a public folder's URL

    Here is the code that I used to get the list of files in Mega's public folder. It uses functions related to decryptions from mega.py library.

    from mega.crypto import base64_to_a32, base64_url_decode, decrypt_attr, decrypt_key
    
    def get_nodes_in_shared_folder(root_folder: str) -> dict:
        data = [{"a": "f", "c": 1, "ca": 1, "r": 1}]
        response = requests.post(
            "https://g.api.mega.co.nz/cs",
            params={'id': 0,  # self.sequence_num
                    'n': root_folder},
            data=json.dumps(data)
        )
        json_resp = response.json()
        return json_resp[0]["f"]
    
    def parse_folder_url(url: str) -> Tuple[str, str]:
        "Returns (public_handle, key) if valid. If not returns None."
        REGEXP1 = re.compile(r"mega.[^/]+/folder/([0-z-_]+)#([0-z-_]+)(?:/folder/([0-z-_]+))*")
        REGEXP2 = re.compile(r"mega.[^/]+/#F!([0-z-_]+)[!#]([0-z-_]+)(?:/folder/([0-z-_]+))*")
        m = re.search(REGEXP1, url)
        if not m:
            m = re.search(REGEXP2, url)
        if not m:
            print("Not a valid URL")
            return None
        root_folder = m.group(1)
        key = m.group(2)
        # You may want to use m.groups()[-1]
        # to get the id of the subfolder
        return (root_folder, key)
    
    def decrypt_node_key(key_str: str, shared_key: str) -> Tuple[int, ...]:
        encrypted_key = base64_to_a32(key_str.split(":")[1])
        return decrypt_key(encrypted_key, shared_key)
    

    Example code to get a list of files and their metadata in the public shared folder.

    (root_folder, shared_enc_key) = parse_folder_url("<insert url here>")
    shared_key = base64_to_a32(shared_enc_key)
    nodes = get_nodes_in_shared_folder(root_folder)
    for node in nodes:
        key = decrypt_node_key(node["k"], shared_key)
        if node["t"] == 0: # Is a file
            k = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6], key[3] ^ key[7])
        elif node["t"] == 1: # Is a folder
            k = key
        attrs = decrypt_attr(base64_url_decode(node["a"]), k)
        file_name = attrs["n"]
        file_id = node["h"]
    

    Downloading files from shared folder

    This wasn't part of your question, but I'll just add a brief summary and maybe others will find it helpful.

    To download, you will need to make a POST request with the same params as above but the data changed to this:

    data = [{ 'a': 'g', 'g': 1, 'n': node['h'] }]
    

    and then basically copy the mega.py library's _download_file function, replacing file_key with the key you got from decrypt_node_key(...).