# This file was generated by the Tkinter Designer by Parth Jadhav # https://github.com/ParthJadhav/Tkinter-Designer # And modified by Mizuki Zou # This was not made with quality in mind, but rather as a quick and dirty GUI. Keep this in mind while using it. from pathlib import Path from shutil import which import os import json import time import subprocess import threading # from tkinter import * # Explicit imports to satisfy Flake8 from tkinter import Tk, Canvas, Entry, Text, Button, PhotoImage, filedialog, messagebox, Listbox, LEFT, BOTH, Scrollbar, RIGHT, END, HORIZONTAL, Toplevel from tkinter.ttk import Progressbar from tkinter.filedialog import askopenfilename OUTPUT_PATH = Path(__file__).parent ASSETS_PATH = OUTPUT_PATH / Path(r".") config_path = "" target_path = "" windows_paths = ["C:\\Progam Files\\File Time Machine\\ftm.exe", "C:\\Program Files (x86)\\File Time Machine\\ftm.exe"] path_windows = "" if os.path.exists(windows_paths[0]): path_windows = windows_paths[0] elif os.path.exists(windows_paths[1]): path_windows = windows_paths[1] platform = os.name # nt for Windows, posix for Linux. def relative_to_assets(path: str) -> Path: return ASSETS_PATH / Path(path) def select_dir_or_file(dir: bool): # If dir, we know it is the target path. Otherwise, it is the config file global config_path, target_path, exists if not exists: messagebox.showerror("No binary", "FTM binary not found! You need to install it before using the gui.") return if dir: messagebox.showwarning("Warning!", "This software is NOT stable, and will probably result in data loss if you use it!") folder_selected = filedialog.askdirectory() target_path = folder_selected if folder_selected != "": print(folder_selected) window.title(folder_selected) if not os.path.isdir(folder_selected+"/.time"): if messagebox.askquestion('Config file','This folder is not currently being tracked, do you want to begin tracking it? A config folder will be created for you, and default settings will be applied. (No hashing, compression level 5, multithreading enabled)'): os.mkdir(folder_selected+"/.time") print("Starting to track "+folder_selected) if platform == "posix": config_path = folder_selected+"/.time/gui-config.json" else: config_path = folder_selected+"\\.time\\gui-config.json" config_file = open(config_path, 'w') print("Writing config to "+str(config_file)) config_file.write('''[ { "folder_path": "'''+folder_selected+'''", "get_hashes": false, "thread_count": 0, "brotli_compression_level": 5, "snapshot_mode": "fastest", "its_my_fault_if_i_lose_data": true } ]''') config_file.close() else: if not os.path.exists(folder_selected+"/.time/gui-config.json"): print(folder_selected+"/.time/gui-config.json") messagebox.showinfo("No config", "Could not find a config file, please specify one") else: config_path = folder_selected+"/.time/gui-config.json" get_snap_list() else: config_path = askopenfilename() print(config_path) def get_snap_list(): global listbox, target_path listbox.delete(0, END) print(target_path+'/.time/snapshots.json') if os.path.exists(target_path+'/.time/snapshots.json'): with open(target_path+'/.time/snapshots.json') as f: d = json.load(f) for i in range(len(d)): print(d[i]["date_created"]) listbox.insert(END, d[i]["date_created"]) else: messagebox.showinfo("No Snapshots", "Did not find any snapshots to list.") def create_snapshot(): global config_path if config_path == "": messagebox.showerror("Select folder", "You need to select a folder before you can create a snapshot!") return output = "" progress_window = Toplevel() progress_window.resizable(width=False, height=False) progress_window.title("Creating snapshot...") progress_window.geometry("300x100") # Create a progress bar in the new window progress = Progressbar(progress_window, orient=HORIZONTAL, length=280, mode='indeterminate') progress.pack(pady=20) if platform == "posix": print("Running command 'ftm -c "+config_path+"'") progress.start() p1 = subprocess.Popen(['ftm', '-c', config_path], stdout=subprocess.PIPE) else: print("Running command '"+path_windows+" -c "+config_path+"'") progress.start() p1 = subprocess.Popen([path_windows, '-c', config_path], stdout=subprocess.PIPE) # p1 = subprocess.Popen(['sleep', '3'], stdout=subprocess.PIPE) output = p1.communicate()[0] print(output) progress.stop() progress_window.destroy() if "No files changed" in str(output): messagebox.showwarning("No changed files", "There were no changed files, so I cannot take a snapshot!") get_snap_list() def restore_snapshot(): global listbox # print(listbox.curselection()[0]) selection = listbox.curselection()[0]+1 if listbox.curselection() == (): messagebox.showerror("No snapshot", "No snapshot is selected!") return progress_window = Toplevel() progress_window.resizable(width=False, height=False) progress_window.title("Restoring snapshot") progress_window.geometry("300x100") # Create a progress bar in the new window progress = Progressbar(progress_window, orient=HORIZONTAL, length=280, mode='indeterminate') progress.pack(pady=20) progress.start() print("Running 'ftm -c "+config_path+" restore --restore-index "+str(selection)+"'") p1 = subprocess.Popen( ['ftm', '-c', config_path, 'restore', '--restore-index', str(selection)], stdout=subprocess.PIPE) output = p1.communicate()[0] print(output) progress.stop() progress_window.destroy() if "Finished restoring" not in str(output): messagebox.showerror("Error", "There was an issue restoring a snapshot! Error: "+str(output)) window = Tk() window.geometry("443x428") window.configure(bg = "#313244") if platform == "posix": exists = which("ftm") else: exists = os.path.exists(path_windows) canvas = Canvas( window, bg = "#313244", height = 428, width = 443, bd = 0, highlightthickness = 0, relief = "ridge" ) canvas.place(x = 0, y = 0) canvas.create_text( 90.0, 19.0, anchor="nw", text="FTM-GUI", fill="#CDD6F4", font=("Jost Regular", 32 * -1) ) if exists: canvas.create_rectangle( 228.0, 20.0, 416.0, 70.0, fill="#A6E3A1", outline="") canvas.create_text( 260.0, 32.0, anchor="nw", text="Found ftm binary!", fill="#000000", font=("Jost Regular", 15 * -1) ) else: canvas.create_rectangle( 228.0, 20.0, 416.0, 70.0, fill="#e78284", outline="") canvas.create_text( 250.0, 32.0, anchor="nw", text="No ftm binary found!", fill="#000000", font=("Jost Regular", 15 * -1) ) listbox = Listbox(window, bg="#9399B2", selectmode='single') scrollbar = Scrollbar(window, bg="#9399B2") # Create scrollbox for list of snapshots listbox.place(x=29, y=154, width=387, height=209) # Listbox within the rectangle scrollbar.place(x=416, y=154, height=209) # Scrollbar on the right side of the Listbox # Attach the Listbox to the Scrollbar # for values in range(100): # listbox.insert(END, values) listbox.config(yscrollcommand=scrollbar.set) scrollbar.config(command=listbox.yview) canvas.create_rectangle( # Scrollbox rectangle 29.0, 154.0, 416.0, 363.0, fill="#9399B2", outline="") canvas.create_text( 29.0, 128.0, anchor="nw", text="Available snapshots", fill="#CDD6F4", font=("Jost Regular", 15 * -1) ) button_image_1 = PhotoImage( file=relative_to_assets("button_1.png")) button_1 = Button( image=button_image_1, borderwidth=0, highlightthickness=0, command=lambda: threading.Thread(target=restore_snapshot, daemon=True).start(), relief="flat" ) button_1.place( x=26.0, y=376.0, width=196.0, height=27.0 ) button_image_2 = PhotoImage( file=relative_to_assets("button_2.png")) button_2 = Button( image=button_image_2, borderwidth=0, highlightthickness=0, command=lambda: threading.Thread(target=create_snapshot, daemon=True).start(), relief="flat" ) button_2.place( x=225.0, y=376.0, width=194.0, height=26.0 ) button_image_3 = PhotoImage( file=relative_to_assets("button_3.png")) button_3 = Button( image=button_image_3, borderwidth=0, highlightthickness=0, command=lambda: select_dir_or_file(True), relief="flat" ) button_3.place( x=17.0, y=86.0, width=194.0, height=26.0 ) button_image_4 = PhotoImage( file=relative_to_assets("button_4.png")) button_4 = Button( image=button_image_4, borderwidth=0, highlightthickness=0, command=lambda: select_dir_or_file(False), relief="flat" ) button_4.place( x=225.0, y=86.0, width=194.0, height=26.0 ) image_image_1 = PhotoImage( file=relative_to_assets("image_1.png")) image_1 = canvas.create_image( 42.0, 42.0, image=image_image_1 ) window.resizable(False, False) window.mainloop()