Skip to content

Instantly share code, notes, and snippets.

@lurch
Created May 6, 2021 21:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lurch/e675ccaf691cc6888d81199276994c7e to your computer and use it in GitHub Desktop.
Save lurch/e675ccaf691cc6888d81199276994c7e to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# Written by Andrew Scheller, May 2021
# Released under the WTFPL
# This is a fun little script that provides an interactive text-based menu for
# the user to select an image from; once an image has been selected it prints
# the "choices path" that was navigated to get to that image, and the URL that
# the image can be downloaded from (e.g. using wget)
#
# Alternatively, if given a "choices path" it runs non-interactively and
# prints out the image download URL corresponding to that option. For example,
# image_chooser.py "Raspberry Pi OS (other)" "Raspberry Pi OS Lite (32-bit)"
# will print out the URL of the latest RasPiOS Lite image (which is
# https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-03-25/2021-03-04-raspios-buster-armhf-lite.zip
# at the time of writing)
BASE_JSON_URL = 'https://downloads.raspberrypi.org/os_list_imagingutility_v2.json'
import urllib.request
import json
import sys
import re
json_cache = {}
def read_json_list(url):
if url not in json_cache:
with urllib.request.urlopen(url) as response:
json_cache[url] = json.loads(response.read())['os_list']
return json_cache[url]
# Allow optional custom BASE_JSON_URL to be supplied
if len(sys.argv) > 1 and (sys.argv[1].startswith('http://') or sys.argv[1].startswith('https://')):
BASE_JSON_URL = sys.argv.pop(1)
if len(sys.argv) > 1:
# Noninteracative mode - use supplied "choices path" to find image
choices = sys.argv[1:]
options = read_json_list(BASE_JSON_URL)
found = False
while choices:
choice = choices.pop(0)
options_lookup = {item['name']: index for index, item in enumerate(options)}
if choice in options_lookup:
chosen = options[options_lookup[choice]]
if 'subitems_url' in chosen:
options = read_json_list(chosen['subitems_url'])
elif 'subitems' in chosen:
options = chosen['subitems']
else:
found = True
# print the selected image url
print(chosen['url'])
if choices:
raise Exception("Found OS before reaching end of choices")
break
else:
raise Exception("\"%s\" not found in %s" % (choice, [item['name'] for item in options]))
if not found:
raise Exception("No matching OS found")
else:
# Interactive mode - display menu for user to navigate
title = "Select an Operating System"
options = read_json_list(BASE_JSON_URL)
parents = []
while True:
print(title)
min_index = 1
if parents:
print(" [%d] Go back to: %s" % (0, parents[-1][0]))
min_index = 0
for index, item in enumerate(options):
prefix = " [%d] %s: " % (index + 1, 'MENU' if 'subitems_url' in item or 'subitems' in item else 'IMAGE')
print("%s%s" % (prefix, item['name']))
if 'description' in item:
print("%s%s" % (' ' * len(prefix), item['description']))
max_index = len(options)
choice = 'invalid'
while choice != 'q' and choice != 'quit' and not (re.match('^\d+$', choice) and (min_index <= int(choice) <= max_index)):
choice = input("Choose option (%d to %d, or q to quit) ? " % (min_index, max_index))
if choice == 'q' or choice == 'quit':
break
choice = int(choice)
if choice == 0:
title, options = parents.pop()
else:
parents.append((title, options))
chosen = options[choice - 1]
title = chosen['name']
if 'subitems_url' in chosen:
options = read_json_list(chosen['subitems_url'])
elif 'subitems' in chosen:
options = chosen['subitems']
else:
choices = [p[0] for p in parents[1:]]
choices.append(title)
# print the selected "choices path"
print(' '.join("\"%s\"" % c for c in choices))
# print the selected image url
print(chosen['url'])
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment