class SelectInput(pyxbmct.AddonDialogWindow): def __init__(self, title=''): print 'Init Called' super(SelectInput, self).__init__(title) self.plugin = RequiredFeature('plugin').request() self.core = RequiredFeature('core').request() self.device_wrapper = RequiredFeature('device-wrapper').request() self.available_devices = self.device_wrapper.devices self.md5 = hashlib.md5() self.input_storage = self.plugin.get_storage('input_storage') for key, device in self.input_storage.iteritems(): print 'Devices during INIT: %s' % device.name background = None if self.core.get_active_skin() == 'skin.osmc': media_path = '/usr/share/kodi/addons/skin.osmc/media' if os.path.exists(media_path): background = os.path.join(media_path, 'dialogs/DialogBackground_old.png') if background is not None: self.background.setImage(background) self.removeControl(self.title_background) self.removeControl(self.window_close_button) self.removeControl(self.title_bar) self.controls = {} self.add_ctrl_btn = None self.setGeometry(1280, 720, 12, 6, padding=60) self.place_add_ctrl_btn() self.setFocus(self.add_ctrl_btn) self.connect(pyxbmct.ACTION_NAV_BACK, self.close_and_save) self.init_existing_controls() # initalise controls / mappings read from .storage def place_add_ctrl_btn(self): self.add_ctrl_btn = create_button() self.add_ctrl_btn.setLabel('Add Controller') self.placeControl(self.add_ctrl_btn, row=12, column=1, rowspan=1, columnspan=2) self.connect(self.add_ctrl_btn, self.add_ctrl) def add_ctrl(self, device=None): idx = len(self.controls) print 'Adding controler with index %s' % idx control = CtrlSelectionWrapper() self.md5.update(str(time.time())) ctrl_id = self.md5.hexdigest() control.id = ctrl_id control.idx = idx if not device: device = InputDevice() device.name = 'None (Disabled)' control.device = device label = create_label() label.setLabel('Controller ' + str(idx)) control.label = label input_select_btn = create_button() input_select_btn.setLabel( control.device.name, ) control.input_select_btn = input_select_btn trigger_adv_mapping_btn = create_button() trigger_adv_mapping_btn.setLabel('Add Mapping') control.trigger_adv_mapping_btn = trigger_adv_mapping_btn remove_btn = create_button() remove_btn.setLabel('Remove') control.remove_btn = remove_btn if idx == 0: row = 0 adv_row = 1 else: row = idx * 2 adv_row = row + 1 control.adv_row = adv_row self.placeControl(control.label, row=row, column=0, rowspan=1, columnspan=1) self.placeControl(control.input_select_btn, row=row, column=1, rowspan=1, columnspan=3) self.placeControl(control.trigger_adv_mapping_btn, row=row, column=4, rowspan=1, columnspan=1) self.placeControl(control.remove_btn, row=row, column=5, rowspan=1, columnspan=1) self.connect_controls(control) if control.device.is_kbd() or control.device.is_mouse() or control.device.is_none_device(): trigger_adv_mapping_btn.setEnabled(False) # Still visible for now, but disabled # trigger_adv_mapping_btn.setVisible(False) control.set_internal_navigation() self.controls[control.id] = control # TODO: Should be a dedicated method (set_navigation) self.add_ctrl_btn.controlUp(control.input_select_btn) if control.adv_on_flag: control.adv_select_mapping.controlDown(self.add_ctrl_btn) else: control.input_select_btn.controlDown(self.add_ctrl_btn) previous_control = None for _ctrl_id, _control in self.controls.iteritems(): print 'Looping controls, current index: %s' % _control.idx if _control.idx == control.idx-1: previous_control = _control if previous_control: if previous_control.adv_on_flag: control.input_select_btn.controlUp(previous_control.adv_select_mapping) previous_control.adv_select_mapping.controlDown(control.input_select_btn) else: control.input_select_btn.controlUp(previous_control.input_select_btn) previous_control.input_select_btn.controlDown(control.input_select_btn) if control.device.mapping: self.trigger_advanced(control) def connect_controls(self, control): self.connect(control.input_select_btn, lambda: self.select_input(control)) self.connect(control.remove_btn, lambda: self.remove_input(control)) self.connect(control.trigger_adv_mapping_btn, lambda: self.trigger_advanced(control)) def select_input(self, control): available_devices = self.filter_input_devices() device_names = [_dev.name for _dev in available_devices] controller = xbmcgui.Dialog().select('Select Input Device', device_names) if controller == -1: return else: print device_names[controller] device = self.device_wrapper.find_device_by_name(device_names[controller]) control.device = device control.input_select_btn.setLabel(device.name) if device.is_kbd() or device.is_mouse() or device.is_none_device(): control.trigger_adv_mapping_btn.setEnabled(False) else: control.trigger_adv_mapping_btn.setEnabled(True) self.input_storage[control.idx] = device def remove_input(self, control, dry=False): self.removeControls(control.controls_as_list()) del_key = None for key, value in self.input_storage.iteritems(): if value.name == control.device.name: del_key = key if not dry: del self.input_storage[del_key] del self.controls[control.id] del control self.init_existing_controls() self.setFocus(self.add_ctrl_btn) def trigger_advanced(self, control): control.adv_on(self) control.set_internal_navigation() next_control = None for _ctrl_id, _control in self.controls.iteritems(): print 'Looping controls, current index: %s' % _control.idx if _control.idx == control.idx+1: next_control = _control if next_control: control.adv_select_mapping.controlDown(next_control.input_select_btn) next_control.input_select_btn.controlUp(control.adv_select_mapping) else: control.adv_select_mapping.controlDown(self.add_ctrl_btn) self.add_ctrl_btn.controlUp(control.adv_select_mapping) self.setFocus(control.input_select_btn) def unset_advanced(self, control): control.adv_off(self) control.set_internal_navigation() control.unset_mapping_file() for key, device in self.input_storage.iteritems(): if device.name == control.device.name: device.mapping = None print 'Found device and saved mapping' break next_control = None for _ctrl_id, _control in self.controls.iteritems(): print 'Looping controls, current index: %s' % _control.idx if _control.idx == control.idx+1: next_control = _control if next_control: control.input_select_btn.controlDown(next_control.input_select_btn) next_control.input_select_btn.controlUp(control.input_select_btn) else: control.input_select_btn.controlDown(self.add_ctrl_btn) self.add_ctrl_btn.controlUp(control.input_select_btn) self.setFocus(control.input_select_btn) def select_mapping(self, control): browser = xbmcgui.Dialog().browse(1, 'Select Mapping File', 'files', '.map|.conf', False, False, os.path.expanduser('~')) if browser: control.set_mapping_file(browser) for key, device in self.input_storage.iteritems(): print 'Iterating devices, current IS device: %s' % device.name if device.name == control.device.name: device.mapping = browser print 'Found device and saved mapping' break def create_mapping(self, control): print 'Starting mapping' map_name = xbmcgui.Dialog().input(self.core.string('enter_filename')) progress_dialog = xbmcgui.DialogProgress() progress_dialog.create( self.core.string('name'), self.core.string('starting_mapping') ) map_file = '%s/%s.map' % (os.path.expanduser('~'), map_name) moonlight_helper = RequiredFeature('moonlight-helper').request() success = moonlight_helper.create_ctrl_map_new(progress_dialog, map_file, control.device) if success: confirmed = xbmcgui.Dialog().yesno( self.core.string('name'), self.core.string('mapping_success'), self.core.string('set_mapping_active') ) self.core.logger.info('Dialog Yes No Value: %s' % confirmed) if confirmed: control.set_mapping_file(map_file) for key, device in self.input_storage.iteritems(): print 'Iterating devices, current IS device: %s' % device.name if device.name == control.device.name: device.mapping = map_file print 'Found device and saved mapping' break else: xbmcgui.Dialog().ok( self.core.string('name'), self.core.string('mapping_failure') ) def init_existing_controls(self): if self.controls is not None: for key, value in self.controls.iteritems(): self.remove_input(value, True) self.controls = {} del_keys = [] for key, device in self.input_storage.iteritems(): print 'Iterating saved input devices in INIT: %s' % device.name if not self.device_wrapper.find_device_by_name(device.name): print 'Could not find device by name: %s' % device.name del_keys.append(key) for key in del_keys: del self.input_storage[key] for key, device in self.input_storage.iteritems(): self.add_ctrl(device) def filter_input_devices(self): device_list = [] current_ctrl_labels = [ctrl.input_select_btn.getLabel() for key, ctrl in self.controls.iteritems()] for device in self.available_devices: if device.name not in current_ctrl_labels: device_list.append(device) return device_list def close_and_save(self): self.input_storage.sync() print self.input_storage.raw_dict() print 'Save called, closing window ... ' self.close()
class SkinPatcher: def __init__(self): self.core = RequiredFeature('core').request() self.plugin = RequiredFeature('plugin').request() self.base_path = '/usr/share/kodi/addons/skin.osmc/16x9/' self.shortcut_path = '/usr/share/kodi/addons/skin.osmc/shortcuts/' self.widget = 'Includes_Widgets.xml' self.var = 'Variables.xml' self.home = 'Home.xml' self.override = 'overrides.xml' self.widget_backup = 'Includes_Widgets.backup' self.var_backup = 'Variables.backup' self.home_backup = 'Home.backup' self.override_backup = 'overrides.backup' self.id = None self.supported = self.core.get_active_skin() == 'skin.osmc' \ and os.path.isfile(os.path.join(self.base_path, self.widget)) \ and os.path.isfile(os.path.join(self.base_path, self.var)) \ and os.path.isfile(os.path.join(self.base_path, self.home)) \ and os.path.isfile(os.path.join(self.shortcut_path, self.override)) self.rollback_supported = os.path.isfile(os.path.join(self.base_path, self.widget_backup)) \ and os.path.isfile(os.path.join(self.base_path, self.var_backup)) \ and os.path.isfile(os.path.join(self.base_path, self.home_backup)) \ and os.path.isfile(os.path.join(self.shortcut_path, self.override_backup)) def backup(self): shutil.copy(os.path.join(self.base_path, self.widget), os.path.join(self.base_path, self.widget_backup)) shutil.copy(os.path.join(self.base_path, self.var), os.path.join(self.base_path, self.var_backup)) shutil.copy(os.path.join(self.base_path, self.home), os.path.join(self.base_path, self.home_backup)) shutil.copy(os.path.join(self.shortcut_path, self.override), os.path.join(self.shortcut_path, self.override_backup)) def patch(self): if self.supported: self.backup() self.patch_widget() self.patch_home() self.patch_var() self.patch_override() self.plugin.set_setting('luna_widget_patched', 'true') else: print 'Not Supported' def patch_widget(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.base_path, self.widget)).getroot() include = ElementTree.SubElement(xml_root, 'include', name="Luna") content = ElementTree.SubElement(include, 'content') for i in range(0, 20): item = ElementTree.SubElement(content, 'item') ElementTree.SubElement(item, 'icon').text = "$INFO[Window.Property(Luna.%s.icon)]" % i ElementTree.SubElement(item, 'thumb').text = "$INFO[Window.Property(Luna.%s.thumb)]" % i ElementTree.SubElement(item, 'label').text = "$INFO[Window.Property(Luna.%s.name)]" % i ElementTree.SubElement(item, 'property', name="fanart").text = "$INFO[Window.Property(Luna.%s.fanart)]" % i ElementTree.SubElement(item, 'onclick')\ .text = "RunPlugin(plugin://script.luna/games/launch-from-widget/%s)" % i ElementTree.SubElement(item, 'visible').text = "!IsEmpty(Window.Property(Luna.%s.name))" % i indent(include) tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.base_path, self.widget)) def patch_home(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.base_path, self.home)).getroot() print self.plugin.get_setting('luna_force_fanart') controls = xml_root.find('controls') control_group = None for control in controls: print control.get('type') if control.get('type') == 'image': print "Found Image Control" if self.plugin.get_setting('luna_force_fanart', bool): control.find('visible').text = "True" print 'Visible Text is %s' % control.find('visible').text if control.get('type') == 'group': control_group = control break inner_control_group = None for control in control_group: if control.get('type') == 'group': inner_control_group = control_group break widget_control = None for control in inner_control_group: if control.get('type') == 'group': widget_control = control break inner_widget_control = None for control in widget_control: if control.get('id') is not None: inner_widget_control = control break current_max_id = "" myosmc_control = None for control in inner_widget_control: if control.get('id') is not None: current_max_id = control.get('id') myosmc_control = control current_max_id = int(current_max_id) + 1 self.id = current_max_id luna_control = copy.deepcopy(myosmc_control) luna_control.set('id', str(current_max_id)) luna_control.find('include').text = "Luna" luna_control.find('visible').text = "StringCompare(Container(9000).ListItem.Property(Widget),Luna)" luna_item_layout = luna_control.find('itemlayout') luna_item_layout.set('width', "270") luna_focus_layout = luna_control.find('focusedlayout') luna_focus_layout.set('width', "270") for control in luna_item_layout: if control.get('type') == 'image': control.find('width').text = "250" if control.find('texture') is not None and control.find('texture').text == 'common/black.png': control.find('texture').text = "" for control in luna_focus_layout: if control.get('type') == 'image': control.find('width').text = "250" if control.find('texture') is not None and control.find('texture').text == 'common/black.png': control.find('texture').text = "" inner_widget_control.append(luna_control) tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.base_path, self.home)) def patch_var(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.base_path, self.var)).getroot() label_group = None heading_group = None fanart_group = None for var in xml_root.findall('variable'): if var.get('name') == 'WidgetLabel': label_group = var if var.get('name') == 'WidgetHeading': heading_group = var if var.get('name') == 'WidgetFanart': fanart_group = var if label_group is not None and heading_group is not None and fanart_group is not None: break ElementTree.SubElement(label_group, "value", condition="StringCompare(Container(9000).ListItem.Property(Widget),Luna)")\ .text = "$INFO[Container(%s).ListItem.Label]" % self.id ElementTree.SubElement(heading_group, "value", condition="StringCompare(Container(9000).ListItem.Property(Widget),Luna)")\ .text = "Games" ElementTree.SubElement(fanart_group, "value", condition="StringCompare(Container(9000).ListItem.Property(Widget),Luna)")\ .text = "$INFO[Container(%s).ListItem.Property(fanart)]" % self.id tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.base_path, self.var)) def patch_override(self): xml_root = ElementTree.ElementTree(file=os.path.join(self.shortcut_path, self.override)).getroot() ElementTree.SubElement(xml_root, "widget", label="Luna").text = "Luna" ElementTree.SubElement(xml_root, "widgetdefault", labelID="script.luna").text = "Luna" tree = ElementTree.ElementTree(xml_root) tree.write(os.path.join(self.shortcut_path, self.override)) def rollback(self): if self.rollback_supported: shutil.move(os.path.join(self.base_path, self.widget_backup), os.path.join(self.base_path, self.widget)) shutil.move(os.path.join(self.base_path, self.var_backup), os.path.join(self.base_path, self.var)) shutil.move(os.path.join(self.base_path, self.home_backup), os.path.join(self.base_path, self.home)) shutil.move(os.path.join(self.shortcut_path, self.override_backup), os.path.join(self.shortcut_path, self.override)) self.plugin.set_setting('luna_widget_patched', 'false')
class SelectInput(pyxbmct.AddonDialogWindow): def __init__(self, title=''): print 'Init Called' super(SelectInput, self).__init__(title) self.plugin = RequiredFeature('plugin').request() self.core = RequiredFeature('core').request() self.device_wrapper = RequiredFeature('device-wrapper').request() self.available_devices = self.device_wrapper.devices self.md5 = hashlib.md5() self.input_storage = self.plugin.get_storage('input_storage') for key, device in self.input_storage.iteritems(): print 'Devices during INIT: %s' % device.name background = None if self.core.get_active_skin() == 'skin.osmc': media_path = '/usr/share/kodi/addons/skin.osmc/media' if os.path.exists(media_path): background = os.path.join(media_path, 'dialogs/DialogBackground_old.png') if background is not None: self.background.setImage(background) self.removeControl(self.title_background) self.removeControl(self.window_close_button) self.removeControl(self.title_bar) self.controls = {} self.add_ctrl_btn = None self.setGeometry(1280, 720, 12, 6, padding=60) self.place_add_ctrl_btn() self.setFocus(self.add_ctrl_btn) self.connect(pyxbmct.ACTION_NAV_BACK, self.close_and_save) self.init_existing_controls( ) # initalise controls / mappings read from .storage def place_add_ctrl_btn(self): self.add_ctrl_btn = create_button() self.add_ctrl_btn.setLabel('Add Controller') self.placeControl(self.add_ctrl_btn, row=12, column=1, rowspan=1, columnspan=2) self.connect(self.add_ctrl_btn, self.add_ctrl) def add_ctrl(self, device=None): idx = len(self.controls) print 'Adding controler with index %s' % idx control = CtrlSelectionWrapper() self.md5.update(str(time.time())) ctrl_id = self.md5.hexdigest() control.id = ctrl_id control.idx = idx if not device: device = InputDevice() device.name = 'None (Disabled)' control.device = device label = create_label() label.setLabel('Controller ' + str(idx)) control.label = label input_select_btn = create_button() input_select_btn.setLabel(control.device.name, ) control.input_select_btn = input_select_btn trigger_adv_mapping_btn = create_button() trigger_adv_mapping_btn.setLabel('Add Mapping') control.trigger_adv_mapping_btn = trigger_adv_mapping_btn remove_btn = create_button() remove_btn.setLabel('Remove') control.remove_btn = remove_btn if idx == 0: row = 0 adv_row = 1 else: row = idx * 2 adv_row = row + 1 control.adv_row = adv_row self.placeControl(control.label, row=row, column=0, rowspan=1, columnspan=1) self.placeControl(control.input_select_btn, row=row, column=1, rowspan=1, columnspan=3) self.placeControl(control.trigger_adv_mapping_btn, row=row, column=4, rowspan=1, columnspan=1) self.placeControl(control.remove_btn, row=row, column=5, rowspan=1, columnspan=1) self.connect_controls(control) if control.device.is_kbd() or control.device.is_mouse( ) or control.device.is_none_device(): trigger_adv_mapping_btn.setEnabled(False) # Still visible for now, but disabled # trigger_adv_mapping_btn.setVisible(False) control.set_internal_navigation() self.controls[control.id] = control # TODO: Should be a dedicated method (set_navigation) self.add_ctrl_btn.controlUp(control.input_select_btn) if control.adv_on_flag: control.adv_select_mapping.controlDown(self.add_ctrl_btn) else: control.input_select_btn.controlDown(self.add_ctrl_btn) previous_control = None for _ctrl_id, _control in self.controls.iteritems(): print 'Looping controls, current index: %s' % _control.idx if _control.idx == control.idx - 1: previous_control = _control if previous_control: if previous_control.adv_on_flag: control.input_select_btn.controlUp( previous_control.adv_select_mapping) previous_control.adv_select_mapping.controlDown( control.input_select_btn) else: control.input_select_btn.controlUp( previous_control.input_select_btn) previous_control.input_select_btn.controlDown( control.input_select_btn) if control.device.mapping: self.trigger_advanced(control) def connect_controls(self, control): self.connect(control.input_select_btn, lambda: self.select_input(control)) self.connect(control.remove_btn, lambda: self.remove_input(control)) self.connect(control.trigger_adv_mapping_btn, lambda: self.trigger_advanced(control)) def select_input(self, control): available_devices = self.filter_input_devices() device_names = [_dev.name for _dev in available_devices] controller = xbmcgui.Dialog().select('Select Input Device', device_names) if controller == -1: return else: print device_names[controller] device = self.device_wrapper.find_device_by_name( device_names[controller]) control.device = device control.input_select_btn.setLabel(device.name) if device.is_kbd() or device.is_mouse() or device.is_none_device(): control.trigger_adv_mapping_btn.setEnabled(False) else: control.trigger_adv_mapping_btn.setEnabled(True) self.input_storage[control.idx] = device def remove_input(self, control, dry=False): self.removeControls(control.controls_as_list()) del_key = None for key, value in self.input_storage.iteritems(): if value.name == control.device.name: del_key = key if not dry: del self.input_storage[del_key] del self.controls[control.id] del control self.init_existing_controls() self.setFocus(self.add_ctrl_btn) def trigger_advanced(self, control): control.adv_on(self) control.set_internal_navigation() next_control = None for _ctrl_id, _control in self.controls.iteritems(): print 'Looping controls, current index: %s' % _control.idx if _control.idx == control.idx + 1: next_control = _control if next_control: control.adv_select_mapping.controlDown( next_control.input_select_btn) next_control.input_select_btn.controlUp(control.adv_select_mapping) else: control.adv_select_mapping.controlDown(self.add_ctrl_btn) self.add_ctrl_btn.controlUp(control.adv_select_mapping) self.setFocus(control.input_select_btn) def unset_advanced(self, control): control.adv_off(self) control.set_internal_navigation() control.unset_mapping_file() for key, device in self.input_storage.iteritems(): if device.name == control.device.name: device.mapping = None print 'Found device and saved mapping' break next_control = None for _ctrl_id, _control in self.controls.iteritems(): print 'Looping controls, current index: %s' % _control.idx if _control.idx == control.idx + 1: next_control = _control if next_control: control.input_select_btn.controlDown(next_control.input_select_btn) next_control.input_select_btn.controlUp(control.input_select_btn) else: control.input_select_btn.controlDown(self.add_ctrl_btn) self.add_ctrl_btn.controlUp(control.input_select_btn) self.setFocus(control.input_select_btn) def select_mapping(self, control): browser = xbmcgui.Dialog().browse(1, 'Select Mapping File', 'files', '.map|.conf', False, False, os.path.expanduser('~')) if browser: control.set_mapping_file(browser) for key, device in self.input_storage.iteritems(): print 'Iterating devices, current IS device: %s' % device.name if device.name == control.device.name: device.mapping = browser print 'Found device and saved mapping' break def create_mapping(self, control): print 'Starting mapping' map_name = xbmcgui.Dialog().input(self.core.string('enter_filename')) progress_dialog = xbmcgui.DialogProgress() progress_dialog.create(self.core.string('name'), self.core.string('starting_mapping')) map_file = '%s/%s.map' % (os.path.expanduser('~'), map_name) moonlight_helper = RequiredFeature('moonlight-helper').request() success = moonlight_helper.create_ctrl_map_new(progress_dialog, map_file, control.device) if success: confirmed = xbmcgui.Dialog().yesno( self.core.string('name'), self.core.string('mapping_success'), self.core.string('set_mapping_active')) self.core.logger.info('Dialog Yes No Value: %s' % confirmed) if confirmed: control.set_mapping_file(map_file) for key, device in self.input_storage.iteritems(): print 'Iterating devices, current IS device: %s' % device.name if device.name == control.device.name: device.mapping = map_file print 'Found device and saved mapping' break else: xbmcgui.Dialog().ok(self.core.string('name'), self.core.string('mapping_failure')) def init_existing_controls(self): if self.controls is not None: for key, value in self.controls.iteritems(): self.remove_input(value, True) self.controls = {} del_keys = [] for key, device in self.input_storage.iteritems(): print 'Iterating saved input devices in INIT: %s' % device.name if not self.device_wrapper.find_device_by_name(device.name): print 'Could not find device by name: %s' % device.name del_keys.append(key) for key in del_keys: del self.input_storage[key] for key, device in self.input_storage.iteritems(): self.add_ctrl(device) def filter_input_devices(self): device_list = [] current_ctrl_labels = [ ctrl.input_select_btn.getLabel() for key, ctrl in self.controls.iteritems() ] for device in self.available_devices: if device.name not in current_ctrl_labels: device_list.append(device) return device_list def close_and_save(self): self.input_storage.sync() print self.input_storage.raw_dict() print 'Save called, closing window ... ' self.close()