1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-13 15:57:14 +03:00

Option to automatically update on docking

Fixes #83
This commit is contained in:
Jonathan Harris 2016-07-17 18:48:12 +01:00
parent 25444410ab
commit e9ef32598d
12 changed files with 87 additions and 25 deletions

View File

@ -249,11 +249,11 @@ class AppWindow:
hotkeymgr.register(self.w, config.getint('hotkey_code'), config.getint('hotkey_mods'))
# Install log monitoring
monitor.set_callback(self.system_change)
monitor.set_callback('Dock', self.getandsend)
monitor.set_callback('Jump', self.system_change)
monitor.start(self.w)
edproxy.set_callback(self.system_change)
if (config.getint('output') & config.OUT_LOG_AUTO) and (config.getint('output') & (config.OUT_LOG_FILE|config.OUT_LOG_EDSM)):
monitor.start(self.w)
edproxy.start(self.w)
edproxy.start(self.w)
# First run
if not config.get('username') or not config.get('password'):
@ -497,7 +497,7 @@ class AppWindow:
except:
pass
def system_change(self, timestamp, system, coordinates):
def system_change(self, event, timestamp, system, coordinates):
if self.system['text'] != system:
self.system['text'] = system

View File

@ -28,6 +28,9 @@
/* Output setting. [prefs.py] */
"Automatically make a log entry on entering a system" = "Automaticky vytvořit záznam při vstoupení do systému";
/* Output setting. [prefs.py] */
"Automatically update on docking" = "Automaticky aktualizovat při zadokování";
/* Cmdr stats. [stats.py] */
"Balance" = "Zůstatek";

View File

@ -28,6 +28,9 @@
/* Output setting. [prefs.py] */
"Automatically make a log entry on entering a system" = "Automatisch Logbucheintrag bei Systemeintritt anlegen";
/* Output setting. [prefs.py] */
"Automatically update on docking" = "Automatisch beim Andocken aktualisieren";
/* Cmdr stats. [stats.py] */
"Balance" = "Kontostand";

View File

@ -28,6 +28,9 @@
/* Output setting. [prefs.py] */
"Automatically make a log entry on entering a system" = "Automatically make a log entry on entering a system";
/* Output setting. [prefs.py] */
"Automatically update on docking" = "Automatically update on docking";
/* Cmdr stats. [stats.py] */
"Balance" = "Balance";

View File

@ -28,6 +28,9 @@
/* Output setting. [prefs.py] */
"Automatically make a log entry on entering a system" = "Crear automáticamente una entrada en el registro al entrar en un sistema";
/* Output setting. [prefs.py] */
"Automatically update on docking" = "Actualizar automáticamente al atracar";
/* Cmdr stats. [stats.py] */
"Balance" = "Saldo";

View File

@ -28,6 +28,9 @@
/* Output setting. [prefs.py] */
"Automatically make a log entry on entering a system" = "別の星系に移動したら自動的にフライトログを記録する";
/* Output setting. [prefs.py] */
"Automatically update on docking" = "ドッキングした際に自動でデータを更新する";
/* Cmdr stats. [stats.py] */
"Balance" = "Balance";

View File

@ -28,6 +28,9 @@
/* Output setting. [prefs.py] */
"Automatically make a log entry on entering a system" = "Automatisch een log regel aanmaken bij het binnengaan van een stelsel";
/* Output setting. [prefs.py] */
"Automatically update on docking" = "Automatisch bijwerken na landing";
/* Cmdr stats. [stats.py] */
"Balance" = "Balans";

View File

@ -10,7 +10,7 @@ This app downloads commodity market and other station data from the game [Elite:
Usage
--------
The user-interface is deliberately minimal - when you land at a station just switch to the app and press the “Update” button or press Enter to automatically download and transmit and/or save your choice of data.
The user-interface is deliberately minimal - when you land at a station just switch to the app and press the “Update” button or press Enter to download and transmit and/or save your choice of data.
Click on the system name to go to its [Elite: Dangerous Star Map](http://www.edsm.net/) (“EDSM”) entry in your web broswer.
@ -44,7 +44,7 @@ Setup
The first time that you run the app you are prompted for your username and password. This is the same username and password
combination that you use to log into the Elite: Dangerous launcher, and is required so that the Frontier servers can send the app *your* data and the market data for the station that *you* are docked at.
You can also choose here what data to save (refer to the next section for details), whether to set up a hotkey so you don't have to switch to the app in order to “Update”, and whether to attach your Cmdr name or a [pseudo-anonymized](http://en.wikipedia.org/wiki/Pseudonymity) ID to the data.
You can also choose here what data to save (refer to the next section for details), whether to “Update” automatically on docking and/or with a hotkey, and whether to attach your Cmdr name or a [pseudo-anonymized](http://en.wikipedia.org/wiki/Pseudonymity) ID to the data.
The first time that you hit “Update” you will be prompted to authenticate with a “verification code”, which you will shortly receive by email from Frontier.
Note that each “verification code” is one-time only - if you enter the code incorrectly or quit the app before

View File

@ -80,6 +80,7 @@ class Config:
OUT_SHIP_CORIOLIS = 128
OUT_LOG_EDSM = 256
OUT_LOG_AUTO = 512
OUT_MANUAL = 1024
if platform=='darwin':

View File

@ -14,6 +14,8 @@ from calendar import timegm
if __debug__:
from traceback import print_exc
from config import config
class _EDProxy:
@ -73,7 +75,7 @@ class _EDProxy:
def jump(self, event):
# Called from Tkinter's main loop
if self.callback and self.last_event:
self.callback(*self.last_event)
self.callback(event, *self.last_event)
def close():
self.discover_sock.shutdown()
@ -131,7 +133,7 @@ class _EDProxy:
s.settimeout(None) # was self.SERVICE_TIMEOUT, but heartbeat doesn't appear to work so wait indefinitely
while True:
msg = json.loads(s.recv(self.MESSAGE_MAX))
if msg['Type'] == self.MESSAGE_SYSTEM:
if msg['Type'] == self.MESSAGE_SYSTEM and config.getint('output') & config.OUT_LOG_AUTO:
if 'DateUtc' in msg:
timestamp = timegm(datetime.strptime(msg['DateUtc'], '%Y-%m-%d %H:%M:%S').utctimetuple())
else:

View File

@ -12,6 +12,9 @@ from datetime import datetime
if __debug__:
from traceback import print_exc
from config import config
if platform=='darwin':
from AppKit import NSWorkspace
from Foundation import NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask
@ -72,6 +75,8 @@ else:
class EDLogs(FileSystemEventHandler):
_POLL = 5 # New system gets posted to log file before hyperspace ends, so don't need to poll too often
def __init__(self):
FileSystemEventHandler.__init__(self) # futureproofing - not need for current version of watchdog
self.root = None
@ -79,11 +84,12 @@ class EDLogs(FileSystemEventHandler):
self.logfile = None
self.observer = None
self.thread = None
self.callback = None
self.callbacks = { 'Jump': None, 'Dock': None }
self.last_event = None # for communicating the Jump event
def set_callback(self, callback):
self.callback = callback
def set_callback(self, name, callback):
if name in self.callbacks:
self.callbacks[name] = callback
def start(self, root):
self.root = root
@ -94,6 +100,7 @@ class EDLogs(FileSystemEventHandler):
return True
self.root.bind_all('<<MonitorJump>>', self.jump) # user-generated
self.root.bind_all('<<MonitorDock>>', self.dock) # user-generated
# Set up a watchog observer. This is low overhead so is left running irrespective of whether monitoring is desired.
if not self.observer:
@ -131,6 +138,10 @@ class EDLogs(FileSystemEventHandler):
self.logfile = event.src_path
def worker(self):
# Tk isn't thread-safe in general.
# event_generate() is the only safe way to poke the main thread from this thread:
# https://mail.python.org/pipermail/tkinter-discuss/2013-November/003522.html
# e.g.:
# "{18:00:41} System:"Shinrarta Dezhra" StarPos:(55.719,17.594,27.156)ly NormalFlight\r\n"
# or with verboseLogging:
@ -140,6 +151,16 @@ class EDLogs(FileSystemEventHandler):
# Note that system name may contain parantheses, e.g. "Pipe (stem) Sector PI-T c3-5".
regexp = re.compile(r'\{(.+)\} System:"(.+)" StarPos:\((.+),(.+),(.+)\)ly.* (\S+)') # (localtime, system, x, y, z, context)
# e.g.:
# "{14:42:11} GetSafeUniversalAddress Station Count 1 moved 0 Docked Not Landed\r\n"
# or:
# "... Undocked Landed\r\n"
# Don't use the simpler "Commander Put ..." message since its more likely to be delayed.
dockre = re.compile(r'\{(.+)\} GetSafeUniversalAddress Station Count \d+ moved \d+ (\S+) ([^\r\n]+)') # (localtime, docked_status, landed_status)
docked = False # Whether we're docked
updated = False # Whether we've sent an update since we docked
# Seek to the end of the latest log file
logfile = self.logfile
if logfile:
@ -149,6 +170,13 @@ class EDLogs(FileSystemEventHandler):
loghandle = None
while True:
if docked and not updated and not config.getint('output') & config.OUT_MANUAL:
self.root.event_generate('<<MonitorDock>>', when="tail")
updated = True
if __debug__:
print "%s :\t%s %s" % ('Updated', docked and " docked" or "!docked", updated and " updated" or "!updated")
# Check whether new log file started, e.g. client (re)started.
newlogfile = self.logfile
if logfile != newlogfile:
@ -168,8 +196,18 @@ class EDLogs(FileSystemEventHandler):
if system == 'ProvingGround':
system = 'CQC'
coordinates = (float(x), float(y), float(z))
else:
match = dockre.match(line)
if match:
if match.group(2) == 'Undocked':
docked = updated = False
elif match.group(2) == 'Docked':
docked = True
# do nothing now in case the API server is lagging, but update on next poll
if __debug__:
print "%s :\t%s %s" % (match.group(2), docked and " docked" or "!docked", updated and " updated" or "!updated")
if system:
if system and not docked and config.getint('output') & config.OUT_LOG_AUTO:
# Convert local time string to UTC date and time
visited_struct = strptime(visited, '%H:%M:%S')
now = localtime()
@ -177,11 +215,10 @@ class EDLogs(FileSystemEventHandler):
# Crossed midnight between timestamp and poll
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
# Tk on Windows doesn't like to be called outside of an event handler, so generate an event
self.last_event = (mktime(time_struct), system, coordinates)
self.root.event_generate('<<MonitorJump>>', when="tail")
sleep(10) # New system gets posted to log file before hyperspace ends, so don't need to poll too often
sleep(self._POLL)
# Check whether we're still supposed to be running
if threading.current_thread() != self.thread:
@ -189,8 +226,14 @@ class EDLogs(FileSystemEventHandler):
def jump(self, event):
# Called from Tkinter's main loop
if self.callback and self.last_event:
self.callback(*self.last_event)
if self.callbacks['Jump'] and self.last_event:
self.callbacks['Jump'](event, *self.last_event)
def dock(self, event):
# Called from Tkinter's main loop
if self.callbacks['Dock']:
self.callbacks['Dock'](event)
if platform=='darwin':

View File

@ -124,6 +124,9 @@ class PreferencesDialog(tk.Toplevel):
nb.Checkbutton(outframe, text=_("Market data in Slopey's BPC format file"), variable=self.out_bpc, command=self.outvarchanged).grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_td = tk.IntVar(value = (output & config.OUT_TD ) and 1)
nb.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged).grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_auto = tk.IntVar(value = 0 if output & config.OUT_MANUAL else 1) # inverted
self.out_auto_button = nb.Checkbutton(outframe, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged) # Output setting
self.out_auto_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_ship_eds= tk.IntVar(value = (output & config.OUT_SHIP_EDS) and 1)
nb.Checkbutton(outframe, text=_('Ship loadout in E:D Shipyard format file'), variable=self.out_ship_eds, command=self.outvarchanged).grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W)
self.out_ship_coriolis= tk.IntVar(value = (output & config.OUT_SHIP_CORIOLIS) and 1)
@ -418,9 +421,10 @@ class PreferencesDialog(tk.Toplevel):
(self.out_bpc.get() and config.OUT_BPC) +
(self.out_td.get() and config.OUT_TD) +
(self.out_csv.get() and config.OUT_CSV) +
(config.OUT_MANUAL if not self.out_auto.get() else 0) +
(self.out_ship_eds.get() and config.OUT_SHIP_EDS) +
(self.out_log_file.get() and config.OUT_LOG_FILE) +
(self.out_ship_coriolis.get() and config.OUT_SHIP_CORIOLIS) +
(self.out_log_file.get() and config.OUT_LOG_FILE) +
(self.out_log_edsm.get() and config.OUT_LOG_EDSM) +
(self.out_log_auto.get() and config.OUT_LOG_AUTO))
config.set('outdir', self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get())
@ -451,14 +455,8 @@ class PreferencesDialog(tk.Toplevel):
self.callback()
def _destroy(self):
# Re-enable hotkey and log monitoring before exit
# Re-enable hotkey monitoring before exit
hotkeymgr.register(self.parent, config.getint('hotkey_code'), config.getint('hotkey_mods'))
if (config.getint('output') & config.OUT_LOG_AUTO) and (config.getint('output') & (config.OUT_LOG_FILE|config.OUT_LOG_EDSM)):
monitor.start(self.parent)
edproxy.start(self.parent)
else:
monitor.stop()
edproxy.stop()
self.parent.wm_attributes('-topmost', config.getint('always_ontop') and 1 or 0)
self.destroy()