Beispiel #1
0
def validate_part(part, options):
    path = os.path.join(options["folder-dir"], "parts", part)
    if not os.path.exists(path):
        thread_print(f'ERROR: Path to files for part "{part}" does not exist, folder will not be generated')
        return None
    
    # Validate titles
    title_map = process_files(sorted(glob.glob(f'{path}/*.pdf')))
    if len(title_map.keys()) == 0:
        thread_print(f'WARNING: No files found for part "{part}", folder will not be generated')
        return None
    validate_titles(title_map, options, resourcePath("res/options/folder_creator_options.json"), verbose=options["verbose"], part=part)

    return title_map
def folder_creator(max_workers=10):
    options = parse_options("folder_creator_options.json")
    if options == None: return 1

    with concurrent.futures.ThreadPoolExecutor(max_workers) as threadPool:
        futures = {
            threadPool.submit(create_part_folder, part, options): part
            for part in options['folder-parts']
        }
        for future in concurrent.futures.as_completed(futures):
            pass

    thread_print("Finished generating folders")

    return 0
Beispiel #3
0
def enumerate_pages(files, options, style=0, start=None, page_map=None, write_pages=False, no_filler_before=None, verbose=False):
    pages = []
    if start == None:
        start = 1 if style == 0 else 'A'
    counter = start

    # Read filler pages if filler needs to be interlaced
    filler = None
    if no_filler_before: filler = add_filler(options)
    valid_filler_indeces = []

    for file in files:
        check_stop_script()
        try:         
            # Save page num assignment to map
            if page_map != None: page_map[counter] = file
            if filler and file not in no_filler_before: valid_filler_indeces.append(len(pages))

            # Read input file
            input = PdfFileReader(open(file, 'rb'))
            num_pages = input.getNumPages()
            page_num = f'{counter}'

            # Add all the pages to the list
            for i in range(num_pages):
                input_page: PageObject = input.getPage(i)

                # Verify that it has the proper dimensions
                mediabox = input_page.mediaBox
                if not validate_mediabox(mediabox, options):
                    thread_print(f'WARNING: Page {i + 1} in "{file}" has incorrect dimensions\nExpected {options["page-size"]["width"]} x {options["page-size"]["height"]}, received {float(mediabox.getWidth()) / inch} x {float(mediabox.getHeight()) / inch}.')
                    continue

                # Calculate this page number
                if not write_pages: continue
                if num_pages > 1: page_num = f'{counter}.{i + 1}'
                pages.append(add_page_num(input_page, page_num, options) if options["enumerate-pages"] else input_page)

        except OSError:
            thread_print(f'Error when parsing "{file}"')
        
        # Increment Counter
        counter = (counter + 1) if style == 0 else (chr(ord(counter) + 1))

    # Interlace filler (if applicable)
    if filler: interlace_filler(pages, filler, valid_filler_indeces)

    return pages
Beispiel #4
0
def merge_page_nums(pages: List[PageObject], options, filename='page_nums.pdf'):
    output = []
    path = os.path.join(options["folder-dir"], "tmp", filename)
    with open(path, 'rb') as f:
        page_num_pdf = PdfFileReader(f)
        for i, page in enumerate(pages):
            target: PageObject = page_num_pdf.getPage(i)
            target.mergePage(page)
            # For some reason the text doesn't appear properly if we don't write first
            thread_print("Writing extra output file because this is somehow necessary")
            tmp_out = PdfFileWriter()
            tmp_out.addPage(target)
            with open(os.path.join(options["folder-dir"], "tmp", "page_num_overlap.pdf"), 'wb') as f:
                pass#tmp_out.write(f)
            output.append(target)

    return output
Beispiel #5
0
def generate_toc(toc_maps, options, file, verbose=False):
    # Get page num information
    check_stop_script()
    width, height = (inch * options["page-size"]["width"], inch * options["page-size"]["height"])
    path = os.path.dirname(file)
    validate_dir(path, verbose)
    check_stop_script()
    
    # Generate toc doc and data
    toc = SimpleDocTemplate(file, pagesize=(width, height),
                            leftMargin=inch * .5, rightMargin=inch * .5,
                            topMargin=.75 * inch, bottomMargin=inch*.25)
    check_stop_script()
    styles = generate_toc_styles(options)
    data = generate_toc_data(toc_maps, options, styles)
    check_stop_script()

    # Construct table
    table = Table(data)
    table.setStyle(TableStyle([
        ('RIGHTPADDING', (0,0), (-1,-1), -3),
        ('LEFTPADDING', (0,0), (-1,-1), -3),
        ('BOTTOMPADDING', (0,0), (-1,-1), 0),
        ('TOPPADDING', (0,0), (-1,-1), 0)
    ]))

    # Add title and footer
    def onFirstPage(canvas: canvas.Canvas, doc):
        canvas.saveState()
        font, size = (options["toc"]["title"]["font"], options["toc"]["title"]["size"])
        canvas.setFont(font, size)
        canvas.drawCentredString(width / 2, height - (.02 * inch * size), options["toc"]["title"]["label"])
        font, size = (options["toc"]["footer"]["font"], options["toc"]["footer"]["size"])
        canvas.setFont(font, size)
        canvas.drawCentredString(width / 2, (.02 * inch * size), options["toc"]["footer"]["label"])
        canvas.restoreState()

    # write the document to disk
    check_stop_script()
    toc.build([table], onFirstPage=onFirstPage)
    if verbose: thread_print(f'Successfully created table of contents file at "{file}"')
Beispiel #6
0
def download_part_files(service, curr_parts_id, part, dir, verbose=False):
    # Retrieve files
    folders = util.get_drive_files(service, curr_parts_id, files_only=False, name=part)
    if not folders or len(folders) != 1:
        thread_print(f'ERROR: Unable to find folder "{part}"')
        return
    files = util.get_drive_files(service, folders[0].get("id"), file_types=[".pdf"], is_shortcut=True)
    if not files or len(files) == 0:
        thread_print(f'WARNING: Could not find any part files for "{part}"')
        return
    
    # Validate target directory
    check_stop_script()
    path = os.path.join(dir, part)
    validate_dir(path, verbose)

    # Delete all existing files in that directory
    to_delete = glob.glob(f'{path}/*')
    for f in to_delete:
        os.remove(f)
    
    # Download files
    for file in files:
        check_stop_script()
        util.download_file(service, file["shortcutDetails"]["targetId"], path, file.get("name"), verbose)
    
    # Print success
    thread_print(f'Successfully finished downloading part files for "{part}"')
Beispiel #7
0
def validate_titles(title_map, options, update_path=None, verbose=False, part=None):
    titles = title_map.keys()
    
    # Helper method to find case-insensitive match
    def find_match(song: str):
        song_lower = song.lower()
        for title in titles:
            if ''.join(song_lower.split()) == ''.join(title.lower().split()):
                if verbose: thread_print(f'DEBUG: Found match for song "{song}": "{title}".')
                return title

    # Go through all the file lists and make repairs if necessary
    for key in ("dollie-songs", "lettered-chartz", "exclude-songs"):
        for i, song in enumerate(options[key]):
            if not song in titles:
                if update_path:
                    match = find_match(song)
                    if match: options[key][i] = match
                    elif verbose: thread_print(f'WARNING: Song "{song}" specified in "{key}" was not found in for {part}.')
    
    for i, rule in enumerate(options["enforce-order"]):
        for j, song in enumerate(rule):
            if not song in titles:
                if update_path:
                    match = find_match(song)
                    if match: options["enforce-order"][i][j] = match
                    elif verbose: thread_print(f'WARNING: Song "{song}" specified in "enforce-order" was not found.')
    
    # Remove any songs on the exclude list
    for excluded_song in options["exclude-songs"]:
        if excluded_song in title_map:
            del title_map[excluded_song]
    
    if update_path:
        with open(update_path, 'w') as f:
            json.dump(options, f, indent=4)
