class WizardExample(vip_base): def cb_initialize_plugin(self): self.wizardwidget = QWizard() self.wizardwidget.addPage(self.createIntroPage()) self.wizardwidget.addPage(sinPage(self.control_api)) self.wizardwidget.addPage(plotPage(self.control_api)) self.wizardwidget.addPage( connectPage(self.control_api, 'WizardExample')) self.pl_set_widget_for_internal_usage(self.wizardwidget) self.wizardwidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.wizardwidget.customContextMenuRequested.connect( self.show_context_menu) return True def show_context_menu(self, pos): gloPos = self.wizardwidget.mapToGlobal(pos) self.cmenu = self.pl_create_control_context_menu() self.cmenu.exec_(gloPos) def cb_execute(self, Data=None, block_name=None, plugin_uname=None): pass def cb_set_parameter(self, name, value): pass def cb_quit(self): pass def cb_get_plugin_configuration(self): config = {} return config def cb_plugin_meta_updated(self): pass def createIntroPage(self): page = QWizardPage() page.setTitle("Introduction") label = QLabel("This wizard will show you a simple wizard.") label.setWordWrap(True) label2 = QLabel( "Therefore it will create a Sine plugin, a plot and connect these two." ) label2.setWordWrap(True) layout = QVBoxLayout() layout.addWidget(label) layout.addWidget(label2) page.setLayout(layout) return page
class WizardExample(vip_base): def cb_initialize_plugin(self): self.wizardwidget = QWizard() self.wizardwidget.addPage(self.createIntroPage()) self.wizardwidget.addPage(sinPage(self.control_api)) self.wizardwidget.addPage(plotPage(self.control_api)) self.wizardwidget.addPage(connectPage(self.control_api,'WizardExample')) self.pl_set_widget_for_internal_usage( self.wizardwidget ) self.wizardwidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.wizardwidget.customContextMenuRequested.connect(self.show_context_menu) return True def show_context_menu(self, pos): gloPos = self.wizardwidget.mapToGlobal(pos) self.cmenu = self.pl_create_control_context_menu() self.cmenu.exec_(gloPos) def cb_execute(self, Data=None, block_name = None, plugin_uname = None): pass def cb_set_parameter(self, name, value): pass def cb_quit(self): pass def cb_get_plugin_configuration(self): config = {} return config def cb_plugin_meta_updated(self): pass def createIntroPage(self): page = QWizardPage() page.setTitle("Introduction") label = QLabel("This wizard will show you a simple wizard.") label.setWordWrap(True) label2 = QLabel("Therefore it will create a Sine plugin, a plot and connect these two.") label2.setWordWrap(True) layout = QVBoxLayout() layout.addWidget(label) layout.addWidget(label2) page.setLayout(layout) return page
class Window(QWidget): def __init__(self): super().__init__() self.title = "PyQt5 Wizard" self.top = 200 self.left = 500 self.width = 400 self.height = 300 self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon("icon.png")) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) vbox = QVBoxLayout() button = QPushButton("Launch") button.clicked.connect(self.btn_clicked) vbox.addWidget(button) self.setLayout(vbox) self.wizard = QWizard() self.wizard.setWindowTitle("Launcher Page") page1 = QWizardPage() page1.setTitle("p11111") page2 = QWizardPage() page2.setTitle("page 2") self.wizard.addPage(page1) self.wizard.addPage(page2) self.show() def btn_clicked(self): self.wizard.open()
def showDialog(self): # Initialise the setup directory empty toavoid exceptions. self.setupDictionary = {} # ask for a project directory. self.projectDirectory = QFileDialog.getExistingDirectory( caption=i18n("Where should the comic project go?"), options=QFileDialog.ShowDirsOnly) if os.path.exists(self.projectDirectory) is False: return self.pagesDirectory = os.path.relpath(self.projectDirectory, self.projectDirectory) self.exportDirectory = os.path.relpath(self.projectDirectory, self.projectDirectory) wizard = QWizard() wizard.setWindowTitle(i18n("Comic Project Setup")) wizard.setOption(QWizard.IndependentPages, True) # Set up the UI for the wizard basicsPage = QWizardPage() basicsPage.setTitle(i18n("Basic Comic Project Settings")) formLayout = QFormLayout() basicsPage.setLayout(formLayout) projectLayout = QHBoxLayout() self.lnProjectName = QLineEdit() basicsPage.registerField("Project Name*", self.lnProjectName) self.lnProjectName.setToolTip( i18n( "A Project name. This can be different from the eventual title" )) btnRandom = QPushButton() btnRandom.setText(i18n("Generate")) btnRandom.setToolTip( i18n( "If you cannot come up with a project name, our highly sophisticated project name generator will serve to give a classy yet down to earth name." )) btnRandom.clicked.connect(self.slot_generate) projectLayout.addWidget(self.lnProjectName) projectLayout.addWidget(btnRandom) lnConcept = QLineEdit() lnConcept.setToolTip( i18n( "What is your comic about? This is mostly for your own convenience so don't worry about what it says too much." )) self.cmbLanguage = comics_metadata_dialog.language_combo_box() self.cmbLanguage.setToolTip(i18n("The main language the comic is in")) self.cmbLanguage.setEntryToCode( str(QLocale.system().name()).split("_")[0]) self.lnProjectDirectory = QLabel(self.projectDirectory) self.chkMakeProjectDirectory = QCheckBox( i18n("Make a new directory with the project name.")) self.chkMakeProjectDirectory.setToolTip( i18n( "This allows you to select a generic comics project directory, in which a new folder will be made for the project using the given project name." )) self.chkMakeProjectDirectory.setChecked(True) self.lnPagesDirectory = QLineEdit() self.lnPagesDirectory.setText(i18n("pages")) self.lnPagesDirectory.setToolTip( i18n( "The name for the folder where the pages are contained. If it doesn't exist, it will be created." )) self.lnExportDirectory = QLineEdit() self.lnExportDirectory.setText(i18n("export")) self.lnExportDirectory.setToolTip( i18n( "The name for the folder where the export is put. If it doesn't exist, it will be created." )) self.lnTemplateLocation = QLineEdit() self.lnTemplateLocation.setText(i18n("templates")) self.lnTemplateLocation.setToolTip( i18n( "The name for the folder where the page templates are sought in." )) self.lnTranslationLocation = QLineEdit() self.lnTranslationLocation.setText(i18n("translations")) self.lnTranslationLocation.setToolTip( "This is the location that POT files will be stored to and PO files will be read from." ) formLayout.addRow(i18n("Comic Concept:"), lnConcept) formLayout.addRow(i18n("Project Name:"), projectLayout) formLayout.addRow(i18n("Main Language:"), self.cmbLanguage) buttonMetaData = QPushButton(i18n("Meta Data")) buttonMetaData.clicked.connect(self.slot_edit_meta_data) wizard.addPage(basicsPage) foldersPage = QWizardPage() foldersPage.setTitle(i18n("Folder names and other.")) folderFormLayout = QFormLayout() foldersPage.setLayout(folderFormLayout) folderFormLayout.addRow(i18n("Project Directory:"), self.lnProjectDirectory) folderFormLayout.addRow("", self.chkMakeProjectDirectory) folderFormLayout.addRow(i18n("Pages Directory"), self.lnPagesDirectory) folderFormLayout.addRow(i18n("Export Directory"), self.lnExportDirectory) folderFormLayout.addRow(i18n("Template Directory"), self.lnTemplateLocation) folderFormLayout.addRow(i18n("Translation Directory"), self.lnTranslationLocation) folderFormLayout.addRow("", buttonMetaData) wizard.addPage(foldersPage) # Execute the wizard, and after wards... if (wizard.exec_()): # First get the directories, check if the directories exist, and otherwise make them. self.pagesDirectory = self.lnPagesDirectory.text() self.exportDirectory = self.lnExportDirectory.text() self.templateLocation = self.lnTemplateLocation.text() self.translationLocation = self.lnTranslationLocation.text() projectPath = Path(self.projectDirectory) # Only make a project directory if the checkbox for that has been checked. if self.chkMakeProjectDirectory.isChecked(): projectPath = projectPath / self.lnProjectName.text() if projectPath.exists() is False: projectPath.mkdir() self.projectDirectory = str(projectPath) if Path(projectPath / self.pagesDirectory).exists() is False: Path(projectPath / self.pagesDirectory).mkdir() if Path(projectPath / self.exportDirectory).exists() is False: Path(projectPath / self.exportDirectory).mkdir() if Path(projectPath / self.templateLocation).exists() is False: Path(projectPath / self.templateLocation).mkdir() if Path(projectPath / self.translationLocation).exists() is False: Path(projectPath / self.translationLocation).mkdir() # Then store the information into the setup diactionary. self.setupDictionary["projectName"] = self.lnProjectName.text() self.setupDictionary["concept"] = lnConcept.text() self.setupDictionary["language"] = str( self.cmbLanguage.codeForCurrentEntry()) self.setupDictionary["pagesLocation"] = self.pagesDirectory self.setupDictionary["exportLocation"] = self.exportDirectory self.setupDictionary["templateLocation"] = self.templateLocation self.setupDictionary[ "translationLocation"] = self.translationLocation # Finally, write the dictionary into the json file. self.writeConfig()
def createConclusionPage(): page = QWizardPage() page.setTitle("Conclusion") label = QLabel("You are now successfully registered. Have a nice day!") label.setWordWrap(True) layout = QVBoxLayout() layout.addWidget(label) page.setLayout(layout) return page if __name__ == '__main__': import sys app = QApplication(sys.argv) wizard = QWizard() wizard.addPage(createIntroPage()) wizard.addPage(createRegistrationPage()) wizard.addPage(createConclusionPage()) wizard.setWindowTitle("Trivial Wizard") wizard.show() sys.exit(app.exec_())
class WizardExample(vip_base): def createIntroPage(self): page = QWizardPage() page.setTitle("Introduction") label = QLabel("This wizard will show you a simple wizard.") label.setWordWrap(True) label2 = QLabel( "Therefore it will create a sinus plugin, a plot and connect these two." ) label2.setWordWrap(True) layout = QVBoxLayout() layout.addWidget(label) layout.addWidget(label2) page.setLayout(layout) return page def cb_initialize_plugin(self): #self.config = config # --------------------------- # Read configuration # --------------------------- # Note: this cfg items have to exist! # self.show_grid_x = int(self.config['x-grid']['value']) == '1' # self.show_grid_y = int(self.config['y-grid']['value']) == '1' # # int_re = re.compile(r'(\d+)') # # self.colors_selected = int_re.findall(self.config['color']['value']); # self.types_selected = int_re.findall(self.config['style']['value']); # -------------------------------- # Create Widget # -------------------------------- # Create Widget needed for this plugin self.wizardwidget = QWizard() self.wizardwidget.addPage(self.createIntroPage()) self.wizardwidget.addPage(sinPage(self.control_api)) self.wizardwidget.addPage(plotPage(self.control_api)) self.wizardwidget.addPage( connectPage(self.control_api, 'WizardExample')) # This call is important, because the background structure needs to know the used widget! # In the background the qmidiwindow will becreated and the widget will be added self.pl_set_widget_for_internal_usage(self.wizardwidget) self.wizardwidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.wizardwidget.customContextMenuRequested.connect( self.show_context_menu) return True def show_context_menu(self, pos): gloPos = self.wizardwidget.mapToGlobal(pos) self.cmenu = self.pl_create_control_context_menu() self.cmenu.exec_(gloPos) def cb_pause(self): # will be called, when plugin gets paused # can be used to get plugin in a defined state before pause # e.a. close communication ports, files etc. pass def cb_resume(self): # will be called when plugin gets resumed # can be used to wake up the plugin from defined pause state # e.a. reopen communication ports, files etc. pass def cb_execute(self, Data=None, block_name=None, plugin_uname=None): # Do main work here! # If this plugin is an IOP plugin, then there will be no Data parameter because it wont get data # If this plugin is a DPP, then it will get Data with data # param: Data is a Data hash and block_name is the block_name of Data origin # Data is a hash, so use ist like: Data[CORE_TIME_SIGNAL] = [t1, t2, ...] where CORE_TIME_SIGNAL is a signal_name # hash signal_name: value # Data could have multiple types stored in it e.a. Data['d1'] = int, Data['d2'] = [] pass def cb_set_parameter(self, name, value): # attetion: value is a string and need to be processed ! # if name == 'irgendeinParameter': # do that .... with value pass def cb_quit(self): # do something before plugin will close, e.a. close connections ... pass def cb_get_plugin_configuration(self): # # Implement a own part of the config # config is a hash of hass object # config_parameter_name : {} # config[config_parameter_name]['value'] NEEDS TO BE IMPLEMENTED # configs can be marked as advanced for create dialog # http://utilitymill.com/utility/Regex_For_Range # config = { # "amax": { # 'value': 3, # 'regex': '[0-9]+', # 'display_text' : 'This AMax', # 'advanced' : '1' # }, 'f': { # 'value': "1", # 'regex': '\d+.{0,1}\d*' # }} config = {} return config def cb_plugin_meta_updated(self): """ Whenever the meta information is updated this function is called (if implemented). :return: """ #dplugin_info = self.dplugin_info pass
class Twitter(InputPlugin): name = 'twitter' hasWizard = True hasLocationBasedMode = True hasRateLimitInfo = True def __init__(self): # Try and read the labels file labels_config = self.getConfigObj(self.name + '.labels') try: self.labels = labels_config['labels'] except Exception as err: self.labels = None logger.error('Could not load the labels file for the ' + self.name + ' plugin .') logger.error(err) self.config, self.options_string = self.readConfiguration( 'string_options') self.options_boolean = self.readConfiguration('boolean_options')[1] self.api = None self.wizard = QWizard() def searchForTargets(self, search_term): possibleTargets = [] logger.debug( 'Searching for Targets from Twitter Plugin. Search term is : ' + search_term) try: if self.api is None: self.api = self.getAuthenticatedAPI() search_results = self.api.search_users(q=search_term) if search_results: logger.debug('Twitter returned ' + str(len(search_results)) + ' results') for i in search_results: if self.options_boolean[ 'exclude_geo_disabled'] == 'True' and not i.geo_enabled: continue target = {'pluginName': 'Twitter Plugin'} target['targetUserid'] = i.id_str target['targetUsername'] = i.screen_name target['targetPicture'] = 'profile_pic_%s' % i.id_str target['targetFullname'] = i.name # save the pic in the temp folder to show it later filename = 'profile_pic_%s' % i.id_str temp_file = os.path.join(GeneralUtilities.getTempDir(), filename) # Retieve and save the profile phot only if it does not exist if not os.path.exists(temp_file): urllib.urlretrieve(i.profile_image_url, temp_file) possibleTargets.append(target) except tweepy.TweepError as e: logger.error('Error authenticating with Twitter API.') logger.error(e) if e.response.status_code == 429: remaining, limit, reset = self.getRateLimitStatus( 'search_users') return False, 'Error authenticating with Twitter: {0}. Your limits will be renewed at : {1}'.format( e.message, reset.strftime('%Y-%m-%d %H:%M:%S %z')) return False, 'Error authenticating with Twitter: {0}'.format( e.message) except Exception as err: logger.error(err) logger.error('Error searching for targets in Twitter plugin.') return possibleTargets def getAuthenticatedAPI(self): try: auth = tweepy.auth.OAuthHandler( self.options_string['hidden_application_key'], self.options_string['hidden_application_secret']) auth.set_access_token( self.options_string['hidden_access_token'], self.options_string['hidden_access_token_secret']) return tweepy.API(auth) except Exception as e: logger.error(e) return None def runConfigWizard(self): try: oAuthHandler = tweepy.OAuthHandler( self.options_string['hidden_application_key'], self.options_string['hidden_application_secret']) authorizationURL = oAuthHandler.get_authorization_url(True) self.wizard.setWindowTitle('Twitter plugin configuration wizard') page1 = QWizardPage() page2 = QWizardPage() layout1 = QVBoxLayout() layout2 = QVBoxLayout() layoutInputPin = QHBoxLayout() label1a = QLabel( 'Click next to connect to twitter.com . Please login with your account and follow the instructions in ' 'order to authorize creepy') label2a = QLabel( 'Copy the PIN that you will receive once you authorize cree.py in the field below and click finish' ) pinLabel = QLabel('PIN') inputPin = QLineEdit() inputPin.setObjectName('inputPin') analysisHtml = QWebEngineView() analysisHtml.load(QUrl(authorizationURL)) layout1.addWidget(label1a) layout2.addWidget(analysisHtml) layout2.addWidget(label2a) layoutInputPin.addWidget(pinLabel) layoutInputPin.addWidget(inputPin) layout2.addLayout(layoutInputPin) page1.setLayout(layout1) page2.setLayout(layout2) page2.registerField('inputPin*', inputPin) self.wizard.addPage(page1) self.wizard.addPage(page2) self.wizard.resize(800, 600) if self.wizard.exec_(): try: oAuthHandler.get_access_token( str(self.wizard.field('inputPin').toString()).strip()) self.options_string[ 'hidden_access_token'] = oAuthHandler.access_token self.options_string[ 'hidden_access_token_secret'] = oAuthHandler.access_token_secret self.saveConfiguration(self.config) except Exception as err: logger.error(err) self.showWarning( 'Error completing the wizard', 'We were unable to obtain the access token for your account, please try to run ' 'the wizard again. Error was {0}'.format(err.message)) except Exception as err: logger.error(err) self.showWarning('Error completing the wizard', 'Error was: {0}'.format(err.message)) def showWarning(self, title, text): try: QMessageBox.warning(self.wizard, title, text, None) except Exception as err: logger.error(err) def getAuthorizationURL(self): """ :return: the authorization URL for Twitter or None if there was an exception """ try: if not self.options_string: self.options_string = self.readConfiguration( 'string_options')[1] oAuthHandler = tweepy.OAuthHandler( self.options_string['hidden_application_key'], self.options_string['hidden_application_secret']) authorizationURL = oAuthHandler.get_authorization_url(True) return authorizationURL except Exception as err: logger.error(err) return None def isConfigured(self): """ :return: a tuple. The first element is True or False, depending if the plugin is configured or not. The second element contains an optional message for the user """ try: if not self.options_string: self.options_string = self.readConfiguration( 'string_options')[1] if self.api is None: oAuthHandler = tweepy.OAuthHandler( self.options_string['hidden_application_key'], self.options_string['hidden_application_secret']) oAuthHandler.set_access_token( self.options_string['hidden_access_token'], self.options_string['hidden_access_token_secret']) self.api = tweepy.API(oAuthHandler) logger.debug(self.api.me().name) return True, '' except tweepy.TweepError as e: logger.error('Error authenticating with Twitter API.') logger.error(e) return False, 'Error authenticating with Twitter. ' + e.message except Exception as e: logger.error('Error authenticating with Twitter API.') logger.error(e) return False, 'Error authenticating with Twitter. ' + e.message def returnAnalysis(self, target, search_params): """ :param target: :param search_params: :return: """ conversionResult = False formalTimezoneName = '' locations_list = [] twitterDiv = div(id='twitter') twitterDiv += h2('Twitter profile information') incl_rts = search_params['boolean']['include_retweets'] excl_rpls = search_params['boolean']['exclude_replies'] if not self.api: self.api = self.getAuthenticatedAPI() try: logger.debug('Attempting to retrieve profile information for ' + target['targetUsername']) userObject = self.api.get_user(user_id=target['targetUserid']) twitterDiv += p('Account was created on {0}'.format( userObject.created_at.strftime('%Y-%m-%d %H:%M:%S %z'))) if userObject.statuses_count: twitterDiv += p( 'The user has tweeted {0} times ( including retweets ).'. format(str(userObject.statuses_count))) if userObject.name: twitterDiv += p(u'Self-reported real name: {0}'.format( userObject.name)) if userObject.description: twitterDiv += p(u'Description: {0}'.format( userObject.description)) if userObject.location: twitterDiv += p(u'Self-reported location: {0}'.format( userObject.location)) if userObject.time_zone: conversionResult, formalTimezoneName = self.getTimezoneNameFromReported( userObject.time_zone) if conversionResult: twitterDiv += p(u'Self-reported time zone: {0}'.format( formalTimezoneName)) else: twitterDiv += p(u'Self-reported time zone: {0}'.format( userObject.time_zone)) if userObject.geo_enabled: twitterDiv += p( 'User has enabled the possibility to geolocate their tweets.' ) else: twitterDiv += p( 'User has disabled the possibility to geolocate their tweets.' ) if userObject.followers_count: twitterDiv += p('The user has {0} followers.'.format( str(userObject.followers_count))) if userObject.friends_count: twitterDiv += p('The user is following {0} users.'.format( str(userObject.friends_count))) if userObject.listed_count: twitterDiv += p( 'The user is listed in {0} public lists.'.format( str(userObject.listed_count))) logger.debug('Attempting to retrieve the tweets for user ' + target['targetUsername']) tweets = Cursor(self.api.user_timeline, count=100, user_id=target['targetUserid'], exclude_replies=excl_rpls, include_rts=incl_rts).items() timestamps = [] repliedTo = [] retweeted = [] clientApplications = [] mentioned = [] hashtags = [] for j in tweets: finalDateTimeObj = pytz.utc.localize(j.created_at) if conversionResult: createdUtcTimezone = pytz.utc.localize(j.created_at) try: userTimezone = pytz.timezone(formalTimezoneName) createdUserTimezone = userTimezone.normalize( createdUtcTimezone.astimezone(userTimezone)) timestamps.append(createdUserTimezone) finalDateTimeObj = createdUserTimezone except Exception: finalDateTimeObj = createdUtcTimezone timestamps.append(createdUtcTimezone) else: timestamps.append(pytz.utc.localize(j.created_at)) if j.in_reply_to_screen_name: repliedTo.append(j.in_reply_to_screen_name) if hasattr(j, 'retweeted_status'): retweeted.append(j.retweeted_status.user.name) if j.source: clientApplications.append(j.source) if j.entities: if hasattr(j, 'entities.user_mentions'): for mention in j.entities.user_mentions: mentioned.append(mention.screen_name) if hasattr(j, 'hashtags'): for hashtag in j.entities.hashtags: hashtags.append(hashtag.text) loc = self.buildLocationFromTweet(j, finalDateTimeObj) if loc: locations_list.append(loc) logger.debug( '{0} locations were retrieved from Twitter Plugin'.format( len(locations_list))) if len(repliedTo) > 0: twitterDiv += p('User has replied to the following users : ') repliedToTable = self.createFrequencyTableFromCounter( Counter(repliedTo), 'User screen name', 'repliedToTable', 10) twitterDiv += repliedToTable if len(retweeted) > 0: twitterDiv += p('User has retweeted the following users : ') retweetedTable = self.createFrequencyTableFromCounter( Counter(retweeted), 'User screen name', 'retweetedTable', 10) twitterDiv += retweetedTable if len(mentioned) > 0: twitterDiv += p('User has mentioned the following users : ') mentionedTable = self.createFrequencyTableFromCounter( Counter(mentioned), 'User screen name', 'mentionedTable', 10) twitterDiv += mentionedTable if len(clientApplications) > 0: twitterDiv += p('User has been using the following clients : ') clientApplicationsTable = self.createFrequencyTableFromCounter( Counter(clientApplications), 'Client Application', 'clientApplicationsTable', 10) twitterDiv += clientApplicationsTable if len(hashtags) > 0: twitterDiv += p('User has used the following hashtags : ') hashtagsTable = self.createFrequencyTableFromCounter( Counter(hashtags), 'Hashtag', 'hashtagsTable', 10) twitterDiv += hashtagsTable if len(timestamps) > 0: twitterDiv += p('User tweets time frequency: ') hourPeriodsTable = self.createFrequencyTableFromList( self.getTimeChunksFrequency(timestamps, 8), 'Hour Period', 'hourPeriodsTable') twitterDiv += hourPeriodsTable twitterDiv += p( 'User has been twitting at the following times : ') hoursTable = self.createFrequencyTableFromCounter( Counter([d.hour for d in timestamps]), 'Hour', 'hoursTable', 24) twitterDiv += hoursTable except tweepy.TweepError as e: logger.error('Error authenticating with Twitter API.') logger.error(e) if e.response.status_code == 429: remaining, limit, reset = self.getRateLimitStatus( 'user_timeline') logger.error( 'Error getting locations from twitter plugin: {0}. Your limits will be renewed at : {1}' .format(e.message, reset.strftime('%Y-%m-%d %H:%M:%S %z'))) except Exception as e: logger.error(e) logger.error('Error getting locations from twitter plugin') return locations_list, twitterDiv def searchForResultsNearPlace(self, geocode): locations_list = [] logger.debug( 'Attempting to retrieve tweets around {0}'.format(geocode)) try: if self.api is None: self.api = self.getAuthenticatedAPI() # Min Radius is 1km, convert m to km and set it to 1km if it is less than that if not geocode.split(',')[2].endswith('km'): if int(geocode.split(',')[2].replace('m', '')) < 1000: geocode = ','.join(geocode.split(',')[:2]) + ',1km' else: radius = int(geocode.split(',')[2].replace('m', '')) / 1000 geocode = ','.join( geocode.split(',')[:2]) + ',{0}km'.format(radius) tweets = Cursor(self.api.search, count=100, q='*', geocode=geocode, result_type='recent').items() for tweet in tweets: finalDateTimeObj = pytz.utc.localize(tweet.created_at) loc = self.buildLocationFromTweet(tweet, finalDateTimeObj) if loc: locations_list.append(loc) except tweepy.TweepError as e: logger.error('Error authenticating with Twitter API.') logger.error(e) if e.response.status_code == 429: remaining, limit, reset = self.getRateLimitStatus( 'search_near_location') logger.error( 'Error getting locations from twitter plugin: {0}. Your limits will be renewed at : {1}' .format(e.message, reset.strftime('%Y-%m-%d %H:%M:%S %z'))) except Exception as e: logger.error(e) logger.error('Error getting locations from twitter plugin') return locations_list def getRateLimitStatus(self, query): try: if self.api is None: self.api = self.getAuthenticatedAPI() reply = self.api.rate_limit_status() if query == 'search_users': return reply['resources']['users']['/users/search']['remaining'], \ reply['resources']['users']['/users/search']['limit'], \ datetime.fromtimestamp(reply['resources']['users']['/users/search']['reset']) elif query == 'search_near_location': return reply['resources']['search']['/search/tweets']['remaining'], \ reply['resources']['search']['/search/tweets']['limit'], \ datetime.fromtimestamp(reply['resources']['search']['/search/tweets']['reset']) elif query == 'user_timeline': return reply['resources']['statuses']['/statuses/user_timeline']['remaining'], \ reply['resources']['statuses']['/statuses/user_timeline']['limit'], \ datetime.fromtimestamp(reply['resources']['statuses']['/statuses/user_timeline']['reset']) elif query == 'all': return reply['resources']['users']['/users/search'], reply['resources']['search']['/search/tweets'], \ reply['resources']['statuses']['/statuses/user_timeline'] except Exception as e: logger.error(e) logger.error('Error getting rate limit status from twitter plugin') def buildLocationFromTweet(self, tweet, finalDateTimeObj): """ First Handle the coordinates return field Twitter API returns GeoJSON, see http://www.geojson.org/geojson-spec.html for the spec We don't handle MultiPoint, LineString, MultiLineString, MultiPolygon and Geometry Collection """ loc = {} loc['plugin'] = 'twitter' loc['username'] = tweet.user.screen_name loc['context'] = tweet.text loc['date'] = finalDateTimeObj loc['infowindow'] = self.constructContextInfoWindow( tweet, finalDateTimeObj) if tweet.coordinates and tweet.place: if tweet.coordinates['type'] == 'Point': loc['lat'] = tweet.coordinates['coordinates'][1] loc['lon'] = tweet.coordinates['coordinates'][0] loc['shortName'] = tweet.place.name loc['accuracy'] = 'high' elif tweet.coordinates.type == 'PolyGon': c = self.getCenterOfPolygon(tweet.coordinates['coordinates']) loc['lat'] = c[1] loc['lon'] = c[0] loc['shortName'] = tweet.place.name loc['accuracy'] = 'low' return loc elif tweet.place and not tweet.coordinates: if tweet.place.bounding_box.type == 'Point': loc['lat'] = tweet.place.bounding_box.coordinates[1] loc['lon'] = tweet.place.bounding_box.coordinates[0] loc['shortName'] = tweet.place.name loc['accuracy'] = 'high' elif tweet.place.bounding_box.type == 'Polygon': c = self.getCenterOfPolygon( tweet.place.bounding_box.coordinates[0]) loc['lat'] = c[1] loc['lon'] = c[0] loc['shortName'] = tweet.place.name loc['accuracy'] = 'low' return loc else: return {} def getTimeChunksFrequency(self, timestamps, chunkSize): hourFreq = Counter([d.hour for d in timestamps]) hourPeriods = self.sliceLinkedList(range(24), chunkSize) hourPeriodTotals = [] for hPeriod in hourPeriods: totalTweets = 0 for hour in hPeriod: totalTweets += hourFreq[hour] hourPeriodTotals.append( ('{0}-{1}'.format(str(hPeriod[0]), str(hPeriod[-1])), totalTweets)) hourPeriodTotals.sort(key=lambda x: x[1], reverse=True) return hourPeriodTotals def createFrequencyTableFromList(self, lst, objectName, tableName): objectTable = table(id=tableName, cls='pure-table pure-table-bordered') head = thead() head.add(th(objectName)) head.add(th('Count')) objectTable.add(head) objectTable.add(tbody()) for item in lst: row = tr() row.add(td(item[0])) row.add(td(item[1])) objectTable.add(row) return objectTable def createFrequencyTableFromCounter(self, counter, objectName, tableName, itemsCount): objectTable = table(id=tableName, cls='pure-table pure-table-bordered') head = thead() head.add(th(objectName)) head.add(th('Count')) objectTable.add(head) objectTable.add(tbody()) for item in counter.most_common(itemsCount): row = tr() row.add(td(item[0])) row.add(td(item[1])) objectTable.add(row) return objectTable def constructContextInfoWindow(self, tweet, finalDateTimeObj): html = unicode(self.options_string['infowindow_html']) # returned value also becomes unicode since tweet.text is unicode, and carries the encoding also return html.replace('@TEXT@', tweet.text). \ replace('@DATE@', finalDateTimeObj.strftime('%Y-%m-%d %H:%M:%S %z')). \ replace('@PLUGIN@', u'twitter').replace('@USERNAME@', tweet.user.screen_name). \ replace('@LINK@', 'https://twitter.com/statuses/{0}'.format(tweet.id_str)) def getCenterOfPolygon(self, coord): """ We need to get the "center" of the polygon. Accuracy is not a major aspect here since we originally got a polygon, so there was not much accuracy to start with. We convert the polygon to a rectangle by selecting 4 points : a) Point with the Lowest latitude b) Point with the Highest Latitude c) Point with the Lowest Longitude d) Point with the Highest Longitude and then get the center of this rectangle as the point to draw on the map """ lat_list = [] lon_list = [] for j in coord: lon_list.append(j[0]) lat_list.append(j[1]) lon_list.sort() lat_list.sort() lat = float(lat_list[0]) + ( (float(lat_list[len(lat_list) - 1]) - float(lat_list[0])) / 2) lon = float(lon_list[0]) + ( (float(lon_list[len(lon_list) - 1]) - float(lon_list[0])) / 2) return lon, lat def getLabelForKey(self, key): """ read the plugin_name.labels file and try to get label text for the key that was asked """ if not self.labels: return key if key not in self.labels.keys(): return key return self.labels[key] def sliceLinkedList(self, lst, chunkSize): n = len(lst) for i in range(n): d = n - chunkSize - i if d > 0: yield lst[i:i + chunkSize:1] else: yield lst[i:] + lst[:-d] def getTimezoneNameFromReported(self, tzReported): allTimezones = pytz.all_timezones for timezone in allTimezones: if tzReported.lower() in timezone.lower(): return True, timezone return False, tzReported
class Instagram(InputPlugin): name = 'instagram' hasWizard = True hasLocationBasedMode = True hasRateLimitInfo = False def __init__(self): # Try and read the labels file labels_config = self.getConfigObj(self.name + '.labels') try: self.labels = labels_config['labels'] except Exception as err: self.labels = None logger.error('Could not load the labels file for the ' + self.name + ' plugin .') logger.error(err) self.config, self.options_string = self.readConfiguration( 'string_options') self.api = None self.wizard = QWizard() def getAuthenticatedAPI(self): return InstagramAPI( access_token=self.options_string['hidden_access_token']) def isConfigured(self): if self.api is None: self.api = self.getAuthenticatedAPI() try: self.api.user() return True, "" except Exception as err: return False, err.message def searchForTargets(self, search_term): logger.debug('Attempting to search for targets. Search term was : ' + search_term) possibleTargets = [] try: if self.api is None: self.api = self.getAuthenticatedAPI() results = self.api.user_search(q=search_term) for i in results: target = {'pluginName': 'Instagram Plugin'} target['targetUserid'] = i.id target['targetUsername'] = i.username target['targetPicture'] = 'profile_pic_%s' % i.id target['targetFullname'] = i.full_name # save the pic in the temp folder to show it later filename = 'profile_pic_%s' % i.id temp_file = os.path.join(GeneralUtilities.getTempDir(), filename) if not os.path.exists(temp_file): urllib.urlretrieve(i.profile_picture, temp_file) possibleTargets.append(target) logger.debug( str(len(possibleTargets)) + ' possible targets were found matching the search query') except Exception as err: logger.error('Error searching for targets with instagram plugin.') logger.error(err) return possibleTargets def getAllPhotos(self, uid, count, max_id, photos): if self.api is None: self.api = self.getAuthenticatedAPI() new_photos, next1 = self.api.user_recent_media(user_id=uid, count=count, max_id=max_id) if new_photos: photos.extend(new_photos) if not next1: logger.debug('Retrieved {0} photos from instagram.'.format( len(photos))) return photos else: a = parse_qs(urlparse(next1).query) return self.getAllPhotos(uid, count, a['max_id'][0], photos) def searchForResultsNearPlace(self, geocode): logger.debug( 'Attempting to retrieve all photos around {0} from instagram'. format(geocode)) locations_list = [] try: if self.api is None: self.api = self.getAuthenticatedAPI() if geocode.split(',')[2].endswith('km'): distance = int(geocode.split(',')[2].replace('km', '')) * 1000 else: distance = int(geocode.split(',')[2].replace('m', '')) # Set defaults if distance == 0 or distance > 5000: distance = 1000 photos_list = self.api.media_search(q='*', distance=geocode.split(',')[2], count=200, lat=geocode.split(',')[0], lng=geocode.split(',')[1]) for i in photos_list: if hasattr(i, 'location'): loc = {} loc['plugin'] = 'instagram' loc['username'] = i.user.username loc['context'] = i.caption.text if i.caption else str( 'No Caption', 'utf-8') loc['infowindow'] = self.constructContextInfoWindow( i, i.user.username) loc['date'] = pytz.utc.localize(i.created_time) loc['lat'] = i.location.point.latitude loc['lon'] = i.location.point.longitude loc['media_url'] = i.get_low_resolution_url() loc['shortName'] = i.location.name if len(str(loc['lat'])) < 4 and len(str(loc['lon'])) < 4: loc['accuracy'] = 'low' else: loc['accuracy'] = 'high' locations_list.append(loc) logger.debug( str(len(locations_list)) + ' photos have been retrieved') except Exception as err: logger.error(err) logger.error('Error getting locations from instagram plugin') return locations_list def returnAnalysis(self, target, search_params): logger.debug('Attempting to retrieve all photos for user ' + target['targetUsername']) locations_list = [] try: if self.api is None: self.api = self.getAuthenticatedAPI() photos_list = self.getAllPhotos(target['targetUserid'], 200, None, []) for i in photos_list: if hasattr(i, 'location'): loc = {} loc['plugin'] = 'instagram' loc['username'] = i.user.username loc['context'] = i.caption.text if i.caption else str( 'No Caption', 'utf-8') loc['infowindow'] = self.constructContextInfoWindow( i, target['targetUsername']) loc['date'] = pytz.utc.localize(i.created_time) loc['lat'] = i.location.point.latitude loc['lon'] = i.location.point.longitude loc['media_url'] = i.get_low_resolution_url() loc['shortName'] = i.location.name if len(str(loc['lat'])) < 4 and len(str(loc['lon'])) < 4: loc['accuracy'] = 'low' else: loc['accuracy'] = 'high' loc['accuracy'] = 'high' locations_list.append(loc) logger.debug('{0} locations have been retrieved'.format( len(locations_list))) except Exception as err: logger.error(err) logger.error('Error getting locations from instagram plugin') return locations_list, None def openLinkInBrowser(self, link): webbrowser.open(link, new=1) def runConfigWizard(self): try: api = InstagramAPI( client_id=self.options_string['hidden_client_id'], client_secret=self.options_string['hidden_client_secret'], redirect_uri=self.options_string['redirect_uri']) url = api.get_authorize_login_url() self.wizard.setWindowTitle('Instagram plugin configuration wizard') page1 = QWizardPage() layout1 = QVBoxLayout() txtArea = QLabel() txtArea.setText( 'Please copy the following link to your browser window. \n ' + 'Once you authenticate with Instagram you will be redirected to ' + 'www.geocreepy.com and get your token. Copy the token to the input field below:' ) urlArea = QLineEdit() urlArea.setObjectName('urlArea') urlArea.setText(url) inputLink = QLineEdit() inputLink.setObjectName('inputLink') labelLink = QLabel('Your token value:') openInBrowserButton = QPushButton('Open in browser') openInBrowserButton.clicked.connect( functools.partial(self.openLinkInBrowser, url)) layout1.addWidget(txtArea) layout1.addWidget(urlArea) layout1.addWidget(openInBrowserButton) layout1.addWidget(labelLink) layout1.addWidget(inputLink) page1.setLayout(layout1) self.wizard.addPage(page1) self.wizard.resize(600, 400) if self.wizard.exec_(): c = str(inputLink.text()) if c: try: access_token = api.exchange_code_for_access_token( code=c) self.options_string[ 'hidden_access_token'] = access_token[0] self.saveConfiguration(self.config) except Exception as err: logger.error(err) self.showWarning( 'Error Getting Access Token', 'Please verify that the link you pasted was correct. ' 'Try running the wizard again.') else: self.showWarning( 'Error Getting Access Token', 'Please verify that the link you pasted was correct. Try running the wizard again.' ) except Exception as err: logger.error(err) self.showWarning('Error', 'Error was {0}'.format(err)) def parseRedirectUrl(self, link): try: return parse_qs(urlparse(link).query)['code'][0] except Exception as err: logger.error(err) return None def showWarning(self, title, text): QMessageBox.warning(self.wizard, title, text, None) def constructContextInfoWindow(self, photo, username): html = str(self.options_string['infowindow_html'], 'utf-8') caption = photo.caption.text if photo.caption else str( 'No Caption', 'utf-8') return html.replace('@TEXT@', caption).replace( "@DATE@", pytz.utc.localize( photo.created_time).strftime('%Y-%m-%d %H:%M:%S %z')).replace( '@PLUGIN@', u'instagram').replace('@LINK@', photo.link).replace( '@MEDIA_URL@', photo.get_low_resolution_url()).replace( '@USERNAME@', username) def getLabelForKey(self, key): """ read the plugin_name.labels file and try to get label text for the key that was asked """ if not self.labels: return key if key not in self.labels.keys(): return key return self.labels[key]
class WizardExample(vip_base): def createIntroPage(self): page = QWizardPage() page.setTitle("Introduction") label = QLabel("This wizard will show you a simple wizard.") label.setWordWrap(True) label2 = QLabel("Therefore it will create a sinus plugin, a plot and connect these two.") label2.setWordWrap(True) layout = QVBoxLayout() layout.addWidget(label) layout.addWidget(label2) page.setLayout(layout) return page def cb_initialize_plugin(self): # self.config = config # --------------------------- # Read configuration # --------------------------- # Note: this cfg items have to exist! # self.show_grid_x = int(self.config['x-grid']['value']) == '1' # self.show_grid_y = int(self.config['y-grid']['value']) == '1' # # int_re = re.compile(r'(\d+)') # # self.colors_selected = int_re.findall(self.config['color']['value']); # self.types_selected = int_re.findall(self.config['style']['value']); # -------------------------------- # Create Widget # -------------------------------- # Create Widget needed for this plugin self.wizardwidget = QWizard() self.wizardwidget.addPage(self.createIntroPage()) self.wizardwidget.addPage(sinPage(self.control_api)) self.wizardwidget.addPage(plotPage(self.control_api)) self.wizardwidget.addPage(connectPage(self.control_api, "WizardExample")) # This call is important, because the background structure needs to know the used widget! # In the background the qmidiwindow will becreated and the widget will be added self.pl_set_widget_for_internal_usage(self.wizardwidget) self.wizardwidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.wizardwidget.customContextMenuRequested.connect(self.show_context_menu) return True def show_context_menu(self, pos): gloPos = self.wizardwidget.mapToGlobal(pos) self.cmenu = self.pl_create_control_context_menu() self.cmenu.exec_(gloPos) def cb_pause(self): # will be called, when plugin gets paused # can be used to get plugin in a defined state before pause # e.a. close communication ports, files etc. pass def cb_resume(self): # will be called when plugin gets resumed # can be used to wake up the plugin from defined pause state # e.a. reopen communication ports, files etc. pass def cb_execute(self, Data=None, block_name=None, plugin_uname=None): # Do main work here! # If this plugin is an IOP plugin, then there will be no Data parameter because it wont get data # If this plugin is a DPP, then it will get Data with data # param: Data is a Data hash and block_name is the block_name of Data origin # Data is a hash, so use ist like: Data[CORE_TIME_SIGNAL] = [t1, t2, ...] where CORE_TIME_SIGNAL is a signal_name # hash signal_name: value # Data could have multiple types stored in it e.a. Data['d1'] = int, Data['d2'] = [] pass def cb_set_parameter(self, name, value): # attetion: value is a string and need to be processed ! # if name == 'irgendeinParameter': # do that .... with value pass def cb_quit(self): # do something before plugin will close, e.a. close connections ... pass def cb_get_plugin_configuration(self): # # Implement a own part of the config # config is a hash of hass object # config_parameter_name : {} # config[config_parameter_name]['value'] NEEDS TO BE IMPLEMENTED # configs can be marked as advanced for create dialog # http://utilitymill.com/utility/Regex_For_Range # config = { # "amax": { # 'value': 3, # 'regex': '[0-9]+', # 'display_text' : 'This AMax', # 'advanced' : '1' # }, 'f': { # 'value': "1", # 'regex': '\d+.{0,1}\d*' # }} config = {} return config def cb_plugin_meta_updated(self): """ Whenever the meta information is updated this function is called (if implemented). :return: """ # dplugin_info = self.dplugin_info pass