Skip to content

Instantly share code, notes, and snippets.

@cellularmitosis
Last active April 4, 2025 08:06
Show Gist options
  • Save cellularmitosis/1dabd7587662f8aa7652369472595806 to your computer and use it in GitHub Desktop.
Save cellularmitosis/1dabd7587662f8aa7652369472595806 to your computer and use it in GitHub Desktop.
randpage.py: Display a random page from a random PDF

Blog 2019/11/27

<- previous | index | next ->

randpage.py: Display a random page from a random PDF

2025/4/3 updates: use python3, use set -e, combine cmdline util + webapp into unified script.

Here's a Python script which will display a random page from a random PDF (in the current directory).

It's a fun way to encourage you to pick up one of your books which has been (digitally) collecting dust.

You can run it as a command-line utility (which will open the random page in Preview.app), or pass the --serve flag to run it as a Flask webapp on localhost:8000.

Assumptions:

  • macOS
  • pdftk (brew install pdftk-java)
  • pdfinfo (brew install xpdf)
  • exiftool (brew install exiftool)
#!/usr/bin/env python3
# randpage.py: display a random page from a directory of pdf files.
# Copyright 2019 Jason Pepas
# Released under the terms of the MIT license, see https://opensource.org/license/mit
# Usage:
# Open a random page using Preview.app:
# $ ./randpage.py
# Run as a webapp on localhost:8000:
# $ ./randpage.py --serve
import sys
import os
import random
import subprocess
def check_deps():
"check if we have all of the dependencies installed"
if os.system("which -s pdfinfo") != 0:
sys.stderr.write("Error: pdfinfo not installed.\n")
sys.stderr.write("Try 'brew install xpdf'.\n")
sys.exit(1)
if os.system("which -s pdftk") != 0:
sys.stderr.write("Error: pdftk not installed.\n")
sys.stderr.write("Try 'brew install pdftk-java'.\n")
sys.exit(1)
if os.system("which -s exiftool") != 0:
sys.stderr.write("Error: exiftool not installed.\n")
sys.stderr.write("Try 'brew install exiftool'.\n")
sys.exit(1)
def random_book(path):
"return a random book among the books in the current directory."
books = [fname for fname in os.listdir(path) if fname.endswith('.pdf')]
return random.choice(books)
def page_count(fname):
"return the page count of the given book."
cmd = "set -e -o pipefail; pdfinfo \"%s\" | grep Pages: | awk '{print $2}'" % fname
output = subprocess.check_output(cmd, shell=True)
return int(output)
def pluck_page(book_fname, pagenum):
"extract the given page from the given book."
cmd = "set -e; pdftk \"%s\" cat %s output /tmp/random-page.pdf" % (book_fname, pagenum)
subprocess.check_call(cmd, shell=True)
# set the metadata title of the pdf to indicate the book title and page number.
title = "%s, page %s" % (book_fname.split('/')[-1], pagenum)
cmd = "set -e; exiftool -Title=\"%s\" /tmp/random-page.pdf" % title
subprocess.check_call(cmd, shell=True)
return "/tmp/random-page.pdf"
def display_page(fname):
"display the extracted book page."
subprocess.check_call("set -e; open %s" % fname, shell=True)
def display_random_page(books_path):
"display a random page from a random book."
book_fname = random_book(books_path)
pages = page_count(book_fname)
pagenum = random.randrange(pages) + 1
print("%s, page %s of %s" % (book_fname, pagenum, pages))
page_fname = pluck_page(book_fname, pagenum)
display_page(page_fname)
def serve(books_path):
"run as a webapp on port 8000."
import flask
application = flask.Flask(__name__)
@application.route("/")
def GET_root(methods=['GET']):
book_fname = random_book(books_path)
pages = page_count(books_path + book_fname)
pagenum = random.randrange(pages) + 1
page_fname = pluck_page(books_path + book_fname, pagenum)
with open(page_fname, 'rb') as f:
pdf = f.read()
response = flask.make_response(pdf)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = \
'inline; filename=%s' % book_fname
response.headers["x-filename"] = book_fname
response.headers["Access-Control-Expose-Headers"] = 'x-filename'
return response
application.run('0.0.0.0', port=8000, debug=False)
if __name__ == "__main__":
check_deps()
books_path = './'
if '--serve' in sys.argv:
serve(books_path)
else:
display_random_page(books_path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment