diff --git a/gui/history.txt b/gui/history.txt index c5e77ff..6e439a2 100644 --- a/gui/history.txt +++ b/gui/history.txt @@ -7,18 +7,16 @@ `````````````````````` - - - - ----------------------------- Version : 0.1.0 Date: ----------------------------- - * Added auto-detect mode. (auto-pilot) + * Added auto-detect mode. * Added a save feature. - * Added the ability to select a file using directory navigation. - * Added settings for you to adjust preferences + * Added a feature which allows you to select a file using directory navigation. + * Added settings for you to adjust preferences. + * Added a feature which allows you to load either a file or text from clipboard into the application. + ----------------------------- Version : Beta Release diff --git a/gui/main.py b/gui/main.py index b61ef8b..e1c6b82 100644 --- a/gui/main.py +++ b/gui/main.py @@ -21,7 +21,7 @@ import pathlib from os import path from subprocess import Popen, PIPE -from os.path import getsize, splitext +from os.path import getsize, splitext, realpath import tempfile from configparser import ConfigParser import sys @@ -44,10 +44,18 @@ drop_type = None #In saving, this checks whether a file or text was dropped temp_files = [] #This is an array which contains a list of temporary files created. checked = False #This is used in auto-detect mode to check if a files mode has been detected. +file_path = '' +#===================================================================================== +# Constants +PICTURES = ['.jpg','.jif','jfif','.jpe', '.png', '.ico', '.jpeg','.gif', '.tiff','.vda','.vst','.tif','.icb','.icns','.webp', '.ppm','.pgm', '.pnm', '.pbm', '.tga', '.pcx', '.jp2','.j2k', '.jpf','jpx','jpm','mj2', 'raw', 'bmp', 'xpm'] +AUDIOS = ['.mp3','.m4r', '.wav','.m4p','m4a', '.pcm','.aiff','.aif', '.aac', '.ogg', '.wma', '.flac', '.alac','.aifc', '.3ga', '.aa','.act', '.al','.bap','.cda','.mp2','.mpa','.oga'] +VIDEOS = ['.mp4','.m4b','.avi','.qt','.mov','.wmv','.flv','.avchd','.webm','.mkv','.ogv','.dirac', '.mpg', '.mpeg','.3gp','.nsv','.3g2','.svi','.m4v'] +#===================================================================================== configurations = { 'default_mode':'encode', 'sys_argv_mode': None, - 'output_dir' : 'output' + 'output_dir' : 'output', + 'temp_dir' : tempfile.gettempdir() } #The default settings for configuration #====================================== #Functions and classes @@ -82,9 +90,13 @@ def show(): def main(self): menu = Menu(self.menubar, tearoff = 0) - menu.add_command(label = 'Settings', command = lambda : Menubar.settings(self)) menu.add_command(label = 'About', command = lambda: Menubar.about(self)) menu.add_separator() + menu.add_command(label = 'New Window', command = new_window) + menu.add_command(label = 'Restart Window', command = restart) + menu.add_separator() + menu.add_command(label = 'Settings', command = lambda : Menubar.settings(self)) + menu.add_separator() menu.add_command(label = 'Quit', command = lambda: root.quit()) self.menubar.add_cascade(label = 'More...', menu = menu) @@ -95,10 +107,15 @@ def save_command(): configurations['default_mode'] = default_mode.get() configurations['sys_argv_mode'] = sys_argv_variable.get() configurations['output_dir'] = path_entry_variable.get() + configurations['temp_dir'] = temp_dir_variable.get() settings_menu.destroy() def select_dir(): path = askdirectory() path_entry_variable.set(path) + def select_temp_dir(): + #Function for choosing temporary tempfiles directory. + path = askdirectory() + temp_dir_variable.set(path) #====================================== settings_menu = Toplevel() settings_menu.transient(root) @@ -110,10 +127,12 @@ def select_dir(): default_mode = StringVar() path_entry_variable = StringVar() sys_argv_variable = IntVar() + temp_dir_variable = StringVar() #---------------------------------- default_mode.set(configurations['default_mode']) sys_argv_variable.set(configurations['sys_argv_mode']) path_entry_variable.set(configurations['output_dir']) + temp_dir_variable.set(configurations['temp_dir']) #============================================== style = ttk.Style() #============================================== @@ -134,9 +153,22 @@ def select_dir(): # general_settings.grid(row = 0, column = 0) #============================================= - + path_settings = ttk.Frame(notebook) + # + output_dir_frame = ttk.LabelFrame(path_settings, text = 'Output directory') + path_entry = ttk.Entry(output_dir_frame, textvariable = path_entry_variable, state = 'disabled', width = 40).grid(row = 0, column = 0) + browse_button = ttk.Button(output_dir_frame, text = 'Browse...', command = select_dir).grid(row = 0, column = 1) + output_dir_frame.grid(row = 0, column = 0) + # + temp_folder_frame = ttk.LabelFrame(path_settings, text = 'Temporary folder path') + temp_path_entry = ttk.Entry(temp_folder_frame, textvariable = temp_dir_variable, state = 'disabled', width = 40).grid(row = 0, column = 0) + browse_button = ttk.Button(temp_folder_frame, text = 'Browse...', command = select_temp_dir).grid(row = 0, column = 1) + temp_folder_frame.grid(row = 1, column = 0) + # + path_settings.grid(row = 0, column = 0) #============================================= notebook.add(general_settings,text = 'General') + notebook.add(path_settings, text = 'Paths') confirmation_frame = Frame(settings_menu) button_ok = ttk.Button(confirmation_frame, text = 'OK', command = save_command).grid(row = 0, column = 0) button_cancel = ttk.Button(confirmation_frame, text = 'Cancel', command = lambda: settings_menu.destroy()).grid(row = 0, column = 1) @@ -157,14 +189,32 @@ def select_dir(): def rightclick_menu_results(event): save_state = DISABLED - if temp_file_name != '': + copy_html_state = DISABLED + if temp_file_name != '': #If the temp_file_name is empty. save_state = NORMAL + copy_html_state = NORMAL + copy_css_state = NORMAL + if drop_type == 'text' or mode_variable.get() == 'decode': #If drop_type is text or mode is decode + copy_html_state = DISABLED + copy_css_state = DISABLED elif drop_type == 'text': save_state = NORMAL + + suffix = str(pathlib.Path(file_path).suffix).lower() + if (suffix in PICTURES) or (suffix in AUDIOS) or (suffix in VIDEOS): + copy_html_state = NORMAL + else: + copy_html_state = DISABLED + if suffix in PICTURES: + copy_css_state = NORMAL + else: + copy_css_state = DISABLED menu = Menu(menubar, tearoff = 0) menu.add_command(label = 'Save', command = save_file, state = save_state) menu.add_command(label = 'Save (Give ext.)', command = save_file_manual, state = save_state) menu.add_command(label = 'Copy', command = copy_to_clipboard, state = save_state) + menu.add_command(label = 'Copy (HTML)', command = copy_html, state = copy_html_state) + menu.add_command(label = 'Copy (CSS)', command = copy_css, state = copy_css_state) menu.tk_popup(event.x_root, event.y_root) def rightclick_menu_file(event): @@ -184,6 +234,7 @@ def rightclick_menu_file(event): menu.add_command(label = 'Clipboard (Text)', state = text_state, command = load_text_clipboard) menu.tk_popup(event.x_root, event.y_root) + def copy_to_clipboard(): if type(results) == str: pyperclip.copy(results) @@ -204,21 +255,34 @@ def save_file_manual(): with open(filename, 'wb') as file: file.write(results) - +def restart(): + os.startfile(__file__) + root.quit() + +def new_window(): + os.startfile(__file__) def save_file(): #Just saves a file mode = mode_variable.get() - if mode == 'encode': + directory = pathlib.Path(configurations['output_dir']) + try: + if str(directory) == 'output': + os.mkdir('output') + except FileExistsError: + pass + if mode == 'encode': if drop_type == 'file' or drop_type == 'load': - p = pathlib.Path(file_path).name - directory = pathlib.Path(configurations['output_dir']) - with open(p+'.txt', 'w') as file: + p = pathlib.Path(file_path).name + path = str(directory.joinpath(p)) + with open(path + '.txt', 'w') as file: file.write(results) elif drop_type == 'text': - p = asksaveasbfilename(filetypes = (("Text files", "*.txt"), ("All files", "*.*"))) + p = asksaveasfilename(filetypes = (("Text files", "*.txt"), ("All files", "*.*"))) if p == '': return + print(p) + path = str(directory.joinpath(p)) with open(p, 'w') as file: file.write(results) elif mode == 'decode': @@ -226,7 +290,8 @@ def save_file(): if save_extension == None: return p = pathlib.Path(file_path).name - with open(p+save_extension, 'wb') as file: + path = str(directory.joinpath(p)) + with open(path+save_extension, 'wb') as file: file.write(results) elif drop_type == 'text': @@ -275,7 +340,7 @@ def load_text_clipboard(): write_to_temp() checked = False else: - insert(results[1:20000]) + insert(results[:20000]) statusbar_label.config(fg ='black') status_variable.set("Text too large to display all output.") write_to_temp() @@ -441,52 +506,72 @@ def get_file_type(filename): print("File type is ", file_type) if file_type == 'text/plain': save_extension = '.txt' + return file_type elif file_type == 'audio/mpeg': save_extension = '.mp3' + return file_type elif file_type == 'application/x-dosexec': save_extension = '.exe' + return file_type elif file_type == 'application/x-font-tff': save_extension = '.ttf' + return file_type elif file_type == 'image/png': save_extension = '.png' + return file_type elif file_type == 'image/gif': save_extension = '.gif' + return file_type elif file_type == 'application/octet-stream': save_extension = '.txt' + return file_type elif file_type == 'text/html': save_extension = '.html' + return file_type elif file_type == 'text/rtf': save_extension = '.rtf' + return file_type elif file_type == 'text/x-c++': save_extension = '.cpp' + return file_type elif file_type == 'text/x-python': save_extension = '.py' + return file_type elif file_type == 'text/x-msdos-batch': save_extension = '.bat' + return file_type elif file_type == 'text/x-php': save_extension = '.php' + return file_type elif file_type == 'application/zip': save_extension = '.zip' + return file_type elif file_type == 'application/x-gzip': save_extension = '.tar' + return file_type elif file_type == 'text/xml': save_extension = '.xml' + return file_type def write_to_temp(): global temp_file_name - #This function writes the data to a temporary file. - __, temp_file_name = tempfile.mkstemp() - if mode_variable.get() == 'encode': - with open(temp_file_name, 'w') as file: - file.write(results) - os.close(__) - temp_files.append(temp_file_name) - elif mode_variable.get() == 'decode': - with open(temp_file_name, 'wb') as file: - file.write(results) - os.close(__) - temp_files.append(temp_file_name) - get_file_type(temp_file_name) + try: + #This function writes the data to a temporary file. + __, temp_file_name = tempfile.mkstemp(dir = configurations['temp_dir']) + if mode_variable.get() == 'encode': + with open(temp_file_name, 'w') as file: + file.write(results) + os.close(__) + temp_files.append(temp_file_name) + elif mode_variable.get() == 'decode': + with open(temp_file_name, 'wb') as file: + file.write(results) + os.close(__) + temp_files.append(temp_file_name) + get_file_type(temp_file_name) + except FileNotFoundError: + os.mkdir(configurations['output']) + write_to_temp() def load_file(filename = None): #In auto-detect mode, if the filename == None, it means the file's mode @@ -573,6 +658,36 @@ def file_contents(file_path): with open(file_path, 'rb') as file: contents = file.read() return contents, 'binary' + +def copy_html(): + #Copy to clipboard for embeddding in HTML + path_suffix = str(pathlib.Path(file_path).suffix).lower() + if drop_type == 'file' or drop_type == 'load': + if path_suffix in PICTURES: + code = '"data:image/%s;base64,%s"' % (path_suffix[1:], results) + pyperclip.copy(code) + elif path_suffix in AUDIOS: + code = '"data:audio/%s;base64,%s"' % (path_suffix[1:], results) + pyperclip.copy(code) + elif path_suffix in VIDEOS: + code = '"data:video/%s;base64,%s"' % (path_suffix[1:], results) + pyperclip.copy(code) + + +def copy_css(): + #Copy to clipboard for embeddding in CSS + path_suffix = str(pathlib.Path(file_path).suffix).lower() + if drop_type == 'file' or drop_type == 'load': + if path_suffix in PICTURES: + code = 'url(data:image/%s;base64,%s)' % (path_suffix[1:], results) + pyperclip.copy(code) + elif path_suffix in AUDIOS: + code = 'url(data:audio/%s;base64,%s)' % (path_suffix[1:], results) + pyperclip.copy(code) + elif path_suffix in VIDEOS: + code = 'url(data:video/%s;base64,%s)' % (path_suffix[1:], results) + pyperclip.copy(code) + def drop_file(event): global drop_type global results @@ -668,7 +783,7 @@ def drop_text(event): insert(results) write_to_temp() else: - insert(results[1:20000]) + insert(results[:20000]) statusbar_label.config(fg ='black') status_variable.set("Text too large to display all output.") write_to_temp() @@ -684,7 +799,7 @@ def drop_text(event): write_to_temp() checked = False else: - insert(results[1:20000]) + insert(results[:20000]) statusbar_label.config(fg ='black') status_variable.set("Text too large to display all output.") write_to_temp() @@ -799,7 +914,7 @@ def sys_argv(): sys_argv() def init_configuration(): - # Note: + # This function is for starting and reading the configuration. global mode_variable global mode try: @@ -807,20 +922,25 @@ def init_configuration(): config.read('configuration.ini') mode = config['general'].get('default_mode') sys_argv_mode = config['general'].get('sys_argv_mode') + output_dir = config['paths'].get('output_dir') + temp_dir = config['paths'].get('temp_dir') #____________________________________________________________ configurations['default_mode'] = mode configurations['sys_argv_mode'] = sys_argv_mode + configurations['output_dir'] = output_dir + configurations['temp_dir'] = temp_dir if mode == 'detect': auto_detect_variable.set(1) mode_variable.set(mode) except: mode = 'encode' configurations['default_mode'] = mode + configurations['output_dir'] = 'output' configurations['sys_argv_mode'] = 1 + configurations['temp_dir'] = tempfile.gettempdir() mode_variable.set('encode') init_configuration() - #=========================================================== #Frames #=================================== @@ -849,14 +969,14 @@ def init_configuration(): text_frame.grid(row = 0, column = 1, sticky = E+W+N+S) controls_frame.grid(row = 1, column = 0, columnspan = 2, sticky = W+E+N) statusbar_frame.grid(row = 2, column = 0, sticky = W+E, columnspan = 2) -#======================================== +#================================================================== # Widgets mode_encode.grid(row = 0, column = 0, sticky = W) mode_auto_detect.grid(row = 0, column = 0) mode_decode.grid(row = 0, column = 2) text_area.grid(row = 0, column = 0, sticky = N+E+W+S) statusbar_label.grid(row = 0, column = 0) -#===================================== +#========================================================== # Making widgets stretchable root.grid_rowconfigure(0, weight = 1) root.grid_columnconfigure(0, weight = 1, minsize = 150) @@ -891,9 +1011,9 @@ def init_configuration(): #=========================================== sys_argv() root.mainloop() -#============================================================ +#========================================================================== #End -#============================================================ +#========================================================================== try: #This statement deletes all the temporary files created #by the application. @@ -912,5 +1032,9 @@ def init_configuration(): 'default_mode' : configurations['default_mode'], 'sys_argv_mode' : configurations['sys_argv_mode'], } +configuration['paths'] = { + 'output_dir' : configurations['output_dir'], + 'temp_dir' : configurations['temp_dir'] +} with open('configuration.ini', 'w') as file: configuration.write(file) diff --git a/gui/readme.txt b/gui/readme.txt index 786f1ed..4fc78c9 100644 --- a/gui/readme.txt +++ b/gui/readme.txt @@ -8,9 +8,92 @@ to base64 format and can decode base64 contents back to it's original format. It's cool auto-detecting feature allows you to encode and decode with ease. Just drop a file, it will detect the mode and perform the action. + +MODES +------- +Encode : This mode encodes an object into base64 format. +Decode : This function decodes an object from base64 format. +auto-detect : This function on it's own set the mode to encode if your file needs to be encoded. +It will also set the mode to decode if your file needs to be decoded. + HOW TO USE ------------- -1. Set a mode, either 'encode' or 'decode' -2. Drop a file onto the surface of the program. -3. You then recieve contents in the results panel. +------------- +1. Set a mode, +NB: If auto-detect is active, it will overide your default mode and choose a mode depending on the object. +2. Drag and drop a file onto the application's left pane, +the results will appear on the right side pane of the application. + +HOW TO SAVE +------------ +The application allows you to save either the encoded or the decoded contents. +After either encoding or decoding, right-click on the right side pane, a pop-up menu will apppear, +select save. + +NB: If you are saving a decoded file, the application automatically use the object's mime-type to +generate an extension for your file, meaning, you don't have to know the file type of the contents +you are decoding. +To overide this feature, select the option 'Save (Give ext.)', this options allows you yourself +to generate a filename with your prefered extension. + +SETTINGS +----------- + +General settings +.................. + +Default mode: This allows you to set the mode you want on application start. +This mode is very useful if you want to encode or decode a file without opening the application. +The best mode for this is 'auto-detect'. For instance, if the mode is on auto-detect, and your drop +a file on Quick Base64's exe, it will determine the mode and encode/decode. This way, the application +will start with the results, saving you a bunch of time. + +Drop file and work on application start? : This option allows you to disable the ability of a file being encoded or decoded when dropped on Quick Base64's exe while's it's closed. +If set to 'yes', when a file is dropped on Quick Base64's exe, a command will be executed, command being +either encode or decode. +If set to 'no', when a file is dropped on Quick Base64's exe, it will just open the application. + +Paths +.............. + +Output directory : This enables you to specify a directory where all encoded or decoded files will +be saved. + +Temporary file directory : This allows you to specify the temporary directory Quick Base64 will use. +Whenever you close Quick Base64, the temporary files are deleted, but on a case of an application crash, +these temporary files, wont be deleted, specifying the temporary folder is useful as it gives you control over the temporary files. + +Right-Click Context Menu on Right Panel. + 1. Save + This option saves the encoded/decoded contents to a file. + 2. Save (Give ext.) + This option allows you to determine the filename and extension of the file to be saved. + 3. Copy + Copies the raw decoded/encoded contents to clipboard. + 4. Copy (HTML) + Converts the encoded results into base64 format which you can embed in html. + For example, if you encode a file 'picture.png', this option will produce the following + results, "data:image/png;base64,base64code". + NB: The results is already wrapped in quotation marks so when coding it in HTML, + just write the tag to paste the results, + wrong : url(data:mime/type;base64, base64contents) + This command works for files which are images only. + + Right-Click Context Menu on Left Panel. + 1.Load file: + This option allows you to select a file using the windows file selector dialog. + 2. Clipboard (File): + This enables you to embed a file which you have copied to clipboard into the application. + NB: Quick Base64 is able to differentiate between text and files in clipboard. + 3. Clipboard (Text): + This allows you to embed text in your clipboard into the application. + + +============================================================================================ +Report bugs to support@eakloe.com or make an issue on github at github.com/biah/quickbase64 \ No newline at end of file