import logging import os import platform import shutil import socket import string import subprocess from datetime import datetime logger = logging.getLogger() def launch_url(url): logger = logging.getLogger(__name__) if shutil.which('xdg-open'): opener = 'xdg-open' elif shutil.which('open'): opener = 'open' elif shutil.which('cmd'): opener = 'start' else: error_message = f"No valid launchers found to launch URL: {url}" logger.error(error_message) raise OSError(error_message) try: if opener == 'start': # For Windows, use 'cmd /c start' subprocess.run(['cmd', '/c', 'start', url], shell=False) else: subprocess.run([opener, url]) except Exception as e: logger.error(f"Failed to launch URL: {url}. Error: {e}") def file_exists_in_mounts(filepath): """ Check if a file exists in any mounted directory. It searches for the file in common mount points like '/Volumes', '/mnt', and '/media'. Returns the path to the file in the mount if found, otherwise returns None. Example: Before: filepath = '/path/to/file.txt' After: '/Volumes/ExternalDrive/path/to/file.txt' """ def get_path_components(path): path = os.path.normpath(path) components = [] while True: path, comp = os.path.split(path) if comp: components.append(comp) else: if path: components.append(path) break components.reverse() return components # Get path components of the directory of the file path_components = get_path_components(os.path.dirname(filepath).strip('/')) # Iterate over possible root paths - this may need to be rethought for Windows support for root in ['/Volumes', '/mnt', '/media']: if os.path.exists(root): # Iterate over mounts in the root path for mount in os.listdir(root): # Since we don't know the home directory, we iterate until we find matching parts of the path matching_components = [s for s in path_components if s in mount] for component in matching_components: possible_mount_path = os.path.join(root, mount, filepath.split(component)[-1].lstrip('/')) if os.path.exists(possible_mount_path): return possible_mount_path def get_time_elapsed(start_time=None, end_time=None): def strfdelta(tdelta, fmt='%H:%M:%S'): days = tdelta.days hours, rem = divmod(tdelta.seconds, 3600) minutes, seconds = divmod(rem, 60) # Using f-strings for formatting formatted_str = fmt.replace('%D', f'{days}') formatted_str = formatted_str.replace('%H', f'{hours:02d}') formatted_str = formatted_str.replace('%M', f'{minutes:02d}') formatted_str = formatted_str.replace('%S', f'{seconds:02d}') return formatted_str # calculate elapsed time elapsed_time = None if start_time: if end_time: elapsed_time = end_time - start_time else: elapsed_time = datetime.now() - start_time elapsed_time_string = strfdelta(elapsed_time) if elapsed_time else None return elapsed_time_string def get_file_size_human(file_path): size_in_bytes = os.path.getsize(file_path) # Convert size to a human-readable format if size_in_bytes < 1024: return f"{size_in_bytes} B" elif size_in_bytes < 1024 ** 2: return f"{size_in_bytes / 1024:.2f} KB" elif size_in_bytes < 1024 ** 3: return f"{size_in_bytes / 1024 ** 2:.2f} MB" elif size_in_bytes < 1024 ** 4: return f"{size_in_bytes / 1024 ** 3:.2f} GB" else: return f"{size_in_bytes / 1024 ** 4:.2f} TB" # Convert path to the appropriate format for the current platform def system_safe_path(path): if platform.system().lower() == "windows": return os.path.normpath(path) return path.replace("\\", "/") def current_system_os(): return platform.system().lower().replace('darwin', 'macos') def current_system_os_version(): return platform.mac_ver()[0] if current_system_os() == 'macos' else platform.release().lower() def current_system_cpu(): # convert all x86 64 to "x64" return platform.machine().lower().replace('amd64', 'x64').replace('x86_64', 'x64') def resources_dir(): resource_environment_path = os.environ.get('RESOURCEPATH', None) if resource_environment_path: # running inside resource bundle return os.path.join(resource_environment_path, 'resources') else: return os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'resources') def copy_directory_contents(src_dir, dst_dir): """ Copy the contents of the source directory (src_dir) to the destination directory (dst_dir). """ for item in os.listdir(src_dir): src_path = os.path.join(src_dir, item) dst_path = os.path.join(dst_dir, item) if os.path.isdir(src_path): shutil.copytree(src_path, dst_path, dirs_exist_ok=True) else: shutil.copy2(src_path, dst_path) def is_localhost(comparison_hostname): # this is necessary because socket.gethostname() does not always include '.local' - This is a sanitized comparison try: comparison_hostname = comparison_hostname.lower().replace('.local', '') local_hostname = socket.gethostname().lower().replace('.local', '') return comparison_hostname == local_hostname except AttributeError: return False def num_to_alphanumeric(num): # List of possible alphanumeric characters characters = string.ascii_letters + string.digits # Make sure number is positive num = abs(num) # Convert number to alphanumeric result = "" while num > 0: num, remainder = divmod(num, len(characters)) result += characters[remainder] return result[::-1] # Reverse the result to get the correct alphanumeric string