This commit is contained in:
Caleb Fultz 2024-08-13 18:57:07 -04:00
parent cf7058e8e2
commit e6312f7933
8 changed files with 0 additions and 605 deletions

View File

@ -1,81 +0,0 @@
import requests
import pandas as pd
import os
import time
# Function to fetch card details from Scryfall using the set code and collector number
def fetch_card_images_by_set_and_number(set_code, collector_number):
url = f"https://api.scryfall.com/cards/{set_code}/{collector_number}"
response = requests.get(url)
if response.status_code == 200:
card_data = response.json()
images = []
# Handle single-sided or multi-sided cards
if 'image_uris' in card_data:
images.append((card_data['image_uris']['art_crop'], card_data['name']))
if 'card_faces' in card_data:
for face in card_data['card_faces']:
if 'image_uris' in face:
images.append((face['image_uris']['art_crop'], face['name']))
return images
else:
print(f"Error fetching card with set code {set_code} and collector number {collector_number}: {response.status_code}")
return None
# Function to download and save an image
def download_image(image_url, save_path):
response = requests.get(image_url)
if response.status_code == 200:
with open(save_path, 'wb') as file:
file.write(response.content)
else:
print(f"Failed to download image from {image_url}")
# Function to process the CSV and download images
def download_images_from_csv(csv_path, output_folder):
# Create output directory if it doesn't exist
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# Read the CSV file
df = pd.read_csv(csv_path)
# Assuming the CSV has columns 'Card Name', 'Set Code', and 'Collector Number'
for index, row in df.iterrows():
card_name = row['Card Name']
set_code = row['Set Code']
collector_number = row['Collector Number']
# Naming convention: set_code_card_name_face_name.jpg
image_base_name = f"{set_code}_{card_name.replace('/', '-').replace(':', '')}"
print(f"Processing {card_name} from set {set_code} with collector number {collector_number}...")
images = fetch_card_images_by_set_and_number(set_code, collector_number)
if images:
for image_url, face_name in images:
# Sanitize file name by removing invalid characters
image_file_name = f"{image_base_name}_{face_name.replace('/', '-').replace(':', '')}_art_crop.jpg"
save_path = os.path.join(output_folder, image_file_name)
# Skip downloading if the image already exists
if os.path.exists(save_path):
print(f"Image already exists for {card_name} ({face_name}), skipping download.")
continue
download_image(image_url, save_path)
time.sleep(0.1) # Sleep to avoid hitting API rate limits
else:
print(f"No images found for {card_name} from set {set_code} with collector number {collector_number}")
# Main execution
if __name__ == "__main__":
# Define the path to the input CSV and output folder
csv_path = 'cards.csv' # Replace with your CSV file path
output_folder = 'artcrop_images'
# Start the download process
download_images_from_csv(csv_path, output_folder)
print("Download completed.")

View File

