diff --git a/app.py b/app.py new file mode 100644 index 0000000..f90f00b --- /dev/null +++ b/app.py @@ -0,0 +1,120 @@ +""" +MODULES +""" +import os +import sys +from urllib import parse +from colorama import Style, Fore +import requests as req +from lib import card as dl +from lib import settings as cfg + +# System call +os.system("") + +def txt_downloader(): + """ + Download basic names decklist + """ + + # Loop through every card + with open(cfg.cardlist, 'r', encoding="utf-8") as cards: + for card in cards: + + # Remove line break + card = card.replace("\n","") + + # Basic land? + if card in cfg.basic_lands: + while True: + + # Have user choose the set, then download + land_set = input("Basic land found! What set should I pull the art from? ex: vow, m21, eld\n") + if len(land_set) >= 3: + c = req.get(f"https://api.scryfall.com/cards/named?fuzzy={parse.quote(card)}&set={parse.quote(land_set)}").json() + dl.Basic(c).download() + break + print("Error! Illegitimate set. Try again!\n") + + elif cfg.download_all: + + # Retrieve scryfall data + r = req.get(f"https://api.scryfall.com/cards/search?q=!\"{parse.quote(card)}\" is:hires&unique="+cfg.unique+"&order=released").json() + + # Loop through prints of this card + for c in r: + card_class = dl.get_card_class(c) + card_class(c).download() + + else: + + # Retrieve scryfall data + r = req.get(f"https://api.scryfall.com/cards/search?q=!\"{parse.quote(card)}\" is:hires&unique="+cfg.unique+"&order=released").json() + + # Remove full art entries? + prepared = [] + if cfg.exclude_fullart: + for t in r['data']: + if t['full_art'] is False: prepared.append(t) + else: prepared = r['data'] + + # Loop through prints of this card + for c in prepared: + card_class = dl.get_card_class(c) + card_class(c).download() + +def sheet_downloader(): + """ + Download given detailed.txt list + """ + + # Open the card list + with open(cfg.detailed, 'r', encoding="utf-8") as cards: + for item in cards: + + # Split the name and set + card = item.split("--") + set_code = card[0] + name = card[1] + + # Lookup card + c = req.get(f"https://api.scryfall.com/cards/named?fuzzy={parse.quote(name)}&set={parse.quote(set_code)}").json() + card_class = dl.get_card_class(c) + card_class(c).download() + +print(f"{Fore.YELLOW}{Style.BRIGHT}\n") +print(" ██████╗ ███████╗████████╗ ███╗ ███╗████████╗ ██████╗ ") +print(" ██╔════╝ ██╔════╝╚══██╔══╝ ████╗ ████║╚══██╔══╝██╔════╝ ") +print(" ██║ ███╗█████╗ ██║ ██╔████╔██║ ██║ ██║ ███╗") +print(" ██║ ██║██╔══╝ ██║ ██║╚██╔╝██║ ██║ ██║ ██║") +print(" ╚██████╔╝███████╗ ██║ ██║ ╚═╝ ██║ ██║ ╚██████╔╝") +print(" ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ") +print(" █████╗ ██████╗ ████████╗ ███╗ ██╗ ██████╗ ██╗ ██╗ ") +print(" ██╔══██╗██╔══██╗╚══██╔══╝ ████╗ ██║██╔═══██╗██║ ██║ ") +print(" ███████║██████╔╝ ██║ ██╔██╗ ██║██║ ██║██║ █╗ ██║ ") +print(" ██╔══██║██╔══██╗ ██║ ██║╚██╗██║██║ ██║██║███╗██║ ") +print(" ██║ ██║██║ ██║ ██║ ██║ ╚████║╚██████╔╝╚███╔███╔╝ ") +print(" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══╝╚══╝ ") +print(f"{Fore.CYAN}{Style.BRIGHT}MTG Art Downloader by Mr Teferi") +print("Additional thanks to Trix are for Scoot + Gikkman") +print(f"http://mpcfill.com --- Support great MTG Proxies!{Style.RESET_ALL}\n") + + +# Does the user want to use Google Sheet queeries or cards from txt file? +choice = input("Enter 1 to download arts from cardname list in cards.txt.\nEnter 2 to download images from \"set--name\" list in detailed.txt.\nFor help using this app, visit: tinyurl.com/mtg-art-dl\n") + +while True: + # Import our Google Sheets generated queeries + if choice == "1": + print("\nCan do! Grab yourself a beer, we might be here a minute..") + txt_downloader() + break + if choice == "2": + print("\nCan do! Grab yourself a beer, we might be here a minute..") + sheet_downloader() + break + choice = input("\nDo you think this is a game? Try again.\n") + +print("\nAll available files downloaded.\nSee failed.txt for images that couldn't be located.\nPress enter to exit :)") +input() +sys.exit() diff --git a/cards.txt b/cards.txt index 8a9cd89..a9092a6 100644 --- a/cards.txt +++ b/cards.txt @@ -1,20 +1,5 @@ -Seachrome Coast -Darkslick Shores -Blackcleave Cliffs -Copperline Gorge -Razorverge Thicket -Concealed Courtyard -Blooming Marsh -Botanical Sanctum -Spirebluff Canal -Inspiring Vantage -Celestial Colonnade -Creeping Tar Pit -Lavaclaw Reaches -Raging Ravine -Stirring Wildwood -Shambling Vent -Hissing Quagmire -Lumbering Falls -Wandering Fumarole -Needle Spires \ No newline at end of file +Kokusho, the Evening Star +Ryusei, the Falling Star +Jugan, the Rising Star +Yosei, the Morning Star +Keiga, the Tide Star \ No newline at end of file diff --git a/config.ini b/config.ini index baa95e0..4f92ba2 100644 --- a/config.ini +++ b/config.ini @@ -2,13 +2,9 @@ Download.Folder = downloaded Scryfall.Art.Folder = scryfall MTGPics.Art.Folder = mtgpics -Scryfall.Backs.Folder = backs -MTGPics.Backs.Folder = backs -Card.List = cards.txt -Card.Detailed.List = detailed.txt [SETTINGS] -If.Missing.Download.Scryfall = true +If.Missing.Download.Scryfall = false Only.Search.Unique.Art = true Exclude.Fullart = false Download.All = true \ No newline at end of file diff --git a/detailed.txt b/detailed.txt index 5de85b1..55b1b85 100644 --- a/detailed.txt +++ b/detailed.txt @@ -1,80 +1,280 @@ -neo--Akki Ember-Keeper -neo--Automated Artificer -neo--Banishing Slash -neo--Behold the Unspeakable -neo--Biting-Palm Ninja -neo--Boon of Boseiju -neo--Born to Drive -neo--Bronze Cudgels -neo--Brute Suit -neo--Careful Cultivation -neo--Cloudsteel Kirin -neo--Crackling Emergence -neo--Debt to the Kami -neo--Dokuchi Silencer -neo--Dragonfly Suit -neo--Ecologist's Terrarium -neo--Eiganjo Exemplar -neo--Experimental Synthesizer -neo--Explosive Singularity -neo--Fade into Antiquity -neo--Forest -neo--Futurist Operative -neo--Futurist Sentinel -neo--Geothermal Kami -neo--Gift of Wrath -neo--Go-Shintai of Ancient Wars -neo--Go-Shintai of Boundless Vigor -neo--Go-Shintai of Hidden Cruelty -neo--Go-Shintai of Lost Wisdom -neo--Grafted Growth -neo--Heir of the Ancient Fang -neo--Hinata, Dawn-Crowned -neo--Hotshot Mechanic -neo--Imperial Recovery Unit -neo--Invigorating Hot Spring -neo--Iron Apprentice -neo--Ironhoof Boar -neo--Island -neo--Jukai Trainee -neo--Junji, the Midnight Sky -neo--Kami of Restless Shadows -neo--Kami of Terrible Secrets -neo--Kami's Flare -neo--Kappa Tech-Wrecker -neo--Kotose, the Silent Spider -neo--Leech Gauntlet -neo--Lizard Blades -neo--Malicious Malfunction -neo--March of Swirling Mist -neo--Master's Rebuke -neo--Mindlink Mech -neo--Mirror Box -neo--Mnemonic Sphere -neo--Moon-Circuit Hacker -neo--Mountain -neo--Mukotai Soulripper -neo--Ninja's Kunai -neo--Oni-Cult Anvil -neo--Papercraft Decoy -neo--Peerless Samurai -neo--Plains -neo--Reckoner Shakedown -neo--Reito Sentinel -neo--Roadside Reliquary -neo--Seismic Wave -neo--Seven-Tail Mentor -neo--Short Circuit -neo--Shrine Steward -neo--Soul Transfer -neo--Spirit-Sister's Call -neo--Suit Up -neo--Swamp -neo--Takenuma, Abandoned Mire -neo--Tempered in Solitude -neo--Towashi Guide-Bot -neo--Tranquil Cove -neo--Upriser Renegade -neo--Virus Beetle -neo--Webspinner Cuff -neo--Wind-Scarred Crag \ No newline at end of file +stx--Academic Dispute +stx--Academic Probation +stx--Access Tunnel +stx--Accomplished Alchemist +stx--Aether Helix +stx--Ageless Guardian +stx--Arcane Subtraction +stx--Archmage Emeritus +stx--Archway Commons +stx--Ardent Dustspeaker +stx--Arrogant Poet +stx--Augmenter Pugilist +stx--Baleful Mastery +stx--Basic Conjuration +stx--Bayou Groff +stx--Beaming Defiance +stx--Beledros Witherbloom +stx--Biblioplex Assistant +stx--Big Play +stx--Biomathematician +stx--Blade Historian +stx--Blex, Vexing Pest +stx--Blood Age General +stx--Blood Researcher +stx--Blot Out the Sky +stx--Body of Research +stx--Bookwurm +stx--Brackish Trudge +stx--Burrog Befuddler +stx--Bury in Books +stx--Callous Bloodmage +stx--Campus Guide +stx--Charge Through +stx--Clever Lumimancer +stx--Closing Statement +stx--Codie, Vociferous Codex +stx--Cogwork Archivist +stx--Combat Professor +stx--Confront the Past +stx--Conspiracy Theorist +stx--Containment Breach +stx--Crackle with Power +stx--Cram Session +stx--Creative Outburst +stx--Crushing Disappointment +stx--Culling Ritual +stx--Culmination of Studies +stx--Curate +stx--Daemogoth Titan +stx--Daemogoth Woe-Eater +stx--Deadly Brew +stx--Decisive Denial +stx--Defend the Campus +stx--Detention Vortex +stx--Devastating Mastery +stx--Devouring Tendrils +stx--Dina, Soul Steeper +stx--Divide by Zero +stx--Double Major +stx--Draconic Intervention +stx--Dragon's Approach +stx--Dragonsguard Elite +stx--Dramatic Finale +stx--Dream Strix +stx--Dueling Coach +stx--Eager First-Year +stx--Ecological Appreciation +stx--Efreet Flamepainter +stx--Elemental Expressionist +stx--Elemental Masterpiece +stx--Elemental Summoning +stx--Elite Spellbinder +stx--Emergent Sequence +stx--Enthusiastic Study +stx--Environmental Sciences +stx--Essence Infusion +stx--Eureka Moment +stx--Excavated Wall +stx--Exhilarating Elocution +stx--Expanded Anatomy +stx--Expel +stx--Explosive Welcome +stx--Exponential Growth +stx--Expressive Iteration +stx--Extus, Oriq Overlord +stx--Eyetwitch +stx--Fervent Mastery +stx--Field Trip +stx--First Day of Class +stx--Flamescroll Celebrant +stx--Flunk +stx--Forest +stx--Fortifying Draught +stx--Fractal Summoning +stx--Fracture +stx--Frostboil Snarl +stx--Frost Trickster +stx--Fuming Effigy +stx--Furycalm Snarl +stx--Galazeth Prismari +stx--Gnarled Professor +stx--Go Blank +stx--Golden Ratio +stx--Grinning Ignus +stx--Guiding Voice +stx--Hall Monitor +stx--Hall of Oracles +stx--Harness Infinity +stx--Heated Debate +stx--Hofri Ghostforge +stx--Honor Troll +stx--Humiliate +stx--Hunt for Specimens +stx--Igneous Inspiration +stx--Illuminate History +stx--Illustrious Historian +stx--Infuse with Vitality +stx--Ingenious Mastery +stx--Inkling Summoning +stx--Introduction to Annihilation +stx--Introduction to Prophecy +stx--Island +stx--Jadzi, Oracle of Arcavios +stx--Karok Wrangler +stx--Kasmina, Enigma Sage +stx--Kelpie Guide +stx--Kianne, Dean of Substance +stx--Killian, Ink Duelist +stx--Lash of Malice +stx--Leech Fanatic +stx--Leonin Lightscribe +stx--Letter of Acceptance +stx--Leyline Invocation +stx--Lorehold Apprentice +stx--Lorehold Campus +stx--Lorehold Command +stx--Lorehold Excavation +stx--Lorehold Pledgemage +stx--Maelstrom Muse +stx--Mage Duel +stx--Mage Hunter +stx--Mage Hunters' Onslaught +stx--Magma Opus +stx--Make Your Mark +stx--Manifestation Sage +stx--Mascot Exhibition +stx--Mascot Interception +stx--Master Symmetrist +stx--Mavinda, Students' Advocate +stx--Mentor's Guidance +stx--Mercurial Transformation +stx--Mila, Crafty Companion +stx--Moldering Karok +stx--Mortality Spear +stx--Mountain +stx--Multiple Choice +stx--Necroblossom Snarl +stx--Necrotic Fumes +stx--Needlethorn Drake +stx--Novice Dissector +stx--Oggyar Battle-Seer +stx--Oriq Loremage +stx--Overgrown Arch +stx--Owlin Shieldmage +stx--Pestilent Cauldron +stx--Pest Summoning +stx--Pigment Storm +stx--Pilgrim of the Ages +stx--Pillardrop Rescuer +stx--Pillardrop Warden +stx--Plains +stx--Plargg, Dean of Chaos +stx--Plumb the Forbidden +stx--Poet's Quill +stx--Pop Quiz +stx--Practical Research +stx--Prismari Apprentice +stx--Prismari Campus +stx--Prismari Command +stx--Prismari Pledgemage +stx--Professor of Symbology +stx--Professor of Zoomancy +stx--Professor Onyx +stx--Professor's Warning +stx--Promising Duskmage +stx--Quandrix Apprentice +stx--Quandrix Campus +stx--Quandrix Command +stx--Quandrix Cultivator +stx--Quandrix Pledgemage +stx--Quintorius, Field Historian +stx--Radiant Scrollwielder +stx--Reckless Amplimancer +stx--Reconstruct History +stx--Reduce to Memory +stx--Reflective Golem +stx--Reject +stx--Relic Sloth +stx--Resculpt +stx--Retriever Phoenix +stx--Returned Pastcaller +stx--Rip Apart +stx--Rise of Extus +stx--Rootha, Mercurial Artist +stx--Rowan, Scholar of Sparks +stx--Rushed Rebirth +stx--Scurrid Colony +stx--Secret Rendezvous +stx--Sedgemoor Witch +stx--Selfless Glyphweaver +stx--Semester's End +stx--Serpentine Curve +stx--Shadewing Laureate +stx--Shadrix Silverquill +stx--Shaile, Dean of Radiance +stx--Shineshadow Snarl +stx--Show of Confidence +stx--Silverquill Apprentice +stx--Silverquill Campus +stx--Silverquill Command +stx--Silverquill Pledgemage +stx--Silverquill Silencer +stx--Snow Day +stx--Solve the Equation +stx--Soothsayer Adept +stx--Sparring Regimen +stx--Spectacle Mage +stx--Specter of the Fens +stx--Spell Satchel +stx--Spined Karok +stx--Spirit Summoning +stx--Spiteful Squad +stx--Springmane Cervin +stx--Square Up +stx--Star Pupil +stx--Start from Scratch +stx--Stonebinder's Familiar +stx--Stonebound Mentor +stx--Stonerise Spirit +stx--Storm-Kiln Artist +stx--Strict Proctor +stx--Strixhaven Stadium +stx--Study Break +stx--Sudden Breakthrough +stx--Swamp +stx--Symmetry Sage +stx--Tanazir Quandrix +stx--Tangletrap +stx--Teach by Example +stx--Teachings of the Archaics +stx--Team Pennant +stx--Tempted by the Oriq +stx--Tend the Pests +stx--Tenured Inkcaster +stx--Test of Talents +stx--The Biblioplex +stx--Thrilling Discovery +stx--Thunderous Orator +stx--Tome Shredder +stx--Torrent Sculptor +stx--Twinscroll Shaman +stx--Umbral Juke +stx--Unwilling Ingredient +stx--Uvilda, Dean of Perfection +stx--Valentin, Dean of the Vein +stx--Vanishing Verse +stx--Velomachus Lorehold +stx--Venerable Warsinger +stx--Verdant Mastery +stx--Vineglimmer Snarl +stx--Vortex Runner +stx--Wandering Archaic +stx--Waterfall Aerialist +stx--Witherbloom Apprentice +stx--Witherbloom Campus +stx--Witherbloom Command +stx--Witherbloom Pledgemage +stx--Wormhole Serpent +stx--Zephyr Boots +stx--Zimone, Quandrix Prodigy \ No newline at end of file diff --git a/downloader.py b/downloader.py deleted file mode 100644 index 5baef60..0000000 --- a/downloader.py +++ /dev/null @@ -1,265 +0,0 @@ -# Requirements -import requests -import settings -import urllib.request -import urllib.error -import re -from colorama import init, Style, Fore, Back -from contextlib import suppress -from pathlib import Path -from bs4 import BeautifulSoup - -def download_card (txt,set_code,code,name,artist,scrylink,name2,layout,set_type,alternate): - - # Make sure numeric code is 3 digits - if len(code) == 1: code = "00"+code - elif len(code) == 2: code = "0"+code - - # Set up the filename - filename = "/" + name + " (" + artist + ") [" + set_code.upper() + "].jpg" - - # Some sets aren't represented accurately on mtgpics, lets fix it - set = fix_set_mtgp(set_code) - - # Get correct mtgp code - mtgp_code = get_mtgp_code (set, name, alternate) - if mtgp_code == "missing": - if set_type == "promo": - mtgp_code = get_mtgp_code ("pmo", name, alternate) - if mtgp_code == "missing": mtg_code = set+code - else: mtgp_code = set+code - - # Which type of card? - if layout == "transform" or layout == "modal_dfc" or layout == "split": - - # Try downloading from mtgp - success = download_mtgp (name,settings.f_mtgp+filename,mtgp_code,False) - - # If failed, download scryfall art - if success == False: scryfall_success = download_scryfall (name,scrylink,settings.f_scry+filename,False) - - # Filename for back - filename2 = "/" + name2 + " (" + artist + ") [" + set_code.upper() + "].jpg" - - # Try downloading back from mtgp - if success: success = download_mtgp (name2,settings.f_mtgp_b+filename2,mtgp_code,True) - - # If failed, download scryfall art - if success == False: - scryfall_success = download_scryfall (name2,scrylink.replace("front","back"),settings.f_scry_b+filename2,True) - else: scryfall_success = True; - - else: - # Try downloading from mtgp - success = download_mtgp (name,settings.f_mtgp+filename,mtgp_code,False) - - # If failed, download scryfall art - if success == False: scryfall_success = download_scryfall (name,scrylink,settings.f_scry+filename,False) - else: scryfall_success = True; - - #if scryfall_success == False: txt.write(name+" (https://www.mtgpics.com/card?ref="+mtgp_code+")\n") # OLD WAY - if scryfall_success == False: txt.write(name+"--"+set_code+"\n") - -def download_mtgp (name,filename,mtgp_code,back): - try: - # Crawl the mtgpics site to find correct link for mdfc card - r = requests.get("https://www.mtgpics.com/card?ref="+mtgp_code) - soup = BeautifulSoup(r.content, "html.parser") - soup_img = soup.find_all("img", {"style": "display:block;border:4px black solid;cursor:pointer;"}) - - # Is this the back face? - if back: - img_src = soup_img[1]['src'] - name = name + " (Back)" - else: img_src = soup_img[0]['src'] - - # Final mtgp IMG link - img_link = img_src.replace("pics/art_th/","https://mtgpics.com/pics/art/") - - # Try to download from MTG Pics - urllib.request.urlretrieve(img_link, filename) - print(f"{Fore.GREEN}SUCCESS MTGP: {Style.RESET_ALL}" + name) - return(True) - except: return(False) - -def download_scryfall (name,scrylink,filename,back): - # Is downloading scryfall enabled? - if settings.download_scryfall: - # Is this a card back? - if back: name = name + " (BACK)" - print(f"{Fore.RED}MTGP is missing " + name + ", checking Scryfall...") - try: - urllib.request.urlretrieve(scrylink, filename) - print(f"{Fore.GREEN}SUCCESS SCRY: {Style.RESET_ALL}" + name) - return(True) - except: - print(f"{Fore.RED}FAILED ALL: {Style.RESET_ALL}" + name) - return(False) - else: - print(f"{Fore.RED}MTGP is missing " + name + f"{Style.RESET_ALL}") - return(False) - -def get_mtgp_code (set, name, alternate): - try: - # Crawl the mtgpics site to find correct set code - r = requests.get("https://www.mtgpics.com/card?ref="+set+"001") - soup = BeautifulSoup(r.content, "html.parser") - soup_td = soup.find("td", {"width": "170", "align": "center"}) - soup_a = soup_td.find('a') - src_link = soup_a['href'] - mtgp_link = "https://mtgpics.com/"+src_link - - # Crawl the set page to find the correct link - r = requests.get(mtgp_link) - soup = BeautifulSoup(r.content, "html.parser") - soup_i = soup.find_all("img", attrs={"alt": re.compile('^'+name+'.*')}) - if alternate: soup_src = soup_i[1]['src'] - else: soup_src = soup_i[0]['src'] - mtgp_code = soup_src.replace("../pics/reg/","") - mtgp_code = mtgp_code.replace("/","") - return(mtgp_code.replace(".jpg","")) - except: return("missing") - -# Beta feature, needs additional work -def download_cards (txt, json): - - # Used to track whether mtgp downloaded for both sides - mtgp = False - mtgp_b = False - - for card in json: - - # Base variables - set_code = card['set'] - card_num = card['collector_number'] - artist = card['artist'] - set = fix_set_mtgp(set_code) - - # Is this double faced? - if 'card_faces' in card: - flipname = card['card_faces'][1]['name'] - art_crop = card['card_faces'][0]['image_uris']['art_crop'] - card_name = card['card_faces'][0]['name'] - filename = "/" + card_name + " (" + artist + ") [" + set_code.upper() + "].jpg" - filename2 = "/" + flipname + " (" + artist + ") [" + set_code.upper() + "].jpg" - else: - art_crop = card['image_uris']['art_crop'] - card_name = card['name'] - filename = "/" + card_name + " (" + artist + ") [" + set_code.upper() + "].jpg" - mtgp_b = True - - # Borderless card? - if card['border_color'] == "borderless": alternate = True - else: alternate = False - - # Get correct mtgp code - mtgp_code = get_mtgp_code(set, card_name, alternate) - if mtgp_code == "missing": - if card['set_type'] == "promo": - mtgp_code = get_mtgp_code("pmo", card_name, alternate) - if mtgp_code == "missing": mtgp_code = set+card_num - else: mtgp_code = set+card_num - - # Has MTGPic art been found yet? - if mtgp == False: mtgp = download_mtgp (card_name,settings.f_mtgp+filename,mtgp_code,False) - - # Has MTGPic art been found for back? - if mtgp_b == False: mtgp_b = download_mtgp (flipname,settings.f_mtgp_b+filename2,mtgp_code,True) - - card = json[0] - - # Base variables - set_code = card['set'] - card_num = card['collector_number'] - artist = card['artist'] - - # Is this mdfc? - if 'card_faces' in card: - flipname = card['card_faces'][1]['name'] - card_name = card['card_faces'][0]['name'] - scrylink = card['card_faces'][0]['image_uris']['art_crop'] - filename = "/" + card_name + " (" + artist + ") [" + set_code.upper() + "].jpg" - filename2 = "/" + flipname + " (" + artist + ") [" + set_code.upper() + "].jpg" - else: - scrylink = card['image_uris']['art_crop'] - card_name = card['name'] - filename = "/" + card_name + " (" + artist + ") [" + set_code.upper() + "].jpg" - - # Did MTGP fail all? - if mtgp == False: download_scryfall (card_name,scrylink,settings.f_scry+filename,False) - - # Did MTGP fail all backs? - if mtgp_b == False: download_scryfall (flipname,scrylink.replace("front","back"),settings.f_scry_b+filename2,True) - -def fix_set_mtgp (set): - if set == "arb": return("alr") - if set == "mp2": return("aki") - if set == "atq": return("ant") - if set == "apc": return("apo") - if set == "arn": return("ara") - if set == "e01": return("anb") - if set == "anb": return("an2") - if set == "bok": return("bek") - if set == "csp": return("col") - if set == "c13": return("13c") - if set == "c14": return("14c") - if set == "c15": return("15c") - if set == "c16": return("16c") - if set == "c17": return("17c") - if set == "cn2": return("2cn") - if set == "dst": return("drs") - if set == "dpa": return("dop") - if set == "e02": return("dop") - if set == "fem": return("fal") - if set == "5dn": return("fda") - if set == "v17": return("ftr") - if set == "gpt": return("gui") - if set == "hml": return("hom") - if set == "mps": return("kli") - if set == "lgn": return("lgi") - if set == "lrw": return("lor") - if set == "m10": return("10m") - if set == "m11": return("11m") - if set == "m12": return("12m") - if set == "m13": return("13m") - if set == "m14": return("14m") - if set == "m15": return("15m") - if set == "a25": return("25m") - if set == "mmq": return("mer") - if set == "mm2": return("mmb") - if set == "mm3": return("mmc") - if set == "hop": return("pch") - if set == "pc2": return("2pc") - if set == "pls": return("pla") - if set == "p02": return("psa") - if set == "pd2": return("fir") - if set == "pd3": return("gra") - if set == "pcy": return("pro") - if set == "3ed": return("rev") - if set == "sok": return("sak") - if set == "scg": return("sco") - if set == "shm": return("sha") - if set == "ala": return("soa") - if set == "sta": return("stm") - if set == "sth": return("str") - if set == "tmp": return("tem") - if set == "drk": return("dar") - if set == "puma": return("uma") - if set == "uma": return("ulm") - if set == "ugl": return("ung") - if set == "wth": return("wea") - if set == "exp": return("zex") - if set == "10e": return("xth") - if set == "9ed": return("9th") - if set == "8ed": return("8th") - if set == "7ed": return("7th") - if set == "6ed": return("6th") - if set == "5ed": return("5th") - if set == "4ed": return("4th") - if set == "pnat": return("pmo") - if set == "pvow": return("vow") - if set == "pmid": return("mid") - if set == "me3": return("3me") - if set == "me2": return("2me") - if set == "me1": return("1me") - else: return(set) \ No newline at end of file diff --git a/find.py b/find.py deleted file mode 100644 index 03ac182..0000000 --- a/find.py +++ /dev/null @@ -1,161 +0,0 @@ -# Requirements -import requests -import settings -import time -import sys -import os -from downloader import download_card, download_cards -from urllib import request, parse, error -from colorama import init, Style, Fore, Back -from contextlib import suppress -from pathlib import Path -from bs4 import BeautifulSoup - -# System call -os.system("") - -# Create folders if they don't exist -Path(settings.f_name).mkdir(mode=511, parents=True, exist_ok=True) -Path(settings.f_mtgp).mkdir(mode=511, parents=True, exist_ok=True) -Path(settings.f_scry).mkdir(mode=511, parents=True, exist_ok=True) -Path(settings.f_mtgp_b).mkdir(mode=511, parents=True, exist_ok=True) -Path(settings.f_scry_b).mkdir(mode=511, parents=True, exist_ok=True) - -def txt_downloader (): - # Open the failed to find txt - failed = open(settings.f_name+"/failed.txt","w+") - - with open(settings.cardlist, 'r') as cards: - for card in cards: - # Remove line break - card = card.replace("\n","") - if card in settings.basic_lands: - z = 0 - while z == 0: - print("Basic land found! What set should I pull the art from? ex: vow, m21, eld\n") - land_set = input() - if len(land_set) >= 3: - z = 1 - r = requests.get(f"https://api.scryfall.com/cards/named?fuzzy={parse.quote(card)}&set={parse.quote(land_set)}").json() - - # Borderless card? - if r['border_color'] == "borderless": alternate = True - else: alternate = False - - download_card(failed, r['set'], r['collector_number'], r['name'], r['artist'], r['image_uris']['art_crop'], "", r['layout'], r['set_type'], alternate) - else: print("Error! Illegitimate set. Try again!\n") - else: - if settings.download_all: - raw = requests.get(f"https://api.scryfall.com/cards/search?q=!\"{parse.quote(card)}\" is:hires&unique="+settings.unique+"&order=released").json() - for r in raw['data']: - set = r['set'] - card_num = r['collector_number'] - artist = r['artist'] - layout = r['layout'] - flipname = "" - - # Extra stuff for flip cards - if "card_faces" in r: - flipname = r['card_faces'][1]['name'] - art_crop = r['card_faces'][0]['image_uris']['art_crop'] - card_name = r['card_faces'][0]['name'] - else: - art_crop = r['image_uris']['art_crop'] - card_name = r['name'] - - # Borderless card? - if r['border_color'] == "borderless" or r['collector_number'][-1] == "s": alternate = True - else: alternate = False - - if settings.exclude_fullart == True: - if r['full_art'] == True: print("\nSkipping fullart image...\n") - else: download_card(failed, set, card_num, card_name, artist, art_crop, flipname, layout, r['set_type'], alternate) - else: download_card(failed, set, card_num, card_name, artist, art_crop, flipname, layout, r['set_type'], alternate) - else: - raw = requests.get(f"https://api.scryfall.com/cards/search?q=!\"{parse.quote(card)}\" is:hires&unique="+settings.unique+"&order=released").json() - # Remove full art entries? - prepared = [] - if settings.exclude_fullart == True: - for foo in raw['data']: - if foo['full_art'] == False: prepared.append(foo) - else: prepared = raw['data'] - if prepared: download_cards(failed,prepared) - else: print(card + " not found!") - # Close the txt file - failed.close() - - print("\nAll available files downloaded.\nSee failed.txt for images that couldn't be located.\nPress enter to exit :)") - input() - sys.exit() - -def sheet_downloader (): - # Open the failed to find txt - failed = open(settings.f_name+"/failed.txt","w+") - - # Open the card list - with open(settings.detailed_list, 'r') as cards: - for item in cards: - - # Split the name and set - card = item.split("--") - set_code = card[0] - name = card[1] - - # Lookup the card - r = requests.get(f"https://api.scryfall.com/cards/named?fuzzy={parse.quote(name)}&set={parse.quote(set_code)}").json() - - # Is this a flip card? - flipname = "" - if "card_faces" in r: - flipname = r['card_faces'][1]['name'] - art_crop = r['card_faces'][0]['image_uris']['art_crop'] - card_name = r['card_faces'][0]['name'] - else: - art_crop = r['image_uris']['art_crop'] - card_name = r['name'] - - # Borderless card? - if r['border_color'] == "borderless" or r['collector_number'][-1] == "s": alternate = True - else: alternate = False - - # Download the card - download_card(failed, r['set'], r['collector_number'], card_name, r['artist'], art_crop, flipname, r['layout'], r['set_type'], alternate) - - # Close the txt file - failed.close() - - print("\nAll available files downloaded.\nSee failed.txt for images that couldn't be located.\nPress enter to exit :)") - input() - sys.exit() - -print(f"{Fore.YELLOW}{Style.BRIGHT}\n ██████╗ ███████╗████████╗ ███╗ ███╗████████╗ ██████╗ ") -print(f" ██╔════╝ ██╔════╝╚══██╔══╝ ████╗ ████║╚══██╔══╝██╔════╝ ") -print(f" ██║ ███╗█████╗ ██║ ██╔████╔██║ ██║ ██║ ███╗") -print(f" ██║ ██║██╔══╝ ██║ ██║╚██╔╝██║ ██║ ██║ ██║") -print(f" ╚██████╔╝███████╗ ██║ ██║ ╚═╝ ██║ ██║ ╚██████╔╝") -print(f" ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ") -print(f" █████╗ ██████╗ ████████╗ ███╗ ██╗ ██████╗ ██╗ ██╗ ") -print(f" ██╔══██╗██╔══██╗╚══██╔══╝ ████╗ ██║██╔═══██╗██║ ██║ ") -print(f" ███████║██████╔╝ ██║ ██╔██╗ ██║██║ ██║██║ █╗ ██║ ") -print(f" ██╔══██║██╔══██╗ ██║ ██║╚██╗██║██║ ██║██║███╗██║ ") -print(f" ██║ ██║██║ ██║ ██║ ██║ ╚████║╚██████╔╝╚███╔███╔╝ ") -print(f" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══╝╚══╝ {Style.RESET_ALL}\n") -print(f"{Fore.CYAN}{Style.BRIGHT}MTG Art Downloader by Mr Teferi") -print(f"Additional credit to Trix are for Scoot + Gikkman") -print(f"http://mpcfill.com --- Support great MTG Proxies!{Style.RESET_ALL}\n") -z = 0 -while z == 0: - # Does the user want to use Google Sheet queeries or cards from txt file? - print("Enter 1 to download arts from cardname list in cards.txt.\nEnter 2 to download images from \"set--name\" list in detailed.txt.\nFor help using this app, visit: tinyurl.com/mtg-art-dl") - choice = input() - - # Import our Google Sheets generated queeries - if choice == "1": - z = 1 - print("\nCan do! Grab yourself a beer, we might be here a minute..") - txt_downloader() - elif choice == "2": - z = 1 - print("\nCan do! Grab yourself a beer, we might be here a minute..") - sheet_downloader() - else: print("\nDo you think this is a game? Try again.\n") \ No newline at end of file diff --git a/lib/card.py b/lib/card.py new file mode 100644 index 0000000..beb58d5 --- /dev/null +++ b/lib/card.py @@ -0,0 +1,329 @@ +""" +CARD CLASSES +""" +# pylint: disable=E0401, R0902, E1101 +import os +from pathlib import Path +from urllib import request +from bs4 import BeautifulSoup +from colorama import Style, Fore +import requests +from lib import settings as cfg +from lib import core +cwd = os.getcwd() + +# SINGLE IMAGE CARDS +class Card (): + """ + Base class to extend all cards to. + """ + + def __init__ (self, c): + + # Inherited card info + self.set = c['set'] + self.artist = c['artist'] + self.num = c['collector_number'] + self.mtgp_set = core.fix_mtgp_set(self.set) + + # Name if not defined + try: self.name + except: self.name = c['name'] + + # Make sure card num is 3 digits + if len(self.num) == 1: self.num = f"00{self.num}" + elif len(self.num) == 2: self.num = f"0{self.num}" + + # Alternate version or promo card + self.alt = bool(c['border_color'] == "borderless" or self.num[-1] == "s") + self.promo = bool(c['set_type'] == "promo") + + # Get the correct mtgp URL code + try: + if self.alt: self.code = core.get_mtgp_code(self.mtgp_set, self.name, True) + else: self.code = core.get_mtgp_code(self.mtgp_set, self.name) + except: + if self.promo: + try: + if self.alt: self.code = core.get_mtgp_code("pmo", self.name, True) + else: self.code = core.get_mtgp_code("pmo", self.name) + except: self.code = self.set+self.num + else: self.code = self.set+self.num + + def download (self, log_failed=True): + """ + Download just one version of this card. + """ + try: self.download_mtgp (self.name, self.mtgp_path, self.code) + except: + if cfg.download_scryfall: self.download_scryfall (self.name, self.scry_path, self.scrylink) + elif log_failed: core.log(self.name, self.set) + + def download_mtgp (self, name, path, mtgp_code, back=False): + """ + Download from MTG Pics + """ + # Crawl the mtgpics site to find correct link for mdfc card + r = requests.get("https://www.mtgpics.com/card?ref="+mtgp_code) + soup = BeautifulSoup(r.content, "html.parser") + soup_img = soup.find_all("img", {"style": "display:block;border:4px black solid;cursor:pointer;"}) + + # Is this the back face? + if back: + img_src = soup_img[1]['src'] + name = name + " (Back)" + else: img_src = soup_img[0]['src'] + + # Final mtgp IMG link + img_link = img_src.replace("pics/art_th/","https://mtgpics.com/pics/art/") + + # Try to download from MTG Pics + request.urlretrieve(img_link, path) + print(f"{Fore.GREEN}SUCCESS: {Style.RESET_ALL}" + name) + + def download_scryfall (self, name, path, scrylink): + """ + Download scryfall art crop + """ + print(f"{Fore.YELLOW}MTGP FAILED: {name} downloaded Scryfall") + request.urlretrieve(scrylink, path) + + def make_folders(self, name): + """ + Check that the folders exist + """ + Path(os.path.join(cfg.mtgp, name)).mkdir(mode=511, parents=True, exist_ok=True) + Path(os.path.join(cfg.scry, name)).mkdir(mode=511, parents=True, exist_ok=True) + +class Normal (Card): + """ + Normal frame card + """ + def __init__ (self, c): + super().__init__(c) + self.scrylink = c['image_uris']['art_crop'] + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + +class Basic (Normal): + """ + Basic land card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Basic Land/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Basic Land/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Basic Land") + +class Saga (Normal): + """ + Saga card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Saga/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Saga/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Saga") + +class Adventure (Normal): + """ + Adventure card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Adventure/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Adventure/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Adventure") + +class Leveler (Normal): + """ + Leveler card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Leveler/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Leveler/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Leveler") + +class Planeswalker (Normal): + """ + Planeswalker card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Planeswalker/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Planeswalker/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Planeswalker") + +class Class (Normal): + """ + Class card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Class/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Class/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Class") + +class Planar (Normal): + """ + Planar card + """ + def __init__ (self, c): + super().__init__(c) + + # Saved filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/Planar/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/Planar/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folder exists + super().make_folders("Planar") + +# MULTIPLE IMAGE CARDS +class MDFC (Card): + """ + Double faced card + """ + def __init__(self, c): + + # Face variables + self.name = c['card_faces'][0]['name'] + self.name_back = c['card_faces'][1]['name'] + self.scrylink = c['card_faces'][0]['image_uris']['art_crop'] + self.scrylink_back = c['card_faces'][1]['image_uris']['art_crop'] + + super().__init__(c) + + # Front filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/MDFC Front/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/MDFC Front/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Back filepath + self.mtgp_path_back = os.path.join(cwd, + f"{cfg.mtgp}/MDFC Back/{self.name_back} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path_back = os.path.join(cwd, + f"{cfg.scry}/MDFC Back/{self.name_back} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folders exist + super().make_folders("MDFC Front") + super().make_folders("MDFC Back") + + def download (self, log_failed=True): + """ + Download each card + """ + # Download Front + front = True + try: self.download_mtgp (self.name, self.mtgp_path, self.code) + except: + if cfg.download_scryfall: self.download_scryfall (self.name, self.scry_path, self.scrylink) + else: front = False + + # Download back + back = True + try: self.download_mtgp (self.name_back, self.mtgp_path_back, self.code, True) + except: + if cfg.download_scryfall: super.download_scryfall (self.name_back, self.scry_path_back, self.scrylink_back) + else: back = False + + # Log any failures + if log_failed: + if not front and not back: core.log(self.name, self.set) + elif not front: core.log(self.name, self.set, "failed_front") + elif not back: core.log(self.name_back, self.set, "failed_back") + +class Transform (MDFC): + """ + Transform card + """ + def __init__(self, c): + super().__init__(c) + + # Front filepath + self.mtgp_path = os.path.join(cwd, + f"{cfg.mtgp}/TF Front/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path = os.path.join(cwd, + f"{cfg.scry}/TF Front/{self.name} ({self.artist}) [{self.set.upper()}].jpg") + + # Back filepath + self.mtgp_path_back = os.path.join(cwd, + f"{cfg.mtgp}/TF Back/{self.name_back} ({self.artist}) [{self.set.upper()}].jpg") + self.scry_path_back = os.path.join(cwd, + f"{cfg.scry}/TF Back/{self.name_back} ({self.artist}) [{self.set.upper()}].jpg") + + # Ensure save folders exist + super().make_folders("TF Front") + super().make_folders("TF Back") + +class Meld (Card): + """ + Meld card -- Will do later + """ + +def get_card_class(c): + """ + Return the card class + """ + class_map = { + "normal": Normal, + "basic": Basic, + "transform": Transform, + "modal_dfc": MDFC, + "adventure": Adventure, + "leveler": Leveler, + "saga": Saga, + "planar": Planar, + "meld": Meld, + "class": Class + } + + # Planeswalker? + if "Planeswalker" in c['type_line'] and "card_faces" not in c: + return Planeswalker + if c['name'] in cfg.basic_lands: + return Basic + return class_map[c['layout']] diff --git a/lib/core.py b/lib/core.py new file mode 100644 index 0000000..dacc556 --- /dev/null +++ b/lib/core.py @@ -0,0 +1,131 @@ +""" +CORE FUNCTIONS +""" +# pylint: disable=E0401 +import os +import re +import sys +from pathlib import Path +from colorama import Style, Fore +import requests +from bs4 import BeautifulSoup +from lib import settings as cfg +cwd = os.getcwd() + +# Create folders if they don't exist +Path(cfg.folder).mkdir(mode=511, parents=True, exist_ok=True) +Path(cfg.mtgp).mkdir(mode=511, parents=True, exist_ok=True) +Path(cfg.scry).mkdir(mode=511, parents=True, exist_ok=True) +Path(os.path.join(cwd, "logs")).mkdir(mode=511, parents=True, exist_ok=True) + +def get_mtgp_code (set_code, name, alternate=False): + """ + Webscrape to find the correct MTG Pics code for the card. + """ + # Crawl the mtgpics site to find correct set code + r = requests.get("https://www.mtgpics.com/card?ref="+set_code+"001") + soup = BeautifulSoup(r.content, "html.parser") + soup_td = soup.find("td", {"width": "170", "align": "center"}) + mtgp_link = f"https://mtgpics.com/{soup_td.find('a')['href']}" + + # Crawl the set page to find the correct link + r = requests.get(mtgp_link) + soup = BeautifulSoup(r.content, "html.parser") + soup_i = soup.find_all("img", attrs={"alt": re.compile('^'+name+'.*')}) + if alternate: soup_src = soup_i[1]['src'] + else: soup_src = soup_i[0]['src'] + return soup_src.replace("../pics/reg/","").replace("/","").replace(".jpg","") + +def log (name, set_code=None, txt="failed"): + """ + Log card that couldn't be found. + """ + Path(os.path.join(cwd, "logs")).mkdir(mode=511, parents=True, exist_ok=True) + with open(os.path.join(cwd, f"logs/{txt}.txt"), "a", encoding="utf-8") as l: + if set_code: l.write(f"{set_code}--{name}\n") + else: l.write(f"{name}\n") + print(f"{Fore.RED}FAILED: {Style.RESET_ALL}" + name) + +def handle (error): + """ + Handle error messages + """ + print(f"{error}\nPress enter to exit...") + sys.exit() + +def fix_mtgp_set (set_code): + """ + Replace the real set code with MTGP's weird code + """ + # pylint: disable=R0911, R0912, R0915 + if set_code == "arb": return "alr" + if set_code == "mp2": return "aki" + if set_code == "atq": return "ant" + if set_code == "apc": return "apo" + if set_code == "arn": return "ara" + if set_code == "e01": return "anb" + if set_code == "anb": return "an2" + if set_code == "bok": return "bek" + if set_code == "csp": return "col" + if set_code == "c13": return "13c" + if set_code == "c14": return "14c" + if set_code == "c15": return "15c" + if set_code == "c16": return "16c" + if set_code == "c17": return "17c" + if set_code == "cn2": return "2cn" + if set_code == "dst": return "drs" + if set_code == "dpa": return "dop" + if set_code == "e02": return "dop" + if set_code == "fem": return "fal" + if set_code == "5dn": return "fda" + if set_code == "v17": return "ftr" + if set_code == "gpt": return "gui" + if set_code == "hml": return "hom" + if set_code == "mps": return "kli" + if set_code == "lgn": return "lgi" + if set_code == "lrw": return "lor" + if set_code == "m10": return "10m" + if set_code == "m11": return "11m" + if set_code == "m12": return "12m" + if set_code == "m13": return "13m" + if set_code == "m14": return "14m" + if set_code == "m15": return "15m" + if set_code == "a25": return "25m" + if set_code == "mmq": return "mer" + if set_code == "mm2": return "mmb" + if set_code == "mm3": return "mmc" + if set_code == "hop": return "pch" + if set_code == "pc2": return "2pc" + if set_code == "pls": return "pla" + if set_code == "p02": return "psa" + if set_code == "pd2": return "fir" + if set_code == "pd3": return "gra" + if set_code == "pcy": return "pro" + if set_code == "3ed": return "rev" + if set_code == "sok": return "sak" + if set_code == "scg": return "sco" + if set_code == "shm": return "sha" + if set_code == "ala": return "soa" + if set_code == "sta": return "stm" + if set_code == "sth": return "str" + if set_code == "tmp": return "tem" + if set_code == "drk": return "dar" + if set_code == "puma": return "uma" + if set_code == "uma": return "ulm" + if set_code == "ugl": return "ung" + if set_code == "wth": return "wea" + if set_code == "exp": return "zex" + if set_code == "10e": return "xth" + if set_code == "9ed": return "9th" + if set_code == "8ed": return "8th" + if set_code == "7ed": return "7th" + if set_code == "6ed": return "6th" + if set_code == "5ed": return "5th" + if set_code == "4ed": return "4th" + if set_code == "pnat": return "pmo" + if set_code == "pvow": return "vow" + if set_code == "pmid": return "mid" + if set_code == "me3": return "3me" + if set_code == "me2": return "2me" + if set_code == "me1": return "1me" + return set_code diff --git a/lib/settings.py b/lib/settings.py new file mode 100644 index 0000000..efec968 --- /dev/null +++ b/lib/settings.py @@ -0,0 +1,35 @@ +""" +MODULES +""" +import os +import configparser +cwd = os.getcwd() + +# Import our config file +config = configparser.ConfigParser() +config.read("config.ini") + +# Lists +cardlist = os.path.join(cwd, "cards.txt") +detailed = os.path.join(cwd, "detailed.txt") + +# Folder names +folder = os.path.join(cwd, config['FILES']['Download.Folder']) # Parent folder of all imgs +scry = os.path.join(cwd, folder+"/"+config['FILES']['Scryfall.Art.Folder']) # Scryfall sub +mtgp = os.path.join(cwd, folder+"/"+config['FILES']['MTGPics.Art.Folder']) # MTG Pics sub + +# Basic lands +basic_lands = ["Plains", "Island", "Swamp", "Mountain", "Forest"] + +# Exclude full arts? +exclude_fullart = config['SETTINGS'].getboolean('Exclude.Fullart') + +# Download all images available or just most recent? +download_all = config['SETTINGS'].getboolean('Download.All') + +# Download unique or ALL? +if config['SETTINGS'].getboolean('Only.Search.Unique.Art'): unique = "art" +else: unique = "prints" + +# Download scryfall if mtgpics missing? +download_scryfall = config['SETTINGS'].getboolean('If.Missing.Download.Scryfall') diff --git a/settings.py b/settings.py deleted file mode 100644 index 6294fe2..0000000 --- a/settings.py +++ /dev/null @@ -1,35 +0,0 @@ -# Requirements -import configparser - -# Import our config file -config = configparser.ConfigParser() -config.read("config.ini") - -# Folder names -f_name = config['FILES']['Download.Folder'] # Parent folder of all imgs -f_scry = f_name+"/"+config['FILES']['Scryfall.Art.Folder'] # Scryfall images sub -f_mtgp = f_name+"/"+config['FILES']['MTGPics.Art.Folder'] # MTGPics images sub -f_scry_b = f_scry+"/"+config['FILES']['Scryfall.Backs.Folder'] # Scryfall BACKS sub -f_mtgp_b = f_mtgp+"/"+config['FILES']['MTGPics.Backs.Folder'] # MTGPics BACKS sub -cardlist = config['FILES']['Card.List'] # Card list txt file -detailed_list = config['FILES']['Card.Detailed.List'] # Card list including set - -# Basic lands -basic_lands = ["Plains", "Island", "Swamp", "Mountain", "Forest"] - -# Exclude full arts? -exclude_fullart = config['SETTINGS'].getboolean('Exclude.Fullart') - -# Download all images available or just most recent? -download_all = config['SETTINGS'].getboolean('Download.All') - -# Download unique or ALL? -if config['SETTINGS'].getboolean('Only.Search.Unique.Art'): unique = "art" -else: unique = "prints" - -# Download scryfall if mtgpics missing? -if config['SETTINGS'].getboolean('If.Missing.Download.Scryfall'): download_scryfall = True -else: download_scryfall = False - -# Refer to this for generating detailed list -# https://docs.google.com/spreadsheets/d/1QnVoQ1gvz1N4TKnkJJ44_FHomy0gNoxZlaPSkua4Rmk/edit?usp=sharing \ No newline at end of file