Last active
December 2, 2025 13:11
-
-
Save helgibbons/7c6918b4389c31723eec8e9ed9481036 to your computer and use it in GitHub Desktop.
Attempt to work around Comic Vine's new Cloudflare shenanigans
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| Python script to fetch a randomised comic cover from the Comic Vine API and show it on an Inky Impression display. | |
| You will need to sign up for an API key at https://comicvine.gamespot.com/api/ to use this script. | |
| Change the search query to the comic series you want to display! | |
| """ | |
| import json | |
| import random | |
| import time | |
| from io import BytesIO | |
| from urllib import parse, request | |
| from PIL import Image | |
| from inky.auto import auto | |
| # Comic Vine API details | |
| API_KEY = "API_KEY_GOES_HERE" # Replace with your Comic Vine API key | |
| BASE_URL = "https://comicvine.gamespot.com/api/" | |
| HEADERS = { | |
| "authority": "www.google.com", | |
| "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", | |
| "accept-language": "en-US,en;q=0.9", | |
| "cache-control": "max-age=0", | |
| "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36" | |
| } | |
| # List of comic series to display, separated by commas. You can add more series to this list, or change the existing ones. | |
| SEARCH_QUERIES = ["Weird Science"] | |
| # Set to True to pick a random volume from the query results (this is helpful if the series is split into multiple volumes): | |
| RANDOM_VOLUME = True | |
| # Inky Impression display setup | |
| inky_display = auto() | |
| def find_volume_id(api_key, query): | |
| # Our first API call finds a list of volumes that match the search query, and then picks one | |
| params = { | |
| "query": query, | |
| "resources": "volume", | |
| "limit": 5, | |
| "api_key": api_key, | |
| "format": "json" | |
| } | |
| url = f"{BASE_URL}search/?{parse.urlencode(params)}" | |
| req = request.Request(url, headers=HEADERS) | |
| try: | |
| with request.urlopen(req) as resp: | |
| data = resp.read() | |
| parsed = json.loads(data.decode("utf-8")) | |
| results = parsed.get("results", []) | |
| except Exception as e: | |
| raise RuntimeError(f"Failed to search for volumes: {e}") | |
| if results: | |
| for idx, volume in enumerate(results, 1): | |
| print(f"{idx}: {volume['name']} (ID: {volume['id']}, Start Year: {volume.get('start_year', 'N/A')})") | |
| if RANDOM_VOLUME: | |
| chosen = random.choice(results) | |
| print(f"Randomly selected: {chosen['name']} (ID: {chosen['id']})") | |
| else: | |
| chosen = results[0] | |
| print("Picked first result!") | |
| return chosen["id"] | |
| else: | |
| raise ValueError("No volumes found for the given query.") | |
| def fetch_random_comic_image(api_key, series_id): | |
| """Fetch a random comic cover image from the given series.""" | |
| params = { | |
| "filter": f"volume:{series_id}", | |
| "limit": 100, | |
| "api_key": api_key, | |
| "format": "json" | |
| } | |
| url = f"{BASE_URL}issues/?{parse.urlencode(params)}" | |
| req = request.Request(url, headers=HEADERS) | |
| try: | |
| with request.urlopen(req) as resp: | |
| data = resp.read() | |
| parsed = json.loads(data.decode("utf-8")) | |
| results = parsed.get("results", []) | |
| except Exception as e: | |
| raise RuntimeError(f"Failed to fetch comic issues: {e}") | |
| if results: | |
| issue = random.choice(results) | |
| print(f"Random issue selected: ID: {issue['id']}") | |
| print(f"Find out more: {issue['site_detail_url']}") | |
| return issue["image"]["original_url"] | |
| else: | |
| raise ValueError("No comic issues found for the specified series.") | |
| def display_image_on_inky(image_url): | |
| """Download and display image on Inky Impression.""" | |
| try: | |
| # Download the image | |
| req = request.Request(image_url, headers=HEADERS) | |
| with request.urlopen(req) as resp: | |
| image_bytes = resp.read() | |
| # Open and process the image | |
| image = Image.open(BytesIO(image_bytes)) | |
| # Rotate if taller than wide | |
| if image.height > image.width: | |
| image = image.rotate(90, expand=True) | |
| # Resize and display | |
| image = image.resize(inky_display.resolution) | |
| inky_display.set_image(image) | |
| print("Updating Inky Impression!") | |
| inky_display.show() | |
| except Exception as e: | |
| raise RuntimeError(f"Failed to display image: {e}") | |
| try: | |
| # Pick a random search term from the list | |
| search_query = random.choice(SEARCH_QUERIES) | |
| print("Searching for volumes...") | |
| volume_id = find_volume_id(API_KEY, search_query) | |
| # Wait 2 seconds between API calls | |
| print("Waiting before fetching issues...") | |
| time.sleep(2) | |
| comic_image_url = fetch_random_comic_image(API_KEY, volume_id) | |
| # Wait 2 seconds before downloading image | |
| print("Waiting before downloading image...") | |
| time.sleep(2) | |
| display_image_on_inky(comic_image_url) | |
| except Exception as e: | |
| print(f"Error: {e}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment