def redvest_creator(): # Build service service = util.build_service() # Read folder locations redvest_options = util.parse_options("redvest_options.json") if redvest_options == None: return 1 # Verify all needed folders exist and retrieve their ids print("Verifying DigitalLibrary format...") lib_ids = util.get_digital_library(service) current_chartz_id = lib_ids.get("current_id") future_chartz_id = lib_ids.get("future_id") if current_chartz_id == None or future_chartz_id == None: return 1 # Verify (and collect) all chart ids print("Validating Chartz...") chart_ids = [ verify_chart_name(service, chart, [current_chartz_id, future_chartz_id]) for chart in redvest_options["chartz"] ] if None in chart_ids: print('Try double-check your spelling, chart names are case-sensitive') print('ERROR: Redvest folder will not be created') return 1 print("Verifying Redvest folder...") new_folder_id, new_resources_id = verify_redvest(service, redvest_options) if new_folder_id == None or new_resources_id == None: return 1 # Only make individual section folders if field set to true alias_map = None section_ids = None check_stop_script() if redvest_options["individual-sections"]: # Read parts parts_dict = util.parse_options("parts.json")['parts'] if parts_dict == None: return 1 # Make individual section folders print("Making individual section folders...") section_ids = make_section_folders(service, new_folder_id, parts_dict.keys()) # Invert parts_dict to create map of alias's -> folder alias_map = util.make_alias_map(parts_dict) # Write each chart to the new redvest folder for index, chart in enumerate(redvest_options["chartz"]): write_song(service, chart, chart_ids[index], new_folder_id, new_resources_id, section_ids, alias_map) print( f'Successfully created new folder "{redvest_options["folder-name"]}"!') return 0
def download_parts(): service = util.build_service() options = util.parse_options("folder_creator_options.json") if options == None: return # Ensure that there are parts to download if len(options["download-parts"]) == 0: print(f'ERROR: No parts specified.') return # Get the current parts id print("Verifying DigitalLibrary format...") library_id = util.get_digital_library(service).get("library_id") if library_id == None: return 1 curr_parts_id = util.get_separated_folders(service, library_id)["sec_curr"] if curr_parts_id == None: return 1 for part in options["download-parts"]: check_stop_script() print(f'Downloading files for part "{part}"') pdf_tools.download_part_files( service, curr_parts_id, part, os.path.join(options["folder-dir"], "parts"), options["verbose"]) print("Finished downloading parts") return 0
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
def validate_folder_files(): options = parse_options("folder_creator_options.json") if options == None: return 1 for part in options["folder-parts"]: check_stop_script() # Validate part files title_map = pdf_tools.validate_part(part, options) if not title_map: continue # Generate sample table of contents if options["toc"]["generate-on-validation"]: validate_toc(part, title_map, options) print("Finished validating folders and parts") return 0
def __init__(self, parent, *args, **kwargs): ttk.Frame.__init__(self, parent, *args, **kwargs) # Parse move_chartz options self.options = parse_options("move_chartz_options.json") # Move chartz selection self.new_chartz = Multiselect(self, input=self.options['chartz'], title='Chartz to Move', key1='name', key2='to', header='Chart Name', addText='Add Chart', orient='vertical', height=10, archive=True) self.new_chartz.grid(row=0, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # Run script/Close buttons close_button = ttk.Button(self, text='Close', command=lambda: parent.master.destroy()) bind_button(close_button) run_script_button = ttk.Button(self, text='Move Chartz', command=self.run_script) bind_button(run_script_button) close_button.grid(row=1, column=0, sticky=(S, W), padx=20, pady=10) run_script_button.grid(row=1, column=1, sticky=(S, E), padx=20, pady=10) # Allow resizing self.rowconfigure(1, weight="1") self.columnconfigure(1, weight="1")
def main(argv): script = None # Parse command line inputs try: opts, args = getopt(argv, "hs:", ["script=", "help"]) except GetoptError: print_help() sys.exit(2) for opt, arg, in opts: if opt in ["-h", "--help"]: print_help() sys.exit() elif opt in ["-s", "--script"]: if arg in SCRIPT_DICT: script = SCRIPT_DICT[arg] else: print_help() sys.exit() # If a script is specified on the command line - run it! if script: script() return # Search for application data directory, if running as executable data_dir = None if is_frozen(): data_dir = user_data_dir('LSJUMB Librarianz Scripts', 'LSJUMB', VERSION) res_options = parse_options("res_paths.json", from_=data_dir) res_options['res-path'] = data_dir make_application_data(data_dir, VERSION != res_options.get('version')) res_options['version'] = VERSION write_options(res_options, "res_paths.json") write_options(res_options, "res_paths.json") # Run Main Application root = tk.Tk() MainMenu(root, data_dir) root.mainloop()
def __init__(self, parent, *args, **kwargs): ttk.Frame.__init__(self, parent, *args, **kwargs) # Parse redvest options self.options = parse_options("redvest_options.json") # Parent folder selection self.parent_entry = LabledEntry( self, title='Redvest Subdirectory Folder', label='Enter Subdirectory Folder Name', defaultEntry=self.options['parent-name'], info='Directory Structure: Redvest -> Subdirectory -> Session') self.parent_entry.grid(row=0, column=0, columnspan=2, sticky=(N, S, E, W), padx=20, pady=10) # Folder name selection self.folder_entry = LabledEntry( self, title='Create New Redvest Session Folder', label='New Folder Name', defaultEntry=self.options['folder-name']) self.folder_entry.grid(row=1, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # Select Chartz multiselect self.select_chartz = Multiselect(self, input=self.options['chartz'], title='Select Chartz for Redvest', header='Chart Name', addText='Add Chart', height=7) self.select_chartz.grid(row=2, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # Individual Sections sep_sec_frame = ttk.LabelFrame(self, text='Separated Section Parts') self.sep_sec = BooleanVar() self.sep_sec.set(self.options['individual-sections']) sep_sec_checkbox = ttk.Checkbutton( sep_sec_frame, text='Include Separated Section Parts', variable=self.sep_sec) sep_sec_checkbox.grid(row=0, column=0, padx=10, pady=5) sep_sec_frame.rowconfigure(0, weight='1') sep_sec_frame.columnconfigure(0, weight='1') sep_sec_frame.grid(row=3, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # Run script/Close buttons close_button = ttk.Button(self, text='Close', command=lambda: parent.master.destroy()) bind_button(close_button) run_script_button = ttk.Button(self, text='Create Redvest Folder', command=self.run_script) bind_button(run_script_button) close_button.grid(row=4, column=0, sticky=(S, W), padx=20, pady=10) run_script_button.grid(row=4, column=1, sticky=(S, E), padx=20, pady=10) # Make resizeable for i in range(5): self.rowconfigure(i, weight='1') self.columnconfigure(1, weight='1')
def upload_files(): # Build service service = util.build_service() # Read options alias_map = util.make_alias_map(util.parse_options("parts.json")['parts']) options = util.parse_options("upload_options.json") if options == None: return 1 check_stop_script() # Get list of files that need to be uploaded files = util.get_dir_files(options["resources-directory"], options["supported-file-types"]) check_stop_script() # Verify all needed folders exist and retrieve their ids print("Verifying DigitalLibrary format...") lib_ids = util.get_digital_library(service) library_id = lib_ids.get("library_id") if library_id == None: return 1 check_stop_script() separated_ids = util.get_separated_folders(service, library_id) if separated_ids == None: return 1 check_stop_script() # Cache will store folder + parts folder ids and a list of files cache = {} # 0 = update only, 1 = new files only, 2 = update and add new files mode = options["mode"] # Create new folders (if in proper mode) if mode != 0: for chart_info in options["new-chartz"]: check_stop_script() chart_dest = chart_info["to"] new_chart_dest_key = "current_id" if chart_dest == 0 else "past_id" if chart_dest == 1 else "future_id" if chart_dest == 2 else "archive_id" chart_id, parts_id, audio_id = lib_management.create_chart_structure( service, lib_ids.get(new_chart_dest_key), chart_info["name"]) if chart_id: cache[chart_info["name"]] = { "chart_id": chart_id, "parts_id": parts_id, "audio_id": audio_id, "loc": chart_info["to"], "files": [] } # Operate on files for file in files: # Check to see if we should exit check_stop_script() # Populate cache lib_management.populate_cache(service, lib_ids.get("current_id"), lib_ids.get("past_id"), lib_ids.get("future_id"), lib_ids.get("archive_id"), util.parse_file(file, alias_map)[0], cache, options) updated = None added = None # Update file if mode != 1: updated = lib_management.update_file(service, file, alias_map, cache, options) # Add file if mode != 0 and not updated: added = lib_management.add_file(service, file, separated_ids, alias_map, cache, options) # print output if updated == True: print(f'Successfully updated "{file}"') elif added == True: print(f'Successfully added "{file}"') elif updated == False: print(f'ERROR: Unable to update "{file}"') print("Finished uploading files") return 0
def __init__(self, parent, *args, **kwargs): ttk.Frame.__init__(self, parent, *args, **kwargs) # Parse upload files options self.options = parse_options("upload_options.json") # Directory selection self.select_directory = SelectDirectory(self, path=self.options["resources-directory"], title='Select Resources Folder') self.select_directory.grid(row=0, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # Mode selection + title match checkbox self.mode = IntVar() self.mode.set(self.options["mode"]) self.title_match = BooleanVar() self.title_match.set(self.options["require-titles-match"]) mode_frame = ttk.Labelframe(self, text='Select Mode') update = ttk.Radiobutton(mode_frame, text='Update Files', variable=self.mode, value=0) add = ttk.Radiobutton(mode_frame, text='Add Files', variable=self.mode, value=1) update_and_add = ttk.Radiobutton(mode_frame, text='Add and Update', variable=self.mode, value=2) title_match_checkbox = ttk.Checkbutton(mode_frame, text='Enforce Matching Titles', variable=self.title_match) mode_frame.grid(row=1, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) update.grid(row=0, column=0) add.grid(row=0, column=1) update_and_add.grid(row=0, column=2) title_match_checkbox.grid(row=0, column=3, padx=20) # New chartz selection self.new_chartz = Multiselect(self, input=self.options['new-chartz'], title='Create New Chartz', key1='name', key2='to', header='Chart Name', addText='Add New Chart', height=3, archive=True) self.new_chartz.grid(row=2, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # File extensions selection self.file_extensions = Multiselect(self, input=self.options["supported-file-types"], title='Supported File Types', header='File Type', addText='Add File Type', warn=True, height=6) self.file_extensions.grid(row=3, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) # Run script/Close buttons close_button = ttk.Button(self, text='Close', command=lambda: parent.master.destroy()) bind_button(close_button) run_script_button = ttk.Button(self, text='Upload Files', command=self.run_script) bind_button(run_script_button) close_button.grid(row=4, column=0, sticky=(S, W), padx=20, pady=10) run_script_button.grid(row=4, column=1, sticky=(S, E), padx=20, pady=10) # Allow resizing for row in range(5): self.rowconfigure(row, weight="1") self.columnconfigure(0, weight="1") for col in range(4): mode_frame.columnconfigure(col, weight="1", minsize="80")
def __init__(self, parent, mode, *args, **kwargs): # Initialize superclass title = kwargs.get('title') or 'Select Font' ttk.LabelFrame.__init__(self, parent, text=title) # Initializes props name = kwargs.get('name') or 'Entry' # Supported fonts fonts_dict = parse_options("supported_fonts.json") supported_fonts: List = fonts_dict['default'] if fonts_dict.get('more'): more: List = fonts_dict['more'] more.sort() supported_fonts.extend(more) # Leftmost entry is either a text entry or a font select, depending on mode left_label_text = kwargs.get('leftLabel') or f'{name} Text:' self.left_entry_text = StringVar() if mode == 0: left_label = ttk.Label(self, text=left_label_text) left_label.grid(row=0, column=0, sticky=S, padx=10, pady=2) self.left_entry_text.set(kwargs.get('leftEntry') or '') left_entry = ttk.Entry(self, textvariable=self.left_entry_text) left_entry.grid(row=1, column=0, sticky=N, padx=10, pady=2) elif mode == 1: left_label = ttk.Label(self, text=left_label_text) left_label.grid(row=0, column=0, sticky=S, padx=10, pady=2) self.left_entry_text.set(kwargs.get('leftEntry') or 'Courier') left_combobox = ttk.Combobox(self, textvariable=self.left_entry_text) left_combobox['values'] = supported_fonts left_combobox.state(['readonly']) left_combobox.grid(row=1, column=0, sticky=N, padx=10, pady=2) # Middle entry is alwas a font select middle_label = ttk.Label(self, text=kwargs.get('middleLabel') or f'{name} Font:') middle_label.grid(row=0, column=1 - (mode > 1), sticky=S, padx=10, pady=2) self.middle_entry_text = StringVar() self.middle_entry_text.set(kwargs.get('middleEntry') or 'Courier') middle_combobox = ttk.Combobox(self, textvariable=self.middle_entry_text) middle_combobox['values'] = supported_fonts middle_combobox.state(['readonly']) middle_combobox.grid(row=1, column=1 - (mode > 1), sticky=N, padx=10, pady=2) # Right entry is always a size selection validate_fn = (self.register(validate_numerical_entry(False)), '%P') right_label = ttk.Label(self, text=kwargs.get('rightLabel') or 'Font Size:') right_label.grid(row=0, column=2 - (mode > 1), sticky=S, padx=10, pady=2) self.right_entry_val = StringVar() self.right_entry_val.set(kwargs.get('rightEntry') or 12) right_spinbox = ttk.Spinbox(self, from_=6, to=36, increment=2, textvariable=self.right_entry_val, width=3, validate='key', validatecommand=validate_fn) right_spinbox.bind('<FocusOut>', lambda _: self.right_entry_val.set(kwargs.get('rightLabel') or 12) if not len(self.right_entry_val.get()) else '') right_spinbox.grid(row=1, column=2 - (mode > 1), sticky=N, padx=10, pady=2) self.bind('<Button-1>', lambda e: e.widget.focus_set()) # Make resizeable for col in range(3 - (mode > 1)): self.columnconfigure(col, weight='1') self.rowconfigure(0, weight='1') self.rowconfigure(1, weight='1')
def __init__(self, parent, *args, **kwargs): ttk.Frame.__init__(self, parent, *args, **kwargs) self.options = parse_options('parts.json') self.DELIMETERS = (":", "|") parts_frame = ttk.Labelframe(self, text='Configure Part Mappings') # Add info label info = ttk.Label( parts_frame, justify='center', text= f'Each line of text is a part alias configuration.\nThe part name is followed by "{self.DELIMETERS[0]}", and aliases are delimited by "{self.DELIMETERS[1]}".\nFor example, if you wish for files "All Right Now - Toobz" and\n"All Right Now - Tööbz" to be mapped to the same folder,\nyou would enter "Toobz{self.DELIMETERS[0]} Toobz {self.DELIMETERS[1]} Tööbz"' ) info.grid(row=0, column=0, padx=10, pady=5) # Add text input area dummy_frame = ttk.Frame(parts_frame) self.parts_text = CustomText(dummy_frame, width=70, height=15, wrap='none', font=('TkDefaultFont'), undo=True) self.parts_text.grid(row=0, column=0, sticky=(N, E, S, W)) self.parts_text.tag_configure('delimeter-0-good', font=('TkFixedFont'), foreground='green') self.parts_text.tag_configure('delimeter-0-bad', font=('TkFixedFont'), foreground='red') self.parts_text.tag_configure('delimeter-1-good', font=('TkFixedFont'), foreground='blue') self.parts_text.tag_configure('delimeter-1-bad', font=('TkFixedFont'), foreground='red') self.parts_text.bind('<<TextModified>>', self.tag_delimeters) scrollx = ttk.Scrollbar(dummy_frame, orient='horizontal', command=self.parts_text.xview) scrolly = ttk.Scrollbar(dummy_frame, orient='vertical', command=self.parts_text.yview) self.parts_text['xscrollcommand'] = scrollx.set self.parts_text['yscrollcommand'] = scrolly.set scrollx.grid(row=1, column=0, sticky=(E, W, N)) scrolly.grid(row=0, column=1, sticky=(N, S, W)) parts_frame.grid(row=0, column=0, columnspan=2, sticky=(N, E, S, W), padx=20, pady=10) dummy_frame.grid(row=1, column=0, sticky=(N, E, S, W), padx=10, pady=5) dummy_frame.rowconfigure(0, weight='1') dummy_frame.columnconfigure(0, weight='1') # Populate text self.populate_parts(self.options['parts']) # Make Text Area Resizeable parts_frame.columnconfigure(0, weight='1') parts_frame.rowconfigure(1, weight='1') # Add exclusion selection self.exclusions = Multiselect( self, input=self.options['exclude'], title='Parts to Exclude from Live Digital Library', header='Part Name', addText='Add Part', warn=True, height=5) self.exclusions.grid(row=1, column=0, columnspan=2, padx=20, pady=10, sticky=(N, E, S, W)) # Run script/Close buttons close_button = ttk.Button(self, text='Close', command=lambda: parent.master.destroy()) bind_button(close_button) run_script_button = ttk.Button(self, text='Remake Shortcuts', command=self.run_script) bind_button(run_script_button) close_button.grid(row=2, column=0, sticky=(S, W), padx=20, pady=10) run_script_button.grid(row=2, column=1, sticky=(S, E), padx=20, pady=10) # Allow resizing self.rowconfigure(0, weight="1") self.rowconfigure(1, weight="1") self.columnconfigure(1, weight="1")
def __init__(self, parent, *args, **kwargs): ttk.Frame.__init__(self, parent, *args, **kwargs) # Parse folder creator options self.options = parse_options("folder_creator_options.json") # Target Directory selection self.select_directory = SelectDirectory(self, path=self.options["folder-dir"], title='Select Target Directory') self.select_directory.grid(row=0, column=0, columnspan=3, sticky=(N, E, S, W), padx=20, pady=10) # Folder Name Selection self.folder_name_entry = LabledEntry(self, title='Enter Output Folder Name', label='Output Name', defaultEntry=self.options['folder-name']) self.folder_name_entry.grid(row=1, column=0, sticky=(N, S, W, E), padx=20, pady=10) # Verbose Output Selection verbose_frame = ttk.LabelFrame(self, text='Console Logging') self.verbose = BooleanVar() self.verbose.set(self.options['verbose']) verbose_checkbox = ttk.Checkbutton(verbose_frame, text='Verbose Logging', variable=self.verbose) verbose_checkbox.grid(row=0, column=0, padx=10, pady=5) verbose_frame.rowconfigure(0, weight='1') verbose_frame.columnconfigure(0, weight='1') verbose_frame.grid(row=1, column=1, sticky=(N, E, S, W), padx=20, pady=10) # Workflows workflow_frame = ttk.Frame(self) # Download Files Workflow dl_workflow = FolderCreatorWorkflow(parent=workflow_frame, description="Downloads files from the Digial Library onto your local machine at the target directory specified above", scriptButtonName="Download Files", scriptCallback=self.runDownloadScript, optionsCallback=lambda: self.open_options(0)) dl_workflow.grid(row=0, column=0, sticky=(N, E, S, W), padx=0, pady=5) # Validate Folders Workflow validate_workflow = FolderCreatorWorkflow(parent=workflow_frame, description="Validates the folder structure at the target directory, and optionally outputs a sample table of contents", scriptButtonName='Validate Folder', scriptCallback=self.runValidateScript, optionsCallback=lambda: self.open_options(1)) validate_workflow.grid(row=0, column=1, sticky=(N, E, S, W), padx=20, pady=5) # Create Folders workflow create_folders = FolderCreatorWorkflow(parent=workflow_frame, description="Writes the folders to the Output folder in the target directory\n\nThis takes about 2-5 minutes", scriptButtonName='Generate Folders', scriptCallback=self.runFolderCreatorScript, optionsCallback=lambda: self.open_options(2)) create_folders.grid(row=0, column=2, sticky=(N, E, S, W), padx=0, pady=5) # Make Workflow Frame resizeable workflow_frame.grid(row=2, column=0, columnspan=3, sticky=(N, E, S, W), padx=20, pady=10) workflow_frame.rowconfigure(0, weight='1') for i in range(3): workflow_frame.columnconfigure(i, weight='1') # Run script/Close buttons close_button = ttk.Button(self, text='Close', command=lambda: parent.master.destroy()) bind_button(close_button) close_button.grid(row=3, column=0, sticky=(S, W), padx=20, pady=10) # Make resizeable for i in range(4): self.rowconfigure(i, weight='1') self.columnconfigure(1, weight='1')