def load(self, *args, **kwargs): """Load a the serialized profiles for the current set of monitors""" dpg_core.log_info("Loading save profile") monitor_set_id = self.get_or_create_monitor_set_id() dpg_core.log_debug(f"Monitor set ID: {monitor_set_id}") serialized_profiles = self._saved_profiles.get(monitor_set_id) if not serialized_profiles: dpg_core.log_debug( f"No serialized profile for monitor set ID {monitor_set_id}") return dpg_core.log_debug( f"Found serialized profile for monitor set ID {monitor_set_id}") self.show_status("Load Successful!") for label in self._profiles: dpg_core.delete_item(label) self._profiles = {} self._tab_number = 1 for serialized_profile in serialized_profiles: profile = self.add_tab() # Ensure the plot width is accurate self.resize_callback(None, None) profile.load_dict(serialized_profile) self.resize_callback(None, None) dpg_core.log_info( f"Successfully loaded saved profile {monitor_set_id}")
def get_or_create_monitor_set_id(self): """Get or create a monitor set id We assign each unique set of monitors their own ID so we can save different profiles to each set. A layout on one set of monitors does not perfectly translate to a good layout on another set so we give each unique set of monitors an id and it's own saved profile. Returns ------- monitor_set_id : str UUID string for the monitor set """ monitor_sets = self._saved_profiles.get("monitor_sets", {}) current_monitor_ids = set(monitor.id for monitor in self._monitors) for monitor_set_id, monitor_ids in monitor_sets.items(): if set(monitor_ids) == current_monitor_ids: dpg_core.log_debug( f"Found existing monitor set: {monitor_set_id}") break else: monitor_set_id = str(uuid4()) monitor_sets[monitor_set_id] = list(current_monitor_ids) self._saved_profiles["monitor_sets"] = monitor_sets dpg_core.log_info(f"Create new monitor set: {monitor_set_id}") return monitor_set_id
def connect_device_usb() -> NoReturn: global device, device_is_connected, device_name, device_android_version, device_user if not os.path.exists(cfg.adb_key_file_path): keygen(cfg.adb_key_file_path) log_info(f"[ADB] generated and stored a new adb-RSA-key (was missing)", logger="debuglog") with open(cfg.adb_key_file_path) as f: priv = f.read() with open(cfg.adb_key_file_path + '.pub') as f: pub = f.read() signer = PythonRSASigner(pub, priv) try: device = AdbDeviceUsb( ) # TODO: there can be more than one phone, determine with "available", "list" or similar except UsbDeviceNotFoundError: device = None log_error( f"[ADB] is the device connected and ADB activated on device?", logger="debuglog") except DevicePathInvalidError: device = None log_error( "[ADB] installation seems incomplete, adb-shell[usb] is missing (or not working as intended) or adb-server is still running on your system", logger="debuglog") if device is not None: device.connect(rsa_keys=[signer], auth_timeout_s=30) if not is_device_available(): return device_is_connected = True log_info(f"[ADB] connected to USB-Device", logger="debuglog") update_device_properties()
def add_info_message(message: str): """Log message for info. Args: message (str): message to display """ core.log_info(message, logger='##log_message')
def __init__(self, port, baudrate, maxlen=100, log_window="", raw_log_window="") -> None: super().__init__() self.port = port self.baudrate = baudrate self.maxlen = maxlen self.log_window = log_window self.raw_log_window = raw_log_window self.data = { "plots": {}, "raw": deque([], maxlen=5000), "messages": deque([], maxlen=500), "errors": deque([], maxlen=500), "warnings": deque([], maxlen=500) } # self.buff = [] self.running = True log_info(f"Starting serial interface at {port} with baud {baudrate}", logger=self.log_window) self.ser = serial.Serial(port, baudrate) # opens the serial port log_info(f"serial interface started", logger=self.log_window) self.ser.flushInput() # clears the buffers to start clean self.serial_listener_thread = self.serial_listener( ) # starts the serial listener self.buf = bytearray()
def __init__(self, port, baudrate, maxlen=100, log_window="", raw_log_window="") -> None: super().__init__() self.port = port self.baudrate = baudrate self.maxlen = maxlen self.log_window = log_window self.raw_log_window = raw_log_window self.data = { "plots": {}, "raw": deque([], maxlen=5000), "messages": deque([], maxlen=500), "errors": deque([], maxlen=500), "warnings": deque([], maxlen=500) } self.buff = [] self.running = True log_info(f"Starting serial interface at {port} with baud {baudrate}", logger=self.log_window) self.serial_listener_thread = self.serial_listener() log_info(f"serial interface started", logger=self.log_window)
def input_callback(self, sender, data): """Callback when the input grids are changed""" dpg_core.log_info( f"Refreshing grid for monitor profile {self.monitor.name} as input changed" ) # First remove each line from the plot for xline in self._xlines: dpg_core.delete_drag_line(self._plot_id, xline) for yline in self._ylines: dpg_core.delete_drag_line(self._plot_id, yline) # Ensure that the values are greater than or equal to 1 rows, cols = dpg_core.get_value(self._input_id) rows = 1 if rows < 1 else rows cols = 1 if cols < 1 else cols dpg_core.set_value(self._input_id, [rows, cols]) # Add horizontal lines to the plot ylines = [] for row in range(1, rows): name = f"yline{row}-{self.id}" pos = int(self.monitor.work.top + (row / rows) * self.monitor.work.height) dpg_core.add_drag_line( self._plot_id, name, y_line=True, show_label=False, default_value=pos, callback=self.line_callback, ) ylines.append(name) # Add vertical lines to the plot xlines = [] for col in range(1, cols): name = f"xline{col}-{self.id}" pos = int(self.monitor.work.left + (col / cols) * self.monitor.work.width) dpg_core.add_drag_line( self._plot_id, name, y_line=False, show_label=False, default_value=pos, callback=self.line_callback, ) xlines.append(name) self._xlines = xlines self._ylines = ylines # Reset the labels and application table to reflect the new grids self.set_labels() self._app_table.clear() self._app_table.set_rows(rows * cols) dpg_core.log_info( f"Refreshed grid for monitor profile {self.monitor.name} as input changed" )
def disconnect_device() -> NoReturn: global device_is_connected, device, device_packages device.close() device = None device_packages = pd.DataFrame(columns=cfg.package_columns + cfg.debloat_columns) device_is_connected = False log_info(f"[ADB] disconnected from Device", logger="debuglog")
def push_device_package_list_backup(_local_file_path: str, _remote_file_path: str) -> bool: global device if not os.path.exists(_local_file_path) or not is_device_available(): return False device.push(_local_file_path, _remote_file_path) log_info(f"[ADB] pushed file to device ({_remote_file_path})", logger="debuglog") mode, size, mtime = device.stat(_remote_file_path) return size > 0
def load_dict(self, serialized_monitor_profile: dict[str, list[float]]) -> None: """Set the monitor profile from a serialized dictionary Parameters ---------- serialized_monitor_profile : dict[str, list[float]] Dictionary to load """ dpg_core.log_info(f"Loading monitor profile {self.id}") for xline in self._xlines: dpg_core.delete_drag_line(self._plot_id, xline) for yline in self._ylines: dpg_core.delete_drag_line(self._plot_id, yline) dpg_core.log_debug("Setting loaded ylines") ylines = [] for row, value in enumerate(serialized_monitor_profile["ylines"]): dpg_core.log_debug("Loading y lines") yline = int(value * self.monitor.work.height) name = f"yline{row}-{self.id}" dpg_core.add_drag_line( self._plot_id, name, y_line=True, show_label=False, default_value=yline, callback=self.line_callback, ) ylines.append(name) dpg_core.log_debug("Setting loaded xlines") xlines = [] for col, value in enumerate(serialized_monitor_profile["xlines"]): yline = int(value * self.monitor.work.width) name = f"xline{col}-{self.id}" dpg_core.add_drag_line( self._plot_id, name, y_line=False, show_label=False, default_value=yline, callback=self.line_callback, ) xlines.append(name) self._xlines = xlines self._ylines = ylines self.set_labels() rows, cols = (len(self._ylines) + 1), (len(self._xlines) + 1) dpg_core.set_value(self._input_id, [rows, cols]) self._app_table.set_rows(rows * cols) dpg_core.log_info(f"Loaded monitor profile {self.id}")
def git_update() -> NoReturn: uad_path = "/".join(cfg.debloater_list_path.split("/")[0:-1]) if not os.path.exists(uad_path): Repo.clone_from( "https://gitlab.com/W1nst0n/universal-android-debloater", uad_path) log_info(f"[GIT] cloned the repo 'universal android debloater'", logger="debuglog") else: repo = Repo(uad_path) repo.git.pull() log_info(f"[GIT] updated local repo of debloat-scripts", logger="debuglog")
def save(self, *args, **kwargs): """Save the current layout to the profiles file for the set of monitors""" dpg_core.log_info("Saving configuration") serialized_profiles = [ profile.to_dict() for profile in self._profiles.values() ] monitor_set_id = self.get_or_create_monitor_set_id() self._saved_profiles[monitor_set_id] = serialized_profiles with self.PROFILES_PATH.open("w") as stream: json.dump(self._saved_profiles, stream) dpg_core.log_info(f"Successfully saved configuration {monitor_set_id}") self.show_status("Save Successful!")
def load_dict(self, serialized_profile: dict[str, dict[str, list[float]]]): """Load a serialized profile Parameters ---------- serialized_profile : dict[str, dict[str, list[float]]] The serialized profile """ dpg_core.log_info(f"Loading profile {self.id}") for monitor_id, serialized_monitor_profile in serialized_profile.items( ): monitor_profile = self._monitor_profiles[monitor_id] monitor_profile.load_dict(serialized_monitor_profile) dpg_core.log_info(f"Loaded profile {self.id}")
def to_dict(self) -> dict[str, dict[str, list[float]]]: """Serialize profile to a dictionary Returns ------- serialized_profile : dict[str, dict[str, list[float]]] The serialized profile """ dpg_core.log_info(f"Serializing profile {self.id}") serialized_profile = {} for monitor_id, monitor_profile in self._monitor_profiles.items(): serialized_profile[monitor_id] = monitor_profile.to_dict() dpg_core.log_info(f"Serialized profile {self.id}") return serialized_profile
def pull_file_from_device(_remote_file_path: str, _local_file_path: str) -> int: global device if not is_device_available(): return 0 mode, size, mtime = device.stat(_remote_file_path) if size > 0: device.pull(_remote_file_path, _local_file_path) log_info( f"[ADB] pulled file '{_remote_file_path}' from device, size = {size} byte", logger="debuglog") else: log_error(f"[ADB] failed pulling file ({_remote_file_path})", logger="debuglog") return size
def snap(self, sender, data): """Snap each window to the selected grid""" dpg_core.log_info( f"Snapping windows in monitor profile {self.monitor.name}") for number, windows in self._app_table._grid_mapping.items(): if number not in self._rectangle_mapping: continue rect = self._rectangle_mapping[number] for name in windows: window = AppTable.ACTIVE_WINDOWS[name] dpg_core.log_debug(f"Snapping window {window}") move_window(window.handle, int(rect.left), int(rect.top), int(rect.width), int(rect.height)) dpg_core.log_info( f"Snapped windows in monitor profile {self.monitor.name}")
def start_development_windows(logger: str): """ Starts doc, debug, and logger window """ add_doc_window(name="Core Documentation", x_pos=0, y_pos=800) end() show_logger() # for some reason the default logger doesn't show the first # log_info call so this clears that out. log_info("Clearing out initial issue with logger", logger=logger) add_debug_window(name="Debug", x_pos=0, y_pos=300) end()
def window_crud_maintenance(sender, data): log_info(f'Function: CRUD Maintenance Window, {sender}, {data}') if does_item_exist(f'{data}##window'): log_info(f'Already exist {data}##window') pass else: if data == 'Key Values': table_headers = ['Key', 'Value', 'Comment'] elif data == 'Plex Shows': table_headers = ['Show Name', 'Show Id', 'Cleaned Show Name'] elif data == 'Plex Episodes': table_headers = [ 'Show Name', 'Season', 'Episode', 'Date Watched', 'TVM Updated', 'TVM Update Status' ] else: table_headers = ['Unknown'] with window(name=f'{data}##window', width=2130, height=650, x_pos=5, y_pos=45): add_input_text(name=f'{data}_input', no_spaces=True, multiline=False, decimal=False, label=data, width=200) add_same_line(spacing=10) add_button(name=f'Search##{data}', callback=func_crud_search, callback_data=data) if data == 'Key Values' or data == 'Plex Shows': add_same_line(spacing=10) add_button(name=f"Add New##{data}") add_same_line(spacing=10) add_button(name=f"Edit##{data}") if data == 'Key Values': add_same_line(spacing=10) add_button(name=f"Delete##{data}") add_same_line(spacing=10) add_button(name=f"Clear##{data}", callback=func_crud_clear, callback_data=f'Table##{data}') add_separator(name=f'##{data}SEP1') add_table(name=f'Table##{data}', headers=table_headers) add_separator(name=f'##{data}SEP1')
def update_package_data() -> NoReturn: global device_packages package_data1 = device_packages if ( len(device_packages) > 0) else restore_device_package_list() package_data1["via_adb"] = False package_data2 = read_package_data() package_data3 = pd.concat([package_data1, package_data2], ignore_index=True) package_data4 = package_data3.sort_values( by="via_adb", ascending=False).groupby("package").first().reset_index() device_packages = uad_fw.enrich_package_list(package_data4) log_info( f"[ADB] read package list (" f"{len(device_packages)} entries, " f"{len(device_packages[device_packages['via_adb'] == False])} via backup / not ADB)", logger="debuglog")
def remove_tab(self, *args, **kwargs): """Close a tab""" # Due to https://github.com/hoffstadt/DearPyGui/issues/429, when a tab is closed, we have to # search for the tab to remove the profile itself remove = set() for label in self._profiles: if dpg_core.is_item_shown(label): dpg_core.configure_item(label, closable=dpg_core.get_value(label)) else: dpg_core.delete_item(label) remove.add(label) self._profiles = { label: self._profiles[label] for label in self._profiles if label not in remove } dpg_core.log_info(f"Profiles {remove} successfully closed")
def func_crud_search(sender, data): db = mariaDB() log_info(f'Searching CRUD {sender}, {data}') key = get_value(f'{data}_input') if data == 'Key Values': sql = f"select * from key_values where `key` like '%{key}%' order by `key`" elif data == 'Plex Shows': sql = f"select * from TVMazeDB.plex_shows where showname like '%{key}%' " \ f"order by `showid`, 'cleaned_showname'" elif data == 'Plex Episodes': sql = f"select * from TVMazeDB.plex_episodes where showname like '%{key}%' " \ f"order by `showname`, 'season', `episode`" else: sql = f'Should not happen, sql is ""' result = db.execute_sql(sqltype='Fetch', sql=sql) func_fill_a_table(f'Table##{data}', result)
def set_rows(self, nrows): """ "Set the rows in the table Each row has two columns. The first column is the grid number. The second column is a list of applications to snap to the grid. We use a table to enable multiselect """ dpg_core.log_info(f"Refreshing rows for table {self.id}") for row in range(1, nrows + 1): name = f"{self._id}_{row}" # If the row already exists, we don't need to do anything else if dpg_core.does_item_exist(name): continue with dpg_simple.managed_columns(name, len(self.HEADER), parent=self.parent): # The first column is the grid number dpg_core.add_input_int( f"##{self._id}_{row}_number", default_value=row, readonly=True, step=0, parent=name, ) # The second column is the table. Wrap in a collapsing header so the screen isn't # too full the entire time. with dpg_simple.collapsing_header(f"##{self._id}_{row}_header", parent=name): dpg_core.add_table( f"{self._id}_{row}_table", [""], # no headers callback=self.selected, parent=f"##{self._id}_{row}_header", ) # populate the table with the names of available windows for window_name in sorted(self.ACTIVE_WINDOWS): dpg_core.add_row(f"{self._id}_{row}_table", [window_name]) # Separate each row with a line dpg_core.add_separator(name=f"{self._id}_{row}_sep", parent=name) self._nrows = nrows dpg_core.log_info(f"Refreshed rows for table {self.id}")
def add_tab(self, *args, **kwargs): """Add a profile tab""" dpg_core.log_debug("Adding profile tab...") label = f"{self._tab_number}##MainWindow-tab{self._tab_number}" with dpg_simple.tab(label, parent="##MainWindow-tabbar", closable=False, no_tooltip=True): profile = Profile(label, self._monitors) self._profiles[label] = profile self._tab_number += 1 # If we previously only had one tab then we need to make the first tab closable if len(self._profiles) == 2: label = list(self._profiles)[0] # get the label of the first tab dpg_core.configure_item(label, closable=dpg_core.get_value(label)) dpg_core.log_info(f"Profile {label} successfully added") return profile
def parse_point(self, s: str): t = time.time() t_str = time.strftime("%T", time.localtime(t)) s = s.strip() raw_str = f"{t_str}: {s}" if (self.raw_log_window != ""): log(raw_str, logger=self.raw_log_window) self.data["raw"].append(raw_str) if s[0] == "#": # parse as a number a = s.strip("#;") a = a.split(":") name = a[0] val = float(a[1]) if name in self.data["plots"]: if len(self.data["plots"][name]["x"]) >= self.maxlen: self.data["plots"][name]["x"].pop(0) self.data["plots"][name]["t"].pop(0) self.data["plots"][name]["x"].append(val) self.data["plots"][name]["t"].append(t) else: self.data["plots"][name] = { "x": (self.maxlen - 1) * [0.] + [val], "t": self.maxlen * [t] } elif s[0] == "!": # parse as error error_msg = f"{t_str}: {s.strip('!;')}" log_error(error_msg, logger=self.log_window) self.data["errors"].append(error_msg) elif s[0] == "?": # parse as warning warning_msg = f"{t_str}: {s.strip('?;')}" log_warning(warning_msg, logger=self.log_window) self.data["warnings"].append(warning_msg) else: info_msg = f"{t_str}: {s.strip(';')}" log_info(info_msg, logger=self.log_window) self.data["messages"].append(info_msg)
def example_two(): """ Commands to put into input """ with s.window("Hello World", autosize=True): c.add_text("Hello world!") c.show_logger() c.log_info("Foo") c.log_info("Check it out ma - no IDE!") with s.window("Canvas", x_pos=0, y_pos=300, autosize=True): c.add_drawing("Draw", width=300, height=300) c.draw_circle( "Draw", center=[150, 150], radius=50, color=[125, 125, 125], fill=[125, 125, 200], )
def to_dict(self) -> dict[str, list[float]]: """Serialize the monitor profile Returns ------- serialized_monitor_profile : dict[str, list[float]] Serialized monitor profile """ dpg_core.log_info(f"Serializing monitor profile: {self.id}") serialized_monitor_profile = { "xlines": sorted( dpg_core.get_value(xline) / self.monitor.work.width for xline in self._xlines), "ylines": sorted( dpg_core.get_value(yline) / self.monitor.work.height for yline in self._ylines), } dpg_core.log_info(f"Serialized monitor profile: {self.id}") return serialized_monitor_profile
def update_device_properties() -> int: global device, device_name, device_android_sdk, device_android_version, device_user if not is_device_available(): return 0 manufacturer = device.shell("getprop ro.product.manufacturer").strip( "\n\r") product_name = device.shell("getprop ro.product.device").strip("\n\r") device_name = manufacturer + " " + product_name device_android_version = device.shell( "getprop ro.build.version.release").strip("\n\r") device_android_sdk = int( device.shell("getprop ro.build.version.sdk").strip("\n\r")) log_info( f"[ADB] read device properties, '{device_name}', android {device_android_version}, sdk={device_android_sdk}", logger="debuglog") users = get_device_users() if len(users) > 1: log_info( "[ADB] NOTE - there are several users, will choose first one in list!", logger="debuglog") log_info(str(users), logger="debuglog") device_user = users["index"].iloc[0] if device_android_sdk < 26: log_error("[ADB] Your android version is old (< 8.0).", logger="debuglog") log_error("[ADB] Uninstalled packages can't be restored.", logger="debuglog") log_error("[ADB] The GUI won't stop you from doing so.", logger="debuglog") return device_android_sdk
def debug_get_window_pos(sender, data): """ Debug setup for getting location configs of windows """ log_info(sender, logger=data) window_name_to_search = get_value("Window Name##input") show_invisible = get_value("Print invisible") log_info(window_name_to_search, logger=data) log_info(show_invisible, logger=data) window_list = list() if window_name_to_search: log_debug(window_name_to_search, logger=data) for window_name in get_windows(): if window_name_to_search.lower() in window_name.lower(): window_list.append(window_name) else: window_list = get_windows() for window_name in window_list: config = get_item_configuration(window_name) if show_invisible is False: if config.get("show") is False: continue x_pos = config.get("x_pos", 0) y_pos = config.get("y_pos", 0) name = config.get("name") if len(name) > 6: name = name[:5] log_debug(f"{name} : {x_pos}, {y_pos}", logger=data)
def get_device_users() -> pd.DataFrame: global device user_columns = ["index", "name", "unknown"] if not is_device_available(): return pd.DataFrame(columns=user_columns) response = device.shell("pm list users") user_list = list([]) for line in response.splitlines(): if "UserInfo{" not in line: continue if "} running" not in line: continue start = line.find("{") + 1 end = line.find("}") user_list.append( pd.DataFrame([line[start:end].split(":")], columns=user_columns)) log_info(f"[ADB] read user list ({len(user_list)} entries)", logger="debuglog") if len(user_list) > 0: user_df = pd.concat(user_list, ignore_index=True).sort_values( by="index", ascending=True).reset_index(drop=True) else: user_df = pd.DataFrame(columns=user_columns) return user_df
def parse_debloat_lists(debug: bool = False) -> NoReturn: global debloat_data file_items = [ x for x in os.scandir(cfg.debloater_list_path) if x.is_file() ] # is List[os.DirEntry] package_list = list([]) for file in file_items: item_ext = file.name.split(".")[-1] if item_ext.find(cfg.debloater_list_extension) < 0: continue if debug: print(f"-> will parse '{file.name}'") with open(file, "r", encoding="utf8") as metafile: # TODO: encoding had to be specified, because of unusual characters in LG.sh, line 135 data = metafile.readlines() data = [ date.replace("\t", "").replace("\r", "").replace("\n", "") for date in data ] data_len = len(data) for data_index in range(data_len): # filter for lines with format: text1 "text2" text3 -> text2 is alphanum with .dot, without spaces or / fragments = data[data_index].split("\"") if (len(fragments) > 3) and debug: print( f"NOTE: filtered out '{fragments}', because of too many >>\"<< in '{file.name}'" ) if len(fragments) != 3: continue package_name = fragments[1] is_safe = fragments[0].find("#") < 0 if (package_name.find(".") < 0) or (package_name.find(" ") > 0) or (package_name.find("/") > 0): if debug: print( f"NOTE: filtered out '{package_name}' package -> invalid name-format in '{file.name}'" ) continue # determine start and end of description line_min = max(0, data_index - 6) for min_index in range(data_index - 1, line_min, -1): if len(data[min_index]) < 2: line_min = min_index + 1 break line_max = min(data_len - 1, data_index + 10) for max_index in range(data_index + 1, line_max, 1): if len(data[max_index]) < 2: line_max = max_index break data_row = [ package_name, True, is_safe, file.name, data_index, range(line_min, line_max), data[line_min:line_max] ] package_list.append( pd.DataFrame([data_row], columns=[cfg.package_columns[0]] + cfg.debloat_columns)) log_info(f"[UAD] parsed debloat lists ({len(package_list)} entries)", logger="debuglog") packages = pd.concat(package_list, ignore_index=True).sort_values(by="package", ascending=True) packages.loc[:, "duplicate"] = packages.duplicated(subset=["package"], keep=False) packages = packages.reset_index(drop=True) debloat_data = packages