Skip to content

Instantly share code, notes, and snippets.

@fractal161
Created May 5, 2024 07:45
Show Gist options
  • Select an option

  • Save fractal161/1cb3e31765c1d4160ba73ca92d32befb to your computer and use it in GitHub Desktop.

Select an option

Save fractal161/1cb3e31765c1d4160ba73ca92d32befb to your computer and use it in GitHub Desktop.
VGO Part Merger
'''
Utility for merging orchestra parts in a printer-friendly manner
Motivation: print.mit.edu has an unfortunate quirk where only one document can
be uploaded at a time. This is quite inconvenient when printing a bunch of
orchestral parts because there are many instruments.
Only dependencies are python and the pypdf package. Its generic usage is of the
form
python merge.py -i INPUT_FOLDER -o OUTPUT_FILE
Further options are documented under the -h option.
List of implemented features:
- merges all top-level files in the specified folder
- can specify the number of copies for each part
List of desired features:
- config file for repeated operations
- better control over how to align each part's pages
- download directly from sharepoint url?
'''
import argparse
import os
from pypdf import PdfReader, PdfWriter
def input_int(prompt):
while True:
try:
result = int(input(prompt))
if result < 0:
raise ValueError
return result
except ValueError:
print('Please enter a nonnegative integer')
# fancy cli thing
parser = argparse.ArgumentParser(
prog='parts-merger',
description='merges parts')
parser.add_argument('-i', '--input',
required=True,
help='directory containing parts to merge')
parser.add_argument('-o', '--output',
required=True,
help='file to write merged pdf to')
parser.add_argument('-c', '--config',
help='load the specified configuration file')
parser.add_argument('-n', '--no-blank',
help='don\'t insert a blank page in front of a part if needed',
action='store_true')
args = parser.parse_args()
if not os.path.isdir(args.input):
raise ValueError('must supply a directory as input!')
# for simplicity, only iterate through top-level files
parts = [f for f in os.listdir(args.input)
if os.path.isfile(os.path.join(args.input, f))]
parts.sort()
outFile = PdfWriter()
# TODO: check for config file's existence
should_save_config = False
for part in parts:
# TODO: use config file to determine copies
copies = input_int(f'How many copies for {part}? ')
if copies == 0:
continue
partFile = PdfReader(os.path.join(args.input, part))
# get page dimensions
pages = partFile.pages
if len(pages) == 0:
print('Empty file, skipping...')
continue
box = partFile.pages[0].mediabox
num_pages = partFile.get_num_pages()
for _ in range(copies):
# we use a naive approach: if the number of pages is even, do
# [BLANK] [PART] [BLANK]
# and if the number of pages is odd, do
# [PART] [BLANK]
if num_pages % 2 == 0:
box = partFile.pages[0].mediabox
outFile.add_blank_page(box.width, box.height)
outFile.append(partFile)
box = partFile.pages[-1].mediabox
outFile.add_blank_page(box.width, box.height)
outFile.write(args.output)
outFile.close()
if should_save_config:
# TODO: write copy counts to config file
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment