class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'sickbeard_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, host={}, apikey={}) def validate_host(self, field, value): if not value: return value url = PING_URL % {'host':value, 'apikey':1234} response = utils.http_request(url, timeout=2).get('response') if not response: raise ValidationError('Host not reachable.') if response.status != 200: raise ValidationError('Invalid response from server: %s' % response.status) return value def validate_apikey(self, field, value): if not value: return value host = self.fields.host.value if host is None: host = self.pkconfig.get(self.namespace, 'host') url = PING_URL % {'host':host, 'apikey':value} response = utils.http_request(url, timeout=2).get('response') if not response: raise ValidationError('Host not reachable.') if response.status != 200: raise ValidationError('Invalid response from server: %s' % response.status) content = json.loads(response.read().decode('utf-8')) if content.get('result') != 'success': raise ValidationError('Invalid API key specified.') return value
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'sonarr_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, host={}, apikey={}) def validate_host(self, field, value): if not value: return value url = UPDATE_URL % {'host': value, 'apikey': 1234, 'end': '2000-01-01'} response = utils.http_request(url, timeout=2) if utils.rget(response, 'error.code') != 401: raise ValidationError('Host not reachable.') return value def validate_apikey(self, field, value): if not value: return value host = self.fields.host.value if host is None: host = self.pkconfig.get(self.namespace, 'host') url = UPDATE_URL % {'host': host, 'apikey': value, 'end': '2000-01-01'} response = utils.http_request(url, timeout=2).get('response') if utils.rget(response, 'error.code') == 401: raise ValidationError('Invalid API key specified.') content = json.loads(response.read().decode('utf-8')) if not isinstance(content, list): raise ValidationError('Invalid response from server.') return value
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'plexserver_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, host={}, username={'save_to_keyring': True}, password={'save_to_keyring': True}) def validate_password(self, field, value): if not value: return value try: MyPlexAccount.signin(self.fields.username.value, value) return value except Unauthorized: raise ValidationError('Invalid username or password.') def validate_host(self, field, value): if not value: return value try: username = self.fields.username.value password = self.fields.password.value fetch_plex_instance(self.pkmeter, username, password, value) return value except Unauthorized: raise ValidationError('Invalid username or password.') except NotFound: raise ValidationError('Server host or name not found.') except: raise ValidationError('Invalid server.')
def _init(self, etree, control, parent=None): self.etree = etree # Element tree to parse self.control = control # Control class (for callback connect) self.parent = parent # Parent widget self.id = None # ID of this widget (if specified) self.data = utils.Bunch() # Metadata to append to object self.actions = [] # List of actions self.manifest = utils.Bunch() # Dict of element ids self.bgimage = None # Background image self.bgpos = (0, 0) # Background position 'x,y' or 'center,top' etc.. self.bgsize = 'fit' # Background size 'x,y' or 'fit' self.bgfade = 0 # Fade bgimage when changed (0 to disable) self.bgopacity = 1.0 # Current bgopacity (used during transition) self.click_enabled = False # Set True when click event enabled self.dblclick_enabled = False # Set True when dblclick event enabled self.installEventFilter(self) # Capture events for interactions self._init_attributes() # Process all attributes (and actions) self.children = self._append_children() # Build all Chiuldren if parent is not None: parent.layout().addWidget(self)
def __init__(self, pkmeter, pkconfig): self.name = utils.name(self.__module__) # Name of this Plugin self.namespace = utils.namespace( self.__module__) # Namespace of this Config self.template = self._init_template() # Template for config settings self.fields = utils.Bunch() # Fields in this Config PKVFrame.__init__(self, self.template, self) # Init parent widget self.pkmeter = pkmeter # Reference to PKMeter self.pkconfig = pkconfig # Reference to Main Config self._init_default_interval() self._init_fields()
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'wunderground_config.html') FIELDS = utils.Bunch( BaseConfig.FIELDS, apikey={}, query={}, location={'default': 'autoip'}, ) def validate_apikey(self, field, value): if not value: return value url = UPDATE_URL % {'apikey': value, 'location': 'autoip'} response = utils.http_request(url, timeout=2).get('response') if not response: raise ValidationError('No response from Weather Underground.') content = json.loads(response.read().decode('utf-8')) if 'response' not in content: raise ValidationError('Invalid response from Weather Underground.') if 'current_observation' not in content: raise ValidationError('Invalid API key specified.') return value def validate_query(self, field, value): if not value or value == 'autoip': self.fields.location.value = 'autoip' field.help.setText(field.help_default) return value url = QUERY_URL % {'query': value} response = utils.http_request(url, timeout=2).get('response') if not response: raise ValidationError('No response from Weather Underground.') content = json.loads(response.read().decode('utf-8')) if not content.get('RESULTS'): raise ValidationError('Unable to determine specified location.') result = content['RESULTS'][0] self.fields.location.value = result['ll'].replace(' ', ',') field.help.setText(result['name']) return value
def _init_field(self, name, meta): field = utils.Bunch(meta) # Convert to Bunch field.name = name # Name of this field field.input = self.manifest.get(name) # QT input element field.controlgroup = self.manifest.get('controlgroup_%s' % name) # QT control group field.status = self.manifest.get('status_%s' % name) # QT status label field.help = self.manifest.get('help_%s' % name) # QT help label field.help_default = field.help.text( ) if field.help else None # Default help text field.default = field.get('default', '') # Default value field.value = self._get_value(field) # Current value (to be saved) field.lastchecked = field.value # Last value verified field.validator = getattr(self, 'validate_%s' % name, None) # Validator callback if name in self.manifest: if getattr(field.input, 'textEdited', None): field.input.textEdited.connect( lambda txt, field=field: self._editing(field, txt)) if getattr(field.input, 'editingFinished', None): field.input.editingFinished.connect( lambda field=field: self._validate(field)) field.input.set_value(field.value) self.fields[name] = field
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'externalip_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, url={'default': DEFUALT_URL})
def _iter_calendars(self): for i in range(6): baseurl = self.pkmeter.config.get(self.namespace, 'cal%s' % i) url = Plugin.build_url(baseurl) color = self.pkmeter.config.get(self.namespace, 'color%s' % i) if baseurl: yield utils.Bunch({'url': url, 'color': color})
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'gcal_config.html') FIELDS = utils.Bunch( BaseConfig.FIELDS, cal1={'default': ''}, color1={'default': '#4986E7'}, cal2={'default': ''}, color2={'default': '#CD74E6'}, cal3={'default': ''}, color3={'default': '#F83A22'}, cal4={'default': ''}, color4={'default': '#FFAD46'}, cal5={'default': ''}, color5={'default': '#7BD148'}, ) def __init__(self, *args, **kwargs): super(Config, self).__init__(*args, **kwargs) self._button = None self.colorpicker = self._init_colorpicker() def _init_colorpicker(self): colorpicker = QtWidgets.QColorDialog() colorpicker.finished.connect(self.colorpicker_finished) return colorpicker def btn_color(self, widget): self._button = widget self.colorpicker.setCurrentColor(utils.hex_to_qcolor( widget.data.color)) self.colorpicker.open() def colorpicker_finished(self): field = self.fields[self._button.id] color = self.colorpicker.currentColor().name() self._button.set_value(color) self._validate(field) def _validate_cal(self, field, value): if not value: field.help.setText(field.help_default) return value url = Plugin.build_url(value) response = utils.http_request(url, timeout=2).get('response') if not response: raise ValidationError('No response from Google.') ical = Calendar.from_ical(response.read().decode('utf-8')) title = ical.get('x-wr-calname', ical.get('version', '')) if not title: raise ValidationError('Invalid response from Google.') field.help.setText(title) return value def validate_cal1(self, field, value): return self._validate_cal(field, value) def validate_cal2(self, field, value): return self._validate_cal(field, value) def validate_cal3(self, field, value): return self._validate_cal(field, value) def validate_cal4(self, field, value): return self._validate_cal(field, value) def validate_cal5(self, field, value): return self._validate_cal(field, value)
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'network_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, ignores={'default': DEFAULT_IGNORES})
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'plexmedia_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, ignores={})
class BaseConfig(PKVFrame): STATUS_OK = '✔' STATUS_ERROR = '✘' STATUS_LOADING = '…' TEMPLATE = os.path.join(SHAREDIR, 'templates', 'default_config.html') FIELDS = utils.Bunch(enabled={'default': True}, interval={'default': 60}) def __init__(self, pkmeter, pkconfig): self.name = utils.name(self.__module__) # Name of this Plugin self.namespace = utils.namespace( self.__module__) # Namespace of this Config self.template = self._init_template() # Template for config settings self.fields = utils.Bunch() # Fields in this Config PKVFrame.__init__(self, self.template, self) # Init parent widget self.pkmeter = pkmeter # Reference to PKMeter self.pkconfig = pkconfig # Reference to Main Config self._init_default_interval() self._init_fields() def _init_template(self): with open(self.TEMPLATE) as tmpl: template = ElementTree.fromstring(tmpl.read()) return template def _init_default_interval(self): if 'interval' in self.FIELDS: module = self.pkmeter.modules[self.namespace] default_interval = module.Plugin.DEFAULT_INTERVAL self.FIELDS.interval['default'] = default_interval def _init_fields(self): for name, meta in self.FIELDS.items(): self._init_field(name, meta) def _init_field(self, name, meta): field = utils.Bunch(meta) # Convert to Bunch field.name = name # Name of this field field.input = self.manifest.get(name) # QT input element field.controlgroup = self.manifest.get('controlgroup_%s' % name) # QT control group field.status = self.manifest.get('status_%s' % name) # QT status label field.help = self.manifest.get('help_%s' % name) # QT help label field.help_default = field.help.text( ) if field.help else None # Default help text field.default = field.get('default', '') # Default value field.value = self._get_value(field) # Current value (to be saved) field.lastchecked = field.value # Last value verified field.validator = getattr(self, 'validate_%s' % name, None) # Validator callback if name in self.manifest: if getattr(field.input, 'textEdited', None): field.input.textEdited.connect( lambda txt, field=field: self._editing(field, txt)) if getattr(field.input, 'editingFinished', None): field.input.editingFinished.connect( lambda field=field: self._validate(field)) field.input.set_value(field.value) self.fields[name] = field def _get_value(self, field): from_keyring = field.get('save_to_keyring', False) return self.pkconfig.get(self.namespace, field.name, field.default, from_keyring) def _editing(self, field, text): self._set_field_status(field, self.STATUS_LOADING, '') @threaded_method def _validate(self, field, force=False): if not field.input: return try: #self._set_field_status(field, self.STATUS_LOADING, '') value = field.input.get_value() if field.validator: result = field.validator(field, value) value = value if result is None else result log.info('Validation passed for %s.%s', self.namespace, field.name) self._set_field_status(field, self.STATUS_OK, '') except Exception as err: log.warn('Validation Error for %s.%s: %s', self.namespace, field.name, err) self._set_field_status(field, self.STATUS_ERROR, str(err)) finally: log.info('Setting value %s.%s: %s', self.namespace, field.name, value) field.value = value def _set_field_status(self, field, status, errmsg): if field.controlgroup: field.controlgroup.setToolTip(errmsg) if field.status: field.status.setText(status) def validate_interval(self, field, value): try: interval = int(value) assert 1 <= interval <= 3600, 'Value out of bounds.' return interval except: raise ValidationError('Interval seconds must be a number 1-3600.')
class Config(BaseConfig): TEMPLATE = os.path.join(SHAREDIR, 'templates', 'filesystem_config.html') FIELDS = utils.Bunch(BaseConfig.FIELDS, fstypes={'default': DEFAULT_FSTYPES})