diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 83107598..011f4789 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -369,12 +369,28 @@ class AppWindow: except: pass - def system_change(self, system, timestamp): + def system_change(self, timestamp, system): if self.system['text'] != system: - # TODO: EDSM lookup and csv and/or EDSM log - self.system['text'] = system - self.station['text'] = EDDB.system(system) and self.STATION_UNDOCKED or '' - self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(timestamp)).decode('utf-8') + try: + self.system['text'] = system + self.system['image'] = '' + self.station['text'] = EDDB.system(system) and self.STATION_UNDOCKED or '' + if config.getint('output') & config.OUT_LOG_FILE: + flightlog.writelog(timestamp, system) + if config.getint('output') & config.OUT_LOG_EDSM: + self.status['text'] = _('Sending data to EDSM...') + self.w.update_idletasks() + edsm.writelog(timestamp, system, lambda:self.edsm.lookup(system, EDDB.system(system))) # Do EDSM lookup during EDSM export + else: + self.edsm.start_lookup(system, EDDB.system(system)) + self.edsmpoll() + self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(timestamp)).decode('utf-8') + except Exception as e: + if __debug__: print_exc() + self.status['text'] = unicode(e) + if not config.getint('hotkey_mute'): + hotkeymgr.play_bad() + def edsmpoll(self): result = self.edsm.result @@ -412,6 +428,7 @@ class AppWindow: self.w.clipboard_append(self.station['text'] == self.STATION_UNDOCKED and self.system['text'] or '%s,%s' % (self.system['text'], self.station['text'])) def onexit(self, event=None): + flightlog.close() if platform!='darwin' or self.w.winfo_rooty()>0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+'))) config.close() diff --git a/edsm.py b/edsm.py index f10523b0..a3fab9f1 100644 --- a/edsm.py +++ b/edsm.py @@ -109,11 +109,16 @@ def export(data, edsmlookupfn): querytime = config.getint('querytime') or int(time.time()) + writelog(querytime, data['lastSystem']['name'], edsmlookupfn) + + +def writelog(timestamp, system, edsmlookupfn): + try: # Look up the system before adding it to the log, since adding it to the log has the side-effect of creating it edsmlookupfn() - r = requests.get('http://www.edsm.net/api-logs-v1/set-log?commanderName=%s&apiKey=%s&systemName=%s&dateVisited=%s' % (urllib.quote(config.get('edsm_cmdrname')), urllib.quote(config.get('edsm_apikey')), urllib.quote(data['lastSystem']['name']), urllib.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(querytime)))), timeout=EDSM._TIMEOUT) + r = requests.get('http://www.edsm.net/api-logs-v1/set-log?commanderName=%s&apiKey=%s&systemName=%s&dateVisited=%s' % (urllib.quote(config.get('edsm_cmdrname')), urllib.quote(config.get('edsm_apikey')), urllib.quote(system), urllib.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(timestamp)))), timeout=EDSM._TIMEOUT) r.raise_for_status() reply = r.json() (msgnum, msg) = reply['msgnum'], reply['msg'] diff --git a/flightlog.py b/flightlog.py index d5ff7292..5d3c0c02 100644 --- a/flightlog.py +++ b/flightlog.py @@ -12,6 +12,8 @@ from companion import ship_map, commodity_map logfile = None +last_timestamp = last_system = last_ship = None +last_commodities = {} def openlog(): @@ -41,24 +43,55 @@ def export(data): querytime = config.getint('querytime') or int(time.time()) - openlog() - commodities = defaultdict(int) for item in data['ship'].get('cargo',{}).get('items',[]): if item['commodity'] != 'drones': commodities[commodity_map.get(item['commodity'], item['commodity'])] += item['qty'] + writelog(querytime, + data['lastSystem']['name'], + data['commander']['docked'] and data['lastStarport']['name'], + ship_map.get(data['ship']['name'].lower(), data['ship']['name']), + commodities) + + +def writelog(timestamp, system, station=None, ship=None, commodities={}): + + global last_timestamp, last_system, last_ship, last_commodities + if last_system and last_system != system: + _writelog(last_timestamp, last_system, None, last_ship, last_commodities) + + if not station: + # If not docked, hold off writing log entry until docked or until system changes + last_timestamp, last_system, last_ship, last_commodities = timestamp, system, ship, commodities + else: + last_system = None + _writelog(timestamp, system, station, ship, commodities) + + +def _writelog(timestamp, system, station=None, ship=None, commodities={}): + + openlog() + logfile.write('%s,%s,%s,%s,%s,%s\r\n' % ( - time.strftime('%Y-%m-%d', time.localtime(querytime)), - time.strftime('%H:%M:%S', time.localtime(querytime)), - data['lastSystem']['name'], - data['commander']['docked'] and data['lastStarport']['name'] or '', - ship_map.get(data['ship']['name'].lower(), data['ship']['name']), + time.strftime('%Y-%m-%d', time.localtime(timestamp)), + time.strftime('%H:%M:%S', time.localtime(timestamp)), + system, + station or '', + ship or '', ','.join([('%d %s' % (commodities[k], k)) for k in sorted(commodities)]))) logfile.flush() +def close(): + global last_timestamp, last_system + + if last_system: + _writelog(last_timestamp, last_system, None, last_ship, last_commodities) + last_system = None + + # return log as list of (timestamp, system_name) def logs(): entries = [] diff --git a/monitor.py b/monitor.py index 14869100..bc5b265f 100644 --- a/monitor.py +++ b/monitor.py @@ -133,17 +133,21 @@ class EDLogs: return False def start(self): - self.stop() if not self.logdir or not self.callback: + self.stop() return False + if self.running(): + return True self.observer = threading.Thread(target = self.worker, name = 'netLog worker') self.observer.daemon = True self.observer.start() + return True def stop(self): - if self.observer: - self.observer.stop() - self.observer = None + self.observer = None # Orphan the worker thread + + def running(self): + return self.observer and self.observer.is_alive() def worker(self): regexp = re.compile('{(.+)} System:[^\(]*\(([^\)]+)') @@ -158,6 +162,10 @@ class EDLogs: loghandle = None while True: + # Check whether we're still supposed to be running + if threading.current_thread() != self.observer: + return # Terminate + # Check whether new log file started, e.g. client restarted. Assumes logs sort alphabetically. logfiles = sorted([x for x in listdir(self.logdir) if x.startswith('netLog.')]) newlogfile = logfiles and logfiles[-1] or None @@ -183,9 +191,9 @@ class EDLogs: now = localtime() if now.tm_hour == 0 and visited_struct.tm_hour == 23: # Crossed midnight between timestamp and poll - now = localtime(time()-60) - datetime_struct = datetime(now.tm_year, now.tm_mon, now.tm_mday, visited_struct.tm_hour, visited_struct.tm_min, visited_struct.tm_sec).timetuple() # still local time - self.callback(system, mktime(datetime_struct)) + now = localtime(time()-12*60%60) # yesterday + time_struct = datetime(now.tm_year, now.tm_mon, now.tm_mday, visited_struct.tm_hour, visited_struct.tm_min, visited_struct.tm_sec).timetuple() # still local time + self.callback(mktime(time_struct), system) sleep(10) # New system gets posted to log file before hyperspace ends, so don't need to poll too often diff --git a/prefs.py b/prefs.py index 7511b1fe..78621b3e 100644 --- a/prefs.py +++ b/prefs.py @@ -199,9 +199,8 @@ class PreferencesDialog(tk.Toplevel): # Selectively disable buttons depending on output settings self.outvarchanged() - # disable hotkey and log monitoring for the duration + # disable hotkey for the duration hotkeymgr.unregister() - monitor.stop() # wait for window to appear on screen before calling grab_set self.wait_visibility() @@ -224,7 +223,7 @@ class PreferencesDialog(tk.Toplevel): self.out_log_auto_text['text'] = "Can't enable automatic logging!" # Shouldn't happen - don't translate self.out_log_auto_text.grid(row=10, padx=(25,5), sticky=tk.EW) elif monitor.restart_required(): - self.out_log_auto_text['text'] = _('Re-start Elite: Dangerous for automatic logging') # Output settings prompt + self.out_log_auto_text['text'] = _('Re-start Elite: Dangerous to use this feature') # Output settings prompt self.out_log_auto_text.grid(row=10, padx=(25,5), sticky=tk.EW) @@ -337,6 +336,8 @@ class PreferencesDialog(tk.Toplevel): if (config.getint('output') & config.OUT_LOG_AUTO) and (config.getint('output') & (config.OUT_LOG_AUTO|config.OUT_LOG_EDSM)): monitor.enable_logging() monitor.start() + else: + monitor.stop() self.destroy() if platform == 'darwin':