Beispiel #8
0
def generate_parts_pages(title_map, toc_maps, options, part, write_pages=False, verbose=False):
    output = []
    filler_pos = options['filler']['position']
    lettered, numbered, special = categorize_parts(title_map, options)

    # Fingering chart
    if filler_pos == 0: output.extend(add_filler(options))
    if write_pages and len(special["fingering_chart"]):
        if verbose:
            thread_print(f'Writing fingering chart to {part} folder')
        output.extend(to_pages(special["fingering_chart"][0]))

    # Lettered chartz
    if verbose:
        thread_print(f'Writing lettered chartz to {part} folder')
    output.extend(enumerate_pages(lettered, options, style=1, page_map=toc_maps[0], write_pages=write_pages, verbose=verbose))
    if filler_pos == 1: output.extend(add_filler(options))

    # Numbered chartz
    if verbose:
        thread_print(f'Writing numbered chartz to {part} folder')
    # interlace filler
    no_filler_before = None
    if filler_pos == 4:
        no_filler_before = enforceRules(numbered, options["enforce-order"], title_map)
    output.extend(enumerate_pages(numbered, options, page_map=toc_maps[1], write_pages=write_pages, no_filler_before=no_filler_before, verbose=verbose))
    if filler_pos == 2: output.extend(add_filler(options))

    # Teazers
    if len(special["teazers"]):
        if verbose:
            thread_print(f'Writing teazers to {part} folder')
        output.extend(enumerate_pages(special["teazers"], options, style=1, start='a', page_map=toc_maps[2], write_pages=write_pages, verbose=verbose))
    if filler_pos == 3: output.extend(add_filler(options))

    return output
Beispiel #9
0
def add_filler(options):
    output = []
    filler_data = options['filler']
    if not filler_data["include"]: return []
    if not len(filler_data["order"]):
        thread_print("WARNING: No filler ordering was specified, filler will not be added")
        return []
    
    for filename in filler_data["order"]:
        try:
            filler = PdfFileReader(open(os.path.join(filler_data["directory"], f'{filename}.pdf'), 'rb'))
            for i in range(filler.getNumPages()):
                page: PageObject = filler.getPage(i)
                if not validate_mediabox(page.mediaBox, options):
                    thread_print(f'WARNING: Page {i + 1} in "{filename}" has incorrect dimensions\nExpected {options["page-size"]["width"]} x {options["page-size"]["height"]}, received {float(page.mediaBox.getWidth()) / inch} x {float(page.mediaBox.getHeight()) / inch}.')
                output.append(filler.getPage(i))
        except OSError:
            thread_print(f'WARNING: Unable to open file "{filename}.pdf", this item will be skipped.')
            continue
    return output
def create_part_folder(part, options):
    # Table of contents + page number path
    toc_path = os.path.join(options["folder-dir"], "tmp", f"toc-{part}.pdf")

    # Validate part files
    thread_print(f'Writing {part} folder...')
    title_map = pdf_tools.validate_part(part, options)
    if not title_map: return 1
    check_stop_script()

    # Write pages
    output = PdfFileWriter()
    toc_maps = [{}, {}, {}]
    for page in pdf_tools.generate_parts_pages(title_map,
                                               toc_maps,
                                               options,
                                               part,
                                               write_pages=True,
                                               verbose=options['verbose']):
        output.addPage(page)

    # Add table of contents (toc)
    if options['verbose']: thread_print(f'Generating {part} Table of Contents')
    pdf_tools.generate_toc(toc_maps, options, toc_path)
    output.insertPage(pdf_tools.to_pages(toc_path)[0], 0)

    # Write file
    check_stop_script()
    file_path = os.path.join(options["folder-dir"], "Output")
    pdf_tools.validate_dir(file_path, options["verbose"])
    with open(
            os.path.join(file_path, f'{options["folder-name"]} - {part}.pdf'),
            'wb') as f:
        output.write(f)
    thread_print(f'Successfully wrote {part} folder to "{file_path}"')

    # Cleanup temp files
    if os.path.isfile(toc_path):
        os.remove(toc_path)

    return 0
Beispiel #11
0
 def find_match(song: str):
     song_lower = song.lower()
     for title in titles:
         if ''.join(song_lower.split()) == ''.join(title.lower().split()):
             if verbose: thread_print(f'DEBUG: Found match for song "{song}": "{title}".')
             return title
Beispiel #12
0
def validate_dir(path, verbose=False):
    if not os.path.exists(path):
        os.makedirs(path)
        if verbose: thread_print(f'DEBUG: Making directory "{path}"')