In our scripts folder, create new file: create_metadata.py
We will use this script to assign the URI for each NFT.
talk about NFT token URI etc - what, how
create_metadata.py
from brownie import AdvancedCollectible, network
from metadata.sample_metadata import metadata_template
from pathlib import Path
breed_mapping = {0: "PUG", 1: "SHIBA_INU", 2: "ST_BERNARD"}
def get_breed(breed_number):
return breed_mapping[breed_number]
def main():
advanced_collectible = AdvancedCollectible[-1]
number_of_NFTS = advanced_collectible.tokenCounter()
print(f"The number of NFTs minted so far is {number_of_NFTS}")
for tokenID in range(number_of_NFTS):
breed = get_breed(advanced_collectible.tokenIdToBreed(tokenID))
metadata_filename = f"./metadata/{network.show_active()}/{tokenID}-{breed}.json"
collectible_metadata = metadata_template
if Path(metadata_filename).exists():
print(f"{metadata_filename} exists! Delete to overwrite")
else:
print(f"Creating Metadata file: {metadata_filename}")
collectible_metadata["name"] = breed
collectible_metadata["description"] = f"An adorable {breed} pup!"
print(collectible_metadata)
image_path = "./img" + breed.lower().replace("_", "-") + ".png"
image_uri = upload_to_ipfs()
collectible_metadata["image_uri"] = image_uri
call on previous rinkeby deployment
check number of NFTs minted
for each tokenID, get the breed via getbreed(), and structure the filename and path as metadata_filename
collectible_metadata collects the metadata_template to be used as a base for modification
We then check if the required metadata_filename exists, using Path library.
Else, we will create a new one using the template as reference, adding the following
name
description
image URI -> collectible_metadata["image_uri"] = image_uri
image-uri
How do we get the image URI? Currently the images are in our local img folder. We need them to be hosted on IPFS and pass their IPFS URI into collectible_metadata["image_uri"]
Interestingly, ipfs daemon command works in terminal, command prompt.
On running ipfs daemon on terminal we will see the following:
def upload_to_ipfs(filepath):
# open image as binary - open(rb)
with Path(filepath).open("rb") as fp:
image_binary = fp.read()
ipfs_url = "http://127.0.0.1:5001" #get from WebUI
endpoint = "/api/v0/add"
response = requests.post(ipfs_url + endpoint, files={"file":image_binary}) #post request
ipfs_hash = response.json()["Hash"] #response returns dictionary
# "./img/0-PUG.png" -> split on /, grab last part of array, which is "0-PUG.png"
filename = filepath.split("/")[-1:][0]
image_uri = f"https://ipfs.io/ipfs/{ipfs_hash}?filename={filename}"
print(image_uri)
return image_uri
def main():
advanced_collectible = AdvancedCollectible[-1]
number_of_NFTS = advanced_collectible.tokenCounter()
print(f"The number of NFTs minted so far is {number_of_NFTS}")
for tokenID in range(number_of_NFTS):
breed = get_breed(advanced_collectible.tokenIdToBreed(tokenID))
metadata_filename = f"./metadata/{network.show_active()}/{tokenID}-{breed}.json"
collectible_metadata = metadata_template
if Path(metadata_filename).exists():
print(f"{metadata_filename} exists! Delete to overwrite")
else:
print(f"Creating Metadata file: {metadata_filename}")
collectible_metadata["name"] = breed
collectible_metadata["description"] = f"An adorable {breed} pup!"
print(collectible_metadata)
# convert underscores to dashes to be URI compatible
image_path = "./img/" + breed.lower().replace("_", "-") + ".png"
image_uri = upload_to_ipfs(image_path)
# collectible_metadata["image_uri"] = image_uri
ipfs_url -> retrieved from running ipds daemon
endpoint -> as per api endpoint reference
response -> structuring and sending a post response (can also use curl)
ipfs_hash -> response returns JSON string on successful call to endpoint - decode it as a python dict via .json()
extract filename from filepath and together with the IPFS hash, construct the image URI
print(image_uri)
will return an ipfs link, like so:
The image will be available as long as you are running your ipfs node.
To make the data highly available without needing to run a local IPFS daemon 24/7, you can request that a remote pinning service store a copy of your IPFS data on their IPFS nodes.
Creating metadate files
Now that we have filled all the fields in the metadata file, we are going to write it as a json file into our directory.
with open(metadata_filename, "w") as file:
json.dump(collectible_metadata, file)
upload_to_ipfs(metadata_filename)
This will create a json file in our metadata/rinkeby folder upon running:
brownie run scripts/advcollectible/create_metadata.py --network rinkeby
Final code at this point:
from brownie import AdvancedCollectible, network
from metadata.sample_metadata import metadata_template
from pathlib import Path
import requests, json
breed_mapping = {0: "PUG", 1: "SHIBA_INU", 2: "ST_BERNARD"}
def get_breed(breed_number):
return breed_mapping[breed_number]
def main():
advanced_collectible = AdvancedCollectible[-1]
number_of_NFTS = advanced_collectible.tokenCounter()
print(f"The number of NFTs minted so far is {number_of_NFTS}")
for tokenID in range(number_of_NFTS):
breed = get_breed(advanced_collectible.tokenIdToBreed(tokenID))
metadata_filename = f"./metadata/{network.show_active()}/{tokenID}-{breed}.json"
collectible_metadata = metadata_template
if Path(metadata_filename).exists():
print(f"{metadata_filename} exists! Delete to overwrite")
else:
print(f"Creating Metadata file: {metadata_filename}")
collectible_metadata["name"] = breed
collectible_metadata["description"] = f"An adorable {breed} pup!"
print(collectible_metadata)
# convert underscores to dashes to be URI compatible
image_path = "./img/" + breed.lower().replace("_", "-") + ".png"
image_uri = upload_to_ipfs(image_path)
collectible_metadata["image_uri"] = image_uri
with open(metadata_filename, "w") as file:
json.dump(collectible_metadata, file)
upload_to_ipfs(metadata_filename)
def upload_to_ipfs(filepath):
# open image as binary - opne(rb)
with Path(filepath).open("rb") as fp:
image_binary = fp.read()
ipfs_url = "http://127.0.0.1:5001" #get from WebUI
endpoint = "/api/v0/add"
response = requests.post(ipfs_url + endpoint, files={"file": image_binary}) #post request
ipfs_hash = response.json()["Hash"] #response returns dictionary.
# "./img/0-PUG.png" -> split on /, grab last part of array, which is "0-PUG.png"
filename = filepath.split("/")[-1:][0]
image_uri = f"https://ipfs.io/ipfs/{ipfs_hash}?filename={filename}"
print(image_uri)
return image_uri
11:33 - Refactor to check if file has already been uploaded to IPFS, so we don't upload every single time. (check github for code)
Alternative: Pinata
deploy to Pinata -> upload_pinata.py
create account at Pinata and generate api key
11:20 - 11:31
You should also see the pinned file:
To that end, we will have to install IPFS cli:
We will be working with /api/v0/add to add our file to IPFS: