def __init__(self, window): log('main addon starting') self.window = window self.set_version() # queue for communication with the comm and Main self.parent_queue = Queue.Queue() # create socket, listen for comms self.listener = Communicator( self.parent_queue, socket_file='/var/tmp/osmc.settings.sockfile') self.listener.start() # the gui is created and stored in memory for quick access # after a few hours, the gui should be removed from memory self.stored_gui = None self.create_gui() self.gui_last_accessed = datetime.datetime.now() self.skip_check = True # monitor created to check for xbmc abort requests self.monitor = xbmc.Monitor() # current skin directory, used to detect when the user has changed skins and prompts a reconstruction of the gui self.skin_dir = xbmc.getSkinDir() self.fonts = osmc_ubiquifonts.UbiquiFonts(ADDON_ID, ADDON, self.window) # run the ubiquifonts script to import the needed fonts into the Font.xml _ = self.fonts.import_osmc_fonts() if not os.path.isfile('/walkthrough_completed'): # Tell Kodi that OSMC is running the walkthrough try: xbmc.setosmcwalkthroughstatus(1) except Exception: log(traceback.format_exc()) else: try: # Tell Kodi that OSMC is done xbmc.setosmcwalkthroughstatus(2) except Exception: log(traceback.format_exc()) # daemon self._daemon() log('_daemon exited')
class Main(object): def __init__(self, window): log('main addon starting') self.window = window self.set_version() # queue for communication with the comm and Main self.parent_queue = Queue.Queue() # create socket, listen for comms self.listener = Communicator( self.parent_queue, socket_file='/var/tmp/osmc.settings.sockfile') self.listener.start() # the gui is created and stored in memory for quick access # after a few hours, the gui should be removed from memory self.stored_gui = None self.create_gui() self.gui_last_accessed = datetime.datetime.now() self.skip_check = True # monitor created to check for xbmc abort requests self.monitor = xbmc.Monitor() # current skin directory, used to detect when the user has changed skins and prompts a reconstruction of the gui self.skin_dir = xbmc.getSkinDir() self.fonts = osmc_ubiquifonts.UbiquiFonts(ADDON_ID, ADDON, self.window) # run the ubiquifonts script to import the needed fonts into the Font.xml _ = self.fonts.import_osmc_fonts() if not os.path.isfile('/walkthrough_completed'): # Tell Kodi that OSMC is running the walkthrough try: xbmc.setosmcwalkthroughstatus(1) except Exception: log(traceback.format_exc()) else: try: # Tell Kodi that OSMC is done xbmc.setosmcwalkthroughstatus(2) except Exception: log(traceback.format_exc()) # daemon self._daemon() log('_daemon exited') def create_gui(self): self.stored_gui = osmc_settings_gui.GuiThread(queue=self.parent_queue, addon=ADDON, window=self.window) self.stored_gui.setDaemon(True) def _daemon(self): log('daemon started') if not os.path.isfile('/walkthrough_completed'): self._walk_through() # start walk through while not self.monitor.abortRequested(): if not self.parent_queue.empty(): try: response = self.parent_queue.get() log('response : %s' % response) abort_requested = self._handle_response(response=response) if abort_requested: break finally: try: self.parent_queue.task_done() except: pass # sleep for one second, exit if Kodi is shutting down if self.monitor.waitForAbort(1): break abort_requested = self._check_skin() if abort_requested: break log('_daemon exiting') self.exit() log('_daemon shutdown') def exit(self): # try to kill the gui and comms try: log('Stopping listener (in wait)') self.listener.stop() log('Deleting listener (in wait)') del self.listener log('Listener deleted.') except: log('Failed to stop/delete listener. (in wait)') @staticmethod def get_sources_list(): query = { "jsonrpc": "2.0", "id": 1, "method": "Files.GetSources", "params": {} } xbmc_request = json.dumps(query) result_raw = xbmc.executeJSONRPC(xbmc_request) result = json.loads(result_raw) media_dict_raw = result.get('result', {}).get('sources', {}) media_list_raw = [v.get('file', '') for k, v in media_dict_raw.items()] media_string = ''.join(media_list_raw) return media_string def open_gui(self): log('Opening OSMC settings GUI') self.gui_last_accessed = datetime.datetime.now() self.skip_check = False try: # try opening the gui self.stored_gui.start() except: # if that doesnt work then it is probably because the gui was too old and has been deleted # so recreate the gui and open it self.create_gui() self.stored_gui.start() log('gui threading finished') @staticmethod def set_walkthrough_status(value): try: # Tell Kodi that OSMC is done xbmc.setosmcwalkthroughstatus(int(value)) except Exception: log(traceback.format_exc()) def check_vendor(self): """ Checks whether OSMC is being installed via N00bs or ts. Returns None if the vendor file is not present or does not contain 'noobs' or 'ts'. Vendor is pass to the Main settings service, which then asks the user whether they would like to update (noobs or ts only). """ current_vendor = self.window.getProperty('osmc_vendor') if current_vendor: return current_vendor current_vendor = None if os.path.isfile('/vendor'): with open('/vendor', 'r', encoding='utf-8') as f: line = f.readline() vendors = ['noobs', 'ts'] for vendor in vendors: if vendor in line: current_vendor = vendor break self.window.clearProperty('osmc_vendor') if current_vendor: self.window.setProperty('osmc_vendor', current_vendor) return current_vendor def set_version(self, overwrite=False): """ Loads the current OSMC version into the Home window for display in MyOSMC """ # Check for "upgraded" Alpha 4 and earlier if not overwrite and self.window.getProperty('osmc_version'): return with open(os.devnull, 'w') as fnull: process = subprocess.call( ['/usr/bin/dpkg-query', '-l', 'rbp-mediacenter-osmc'], stderr=fnull, stdout=fnull) if process == 0: version_string = 'Unsupported OSMC Alpha release' else: version = [] with open('/etc/os-release', 'r', encoding='utf-8') as f: lines = f.readlines() tags = ['NAME=', 'VERSION=', 'VERSION_ID='] for line in lines: for tag in tags: if line.startswith(tag): version.append(line[len(tag):].replace('"', '').replace( '\n', '')) version_string = ' '.join(version) log('Current Version: %s' % version_string) self.window.setProperty('osmc_version', version_string) def _check_skin(self): # Check the current skin directory, if it is different to the previous one, then # recreate the gui. This is required because reference in the gui left in memory # do not survive a refresh of the skins textures (???) if self.skin_dir != xbmc.getSkinDir(): log('Old Skin: %s' % self.skin_dir) self.skin_dir = xbmc.getSkinDir() log('New Skin: %s' % self.skin_dir) try: resp = self.fonts.import_osmc_fonts() log('Ubiquifonts result: %s' % resp) if resp == 'reload_please': while not self.monitor.abortRequested(): if self.monitor.waitForAbort(1): return True xml = xbmc.getInfoLabel('Window.Property(xmlfile)') if xml != 'DialogConfirm.xml': log('Skin reload requested') xbmc.executebuiltin('ReloadSkin()') break except Exception: log(traceback.format_exc()) try: log('skin changed, reloading gui') del self.stored_gui except: pass self.create_gui() return False def _walk_through(self): # Tell Kodi that OSMC is running the walkthrough self.window.setProperty("walkthrough_is_running", 'any_value') self.set_walkthrough_status(1) network_module = next( iter(module for module in self.stored_gui.live_modules if module.get('id') == 'osmcnetworking'), None) if not network_module: log('Networking module not found') else: vendor = self.check_vendor() log("Vendor is %s" % vendor) osmc_walkthru.open_gui( ADDON, networking_instance=network_module['class_instance']) with open('/tmp/walkthrough_completed', 'w+', encoding='utf-8') as _: log('/tmp/walkthrough_completed written') subprocess.call([ 'sudo', 'mv', '/tmp/walkthrough_completed', '/walkthrough_completed' ]) self.set_walkthrough_status(2) self.window.clearProperty('walkthrough_is_running') del self.stored_gui xbmc.executebuiltin('ReloadSkin()') log('Skin reloaded') # Query user about whether they would like to update now update_check_now = False if vendor == 'noobs': update_check_now = DIALOG.yesno( lang(32026), '[CR]'.join([lang(32027), lang(32028), lang(32029)])) elif vendor == 'ts': update_check_now = DIALOG.yesno( lang(32026), '[CR]'.join([lang(32030), lang(32031), lang(32029)])) if update_check_now: log('User elected to update now') try: message = ('settings_command', {'action': 'update'}) message = json.dumps(message) with closing( socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)) as open_socket: open_socket.connect( '/var/tmp/osmc.settings.update.sockfile') if not isinstance(message, (bytes, bytearray)): message = message.encode('utf-8', 'ignore') open_socket.sendall(message) except Exception: log(traceback.format_exc()) def _handle_response(self, response): if response == 'open': self.open_gui() elif response == 'refresh_gui': ''' This may need to be moved to a separate thread, so that it doesnt hold up the other functions. if the gui calls for its own refresh, then delete the existing one and open a new instance ''' self.open_gui() elif response == 'exit': return True # signal abort elif response == 'walkthru': log('Running manually called walkthru') osmc_walkthru.open_gui(ADDON, networking_instance=None, testing=True) elif 'new_device:' in response: # a usb device is attached to the hardware # get the device id device_id = response[len('new_device:'):] # proceed only if the device_id is not null if device_id: # get ignore list ignore_list_raw = ADDON.getSetting('ignored_devices') ignore_list_initial = ignore_list_raw.split('|') ignore_list = deepcopy(ignore_list_initial) # get sources list media_string = self.get_sources_list() # post dialogs to ask the user if they want to add the source, or ignore the device if device_id not in ignore_list and device_id not in media_string: result = DIALOG.yesno( lang(32002), '[CR]'.join([lang(32003), lang(32004)])) if result: xbmc.executebuiltin("ActivateWindow(mediasource)") else: result = DIALOG.yesno(lang(32002), lang(32005)) if result: ignore_list.append(str(device_id)) if ignore_list_initial != ignore_list: ignore_string = '|'.join(ignore_list) ADDON.setSetting('ignored_devices', ignore_string) else: # check whether the response is one of the live_modules, if it is then launch that module for module in self.stored_gui.live_modules: module_id = module.get('id', 'id_not_found') if response != module_id: continue class_instance = module.get('class_instance', None) module_instance = module.get('module_instance', None) if class_instance and class_instance.isAlive(): log('Opening %s from widget' % module_id) class_instance.run() elif module_instance: log('Starting %s from widget' % module_id) class_instance = module_instance.OSMCSettingClass() class_instance.setDaemon(True) module['class_instance'] = class_instance class_instance.start() break return False