Skip to content

Instantly share code, notes, and snippets.

@thiagokokada
Last active October 13, 2017 22:20
Show Gist options
  • Save thiagokokada/20b63bb67c49b02f33860193c8476430 to your computer and use it in GitHub Desktop.
Save thiagokokada/20b63bb67c49b02f33860193c8476430 to your computer and use it in GitHub Desktop.
Downloads and show random xkcd comic as i3lock background
#!/usr/bin/env python3
# i3lock-xkcd.py
# Downloads and show random xkcd comic as i3lock background
import os
import sys
from subprocess import run
from tempfile import NamedTemporaryFile
from textwrap import wrap
from xkcd import getRandomComic
from PIL import Image, ImageDraw, ImageFont
from screeninfo import get_monitors
# Set options below
FONT_FAMILY = "xkcd.otf"
FONT_TITLE_SIZE = 36
FONT_ALTTEXT_SIZE = 12
RESIZE_RATIO = 0.8
class I3LockXkcdException(Exception):
pass
class I3LockXkcd(object):
def __init__(self, filename, resolution, retries=3):
for i in range(retries):
try:
self.xkcd = getRandomComic()
self.xkcd.download(
os.path.dirname(filename),
os.path.basename(filename)
)
except:
# Maybe we got a comic that can't be downloaded
# (like 1190: Time), so we try again
next
self.bg = Image.new("RGBA", resolution, "white")
self.bg_w, self.bg_h = self.bg.size
self.comic = Image.open(filename)
self.comic_w, self.comic_h = self.comic.size
if not self.comic:
raise I3LockXkcdException("No comic has been downloaded")
def get_image(self):
self.draw_comic()
self.draw_title()
self.draw_alttext()
return self.bg
def draw_comic(self):
# Calculate comic offset relative to background
offset_w = (self.bg_w - self.comic_w) // 2
offset_h = (self.bg_h - self.comic_h) // 2
offset = (offset_w, offset_h)
# Draw comic inside background
self.bg.paste(self.comic, offset)
def draw_title(self, base_offset=100):
# Draw title above comic
font = ImageFont.truetype(FONT_FAMILY, FONT_TITLE_SIZE)
title = ImageDraw.Draw(self.bg)
xkcd_title = self.xkcd.getTitle()
title_w, title_h = title.textsize(xkcd_title, font=font)
# Calculate title offset relative to comic
offset_w = (self.bg_w - title_w) // 2
offset_h = (self.bg_h - self.comic_h - base_offset - title_h) // 2
offset = (offset_w, offset_h)
# Draw title inside background
title.text(offset, xkcd_title, font=font, fill="black")
def draw_alttext(self, line_offset=100):
# Draw alt-text above comic
font = ImageFont.truetype(FONT_FAMILY, FONT_ALTTEXT_SIZE)
alt_text = ImageDraw.Draw(self.bg)
# Since alt-text can be too long, we wrap it using textwrap.wrap
for line in wrap(self.xkcd.getAltText(), width=120):
line_w, line_h = alt_text.textsize(line, font=font)
offset_w = (self.bg_w - line_w) // 2
offset_h = (self.bg_h + self.comic_h + line_offset - line_h) // 2
offset = (offset_w, offset_h)
alt_text.text(offset, line, font=font, fill="black")
line_offset += 40
def main():
monitor = get_monitors()[0]
monitor_w = monitor.width
monitor_h = monitor.height
resolution = (monitor_w, monitor_h)
with NamedTemporaryFile(suffix=".png") as tempfile:
try:
image = I3LockXkcd(tempfile.name, resolution).get_image()
except I3LockXkcdException as e:
# Failed to get comic, just open i3lock instead
print(e, file=sys.stderr)
run(["i3lock"])
sys.exit(1)
# Write result in temporary file, loads in i3lock
with NamedTemporaryFile(suffix=".png") as tempfile:
image.save(tempfile.name)
run(['i3lock', '-i', tempfile.name])
if __name__ == "__main__":
main()
olefile==0.44
Pillow==4.3.0
screeninfo==0.3
xkcd==2.4.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment