Search code examples
pythonsolidityipfsnftpinata

How do i upload a folder containing metadata to pinata using a script in python-brownie?


I've been trying for the past 24 hours but can't find a solution. This is the code:

import os
from pathlib import Path
import requests

PINATA_BASE_URL = "https://api.pinata.cloud/"
endpoint = "pinning/pinFileToIPFS"
# Change this filepath
filepath = "C:/Users/acer/Desktop/Ciao"
filename = os.listdir(filepath)
print(filename)
headers = {
    "pinata_api_key": os.getenv("PINATA_API_KEY"),
    "pinata_secret_api_key": os.getenv("PINATA_API_SECRET"),
}


def main():
    with Path(filepath).open("rb") as fp:
        image_binary = filepath.read()
        print(image_binary)
        response = requests.post(
            PINATA_BASE_URL + endpoint,
            files={"file": (filename, image_binary)},
            headers=headers,
        )
        print(response.json())


if __name__ == "__main__":
    main()

I tried to open the folder where the metadata was stored and than i sent the request with the list of files in the folder. This is the error:

['no.txt', 'yeah.txt']
Traceback (most recent call last):
  File "C:\Users\acer\Desktop\SOLIDITY_PYTHON\nft-bored-ape\scripts\upload_to_pinata.py", line 30, in <module>
    main()
  File "C:\Users\acer\Desktop\SOLIDITY_PYTHON\nft-bored-ape\scripts\upload_to_pinata.py", line 18, in main    
    with Path(filepath).open("rb") as fp:
  File "C:\Users\acer\AppData\Local\Programs\Python\Python310\lib\pathlib.py", line 1119, in open
    return self._accessor.open(self, mode, buffering, encoding, errors,
PermissionError: [Errno 13] Permission denied: 'C:\\Users\\acer\\Desktop\\Ciao'

Solution

  • Nevermind... After some research i found the answer to my own question. Here is the code:

    # Tulli's script :-)
    from brownie import config
    import requests, os, typing as tp
    
    
    PINATA_BASE_URL = "https://api.pinata.cloud/"
    endpoint = "pinning/pinFileToIPFS"
    # Here you could use os.getenv("VARIABLE_NAME"),
    # i used config from my .yaml file. Your choice!
    headers = {
        "pinata_api_key": config["pinata"]["api-keys"],
        "pinata_secret_api_key": config["pinata"]["api-private"],
    }
    
    
    def get_all_files(directory: str) -> tp.List[str]:
        """get a list of absolute paths to every file located in the directory"""
        paths: tp.List[str] = []
        for root, dirs, files_ in os.walk(os.path.abspath(directory)):
            for file in files_:
                paths.append(os.path.join(root, file))
        return paths
    
    
    def upload_folder_to_pinata(filepath):
        all_files: tp.List[str] = get_all_files(filepath)
        # The replace function is a must, 
        # pinata servers doesn't recognize the backslash. 
        # Your filepath is probably different than mine,
        # so in the split function put your "penultimate_file/".
        # Strip the square brackets and the apostrophe,
        # because we don't want it as part of the metadata ipfs name
        files = [
            (
                "file",
                (
                    str(file.replace("\\", "/").split("Desktop/")[-1:])
                    .strip("[]")
                    .strip("'"),
                    open(file, "rb"),
                ),
            )
            for file in all_files
        ]
        response: requests.Response = requests.post(
            PINATA_BASE_URL + endpoint,
            files=files,
            headers=headers,
        )
        # If you want to see all the stats then do this: 
        # return/print/do both separately response.json()
        return "ipfs.io/ipfs/" + response.json()["IpfsHash"]
    
    
    def main():
        upload_folder_to_pinata("Put your full filepath here")
    
    
    if __name__ == "__main__":
        main()