@ -1,48 +0,0 @@
Card Name,Set Code,Collector Number,Quantity,Foil
"Flubs, The Fool",blc,356,1,True
"Flubs, The Fool",blc,356,1,False
Skemfar Shadowsage,sld,759,3,True
Pollenbright Druid,sld,776,1,True
Timberwatch Elf,sld,780,2,True
Frilled Mystic,sld,786,1,True
Coveted Jewel,sld,799,1,False
The Scorpion God,sld,904,1,True
"Linda, Kandarian Queen",sld,1355,1,True
Felidar Guardian,sld,1487,1,False
Peregrine Drake,sld,1488,1,False
Serpent of Yawning Depths,sld,1489,1,False
Scourage of Valkas,sld,1490,1,False
Voracious Hydra,sld,1491,1,False
Wall of Omens,sld,1518,1,False
Circular Logic,sld,1519,1,False
Scheming Symmentry,sld,1520,1,False
Price of Progress,sld,1521,1,False
Eternal Witness,sld,1522,1,False
Sakashima of a Thousand Faces,sld,1541,1,False
"Yargle, Glutton of Urborg",sld,1542,1,False
"Krark, The Thumbless",sld,1543,1,False
"Adrix and Nev, Twincasters",sld,1544,1,False
Arcance Denial,sld,1545,1,False
Nightscape Familiar,sld,1546,1,False
Rain of Filth,sld,1547,1,False
Simian Spirit Guide,sld,1548,1,False
Prince of Thralls,sld,1549,1,False
"Gonti, Lord of Luxury",sld,1566,1,False
"Vilis, Broker of Blood",sld,1567,1,False
"Anowon, the Ruin Thief",sld,1568,1,False
"Grenzo, Dungeon Warden",sld,1569,1,False
Reconnasissance,sld,1575,1,False
"Jace, Wielder of Mysteries",sld,1576,1,False
Black Market,sld,1577,1,False
Dire Undercurrents,sld,1578,1,False
"Obeka, Brute Chronolgoist",sld,1579,1,False
Sorin Markov,sld,1698,1,False
Sorin Markov,sld,1698,1,True
"Huatli, Radiant Champion",sld,1699,1,False
"Huatli, Radiant Champion",sld,1699,1,True
"Kiora, Behemoth Beckoner",sld,1700,1,False
"Kiora, Behemoth Beckoner",sld,1700,1,True
"Tezzeret, Master of the Bridge",sld,1701,1,False
"Tezzeret, Master of the Bridge",sld,1701,1,True
"Vraska, Golgari Queen",sld,1702,1,False
"Vraska, Golgari Queen",sld,1702,1,True
1 Card Name Set Code Collector Number Quantity Foil
2 Flubs, The Fool blc 356 1 True
3 Flubs, The Fool blc 356 1 False
4 Skemfar Shadowsage sld 759 3 True
5 Pollenbright Druid sld 776 1 True
6 Timberwatch Elf sld 780 2 True
7 Frilled Mystic sld 786 1 True
8 Coveted Jewel sld 799 1 False
9 The Scorpion God sld 904 1 True
10 Linda, Kandarian Queen sld 1355 1 True
11 Felidar Guardian sld 1487 1 False
12 Peregrine Drake sld 1488 1 False
13 Serpent of Yawning Depths sld 1489 1 False
14 Scourage of Valkas sld 1490 1 False
15 Voracious Hydra sld 1491 1 False
16 Wall of Omens sld 1518 1 False
17 Circular Logic sld 1519 1 False
18 Scheming Symmentry sld 1520 1 False
19 Price of Progress sld 1521 1 False
20 Eternal Witness sld 1522 1 False
21 Sakashima of a Thousand Faces sld 1541 1 False
22 Yargle, Glutton of Urborg sld 1542 1 False
23 Krark, The Thumbless sld 1543 1 False
24 Adrix and Nev, Twincasters sld 1544 1 False
25 Arcance Denial sld 1545 1 False
26 Nightscape Familiar sld 1546 1 False
27 Rain of Filth sld 1547 1 False
28 Simian Spirit Guide sld 1548 1 False
29 Prince of Thralls sld 1549 1 False
30 Gonti, Lord of Luxury sld 1566 1 False
31 Vilis, Broker of Blood sld 1567 1 False
32 Anowon, the Ruin Thief sld 1568 1 False
33 Grenzo, Dungeon Warden sld 1569 1 False
34 Reconnasissance sld 1575 1 False
35 Jace, Wielder of Mysteries sld 1576 1 False
36 Black Market sld 1577 1 False
37 Dire Undercurrents sld 1578 1 False
38 Obeka, Brute Chronolgoist sld 1579 1 False
39 Sorin Markov sld 1698 1 False
40 Sorin Markov sld 1698 1 True
41 Huatli, Radiant Champion sld 1699 1 False
42 Huatli, Radiant Champion sld 1699 1 True
43 Kiora, Behemoth Beckoner sld 1700 1 False
44 Kiora, Behemoth Beckoner sld 1700 1 True
45 Tezzeret, Master of the Bridge sld 1701 1 False
46 Tezzeret, Master of the Bridge sld 1701 1 True
47 Vraska, Golgari Queen sld 1702 1 False
48 Vraska, Golgari Queen sld 1702 1 True

