|
| 1 | +from bs4 import BeautifulSoup |
| 2 | +from pathlib import Path |
| 3 | +from generator.utils import pick_choice |
| 4 | +from generator.utils import calculate_weights, check_for_triples, get_filenames, add_assets, add_petal_animation, get_trait, print_progress_bar |
| 5 | +from generator.oracle import add_oracle |
| 6 | +from generator.plot import plot_bar |
| 7 | +import generator.weights as weights |
| 8 | +import json |
| 9 | +import csv |
| 10 | + |
| 11 | + |
| 12 | +ASSET_CANISTER_URL = "https://zt63f-rqaaa-aaaae-qadaq-cai.raw.ic0.app/" |
| 13 | +# ASSET_CANISTER_URL = "./" |
| 14 | +COLLECTION_NAME = "punks" |
| 15 | +COLLECTION_SIZE = 7761 # + 16 uniques = 7777 |
| 16 | + |
| 17 | + |
| 18 | +def assemble_svgs(): |
| 19 | + """assemble the svgs for the collection""" |
| 20 | + |
| 21 | + # get all the relative filenames for the different layers. |
| 22 | + # specify substrings in exclude_list to exclude certain files by substrings |
| 23 | + backgrounds = get_filenames("../assets/BACKGROUNDS", |
| 24 | + exclude_list=["thumbnail", ".DS_Store"]) |
| 25 | + background_accessories = get_filenames( |
| 26 | + "../assets/BACKGROUND_ACCESSORIES", exclude_list=["thumbnail", ".DS_Store"]) |
| 27 | + |
| 28 | + body_heads = get_filenames( |
| 29 | + "../assets/BODY_HEAD", exclude_list=["thumbnail", ".DS_Store"]) |
| 30 | + |
| 31 | + top_head_leafs = get_filenames( |
| 32 | + "../assets/BODY_HEAD_BASIC/TOP_HEAD_LEAFS", exclude_list=["thumbnail", ".DS_Store"]) |
| 33 | + |
| 34 | + top_head_crowns = get_filenames( |
| 35 | + "../assets/BODY_HEAD_BASIC/TOP_HEAD_CROWNS", exclude_list=["thumbnail", ".DS_Store"]) |
| 36 | + |
| 37 | + top_head_chains = get_filenames( |
| 38 | + "../assets/BODY_HEAD_BASIC/TOP_HEAD_CHAINS", exclude_list=["thumbnail", ".DS_Store"]) |
| 39 | + |
| 40 | + masks = get_filenames( |
| 41 | + "../assets/MASKS", exclude_list=["thumbnail", ".DS_Store"]) |
| 42 | + |
| 43 | + eyes = get_filenames( |
| 44 | + "../assets/MID_HEAD/EYES", exclude_list=["thumbnail", ".DS_Store"]) |
| 45 | + |
| 46 | + accessories = get_filenames( |
| 47 | + "../assets/MID_HEAD/ACCESSORIES", exclude_list=["thumbnail", ".DS_Store"]) |
| 48 | + |
| 49 | + bottom_head_accessories = get_filenames( |
| 50 | + "../assets/MID_HEAD/BOTTOM_HEAD_ACCESSORIES", exclude_list=["thumbnail", ".DS_Store"]) |
| 51 | + |
| 52 | + body_accessories = get_filenames( |
| 53 | + "../assets/BODY_ACCESSORIES/BODY", exclude_list=["thumbnail", ".DS_Store"]) |
| 54 | + |
| 55 | + necks = get_filenames( |
| 56 | + "../assets/BODY_ACCESSORIES/NECK", exclude_list=["thumbnail", ".DS_Store"]) |
| 57 | + |
| 58 | + frames = get_filenames( |
| 59 | + "../assets/FRONT_FRAME", exclude_list=["thumbnail", ".DS_Store"]) |
| 60 | + |
| 61 | + lasers = get_filenames( |
| 62 | + "../assets/LASER_EYE", exclude_list=["thumbnail", ".DS_Store"]) |
| 63 | + |
| 64 | + uniques = get_filenames( |
| 65 | + "../assets/UNIQUES", exclude_list=["thumbnail", ".DS_Store"]) |
| 66 | + |
| 67 | + # get the path to the template svg file the assets will be embedded in |
| 68 | + template = Path(__file__).parent / "template.svg" |
| 69 | + |
| 70 | + # open the template file and get the soup |
| 71 | + # this has to be done twice because we have call by reference |
| 72 | + with template.open() as svg_template: |
| 73 | + soup = BeautifulSoup(svg_template, 'xml') |
| 74 | + |
| 75 | + with template.open() as svg_template: |
| 76 | + lowres_soup = BeautifulSoup(svg_template, 'xml') |
| 77 | + # the oracle code has to be added to the template only once |
| 78 | + # add_oracle(soup) |
| 79 | + # add_oracle(lowres_soup) |
| 80 | + |
| 81 | + nfts = [] |
| 82 | + |
| 83 | + for i in range(COLLECTION_SIZE): |
| 84 | + |
| 85 | + print_progress_bar(i, COLLECTION_SIZE, "Progress", "Complete") |
| 86 | + |
| 87 | + background, lowres_background = pick_choice( |
| 88 | + backgrounds, weights.background) |
| 89 | + |
| 90 | + background_accessory, lowres_background_accessory = pick_choice( |
| 91 | + background_accessories, weights.background_accessory) |
| 92 | + |
| 93 | + body_head, lowres_body_head = pick_choice( |
| 94 | + body_heads, weights.body_head) |
| 95 | + |
| 96 | + top_head_leaf, lowres_top_head_leaf = pick_choice( |
| 97 | + top_head_leafs, weights.top_head_leaf) |
| 98 | + top_head_crown, lowres_top_head_crown = pick_choice( |
| 99 | + top_head_crowns, weights.top_head_crown) |
| 100 | + top_head_chain, lowres_top_head_chain = pick_choice( |
| 101 | + top_head_chains, weights.top_head_chain) |
| 102 | + mask, lowres_mask = pick_choice(masks, weights.mask) |
| 103 | + |
| 104 | + # those are only present when the punk doesnt wear a mask |
| 105 | + eye, lowres_eye = pick_choice(eyes, weights.eye) |
| 106 | + accessory, lowres_accessory = pick_choice( |
| 107 | + accessories, weights.accessory) |
| 108 | + bottom_head_accessory, lowres_bottom_head_accessory = pick_choice( |
| 109 | + bottom_head_accessories, weights.bottom_head_accessory) |
| 110 | + |
| 111 | + body_accessory, lowres_body_accessory = pick_choice( |
| 112 | + body_accessories, weights.body_accessory) |
| 113 | + neck, lowres_neck = pick_choice( |
| 114 | + necks, weights.neck) |
| 115 | + frame, lowres_frame = pick_choice( |
| 116 | + frames, weights.frame) |
| 117 | + |
| 118 | + laser, lowres_laser = pick_choice( |
| 119 | + lasers, weights.laser) |
| 120 | + |
| 121 | + # check if mask is present and we use it instead |
| 122 | + if not 'NONE' in mask: |
| 123 | + eye, lowres_eye = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 124 | + accessory, lowres_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 125 | + bottom_head_accessory, lowres_bottom_head_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 126 | + |
| 127 | + # check if bodyhead string contains btcflowerbrain |
| 128 | + if 'BTCFLOWERBRAIN' in body_head: |
| 129 | + top_head_leaf, lowres_top_head_leaf = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 130 | + top_head_crown, lowres_top_head_crown = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 131 | + top_head_chain, lowres_top_head_chain = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 132 | + |
| 133 | + # headphones dont work with btcflower brain |
| 134 | + if 'BTCFLOWERBRAIN' in body_head and 'HEADPHONES' in accessory: |
| 135 | + accessory, lowres_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 136 | + |
| 137 | + # neck accessories dont work with hoodies or jackets |
| 138 | + if 'WINTER' in body_accessory or 'HOODIE' in body_accessory: |
| 139 | + neck, lowres_neck = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 140 | + |
| 141 | + # googles and glasses dont work with laser eyes and other accessories |
| 142 | + if 'GOGGLES' in eye or 'GLASSES' in eye: |
| 143 | + laser, lowres_laser = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 144 | + accessory, lowres_accessory = 'BODY_HEAD_BASIC/NONE.png', 'BODY_HEAD_BASIC/_thumbnail_NONE.png' |
| 145 | + |
| 146 | + add_assets( |
| 147 | + soup, |
| 148 | + ASSET_CANISTER_URL, |
| 149 | + background=background, |
| 150 | + background_accessory=background_accessory, |
| 151 | + body_head=body_head, |
| 152 | + top_head_leaf=top_head_leaf, |
| 153 | + top_head_crown=top_head_crown, |
| 154 | + top_head_chain=top_head_chain, |
| 155 | + mask=mask, |
| 156 | + eye=eye, |
| 157 | + accessory=accessory, |
| 158 | + bottom_head_accessory=bottom_head_accessory, |
| 159 | + body_accessory=body_accessory, |
| 160 | + neck=neck, |
| 161 | + frame=frame, |
| 162 | + laser=laser, |
| 163 | + ) |
| 164 | + |
| 165 | + add_assets( |
| 166 | + lowres_soup, |
| 167 | + ASSET_CANISTER_URL, |
| 168 | + background=lowres_background, |
| 169 | + background_accessory=lowres_background_accessory, |
| 170 | + body_head=lowres_body_head, |
| 171 | + top_head_leaf=lowres_top_head_leaf, |
| 172 | + top_head_crown=lowres_top_head_crown, |
| 173 | + top_head_chain=lowres_top_head_chain, |
| 174 | + mask=lowres_mask, |
| 175 | + eye=lowres_eye, |
| 176 | + accessory=lowres_accessory, |
| 177 | + bottom_head_accessory=lowres_bottom_head_accessory, |
| 178 | + body_accessory=lowres_body_accessory, |
| 179 | + neck=lowres_neck, |
| 180 | + frame=lowres_frame, |
| 181 | + laser=lowres_laser, |
| 182 | + ) |
| 183 | + |
| 184 | + with Path("../assets/"+str(i+1)+".svg").open('w') as random_svg: |
| 185 | + random_svg.write(str(soup)) |
| 186 | + with Path("../assets/"+str(i+1)+"_thumbnail.svg").open('w') as random_svg_low: |
| 187 | + random_svg_low.write(str(lowres_soup)) |
| 188 | + |
| 189 | + nfts.append( |
| 190 | + { |
| 191 | + "mint_number": i+1, |
| 192 | + "background": get_trait(background), |
| 193 | + "background_accessory": get_trait(background_accessory), |
| 194 | + "body_head": get_trait(body_head), |
| 195 | + "top_head_leaf": get_trait(top_head_leaf), |
| 196 | + "top_head_crown": get_trait(top_head_crown), |
| 197 | + "top_head_chain": get_trait(top_head_chain), |
| 198 | + "mask": get_trait(mask), |
| 199 | + "eye": get_trait(eye), |
| 200 | + "accessory": get_trait(accessory), |
| 201 | + "bottom_head_accessory": get_trait(bottom_head_accessory), |
| 202 | + "body_accessory": get_trait(body_accessory), |
| 203 | + "neck": get_trait(neck), |
| 204 | + "frame": get_trait(frame), |
| 205 | + "laser": get_trait(laser), |
| 206 | + 'unique': 'NONE' |
| 207 | + } |
| 208 | + ) |
| 209 | + |
| 210 | + # build uniques |
| 211 | + for id, item in enumerate(uniques): |
| 212 | + unique, lowres_unique = pick_choice([item], [1]) |
| 213 | + add_assets( |
| 214 | + soup, |
| 215 | + ASSET_CANISTER_URL, |
| 216 | + unique=unique, |
| 217 | + ) |
| 218 | + |
| 219 | + add_assets( |
| 220 | + lowres_soup, |
| 221 | + ASSET_CANISTER_URL, |
| 222 | + unique=lowres_unique, |
| 223 | + ) |
| 224 | + |
| 225 | + with Path("../assets/"+str(7761+id+1)+".svg").open('w') as random_svg: |
| 226 | + random_svg.write(str(soup)) |
| 227 | + with Path("../assets/"+str(7761+id+1)+"_thumbnail.svg").open('w') as random_svg_low: |
| 228 | + random_svg_low.write(str(lowres_soup)) |
| 229 | + |
| 230 | + nfts.append( |
| 231 | + { |
| 232 | + "mint_number": 7761+id+1, |
| 233 | + "background": 'NONE', |
| 234 | + "background_accessory": 'NONE', |
| 235 | + "body_head": 'NONE', |
| 236 | + "top_head_leaf": 'NONE', |
| 237 | + "top_head_crown": 'NONE', |
| 238 | + "top_head_chain": 'NONE', |
| 239 | + "mask": 'NONE', |
| 240 | + "eye": 'NONE', |
| 241 | + "accessory": 'NONE', |
| 242 | + "bottom_head_accessory": 'NONE', |
| 243 | + "body_accessory": 'NONE', |
| 244 | + "neck": 'NONE', |
| 245 | + "frame": 'NONE', |
| 246 | + "laser": 'NONE', |
| 247 | + 'unique': get_trait(unique, ".jpg"), |
| 248 | + } |
| 249 | + ) |
| 250 | + |
| 251 | + with open(f'{COLLECTION_NAME}.json', 'w') as f: |
| 252 | + json.dump(nfts, f, ensure_ascii=False, indent=4) |
| 253 | + |
| 254 | + with open(f'{COLLECTION_NAME}.csv', 'w', newline='') as csvfile: |
| 255 | + spamwriter = csv.writer(csvfile) |
| 256 | + spamwriter.writerow( |
| 257 | + ["mint_number", "background", "background_accessory", "body_head", "top_head_leaf", "top_head_crown", "top_head_chain", "mask", "eye", "accessory", "bottom_head_accessory", "body_accessory", "neck", "frame", "laser"]) |
| 258 | + for entry in nfts: |
| 259 | + spamwriter.writerow( |
| 260 | + [entry["mint_number"], entry["background"], entry["background_accessory"], entry["body_head"], entry["top_head_leaf"], entry["top_head_crown"], entry["top_head_chain"], entry["mask"], entry["eye"], entry["accessory"], entry["bottom_head_accessory"], entry["body_accessory"], entry["neck"], entry["frame"], entry["laser"]]) |
| 261 | + |
| 262 | + |
| 263 | +def stop_mint(): |
| 264 | + print("you already minted") |
0 commit comments