Repository navigation
Expand file tree
/
Copy pathboardingpass_print.py
More file actions
110 lines (95 loc) · 4.88 KB
/
Copy pathboardingpass_print.py
File metadata and controls
110 lines (95 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python3
"""Print a (fake) boarding pass on the S01 thermal printer.
Generates a plausible-looking airline boarding pass -- random route between real
airports, flight number, gate, seat, boarding time -- topped off with a decorative
barcode strip. Pure novelty; do not attempt to fly with it.
Examples:
python boardingpass_print.py # random flight
python boardingpass_print.py --name "ADA LOVELACE"
python boardingpass_print.py --from JFK --to NRT
python boardingpass_print.py --no-print
"""
from __future__ import annotations
import argparse
from datetime import datetime, timedelta
from pathlib import Path
import random
import string
from PIL import Image, ImageDraw
from print_common import ROOT, Card
AIRPORTS = {
"JFK": "New York", "LAX": "Los Angeles", "ORD": "Chicago", "LHR": "London",
"CDG": "Paris", "NRT": "Tokyo", "HND": "Tokyo", "SFO": "San Francisco",
"DXB": "Dubai", "SIN": "Singapore", "FRA": "Frankfurt", "AMS": "Amsterdam",
"HKG": "Hong Kong", "SYD": "Sydney", "GRU": "Sao Paulo", "MAD": "Madrid",
"YYZ": "Toronto", "ICN": "Seoul", "BOM": "Mumbai", "ATH": "Athens",
"IST": "Istanbul", "MEX": "Mexico City", "SEA": "Seattle", "BER": "Berlin",
}
AIRLINES = [("AeroNova", "AN"), ("Polaris Air", "PL"), ("Skybound", "SB"),
("Meridian", "MD"), ("Nimbus", "NB"), ("Vanguard Air", "VG")]
FIRST = ["ADA", "ALAN", "GRACE", "LINUS", "MARIE", "NIKOLA", "ROSA", "KATIA",
"OMAR", "YUKI", "INES", "MATEO", "PRIYA", "BJORN"]
LAST = ["LOVELACE", "TURING", "HOPPER", "TORVALDS", "CURIE", "TESLA", "PARKS",
"KHAN", "TANAKA", "VARGAS", "REYES", "PATEL", "ANDERSEN", "NGUYEN"]
def barcode(width: int, rng: random.Random, height: int = 46) -> Image.Image:
img = Image.new("L", (width, height), 255)
d = ImageDraw.Draw(img)
x = 2
while x < width - 2:
bw = rng.choice([1, 1, 2, 2, 3])
if rng.random() < 0.55:
d.rectangle((x, 0, x + bw - 1, height - 1), fill=0)
x += bw + rng.choice([1, 1, 2])
return img
def main() -> int:
parser = argparse.ArgumentParser(description="Print a fake boarding pass on the S01 thermal printer.")
parser.add_argument("--name", default=None, help="Passenger name (default: random).")
parser.add_argument("--from", dest="origin", default=None, help="Origin IATA code.")
parser.add_argument("--to", dest="dest", default=None, help="Destination IATA code.")
parser.add_argument("--seed", type=int, default=None)
parser.add_argument("--out", type=Path, default=ROOT / "boardingpass.png")
parser.add_argument("--darkness", type=int, choices=range(1, 6), default=3)
parser.add_argument("--bottom-feed", type=int, default=24)
parser.add_argument("--no-print", action="store_true")
args = parser.parse_args()
seed = args.seed if args.seed is not None else random.randrange(1, 100000)
rng = random.Random(seed)
codes = list(AIRPORTS)
origin = (args.origin or rng.choice(codes)).upper()
dest = (args.dest or rng.choice([c for c in codes if c != origin])).upper()
for code in (origin, dest):
if code not in AIRPORTS:
raise SystemExit(f"Unknown airport code {code!r}")
airline, al_code = rng.choice(AIRLINES)
flight = f"{al_code}{rng.randint(100, 9999)}"
name = args.name or f"{rng.choice(FIRST)} {rng.choice(LAST)}"
depart = datetime.now() + timedelta(days=rng.randint(1, 60),
hours=rng.randint(0, 23), minutes=rng.choice([0, 5, 10, 15, 20, 30, 45]))
boarding = depart - timedelta(minutes=40)
seat = f"{rng.randint(1, 45)}{rng.choice('ABCDEF')}"
gate = f"{rng.choice('ABCDEFG')}{rng.randint(1, 40)}"
group = rng.randint(1, 5)
seq = rng.randint(1, 199)
pnr = "".join(rng.choice(string.ascii_uppercase + string.digits) for _ in range(6))
cls = rng.choice(["ECONOMY", "ECONOMY", "ECONOMY", "BUSINESS", "FIRST"])
print(f"{name}: {origin}->{dest} {flight} seat {seat} ({pnr})")
card = Card()
card.title("BOARDING PASS")
card.line(f"{airline} - {cls}", size=13, bold=True, center=True)
card.gap(2).heading(f"{origin} >> {dest}", size=26)
card.line(f"{AIRPORTS[origin]} to {AIRPORTS[dest]}", size=12, bold=False, center=True)
card.gap(2).divider()
card.kv("Passenger", name)
card.kv("Flight", flight)
card.kv("Date", depart.strftime("%a %d %b %Y"))
card.kv("Departs", depart.strftime("%H:%M"))
card.kv("Boarding", boarding.strftime("%H:%M"))
card.kv("Gate", gate)
card.kv("Seat", seat)
card.kv("Group / Seq", f"{group} / {seq:03d}")
card.gap(6).image(barcode(card.inner_w, rng), border=False)
card.line(f"{pnr} {flight} {origin}{dest}", size=12, bold=False, center=True)
card.footer("not a real ticket", f"conf {pnr}")
return card.finish(args.out, args.bottom_feed, args.darkness, do_print=not args.no_print)
if __name__ == "__main__":
raise SystemExit(main())