View File

@ -1,60 +0,0 @@
import csv
import os
import argparse
# Function to append a card entry to the CSV file
def add_card_to_csv(csv_path, card_name, set_code, collector_number, quantity, foil):
file_exists = os.path.isfile(csv_path)
with open(csv_path, mode='a', newline='') as file:
writer = csv.writer(file)
# Write header if the file doesn't exist
if not file_exists:
writer.writerow(['Card Name', 'Set Code', 'Collector Number', 'Quantity', 'Foil'])
# Append the card data
writer.writerow([card_name, set_code, collector_number, quantity, foil])
print(f"Added {quantity}x {card_name} from set {set_code} with collector number {collector_number} (Foil: {foil}) to {csv_path}.")
# Function to parse and add multiple cards
def add_multiple_cards(csv_path, card_entries):
for entry in card_entries:
card_name, set_code, collector_number, quantity, foil = entry
add_card_to_csv(csv_path, card_name, set_code, collector_number, quantity, foil)
# Main function to handle command-line arguments
def main():
parser = argparse.ArgumentParser(description="Add one or more Magic: The Gathering cards to a CSV file.")
parser.add_argument('csv_path',
help="The path to the CSV file where the card data will be stored. If the file does not exist, it will be created.")
# Allow multiple --card entries
parser.add_argument('--card',
action='append',
nargs=5,
metavar=('Card_Name', 'Set_Code', 'Collector_Number', 'Quantity', 'Foil'),
help=("Add a card to the CSV file. "
"Each card entry should be specified in the following format: "
"Card_Name Set_Code Collector_Number Quantity Foil. "
"Foil should be 'True' or 'False' indicating if the card is foil or not. "
"This option can be used multiple times to add multiple cards in one command. "))
args = parser.parse_args()
if args.card:
card_entries = []
for card in args.card:
card_name, set_code, collector_number, quantity, foil = card
quantity = int(quantity)
foil = foil.lower() == 'true' # Convert the foil input to a boolean
card_entries.append((card_name, set_code, collector_number, quantity, foil))
add_multiple_cards(args.csv_path, card_entries)
else:
print("No cards provided. Use the --card option to add cards.")
if __name__ == "__main__":
main()

View File

@ -1,102 +0,0 @@
import os
import random
from PIL import Image
# Function to load, resize, and crop JPG images from a directory
def load_resize_and_crop_images(directory, target_size):
images = []
for filename in os.listdir(directory):
if filename.lower().endswith((".jpg", ".jpeg")):
try:
img = Image.open(os.path.join(directory, filename))
# Calculate the aspect ratios for scaling
img_aspect = img.width / img.height
target_aspect = target_size[0] / target_size[1]
if img_aspect > target_aspect:
# Image is wider than the target: scale height and crop width
img = img.resize((int(img_aspect * target_size[1]), target_size[1]), Image.Resampling.LANCZOS)
left = (img.width - target_size[0]) / 2
img = img.crop((left, 0, left + target_size[0], target_size[1]))
else:
# Image is taller than the target: scale width and crop height
img = img.resize((target_size[0], int(target_size[0] / img_aspect)), Image.Resampling.LANCZOS)
top = (img.height - target_size[1]) / 2
img = img.crop((0, top, target_size[0], top + target_size[1]))
images.append(img)
except IOError:
print(f"Warning: Unable to open image {filename}. It may be corrupted or not a valid image file.")
return images
# Function to create a wallpaper from images
def create_wallpaper(images, screen_size, output_file):
wallpaper = Image.new('RGB', screen_size)
random.shuffle(images) # Randomize the order of images
x_offset = 0
y_offset = 0
for img in images:
img_width, img_height = img.size
if x_offset + img_width > screen_size[0]: # Move to next row if needed
x_offset = 0
y_offset += img_height
if y_offset + img_height > screen_size[1]: # Stop if out of vertical space
break
wallpaper.paste(img, (x_offset, y_offset))
x_offset += img_width
wallpaper.save(output_file, format='JPEG')
print(f"Wallpaper saved as {output_file}")
# Function to prompt user for screen size
def get_screen_size():
sizes = {
"1": (1920, 1080),
"2": (2560, 1440),
"3": (3840, 2160),
"4": (1280, 720),
"5": (1600, 900)
}
print("Choose a screen size:")
print("1: 1920x1080 (Full HD)")
print("2: 2560x1440 (2K)")
print("3: 3840x2160 (4K)")
print("4: 1280x720 (HD)")
print("5: 1600x900 (HD+)")
choice = input("Enter the number corresponding to your choice: ")
return sizes.get(choice, (1920, 1080)) # Default to 1920x1080 if invalid choice
def main():
directory = input("Enter the directory containing JPG files: ")
screen_size = get_screen_size()
# Determine the target size for each image based on the screen size
# Here, we assume a grid of 5 images across and as many rows as needed
target_size = (screen_size[0] // 5, screen_size[1] // 5)
output_file = input("Enter the name of the output wallpaper file (e.g., wallpaper.jpg): ")
# Ensure the output file has a .jpg extension
if not output_file.lower().endswith('.jpg'):
output_file += '.jpg'
images = load_resize_and_crop_images(directory, target_size)
if not images:
print("No JPG files found in the directory.")
return
create_wallpaper(images, screen_size, output_file)
if __name__ == "__main__":
main()

View File

@ -1,80 +0,0 @@
import requests
def refactor_commander_name(name):
# Replace spaces, commas, and apostrophes with dashes, and convert to lowercase
name = name.replace(" ", "-").replace(",", "").replace("'", "")
return name.lower()
def fetch_edhrec_data(commander_name):
url = f"https://json.edhrec.com/pages/commanders/{commander_name}.json"
response = requests.get(url)
if response.status_code == 200:
return response.json()
else:
print(f"Failed to fetch data for {commander_name}")
return None
def fetch_card_name_from_scryfall(uuid):
scryfall_url = f"https://api.scryfall.com/cards/{uuid}"
response = requests.get(scryfall_url)
if response.status_code == 200:
data = response.json()
return data['name']
else:
print(f"Failed to fetch card name from Scryfall for UUID: {uuid}")
return None
def extract_uuids_and_quantities_from_archidekt(edhrec_data):
card_info = []
if 'archidekt' in edhrec_data:
for idx, deck_section in enumerate(edhrec_data['archidekt']):
if isinstance(deck_section, dict) and 'u' in deck_section and 'q' in deck_section:
uuid = deck_section['u']
quantity = deck_section['q']
card_info.append((uuid, quantity))
else:
print("No Archidekt section found in the EDHREC data.")
return card_info
def fetch_card_names_from_uuids(card_info):
card_entries = []
for uuid, quantity in card_info:
card_name = fetch_card_name_from_scryfall(uuid)
if card_name:
card_entries.append(f"{quantity}x {card_name}")
return card_entries
def create_moxfield_deck_file(commander_name, card_entries):
filename = f"{commander_name}_edh.txt"
with open(filename, 'w') as file:
for entry in card_entries:
file.write(f"{entry}\n")
print(f"Deck list saved to {filename}")
def main():
commander_name = input("Enter the commander card name: ")
refactored_name = refactor_commander_name(commander_name)
print(f"Fetching EDHREC data for {commander_name}...")
edhrec_data = fetch_edhrec_data(refactored_name)
if edhrec_data:
print(f"Extracting UUIDs and quantities from Archidekt section...")
card_info = extract_uuids_and_quantities_from_archidekt(edhrec_data)
if card_info:
print(f"Fetching card names from Scryfall...")
card_entries = fetch_card_names_from_uuids(card_info)
if card_entries:
create_moxfield_deck_file(refactored_name, card_entries)
else:
print("No card names found for the given UUIDs.")
else:
print("No UUIDs found in the Archidekt decks.")
if __name__ == "__main__":
main()

View File

@ -1,81 +0,0 @@
import requests
import pandas as pd
import os
import time
# Function to fetch card details from Scryfall using the set code and collector number
def fetch_card_images_by_set_and_number(set_code, collector_number):
url = f"https://api.scryfall.com/cards/{set_code}/{collector_number}"
response = requests.get(url)
if response.status_code == 200:
card_data = response.json()
images = []
# Handle single-sided or multi-sided cards
if 'image_uris' in card_data:
images.append((card_data['image_uris']['normal'], card_data['name']))
if 'card_faces' in card_data:
for face in card_data['card_faces']:
if 'image_uris' in face:
images.append((face['image_uris']['normal'], face['name']))
return images
else:
print(f"Error fetching card with set code {set_code} and collector number {collector_number}: {response.status_code}")
return None
# Function to download and save an image
def download_image(image_url, save_path):
response = requests.get(image_url)
if response.status_code == 200:
with open(save_path, 'wb') as file:
file.write(response.content)
else:
print(f"Failed to download image from {image_url}")
# Function to process the CSV and download images
def download_images_from_csv(csv_path, output_folder):
# Create output directory if it doesn't exist
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# Read the CSV file
df = pd.read_csv(csv_path)
# Assuming the CSV has columns 'Card Name', 'Set Code', and 'Collector Number'
for index, row in df.iterrows():
card_name = row['Card Name']
set_code = row['Set Code']
collector_number = row['Collector Number']
# Naming convention: set_code_card_name_face_name.jpg
image_base_name = f"{set_code}_{card_name.replace('/', '-').replace(':', '')}"
print(f"Processing {card_name} from set {set_code} with collector number {collector_number}...")
images = fetch_card_images_by_set_and_number(set_code, collector_number)
if images:
for image_url, face_name in images:
# Sanitize file name by removing invalid characters
image_file_name = f"{image_base_name}_{face_name.replace('/', '-').replace(':', '')}.jpg"
save_path = os.path.join(output_folder, image_file_name)
# Skip downloading if the image already exists
if os.path.exists(save_path):
print(f"Image already exists for {card_name} ({face_name}), skipping download.")
continue
download_image(image_url, save_path)
time.sleep(0.2) # Sleep to avoid hitting API rate limits
else:
print(f"No images found for {card_name} from set {set_code} with collector number {collector_number}")
# Main execution
if __name__ == "__main__":
# Define the path to the input CSV and output folder
csv_path = 'cards.csv' # Replace with your CSV file path
output_folder = 'downloaded_images'
# Start the download process
download_images_from_csv(csv_path, output_folder)
print("Download complete.")

View File

@ -1,57 +0,0 @@
import csv
import os
# Function to append a card entry to the CSV file
def add_card_to_csv(csv_path, card_name, set_code, collector_number, quantity, foil):
file_exists = os.path.isfile(csv_path)
with open(csv_path, mode='a', newline='') as file:
writer = csv.writer(file)
# Write header if the file doesn't exist
if not file_exists:
writer.writerow(['Card Name', 'Set Code', 'Collector Number', 'Quantity', 'Foil'])
# Append the card data
writer.writerow([card_name, set_code, collector_number, quantity, foil])
print(f"Added {quantity}x {card_name} from set {set_code} with collector number {collector_number} (Foil: {foil}) to {csv_path}.")
# Function to sort the CSV file by Set Code and Collector Number
def sort_csv_file(csv_path):
with open(csv_path, mode='r') as file:
reader = csv.reader(file)
header = next(reader) # Read the header
sorted_rows = sorted(reader, key=lambda row: (row[1], int(row[2]))) # Sort by Set Code (row[1]) and Collector Number (row[2])
# Write the sorted data back to the CSV
with open(csv_path, mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerow(header) # Write the header back
writer.writerows(sorted_rows) # Write the sorted rows
print(f"CSV file sorted by Set Code and Collector Number.")
# Function to get user input and add multiple cards interactively
def interactive_card_entry(csv_path):
while True:
# Get the card details from the user
card_name = input("Enter the card name (or type 'exit' to quit): ").strip()
if card_name.lower() == 'exit':
print("Exiting the program.")
break
set_code = input("Enter the set code: ").strip()
collector_number = input("Enter the collector number: ").strip()
quantity = int(input("Enter the quantity: ").strip())
foil = input("Is this card a foil? (yes/no): ").strip().lower() == 'yes'
# Add the card to the CSV file
add_card_to_csv(csv_path, card_name, set_code, collector_number, quantity, foil)
# Sort the CSV file after each entry
sort_csv_file(csv_path)
if __name__ == "__main__":
csv_path = input("Enter the path to the CSV file: ").strip()
interactive_card_entry(csv_path)

View File

@ -1,96 +0,0 @@
import csv
import os
import requests
# Function to append a card entry to the CSV file
def add_card_to_csv(csv_path, card_name, set_code, collector_number, quantity, foil):
file_exists = os.path.isfile(csv_path)
with open(csv_path, mode='a', newline='') as file:
writer = csv.writer(file)
# Write header if the file doesn't exist
if not file_exists:
writer.writerow(['Card Name', 'Set Code', 'Collector Number', 'Quantity', 'Foil'])
# Append the card data
writer.writerow([card_name, set_code, collector_number, quantity, foil])
print(f"Added {quantity}x {card_name} from set {set_code} with collector number {collector_number} (Foil: {foil}) to {csv_path}.")
# Function to download the full card image
def download_full_card_image(set_code, collector_number, card_name, foil):
url = f"https://api.scryfall.com/cards/{set_code}/{collector_number}"
response = requests.get(url)
if response.status_code == 200:
card_data = response.json()
# Determine the image URL (normal)
image_url = card_data['image_uris']['normal'] if 'image_uris' in card_data else None
if not image_url and 'card_faces' in card_data: # Check for double-sided cards
image_url = card_data['card_faces'][0]['image_uris']['normal']
if image_url:
# Create the full_card directory if it doesn't exist
directory = 'full_card'
if not os.path.exists(directory):
os.makedirs(directory)
# Create a filename for the image
foil_text = "_foil" if foil else ""
file_name = f"{card_name.replace('/', '-').replace(':', '').replace(' ', '_')}_{set_code}_{collector_number}{foil_text}.jpg"
file_path = os.path.join(directory, file_name)
# Download and save the image
image_response = requests.get(image_url)
with open(file_path, 'wb') as file:
file.write(image_response.content)
print(f"Downloaded full card image for {card_name} (Set: {set_code}, Collector Number: {collector_number}, Foil: {foil})")
else:
print(f"No full card image found for {card_name} (Set: {set_code}, Collector Number: {collector_number})")
else:
print(f"Failed to fetch data for {card_name} (Set: {set_code}, Collector Number: {collector_number}) from Scryfall.")
# Function to sort the CSV file by Set Code and Collector Number
def sort_csv_file(csv_path):
with open(csv_path, mode='r') as file:
reader = csv.reader(file)
header = next(reader) # Read the header
sorted_rows = sorted(reader, key=lambda row: (row[1], int(row[2]))) # Sort by Set Code (row[1]) and Collector Number (row[2]))
# Write the sorted data back to the CSV
with open(csv_path, mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerow(header) # Write the header back
writer.writerows(sorted_rows) # Write the sorted rows
print(f"CSV file sorted by Set Code and Collector Number.")
# Function to get user input and add multiple cards interactively
def interactive_card_entry(csv_path):
while True:
# Get the card details from the user
card_name = input("Enter the card name (or type 'exit' to quit): ").strip()
if card_name.lower() == 'exit':
print("Exiting the program.")
break
set_code = input("Enter the set code: ").strip()
collector_number = input("Enter the collector number: ").strip()
quantity = int(input("Enter the quantity: ").strip())
foil = input("Is this card a foil? (yes/no): ").strip().lower() == 'yes'
# Add the card to the CSV file
add_card_to_csv(csv_path, card_name, set_code, collector_number, quantity, foil)
# Download the full card image
download_full_card_image(set_code, collector_number, card_name, foil)
# Sort the CSV file after each entry
sort_csv_file(csv_path)
if __name__ == "__main__":
csv_path = input("Enter the path to the CSV file: ").strip()
interactive_card_entry(csv_path)