def get_hardware_flags_x86_64(self): gpu_props = {} gpu_driver = "" gpu_card = self.get_gpu_card() oe.dbg_log('updates::get_hardware_flags_x86_64', f'Using card: {gpu_card}', oe.LOGDEBUG) gpu_path = oe.execute( f'/usr/bin/udevadm info --name=/dev/dri/{gpu_card} --query path 2>/dev/null', get_result=1).replace('\n', '') oe.dbg_log('updates::get_hardware_flags_x86_64', f'gpu path: {gpu_path}', oe.LOGDEBUG) if gpu_path: drv_path = os.path.dirname(os.path.dirname(gpu_path)) props = oe.execute( f'/usr/bin/udevadm info --path={drv_path} --query=property 2>/dev/null', get_result=1) if props: for key, value in [ x.strip().split('=') for x in props.strip().split('\n') ]: gpu_props[key] = value oe.dbg_log('updates::get_gpu_type', f'gpu props: {gpu_props}', oe.LOGDEBUG) gpu_driver = gpu_props.get("DRIVER", "") if not gpu_driver: gpu_driver = oe.execute( 'lspci -k | grep -m1 -A999 "VGA compatible controller" | grep -m1 "Kernel driver in use" | cut -d" " -f5', get_result=1).replace('\n', '') if gpu_driver == 'nvidia' and os.path.realpath( '/var/lib/nvidia_drv.so').endswith('nvidia-legacy_drv.so'): gpu_driver = 'nvidia-legacy' oe.dbg_log('updates::get_hardware_flags_x86_64', f'gpu driver: {gpu_driver}', oe.LOGDEBUG) return gpu_driver if gpu_driver else "unknown"
def do_sshpasswd(self, **kwargs): SSHchange = False newpwd = xbmcDialog.input(oe._(746)) if newpwd: if newpwd == "libreelec": oe.execute('cp -fp /usr/cache/shadow /storage/.cache/shadow') readout3 = "Retype password" else: ssh = subprocess.Popen(["passwd"], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=0) readout1 = ssh.stdout.readline() ssh.stdin.write(f'{newpwd}\n') readout2 = ssh.stdout.readline() ssh.stdin.write(f'{newpwd}\n') readout3 = ssh.stdout.readline() if "Bad password" in readout3: xbmcDialog.ok(oe._(32220), oe._(32221)) log.log('Password too weak') return elif "Retype password" in readout3: xbmcDialog.ok(oe._(32222), oe._(32223)) SSHchange = True else: xbmcDialog.ok(oe._(32224), oe._(32225)) else: log.log('User cancelled') return SSHchange
def start(self): oe.notify('OpenVPN', 'Establishing Connection', icon='eth') oe.execute( '/storage/.kodi/addons/service.network.openvpn/bin/openvpn --daemon --writepid /var/run/openvpn.pid --log /var/log/openvpn.log --config ' + self.get_config_file() + ' ' + self.get_custom_options()) time.sleep(3) if self.status(): oe.notify('OpenVPN', 'Connection Established', icon='eth')
def __init__(self, *args, **kwargs): ############################# # Temp cleanup for old method restart_docker = False if os.path.islink( '/storage/.config/system.d/service.system.docker.socket'): os.remove('/storage/.config/system.d/service.system.docker.socket') if os.path.islink('/storage/.config/system.d/docker.socket'): os.remove('/storage/.config/system.d/docker.socket') if os.path.islink( '/storage/.config/system.d/service.system.docker.service'): if 'systemd' in os.readlink( '/storage/.config/system.d/service.system.docker.service'): os.remove( '/storage/.config/system.d/service.system.docker.service') restart_docker = True if os.path.islink('/storage/.config/system.d/docker.service'): if 'systemd' in os.readlink( '/storage/.config/system.d/docker.service'): os.remove('/storage/.config/system.d/docker.service') restart_docker = True if os.path.islink( '/storage/.config/system.d/multi-user.target.wants/service.system.docker.service' ): if 'systemd' in os.readlink( '/storage/.config/system.d/multi-user.target.wants/service.system.docker.service' ): os.remove( '/storage/.config/system.d/multi-user.target.wants/service.system.docker.service' ) restart_docker = True if restart_docker: oe.execute( 'systemctl enable /storage/.kodi/addons/service.system.docker/system.d/service.system.docker.service' ) oe.execute( 'systemctl restart /storage/.kodi/addons/service.system.docker/system.d/service.system.docker.service' ) # end temp cleanup ############################# monitor = DockerMonitor(self) while not monitor.abortRequested(): if monitor.waitForAbort(): # we don't want to stop or disable docker while it's installed pass
def install_widevine(): try: download() oe.notify('Chromium', 'Extracting libwidevinecdm.so') if not os.path.isdir(__tmp__ + __tar__): oe.execute('cd ' + __tmp__ + ' && ar -x ' + __file__) oe.execute('tar xf ' + __tmp__ + __tar__ + ' -C ' + __tmp__ + ' ./' + __lib__) oe.copy_file(__tmp__ + __lib__, __path__ + __lib__.split('/')[-1]) oe.notify('Chromium', 'Installation of libwidevinecdm.so succeeded') except Exception, e: oe.notify('Chromium', 'Installation of libwidevinecdm.so failed')
def install_flash(): try: download() oe.notify('Chromium', 'Extracting libpepflashplayer.so') if not os.path.isdir(__tmp__ + __tar__): oe.execute('cd ' + __tmp__ + ' && ar -x ' + __file__) oe.execute('tar xf ' + __tmp__ + __tar__ + ' -C ' + __tmp__ + ' ./' + __flash__) if not os.path.isdir(__path__ + 'PepperFlash'): os.mkdir(__path__ + 'PepperFlash') oe.copy_file(__tmp__ + __flash__, __path__ + 'PepperFlash/' + __flash__.split('/')[-1]) oe.notify('Chromium', 'Installation of libpepflashplayer.so succeeded') except Exception, e: oe.notify('Chromium', 'Installation of libpepflashplayer.so failed')
def startChromium(args): oe.execute('chmod +x ' + __path__ + 'chromium') oe.execute('chmod +x ' + __path__ + 'chromium.bin') oe.execute('chmod 4755 ' + __path__ + 'chrome-sandbox') try: window_mode = { 'maximized': '--start-maximized', 'kiosk': '--kiosk', 'none': '', } gpu_blacklist = '' if __addon__.getSetting('IGNORE_GPU_BLACKLIST') == 'true': gpu_blacklist = '--ignore-gpu-blacklist' if (__addon__.getSetting('USE_CUST_AUDIODEVICE') == 'true'): alsa_device = __addon__.getSetting('CUST_AUDIODEVICE_STR') else: alsa_device = getAudioDevice() alsa_param = '' if not alsa_device == None and not alsa_device == '': alsa_param = '--alsa-output-device=' + alsa_device chrome_params = window_mode.get(__addon__.getSetting('WINDOW_MODE')) + ' ' + gpu_blacklist + ' ' + alsa_param + ' ' + args + ' ' + __addon__.getSetting('HOMEPAGE') oe.execute(__path__ + 'chromium ' + chrome_params) except: pass
def get_hardware_flags_dtflag(self): if os.path.exists('/usr/bin/dtflag'): dtflag = oe.execute('/usr/bin/dtflag', get_result=1).rstrip('\x00\n') else: dtflag = "unknown" oe.dbg_log('system::get_hardware_flags_dtflag', f'ARM board: {dtflag}', oe.LOGDEBUG) return dtflag
def ipinfo(self): ipinfo = ast.literal_eval( oe.execute('curl ipinfo.io 2> /dev/null', get_result=1).replace('\n', '')) dialog = xbmcgui.Dialog() dialog.ok('OpenVPN', "IP : " + ipinfo['ip'], 'Country : ' + ipinfo['country'], 'City : ' + ipinfo['city'])
def get_rpi_flashing_state(self): try: oe.dbg_log('updates::get_rpi_flashing_state', 'enter_function', oe.LOGDEBUG) jdata = { 'EXITCODE': 'EXIT_FAILED', 'BOOTLOADER_CURRENT': 0, 'BOOTLOADER_LATEST': 0, 'VL805_CURRENT': '', 'VL805_LATEST': '' } state = { 'incompatible': True, 'bootloader': {'state': '', 'current': 'unknown', 'latest': 'unknown'}, 'vl805': {'state': '', 'current': 'unknown', 'latest': 'unknown'} } with tempfile.NamedTemporaryFile(mode='r', delete=True) as machine_out: console_output = oe.execute(f'/usr/bin/.rpi-eeprom-update.real -j -m "{machine_out.name}"', get_result=1).split('\n') if os.path.getsize(machine_out.name) != 0: state['incompatible'] = False jdata = json.load(machine_out) oe.dbg_log('updates::get_rpi_flashing_state', f'console output: {console_output}', oe.LOGDEBUG) oe.dbg_log('updates::get_rpi_flashing_state', f'json values: {jdata}', oe.LOGDEBUG) if jdata['BOOTLOADER_CURRENT'] != 0: state['bootloader']['current'] = datetime.datetime.utcfromtimestamp(jdata['BOOTLOADER_CURRENT']).strftime('%Y-%m-%d') if jdata['BOOTLOADER_LATEST'] != 0: state['bootloader']['latest'] = datetime.datetime.utcfromtimestamp(jdata['BOOTLOADER_LATEST']).strftime('%Y-%m-%d') if jdata['VL805_CURRENT']: state['vl805']['current'] = jdata['VL805_CURRENT'] if jdata['VL805_LATEST']: state['vl805']['latest'] = jdata['VL805_LATEST'] if jdata['EXITCODE'] in ['EXIT_SUCCESS', 'EXIT_UPDATE_REQUIRED']: if jdata['BOOTLOADER_LATEST'] > jdata['BOOTLOADER_CURRENT']: state['bootloader']['state'] = oe._(32028) % (state['bootloader']['current'], state['bootloader']['latest']) else: state['bootloader']['state'] = oe._(32029) % state['bootloader']['current'] if jdata['VL805_LATEST'] and jdata['VL805_LATEST'] > jdata['VL805_CURRENT']: state['vl805']['state'] = oe._(32028) % (state['vl805']['current'], state['vl805']['latest']) else: state['vl805']['state'] = oe._(32029) % state['vl805']['current'] oe.dbg_log('updates::get_rpi_flashing_state', f'state: {state}', oe.LOGDEBUG) oe.dbg_log('updates::get_rpi_flashing_state', 'exit_function', oe.LOGDEBUG) return state except Exception as e: oe.dbg_log('updates::get_rpi_flashing_state', f'ERROR: ({repr(e)})') return {'incompatible': True}
def __init__(self, *args, **kwargs): ############################# # Temp cleanup for old method restart_docker = False if os.path.islink('/storage/.config/system.d/service.system.docker.socket'): os.remove('/storage/.config/system.d/service.system.docker.socket') if os.path.islink('/storage/.config/system.d/docker.socket'): os.remove('/storage/.config/system.d/docker.socket') if os.path.islink('/storage/.config/system.d/service.system.docker.service'): if 'systemd' in os.readlink('/storage/.config/system.d/service.system.docker.service'): os.remove('/storage/.config/system.d/service.system.docker.service') restart_docker = True if os.path.islink('/storage/.config/system.d/docker.service'): if 'systemd' in os.readlink('/storage/.config/system.d/docker.service'): os.remove('/storage/.config/system.d/docker.service') restart_docker = True if os.path.islink('/storage/.config/system.d/multi-user.target.wants/service.system.docker.service'): if 'systemd' in os.readlink('/storage/.config/system.d/multi-user.target.wants/service.system.docker.service'): os.remove('/storage/.config/system.d/multi-user.target.wants/service.system.docker.service') restart_docker = True if restart_docker: oe.execute('systemctl enable /storage/.kodi/addons/service.system.docker/system.d/service.system.docker.service') oe.execute('systemctl restart /storage/.kodi/addons/service.system.docker/system.d/service.system.docker.service') # end temp cleanup ############################# monitor = DockerMonitor(self) while not monitor.abortRequested(): if monitor.waitForAbort(): # we don't want to stop or disable docker while it's installed pass
def install_flash(): __url__ = 'https://fpdownload.adobe.com/pub/flashplayer/pdc/24.0.0.186/flash_player_ppapi_linux.x86_64.tar.gz' __file__ = __url__.split('/')[-1] __tmp__ = '/tmp/pepperflash/' __lib__ = 'libpepflashplayer.so' try: if not os.path.isdir(__tmp__): os.mkdir(__tmp__) if not os.path.exists(__tmp__ + __file__): oe.download_file(__url__, __tmp__ + __file__) if not os.path.exists(__tmp__ + __file__): oe.notify('Chromium', 'Could not download file') else: oe.notify('Chromium', 'Extracting libpepflashplayer.so') if not os.path.isdir(__tmp__ + __file__): oe.execute('tar zxf ' + __tmp__ + __file__ + ' -C ' + __tmp__ + '') if not os.path.isdir(__path__ + 'PepperFlash'): os.mkdir(__path__ + 'PepperFlash') oe.copy_file(__tmp__ + __lib__, __path__ + 'PepperFlash/' + __lib__) oe.notify('Chromium', 'Installation of libpepflashplayer.so succeeded') except Exception, e: oe.notify('Chromium', 'Installation of libpepflashplayer.so failed')
def install_widevine(): __url__ = 'https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb' __file__ = __url__.split('/')[-1] __tar__ = 'data.tar.xz' __tmp__ = '/tmp/widevine/' __lib__ = 'opt/google/chrome/libwidevinecdm.so' try: if not os.path.isdir(__tmp__): os.mkdir(__tmp__) if not os.path.exists(__tmp__ + __file__): oe.download_file(__url__, __tmp__ + __file__) if not os.path.exists(__tmp__ + __file__): oe.notify('Chromium', 'Could not download file') else: oe.notify('Chromium', 'Extracting libwidevinecdm.so') if not os.path.isdir(__tmp__ + __tar__): oe.execute('cd ' + __tmp__ + ' && ar -x ' + __file__) oe.execute('tar xf ' + __tmp__ + __tar__ + ' -C ' + __tmp__ + ' ./' + __lib__) oe.copy_file(__tmp__ + __lib__, __path__ + __lib__.split('/')[-1]) oe.notify('Chromium', 'Installation of libwidevinecdm.so succeeded') except Exception, e: oe.notify('Chromium', 'Installation of libwidevinecdm.so failed')
def do_send_logs(self, log_cmd): paste_dlg = xbmcgui.DialogProgress() paste_dlg.create('Pasting log files', 'Pasting...') result = oe.execute(log_cmd, get_result=1) if not paste_dlg.iscanceled(): paste_dlg.close() link = result.find('http') if link != -1: log.log(result[link:], log.WARNING) xbmcDialog.ok('Paste complete', f'Log files pasted to {result[link:]}') else: xbmcDialog.ok('Failed paste', 'Failed to paste log files, try again')
def startChromium(args): oe.execute('chmod +x ' + __path__ + 'chromium') oe.execute('chmod +x ' + __path__ + 'chromium.bin') oe.execute('chmod 4755 ' + __path__ + 'chrome-sandbox') try: window_mode = { 'maximized': '--start-maximized', 'kiosk': '--kiosk', 'none': '', } raster_mode = { 'default': '', 'off': '--disable-accelerated-2d-canvas --disable-gpu-compositing', 'force': '--enable-gpu-rasterization --enable-accelerated-2d-canvas --ignore-gpu-blacklist', } new_env = os.environ.copy() vaapi_mode = __addon__.getSetting('VAAPI_MODE') gpu_accel_mode = '' if vaapi_mode == 'intel': new_env['LIBVA_DRIVERS_PATH'] = '/usr/lib/va' new_env['LIBVA_DRIVER_NAME'] = 'i965' elif vaapi_mode == 'amd': new_env['LIBVA_DRIVERS_PATH'] = os.path.join(__addon__.getAddonInfo('path'), 'lib') new_env['LIBVA_DRIVER_NAME'] = 'vdpau' elif vaapi_mode == 'nvidia': new_env['LIBVA_DRIVERS_PATH'] = os.path.join(__addon__.getAddonInfo('path'), 'lib') new_env['LIBVA_DRIVER_NAME'] = 'vdpau' gpu_accel_mode = '--allow-no-sandbox-job --disable-gpu-sandbox' else: new_env['LIBGL_ALWAYS_SOFTWARE'] = '1' flash_plugin = '' if os.path.exists(__path__ + 'PepperFlash/libpepflashplayer.so'): flash_plugin = '--ppapi-flash-path=' + __path__ + 'PepperFlash/libpepflashplayer.so' if __addon__.getSetting('USE_CUST_AUDIODEVICE') == 'true': alsa_device = __addon__.getSetting('CUST_AUDIODEVICE_STR') else: alsa_device = getAudioDevice() alsa_param = '' if not alsa_device == None and not alsa_device == '': alsa_param = '--alsa-output-device=' + alsa_device chrome_params = window_mode.get(__addon__.getSetting('WINDOW_MODE')) + ' ' + \ raster_mode.get(__addon__.getSetting('RASTER_MODE')) + ' ' + \ flash_plugin + ' ' + \ gpu_accel_mode + ' ' + \ alsa_param + ' ' + \ args + ' ' + \ __addon__.getSetting('HOMEPAGE') subprocess.call(__path__ + 'chromium ' + chrome_params, shell=True, env=new_env) except Exception, e: oe.dbg_log('chromium', unicode(e))
def do_restore(self, listItem=None): copy_success = 0 restore_file_path = xbmcDialog.browse(1, oe._(32373), 'files', '??????????????.tar', False, False, self.BACKUP_DESTINATION) # Do nothing if the dialog is cancelled - path will be the backup destination if not os.path.isfile(restore_file_path): return log.log(f'Restore file: {restore_file_path}', log.INFO) restore_file_name = restore_file_path.split('/')[-1] if os.path.exists(self.RESTORE_DIR): oe.execute(f'rm -rf {self.RESTORE_DIR}') os.makedirs(self.RESTORE_DIR) folder_stat = os.statvfs(self.RESTORE_DIR) file_size = os.path.getsize(restore_file_path) free_space = folder_stat.f_frsize * folder_stat.f_bavail if free_space > file_size * 2: if os.path.exists(self.RESTORE_DIR + restore_file_name): os.remove(self.RESTORE_DIR + restore_file_name) if oe.copy_file(restore_file_path, self.RESTORE_DIR + restore_file_name) != None: copy_success = 1 log.log('Restore file successfully copied.', log.INFO) else: log.log(f'Failed to copy restore file to: {self.RESTORE_DIR}', log.ERROR) oe.execute(f'rm -rf {self.RESTORE_DIR}') else: txt = oe.split_dialog_text(oe._(32379)) answer = xbmcDialog.ok('Restore', f'{txt[0]}\n{txt[1]}\n{txt[2]}') if copy_success == 1: txt = oe.split_dialog_text(oe._(32380)) answer = xbmcDialog.yesno('Restore', f'{txt[0]}\n{txt[1]}\n{txt[2]}') if answer == 1: if oe.reboot_counter(10, oe._(32371)) == 1: oe.winOeMain.close() oe.xbmcm.waitForAbort(1) subprocess.call( ['/usr/bin/systemctl', '--no-block', 'reboot'], close_fds=True) else: log.log('User Abort!') oe.execute(f'rm -rf {self.RESTORE_DIR}')
def do_restore(self, listItem=None): copy_success = 0 restore_file_path = xbmcDialog.browse(1, oe._(32373), 'files', '??????????????.tar', False, False, self.BACKUP_DESTINATION) # Do nothing if the dialog is cancelled - path will be the backup destination if not os.path.isfile(restore_file_path): return restore_file_name = restore_file_path.split('/')[-1] if os.path.exists(self.RESTORE_DIR): oe.execute('rm -rf %s' % self.RESTORE_DIR) os.makedirs(self.RESTORE_DIR) folder_stat = os.statvfs(self.RESTORE_DIR) file_size = os.path.getsize(restore_file_path) free_space = folder_stat.f_frsize * folder_stat.f_bavail if free_space > file_size * 2: if os.path.exists(self.RESTORE_DIR + restore_file_name): os.remove(self.RESTORE_DIR + restore_file_name) if oe.copy_file(restore_file_path, self.RESTORE_DIR + restore_file_name) != None: copy_success = 1 else: oe.execute(f'rm -rf {self.RESTORE_DIR}') else: txt = oe.split_dialog_text(oe._(32379)) answer = xbmcDialog.ok('Restore', f'{txt[0]}\n{txt[1]}\n{txt[2]}') if copy_success == 1: txt = oe.split_dialog_text(oe._(32380)) answer = xbmcDialog.yesno('Restore', f'{txt[0]}\n{txt[1]}\n{txt[2]}') if answer == 1: if oe.reboot_counter(10, oe._(32371)) == 1: oe.winOeMain.close() oe.xbmcm.waitForAbort(1) xbmc.executebuiltin('Reboot') else: log.log('User Abort!') oe.execute(f'rm -rf {self.RESTORE_DIR}')
def execute(self, command_line, get_result=0): result = oe.execute(command_line, get_result=get_result) if get_result: return result
def status(self): status = oe.execute('pgrep openvpn', get_result=1) if status is not '': return 1 else: return 0
def stop(self): oe.notify('OpenVPN', 'Stopping Connection', icon='eth') oe.execute('pkill openvpn') time.sleep(3) if not self.status(): oe.notify('OpenVPN', 'Connection Stopped', icon='eth')
def start(self): oe.notify('OpenVPN', 'Establishing Connection', icon='eth') oe.execute('/storage/.kodi/addons/service.network.openvpn/bin/openvpn --daemon --writepid /var/run/openvpn.pid --log /var/log/openvpn.log --config ' + self.get_config_file() + ' ' + self.get_custom_options()) time.sleep(3) if self.status(): oe.notify('OpenVPN', 'Connection Established', icon='eth')
def ipinfo(self): ipinfo = ast.literal_eval(oe.execute('curl ipinfo.io 2> /dev/null', get_result=1).replace('\n','')) dialog = xbmcgui.Dialog() dialog.ok('OpenVPN', "IP : " + ipinfo['ip'], 'Country : ' + ipinfo['country'], 'City : ' + ipinfo['city'])
def set_hw_clock(self): oe.execute(f'{self.SET_CLOCK_CMD} 2>/dev/null')
def set_keyboard_layout(self, listItem=None): if not listItem == None: if listItem.getProperty('entry') == 'KeyboardLayout1': if self.struct['keyboard']['settings']['KeyboardLayout1'][ 'value'] != listItem.getProperty('value'): self.struct['keyboard']['settings']['KeyboardVariant1'][ 'value'] = '' if listItem.getProperty('entry') == 'KeyboardLayout2': if self.struct['keyboard']['settings']['KeyboardLayout2'][ 'value'] != listItem.getProperty('value'): self.struct['keyboard']['settings']['KeyboardVariant2'][ 'value'] = '' self.set_value(listItem) if self.keyboard_layouts == True: self.struct['keyboard']['settings']['KeyboardVariant1'][ 'values'] = self.arrVariants[self.struct['keyboard'][ 'settings']['KeyboardLayout1']['value']] self.struct['keyboard']['settings']['KeyboardVariant2'][ 'values'] = self.arrVariants[self.struct['keyboard'][ 'settings']['KeyboardLayout2']['value']] log.log( str(self.struct['keyboard']['settings']['KeyboardLayout1'] ['value']) + ',' + str(self.struct['keyboard']['settings'] ['KeyboardLayout2']['value']) + ' ' + '-model ' + str(self.struct['keyboard']['settings'] ['KeyboardType']['value']), log.INFO) if not os.path.exists(os.path.dirname(self.UDEV_KEYBOARD_INFO)): os.makedirs(os.path.dirname(self.UDEV_KEYBOARD_INFO)) config_file = open(self.UDEV_KEYBOARD_INFO, 'w') config_file.write( f"XKBMODEL=\"{self.struct['keyboard']['settings']['KeyboardType']['value']}\"\n" ) config_file.write( f"XKBVARIANT=\"{self.struct['keyboard']['settings']['KeyboardVariant1']['value']}, \ {self.struct['keyboard']['settings']['KeyboardVariant2']['value']}\"\n" ) config_file.write( f"XKBLAYOUT=\"{self.struct['keyboard']['settings']['KeyboardLayout1']['value']}, {self.struct['keyboard']['settings']['KeyboardLayout2']['value']}\"\n" ) config_file.write('XKBOPTIONS="grp:alt_shift_toggle"\n') config_file.close() parameters = [ '-display ' + os.environ['DISPLAY'], '-layout ' + self.struct['keyboard']['settings']['KeyboardLayout1']['value'] + ',' + self.struct['keyboard']['settings']['KeyboardLayout2'] ['value'], '-variant ' + self.struct['keyboard']['settings'] ['KeyboardVariant1']['value'] + ',' + self.struct['keyboard'] ['settings']['KeyboardVariant2']['value'], '-model ' + str(self.struct['keyboard']['settings'] ['KeyboardType']['value']), '-option "grp:alt_shift_toggle"', ] oe.execute('setxkbmap ' + ' '.join(parameters)) elif self.nox_keyboard_layouts == True: log.log( str(self.struct['keyboard']['settings']['KeyboardLayout1'] ['value']), log.INFO) parameter = self.struct['keyboard']['settings']['KeyboardLayout1'][ 'value'] command = f'loadkmap < `ls -1 {self.NOX_KEYBOARD_INFO}/*/{parameter}.bmap`' log.log(command, log.INFO) oe.execute(command)