1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-17 17:42:20 +03:00

Switch EDSM integration to a plugin

This commit is contained in:
Jonathan Harris 2017-07-29 11:35:56 +01:00
parent 93ff800f90
commit e810b87dd4
8 changed files with 377 additions and 405 deletions

View File

@ -54,7 +54,6 @@ import commodity
from commodity import COMMODITY_CSV from commodity import COMMODITY_CSV
import td import td
import eddn import eddn
import edsm
import coriolis import coriolis
import edshipyard import edshipyard
import loadout import loadout
@ -68,7 +67,6 @@ from theme import theme
SERVER_RETRY = 5 # retry pause for Companion servers [s] SERVER_RETRY = 5 # retry pause for Companion servers [s]
EDSM_POLL = 0.1
# Limits on local clock drift from EDDN gateway # Limits on local clock drift from EDDN gateway
DRIFT_THRESHOLD = 3 * 60 DRIFT_THRESHOLD = 3 * 60
@ -87,7 +85,6 @@ class AppWindow:
self.holdofftime = config.getint('querytime') + companion.holdoff self.holdofftime = config.getint('querytime') + companion.holdoff
self.session = companion.Session() self.session = companion.Session()
self.edsm = edsm.EDSM()
self.eddn = eddn.EDDN(self) self.eddn = eddn.EDDN(self)
self.w = master self.w = master
@ -113,19 +110,15 @@ class AppWindow:
self.cmdr_label = tk.Label(frame) self.cmdr_label = tk.Label(frame)
self.ship_label = tk.Label(frame) self.ship_label = tk.Label(frame)
self.system_label = tk.Label(frame)
self.cmdr_label.grid(row=1, column=0, sticky=tk.W) self.cmdr_label.grid(row=1, column=0, sticky=tk.W)
self.ship_label.grid(row=2, column=0, sticky=tk.W) self.ship_label.grid(row=2, column=0, sticky=tk.W)
self.system_label.grid(row=3, column=0, sticky=tk.W)
self.cmdr = tk.Label(frame, anchor=tk.W) self.cmdr = tk.Label(frame, anchor=tk.W)
self.ship = HyperlinkLabel(frame, url = self.shipyard_url) self.ship = HyperlinkLabel(frame, url = self.shipyard_url)
self.system = HyperlinkLabel(frame, compound=tk.RIGHT, url = self.system_url, popup_copy = True)
self.cmdr.grid(row=1, column=1, sticky=tk.EW) self.cmdr.grid(row=1, column=1, sticky=tk.EW)
self.ship.grid(row=2, column=1, sticky=tk.EW) self.ship.grid(row=2, column=1, sticky=tk.EW)
self.system.grid(row=3, column=1, sticky=tk.EW)
for plugin in plug.PLUGINS: for plugin in plug.PLUGINS:
appitem = plugin.get_app(frame) appitem = plugin.get_app(frame)
@ -347,7 +340,6 @@ class AppWindow:
self.cmdr_label['text'] = _('Cmdr') + ':' # Main window self.cmdr_label['text'] = _('Cmdr') + ':' # Main window
self.ship_label['text'] = (monitor.state['Captain'] and _('Role') or # Multicrew role label in main window self.ship_label['text'] = (monitor.state['Captain'] and _('Role') or # Multicrew role label in main window
_('Ship')) + ':' # Main window _('Ship')) + ':' # Main window
self.system_label['text'] = _('System') + ':' # Main window
self.button['text'] = self.theme_button['text'] = _('Update') # Update button in main window self.button['text'] = self.theme_button['text'] = _('Update') # Update button in main window
if platform == 'darwin': if platform == 'darwin':
self.menubar.entryconfigure(1, label=_('File')) # Menu title self.menubar.entryconfigure(1, label=_('File')) # Menu title
@ -434,7 +426,6 @@ class AppWindow:
hotkeymgr.play_good() hotkeymgr.play_good()
self.status['text'] = _('Fetching data...') self.status['text'] = _('Fetching data...')
self.button['state'] = self.theme_button['state'] = tk.DISABLED self.button['state'] = self.theme_button['state'] = tk.DISABLED
self.edit_menu.entryconfigure(0, state=tk.DISABLED) # Copy
self.w.update_idletasks() self.w.update_idletasks()
try: try:
@ -469,11 +460,10 @@ class AppWindow:
self.ship['text'] = companion.ship_map.get(data['ship']['name'].lower(), data['ship']['name']) self.ship['text'] = companion.ship_map.get(data['ship']['name'].lower(), data['ship']['name'])
monitor.state['ShipID'] = data['ship']['id'] monitor.state['ShipID'] = data['ship']['id']
monitor.state['ShipType'] = data['ship']['name'].lower() monitor.state['ShipType'] = data['ship']['name'].lower()
if not monitor.system:
self.system['text'] = data['lastSystem']['name'] if data['commander'].get('credits') is not None:
self.system['image'] = '' monitor.state['Credits'] = data['commander']['credits']
self.status['text'] = '' monitor.state['Loan'] = data['commander'].get('debt', 0)
self.edit_menu.entryconfigure(0, state=tk.NORMAL) # Copy
# stuff we can do when not docked # stuff we can do when not docked
err = plug.notify_newdata(data, monitor.is_beta) err = plug.notify_newdata(data, monitor.is_beta)
@ -484,16 +474,6 @@ class AppWindow:
if config.getint('output') & config.OUT_SHIP: if config.getint('output') & config.OUT_SHIP:
loadout.export(data) loadout.export(data)
# Send flightlog EDSM if FSDJump failed to do so
if config.getint('output') & config.OUT_SYS_EDSM and self.edsm.result['img'] == self.edsm._IMG_ERROR and not monitor.is_beta and not monitor.captain and config.get('cmdrs') and monitor.cmdr in config.get('cmdrs') and config.get('edsm_usernames')[config.get('cmdrs').index(monitor.cmdr)]:
try:
self.edsm.writelog(querytime, monitor.system, monitor.coordinates, monitor.state['ShipID'])
except Exception as e:
if __debug__: print_exc()
self.status['text'] = unicode(e)
play_bad = True
self.edsmpoll()
if not (config.getint('output') & ~config.OUT_SHIP & config.OUT_STATION_ANY): if not (config.getint('output') & ~config.OUT_SHIP & config.OUT_STATION_ANY):
# no station data requested - we're done # no station data requested - we're done
pass pass
@ -546,27 +526,6 @@ class AppWindow:
if not old_status: if not old_status:
self.status['text'] = '' self.status['text'] = ''
# Update credits and ship info and send to EDSM
if not monitor.is_beta and config.getint('output') & config.OUT_SYS_EDSM:
try:
if data['commander'].get('credits') is not None:
monitor.state['Credits'] = data['commander']['credits']
monitor.state['Loan'] = data['commander'].get('debt', 0)
self.edsm.setcredits(monitor.state['Credits'], monitor.state['Loan'])
ship = companion.ship(data)
if ship != self.edsm.lastship:
self.edsm.updateship(monitor.state['ShipID'],
monitor.state['ShipType'],
[
('linkToCoriolis', coriolis.url(data, monitor.is_beta)),
('linkToEDShipyard', edshipyard.url(data, monitor.is_beta)),
])
self.edsm.lastship = ship
except Exception as e:
# Not particularly important so silent on failure
if __debug__: print_exc()
except companion.VerificationRequired: except companion.VerificationRequired:
return prefs.AuthenticationDialog(self.w, partial(self.verify, self.getandsend)) return prefs.AuthenticationDialog(self.w, partial(self.verify, self.getandsend))
@ -627,7 +586,6 @@ class AppWindow:
if not entry: if not entry:
return return
system_changed = monitor.system and self.system['text'] != monitor.system
# Update main window # Update main window
if monitor.cmdr and monitor.state['Captain']: if monitor.cmdr and monitor.state['Captain']:
@ -649,63 +607,13 @@ class AppWindow:
self.ship_label['text'] = _('Ship') + ':' # Main window self.ship_label['text'] = _('Ship') + ':' # Main window
self.ship['text'] = '' self.ship['text'] = ''
if self.system['text'] != monitor.system: self.edit_menu.entryconfigure(0, state=monitor.system and tk.NORMAL or tk.DISABLED) # Copy
self.system['text'] = monitor.system or ''
self.edsm.link(monitor.system)
self.edsmpoll()
if entry['event'] in ['Undocked', 'StartJump', 'SetUserShipName', 'ShipyardBuy', 'ShipyardSell', 'ShipyardSwap', 'ModuleBuy', 'ModuleSell', 'MaterialCollected', 'MaterialDiscarded', 'ScientificResearch', 'EngineerCraft', 'Synthesis', 'JoinACrew']: if entry['event'] in ['Undocked', 'StartJump', 'SetUserShipName', 'ShipyardBuy', 'ShipyardSell', 'ShipyardSwap', 'ModuleBuy', 'ModuleSell', 'MaterialCollected', 'MaterialDiscarded', 'ScientificResearch', 'EngineerCraft', 'Synthesis', 'JoinACrew']:
self.status['text'] = '' # Periodically clear any old error self.status['text'] = '' # Periodically clear any old error
self.w.update_idletasks() self.w.update_idletasks()
# Send interesting events to EDSM # Companion login
if config.getint('output') & config.OUT_SYS_EDSM and not monitor.is_beta and not monitor.captain and config.get('cmdrs') and monitor.cmdr in config.get('cmdrs') and config.get('edsm_usernames')[config.get('cmdrs').index(monitor.cmdr)]:
try:
# Update system status on startup
if entry['event'] in [None, 'StartUp'] and monitor.mode and monitor.system:
self.edsm.lookup(monitor.system)
# Send credits to EDSM on new game (but not on startup - data might be old)
if entry['event'] == 'LoadGame':
self.edsm.setcredits(monitor.state['Credits'], monitor.state['Loan'])
# Send rank info to EDSM on startup or change
if entry['event'] in ['StartUp', 'Progress', 'Promotion'] and monitor.state['Rank']:
self.edsm.setranks(monitor.state['Rank'])
# Send ship info to EDSM on startup or change
if entry['event'] in ['StartUp', 'Loadout', 'LoadGame', 'SetUserShipName'] and monitor.cmdr and monitor.state['ShipID']:
self.edsm.setshipid(monitor.state['ShipID'])
props = []
if monitor.state['ShipIdent'] is not None:
props.append(('shipIdent', monitor.state['ShipIdent']))
if monitor.state['ShipName'] is not None:
props.append(('shipName', monitor.state['ShipName']))
if monitor.state['PaintJob'] is not None:
props.append(('paintJob', monitor.state['PaintJob']))
self.edsm.updateship(monitor.state['ShipID'], monitor.state['ShipType'], props)
elif entry['event'] in ['ShipyardBuy', 'ShipyardSell']:
self.edsm.sellship(entry.get('SellShipID'))
# Send materials info to EDSM on startup or change
if entry['event'] in ['StartUp', 'LoadGame', 'MaterialCollected', 'MaterialDiscarded', 'ScientificResearch', 'EngineerCraft', 'Synthesis']:
self.edsm.setmaterials(monitor.state['Raw'], monitor.state['Manufactured'], monitor.state['Encoded'])
# Send paintjob info to EDSM on change
if entry['event'] in ['ModuleBuy', 'ModuleSell'] and entry['Slot'] == 'PaintJob':
self.edsm.updateship(monitor.state['ShipID'], monitor.state['ShipType'], [('paintJob', monitor.state['PaintJob'])])
# Write EDSM log on change
if monitor.mode and entry['event'] in ['Location', 'FSDJump']:
self.edsm.writelog(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates, monitor.state['ShipID'])
except Exception as e:
if __debug__: print_exc()
self.status['text'] = unicode(e)
if not config.getint('hotkey_mute'):
hotkeymgr.play_bad()
self.edsmpoll()
# Companion login - do this after EDSM so any EDSM errors don't mask login errors
if entry['event'] in [None, 'StartUp', 'NewCommander', 'LoadGame'] and monitor.cmdr: if entry['event'] in [None, 'StartUp', 'NewCommander', 'LoadGame'] and monitor.cmdr:
if config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'): if config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'):
prefs.make_current(monitor.cmdr) prefs.make_current(monitor.cmdr)
@ -737,7 +645,7 @@ class AppWindow:
return return
# Plugin backwards compatibility # Plugin backwards compatibility
if system_changed: if monitor.mode and entry['event'] in ['StartUp', 'Location', 'FSDJump']:
plug.notify_system_changed(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates) plug.notify_system_changed(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates)
# Auto-Update after docking # Auto-Update after docking
@ -812,13 +720,6 @@ class AppWindow:
if not config.getint('hotkey_mute'): if not config.getint('hotkey_mute'):
hotkeymgr.play_bad() hotkeymgr.play_bad()
def edsmpoll(self):
result = self.edsm.result
if result['done']:
self.system['image'] = result['img']
else:
self.w.after(int(EDSM_POLL * 1000), self.edsmpoll)
def shipyard_url(self, shipname=None): def shipyard_url(self, shipname=None):
if not monitor.cmdr or not monitor.mode: if not monitor.cmdr or not monitor.mode:
@ -856,9 +757,6 @@ class AppWindow:
assert False, config.getint('shipyard') assert False, config.getint('shipyard')
return False return False
def system_url(self, text):
return text and self.edsm.result['url']
def cooldown(self): def cooldown(self):
if time() < self.holdofftime: if time() < self.holdofftime:
self.button['text'] = self.theme_button['text'] = _('cooldown {SS}s').format(SS = int(self.holdofftime - time())) # Update button in main window self.button['text'] = self.theme_button['text'] = _('cooldown {SS}s').format(SS = int(self.holdofftime - time())) # Update button in main window

View File

@ -138,6 +138,9 @@
<Component Guid="*"> <Component Guid="*">
<File KeyPath="yes" Source="SourceDir\eddb.py" /> <File KeyPath="yes" Source="SourceDir\eddb.py" />
</Component> </Component>
<Component Guid="*">
<File KeyPath="yes" Source="SourceDir\edsm.py" />
</Component>
<Component Guid="*"> <Component Guid="*">
<File KeyPath="yes" Source="SourceDir\es.strings" /> <File KeyPath="yes" Source="SourceDir\es.strings" />
</Component> </Component>
@ -447,6 +450,7 @@
<ComponentRef Id="EDMarketConnector.VisualElementsManifest.xml" /> <ComponentRef Id="EDMarketConnector.VisualElementsManifest.xml" />
<ComponentRef Id="EDMC.exe" /> <ComponentRef Id="EDMC.exe" />
<ComponentRef Id="eddb.py" /> <ComponentRef Id="eddb.py" />
<ComponentRef Id="edsm.py" />
<ComponentRef Id="es.strings" /> <ComponentRef Id="es.strings" />
<ComponentRef Id="fi.strings" /> <ComponentRef Id="fi.strings" />
<ComponentRef Id="fr.strings" /> <ComponentRef Id="fr.strings" />

View File

@ -19,7 +19,7 @@
/* CQC rank. [stats.py] */ /* CQC rank. [stats.py] */
"Amateur" = "Amateur"; "Amateur" = "Amateur";
/* EDSM setting. [prefs.py] */ /* EDSM setting. [edsm.py] */
"API Key" = "API Key"; "API Key" = "API Key";
/* Tab heading in settings. [prefs.py] */ /* Tab heading in settings. [prefs.py] */
@ -70,7 +70,7 @@
/* Ranking. [stats.py] */ /* Ranking. [stats.py] */
"Combat" = "Combat"; "Combat" = "Combat";
/* EDSM setting. [prefs.py] */ /* EDSM setting. [edsm.py] */
"Commander Name" = "Commander Name"; "Commander Name" = "Commander Name";
/* Combat rank. [stats.py] */ /* Combat rank. [stats.py] */
@ -139,7 +139,7 @@
/* Top rank. [stats.py] */ /* Top rank. [stats.py] */
"Elite" = "Elite"; "Elite" = "Elite";
/* Section heading in settings. [prefs.py] */ /* Section heading in settings. [edsm.py] */
"Elite Dangerous Star Map credentials" = "Elite Dangerous Star Map credentials"; "Elite Dangerous Star Map credentials" = "Elite Dangerous Star Map credentials";
/* Ranking. [stats.py] */ /* Ranking. [stats.py] */
@ -430,7 +430,7 @@
/* CQC rank. [stats.py] */ /* CQC rank. [stats.py] */
"Semi Professional" = "Semi Professional"; "Semi Professional" = "Semi Professional";
/* [prefs.py] */ /* [edsm.py] */
"Send flight log to Elite Dangerous Star Map" = "Send flight log to Elite Dangerous Star Map"; "Send flight log to Elite Dangerous Star Map" = "Send flight log to Elite Dangerous Star Map";
/* Output setting. [prefs.py] */ /* Output setting. [prefs.py] */
@ -475,7 +475,7 @@
/* Explorer rank. [stats.py] */ /* Explorer rank. [stats.py] */
"Surveyor" = "Surveyor"; "Surveyor" = "Surveyor";
/* Main window. [EDMarketConnector.py] */ /* Main window. [edsm.py] */
"System" = "System"; "System" = "System";
/* Appearance setting. [prefs.py] */ /* Appearance setting. [prefs.py] */

View File

@ -102,7 +102,7 @@ class Config:
# OUT_STAT = 64 # No longer available # OUT_STAT = 64 # No longer available
OUT_SHIP_CORIOLIS = 128 # Replaced by OUT_SHIP OUT_SHIP_CORIOLIS = 128 # Replaced by OUT_SHIP
OUT_STATION_ANY = OUT_MKT_EDDN|OUT_MKT_TD|OUT_MKT_CSV|OUT_SHIP|OUT_SHIP_EDS|OUT_SHIP_CORIOLIS OUT_STATION_ANY = OUT_MKT_EDDN|OUT_MKT_TD|OUT_MKT_CSV|OUT_SHIP|OUT_SHIP_EDS|OUT_SHIP_CORIOLIS
OUT_SYS_EDSM = 256 # OUT_SYS_EDSM = 256 # Now a plugin
# OUT_SYS_AUTO = 512 # Now always automatic # OUT_SYS_AUTO = 512 # Now always automatic
OUT_MKT_MANUAL = 1024 OUT_MKT_MANUAL = 1024
OUT_SYS_EDDN = 2048 OUT_SYS_EDDN = 2048

233
edsm.py
View File

@ -1,233 +0,0 @@
import json
import threading
from sys import platform
import time
import urllib2
import Tkinter as tk
from config import appname, applongname, appversion, config
from monitor import monitor
if __debug__:
from traceback import print_exc
if platform=='darwin':
# mimimal implementation of requests interface since OpenSSL 0.9.8 on OSX
# fails to negotiate with Cloudflare unless cipher is forced
import ssl
class Response(object):
def __init__(self, url, status_code, headers, content):
self.url = url
self.status_code = status_code
self.headers = headers # actually a mimetools.Message instance
self.content = content
def json(self):
return json.loads(self.content)
def raise_for_status(self):
if self.status_code >= 400:
raise urllib2.HTTPError(self.url, self.status_code, '%d %s' % (self.status_code, self.status_code >= 500 and 'Server Error' or 'Client Error'), self.headers, None)
class Session(object):
def __init__(self):
self.headers = {}
sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # Requires Python >= 2.7.9 on OSX >= 10.10
sslcontext.set_ciphers("ECCdraft:HIGH:!aNULL")
self.opener = urllib2.build_opener(urllib2.HTTPSHandler(context=sslcontext))
self.opener.addheaders = [('User-Agent', '%s/%s' % (appname, appversion))]
def get(self, url, timeout=None, headers={}):
try:
h = self.opener.open(url, timeout=timeout)
r = Response(h.geturl(), h.code, h.info(), h.read())
h.close()
return r
except urllib2.HTTPError, e:
return Response(url, e.code, {}, '') # requests doesn't raise exceptions for HTTP errors
except:
raise
def close(self):
pass
else:
from requests import Session
class EDSM:
_TIMEOUT = 10
FAKE = ['CQC', 'Training', 'Destination'] # Fake systems that shouldn't be sent to EDSM
def __init__(self):
self.result = { 'img': None, 'url': None, 'done': True }
self.syscache = set() # Cache URLs of systems with known coordinates
self.session = Session()
self.lastship = None # Description of last ship that we sent to EDSM
# Can't be in class definition since can only call PhotoImage after window is created
EDSM._IMG_KNOWN = tk.PhotoImage(data = 'R0lGODlhEAAQAMIEAFWjVVWkVWS/ZGfFZ////////////////yH5BAEKAAQALAAAAAAQABAAAAMvSLrc/lAFIUIkYOgNXt5g14Dk0AQlaC1CuglM6w7wgs7rMpvNV4q932VSuRiPjQQAOw==') # green circle
EDSM._IMG_UNKNOWN = tk.PhotoImage(data = 'R0lGODlhEAAQAKEDAGVLJ+ddWO5fW////yH5BAEKAAMALAAAAAAQABAAAAItnI+pywYRQBtA2CtVvTwjDgrJFlreEJRXgKSqwB5keQ6vOKq1E+7IE5kIh4kCADs=') # red circle
EDSM._IMG_NEW = tk.PhotoImage(data = 'R0lGODlhEAAQAMZwANKVHtWcIteiHuiqLPCuHOS1MN22ZeW7ROG6Zuu9MOy+K/i8Kf/DAuvCVf/FAP3BNf/JCf/KAPHHSv7ESObHdv/MBv/GRv/LGP/QBPXOPvjPQfjQSvbRSP/UGPLSae7Sfv/YNvLXgPbZhP7dU//iI//mAP/jH//kFv7fU//fV//ebv/iTf/iUv/kTf/iZ/vgiP/hc/vgjv/jbfriiPriiv7ka//if//jd//sJP/oT//tHv/mZv/sLf/rRP/oYv/rUv/paP/mhv/sS//oc//lkf/mif/sUf/uPv/qcv/uTv/uUv/vUP/qhP/xP//pm//ua//sf//ubf/wXv/thv/tif/slv/tjf/smf/yYP/ulf/2R//2Sv/xkP/2av/0gP/ylf/2df/0i//0j//0lP/5cP/7a//1p//5gf/7ev/3o//2sf/5mP/6kv/2vP/3y//+jP///////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAQABAAAAePgH+Cg4SFhoJKPIeHYT+LhVppUTiPg2hrUkKPXWdlb2xHJk9jXoNJQDk9TVtkYCUkOy4wNjdGfy1UXGJYOksnPiwgFwwYg0NubWpmX1ArHREOFYUyWVNIVkxXQSoQhyMoNVUpRU5EixkcMzQaGy8xhwsKHiEfBQkSIg+GBAcUCIIBBDSYYGiAAUMALFR6FAgAOw==')
EDSM._IMG_ERROR = tk.PhotoImage(data = 'R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAIwlBWpeR0AIwwNPRmZuVNJinyWuClhBlZjpm5fqnIAHJPtOd3Hou9mL6NVgj2LplEAADs=') # BBC Mode 5 '?'
# Call an EDSM endpoint with args (which should be quoted)
def call(self, endpoint, args, check_msgnum=True):
try:
idx = config.get('cmdrs').index(monitor.cmdr)
url = 'https://www.edsm.net/%s?commanderName=%s&apiKey=%s&fromSoftware=%s&fromSoftwareVersion=%s' % (
endpoint,
urllib2.quote(config.get('edsm_usernames')[idx].encode('utf-8')),
urllib2.quote(config.get('edsm_apikeys')[idx]),
urllib2.quote(applongname),
urllib2.quote(appversion),
) + args
r = self.session.get(url, timeout=EDSM._TIMEOUT)
r.raise_for_status()
reply = r.json()
if not check_msgnum:
return reply
(msgnum, msg) = reply['msgnum'], reply['msg']
except:
if __debug__: print_exc()
raise Exception(_("Error: Can't connect to EDSM"))
# Message numbers: 1xx = OK, 2xx = fatal error, 3xx = error (but not generated in practice), 4xx = ignorable errors
if msgnum // 100 not in (1,4):
raise Exception(_('Error: EDSM {MSG}').format(MSG=msg))
else:
return reply
# Just set link without doing a lookup
def link(self, system_name):
self.cancel_lookup()
if not system_name or system_name in self.FAKE:
self.result = { 'img': '', 'url': None, 'done': True, 'uncharted': False }
else:
self.result = { 'img': '', 'url': 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system_name), 'done': True, 'uncharted': False }
def lookup(self, system_name, known=0):
self.cancel_lookup()
if system_name in self.FAKE:
self.result = { 'img': '', 'url': None, 'done': True, 'uncharted': False }
elif known or system_name in self.syscache:
self.result = { 'img': EDSM._IMG_KNOWN, 'url': 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system_name), 'done': True, 'uncharted': False }
else:
self.result = { 'img': EDSM._IMG_ERROR, 'url': 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system_name), 'done': True, 'uncharted': False }
data = self.call('api-v1/system', '&sysname=%s&coords=1' % urllib2.quote(system_name), check_msgnum=False)
if data == -1 or not data:
# System not present - but don't create it on the assumption that the caller will
self.result['img'] = EDSM._IMG_NEW
self.result['uncharted'] = True
elif data.get('coords'):
self.result['img'] = EDSM._IMG_KNOWN
self.syscache.add(system_name)
else:
self.result['img'] = EDSM._IMG_UNKNOWN
self.result['uncharted'] = True
# Asynchronous version of the above
def start_lookup(self, system_name, known=0):
self.cancel_lookup()
if system_name in self.FAKE:
self.result = { 'img': '', 'url': None, 'done': True, 'uncharted': False }
elif known or system_name in self.syscache:
self.result = { 'img': EDSM._IMG_KNOWN, 'url': 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system_name), 'done': True, 'uncharted': False }
else:
self.result = { 'img': '', 'url': 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system_name), 'done': False, 'uncharted': False }
self.thread = threading.Thread(target = self.worker, name = 'EDSM worker', args = (system_name, self.result))
self.thread.daemon = True
self.thread.start()
def cancel_lookup(self):
self.thread = None # orphan any existing thread
self.result = { 'img': '', 'url': None, 'done': True } # orphan existing thread's results
def worker(self, system_name, result):
try:
data = self.call('api-v1/system', '&sysname=%s&coords=1' % urllib2.quote(system_name), check_msgnum=False)
if data == -1 or not data:
# System not present - create it
result['img'] = EDSM._IMG_NEW
result['uncharted'] = True
elif data.get('coords'):
result['img'] = EDSM._IMG_KNOWN
self.syscache.add(system_name)
else:
result['img'] = EDSM._IMG_UNKNOWN
result['uncharted'] = True
except:
if __debug__: print_exc()
result['img'] = EDSM._IMG_ERROR
result['done'] = True
# Send flight log and also do lookup
def writelog(self, timestamp, system_name, coordinates, shipid = None):
if system_name in self.FAKE:
self.result = { 'img': '', 'url': None, 'done': True, 'uncharted': False }
return
self.result = { 'img': EDSM._IMG_ERROR, 'url': 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system_name), 'done': True, 'uncharted': False }
args = '&systemName=%s&dateVisited=%s' % (
urllib2.quote(system_name),
urllib2.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(timestamp))),
)
if coordinates:
args += '&x=%.3f&y=%.3f&z=%.3f' % coordinates
if shipid is not None:
args += '&shipId=%d' % shipid
reply = self.call('api-logs-v1/set-log', args)
if reply.get('systemCreated'):
self.result['img'] = EDSM._IMG_NEW
else:
self.result['img'] = EDSM._IMG_KNOWN
self.syscache.add(system_name)
def setranks(self, ranks):
args = ''
if ranks:
for k,v in ranks.iteritems():
if v is not None:
args += '&%s=%s' % (k, urllib2.quote('%d;%d' % v))
if args:
self.call('api-commander-v1/set-ranks', args)
def setcredits(self, balance, loan):
if balance is not None:
self.call('api-commander-v1/set-credits', '&balance=%d&loan=%d' % (balance, loan))
def setmaterials(self, raw, manufactured, encoded):
self.call('api-commander-v1/set-materials', "&type=data&values=%s" % json.dumps(encoded, separators = (',', ':')))
materials = {}
materials.update(raw)
materials.update(manufactured)
self.call('api-commander-v1/set-materials', "&type=materials&values=%s" % json.dumps(materials, separators = (',', ':')))
def setshipid(self, shipid):
if shipid is not None:
self.call('api-commander-v1/set-ship-id', '&shipId=%d' % shipid)
def updateship(self, shipid, shiptype, props=[]):
if shipid is not None and shiptype:
args = '&shipId=%d&type=%s' % (shipid, shiptype)
for (slot, thing) in props:
args += '&%s=%s' % (slot, urllib2.quote(unicode(thing)))
self.call('api-commander-v1/update-ship', args)
def sellship(self, shipid):
if shipid is not None:
self.call('api-commander-v1/sell-ship', '&shipId=%d' % shipid)

357
plugins/edsm.py Normal file
View File

@ -0,0 +1,357 @@
#
# System display and EDSM lookup
#
import json
import requests
import sys
import time
import urllib2
from calendar import timegm
import Tkinter as tk
from ttkHyperlinkLabel import HyperlinkLabel
import myNotebook as nb
from config import appname, applongname, appversion, config
import companion
import coriolis
import edshipyard
if __debug__:
from traceback import print_exc
EDSM_POLL = 0.1
_TIMEOUT = 10
FAKE = ['CQC', 'Training', 'Destination'] # Fake systems that shouldn't be sent to EDSM
this = sys.modules[__name__] # For holding module globals
this.syscache = set() # Cache URLs of systems with known coordinates
this.session = requests.Session()
this.lastship = None # Description of last ship that we sent to EDSM
this.lastlookup = False # whether the last lookup succeeded
# Game state
this.multicrew = False # don't send captain's ship info to EDSM while on a crew
def plugin_start():
# Can't be earlier since can only call PhotoImage after window is created
this._IMG_KNOWN = tk.PhotoImage(data = 'R0lGODlhEAAQAMIEAFWjVVWkVWS/ZGfFZ////////////////yH5BAEKAAQALAAAAAAQABAAAAMvSLrc/lAFIUIkYOgNXt5g14Dk0AQlaC1CuglM6w7wgs7rMpvNV4q932VSuRiPjQQAOw==') # green circle
this._IMG_UNKNOWN = tk.PhotoImage(data = 'R0lGODlhEAAQAKEDAGVLJ+ddWO5fW////yH5BAEKAAMALAAAAAAQABAAAAItnI+pywYRQBtA2CtVvTwjDgrJFlreEJRXgKSqwB5keQ6vOKq1E+7IE5kIh4kCADs=') # red circle
this._IMG_NEW = tk.PhotoImage(data = 'R0lGODlhEAAQAMZwANKVHtWcIteiHuiqLPCuHOS1MN22ZeW7ROG6Zuu9MOy+K/i8Kf/DAuvCVf/FAP3BNf/JCf/KAPHHSv7ESObHdv/MBv/GRv/LGP/QBPXOPvjPQfjQSvbRSP/UGPLSae7Sfv/YNvLXgPbZhP7dU//iI//mAP/jH//kFv7fU//fV//ebv/iTf/iUv/kTf/iZ/vgiP/hc/vgjv/jbfriiPriiv7ka//if//jd//sJP/oT//tHv/mZv/sLf/rRP/oYv/rUv/paP/mhv/sS//oc//lkf/mif/sUf/uPv/qcv/uTv/uUv/vUP/qhP/xP//pm//ua//sf//ubf/wXv/thv/tif/slv/tjf/smf/yYP/ulf/2R//2Sv/xkP/2av/0gP/ylf/2df/0i//0j//0lP/5cP/7a//1p//5gf/7ev/3o//2sf/5mP/6kv/2vP/3y//+jP///////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAQABAAAAePgH+Cg4SFhoJKPIeHYT+LhVppUTiPg2hrUkKPXWdlb2xHJk9jXoNJQDk9TVtkYCUkOy4wNjdGfy1UXGJYOksnPiwgFwwYg0NubWpmX1ArHREOFYUyWVNIVkxXQSoQhyMoNVUpRU5EixkcMzQaGy8xhwsKHiEfBQkSIg+GBAcUCIIBBDSYYGiAAUMALFR6FAgAOw==')
this._IMG_ERROR = tk.PhotoImage(data = 'R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAIwlBWpeR0AIwwNPRmZuVNJinyWuClhBlZjpm5fqnIAHJPtOd3Hou9mL6NVgj2LplEAADs=') # BBC Mode 5 '?'
# Migrate old settings
if not config.get('edsm_cmdrs'):
if isinstance(config.get('cmdrs'), list) and config.get('edsm_usernames') and config.get('edsm_apikeys'):
# Migrate <= 2.34 settings
config.set('edsm_cmdrs', config.get('cmdrs'))
elif config.get('edsm_cmdrname'):
# Migrate <= 2.25 settings. edsm_cmdrs is unknown at this time
config.set('edsm_usernames', [config.get('edsm_cmdrname') or ''])
config.set('edsm_apikeys', [config.get('edsm_apikey') or ''])
config.delete('edsm_cmdrname')
config.delete('edsm_apikey')
if config.getint('output') & 256:
# Migrate <= 2.34 setting
config.set('edsm_out', 1)
config.delete('edsm_autoopen')
config.delete('edsm_historical')
return 'EDSM'
def plugin_app(parent):
this.system_label = tk.Label(parent, text = _('System') + ':') # Main window
this.system = HyperlinkLabel(parent, compound=tk.RIGHT, url = None, popup_copy = True)
return (this.system_label, this.system)
def plugin_prefs(parent, cmdr, is_beta):
PADX = 10
BUTTONX = 12 # indent Checkbuttons and Radiobuttons
PADY = 2 # close spacing
frame = nb.Frame(parent)
frame.columnconfigure(1, weight=1)
HyperlinkLabel(frame, text='Elite Dangerous Star Map', background=nb.Label().cget('background'), url='https://www.edsm.net/', underline=True).grid(columnspan=2, padx=PADX, sticky=tk.W) # Don't translate
this.log = tk.IntVar(value = config.getint('edsm_out') and 1)
this.log_button = nb.Checkbutton(frame, text=_('Send flight log to Elite Dangerous Star Map'), variable=this.log, command=prefsvarchanged)
this.log_button.grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W)
nb.Label(frame).grid(sticky=tk.W) # big spacer
this.label = HyperlinkLabel(frame, text=_('Elite Dangerous Star Map credentials'), background=nb.Label().cget('background'), url='https://www.edsm.net/settings/api', underline=True) # Section heading in settings
this.label.grid(columnspan=2, padx=PADX, sticky=tk.W)
this.cmdr_label = nb.Label(frame, text=_('Cmdr')) # Main window
this.cmdr_label.grid(row=10, padx=PADX, sticky=tk.W)
this.cmdr_text = nb.Label(frame)
this.cmdr_text.grid(row=10, column=1, padx=PADX, pady=PADY, sticky=tk.W)
this.user_label = nb.Label(frame, text=_('Commander Name')) # EDSM setting
this.user_label.grid(row=11, padx=PADX, sticky=tk.W)
this.user = nb.Entry(frame)
this.user.grid(row=11, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
this.apikey_label = nb.Label(frame, text=_('API Key')) # EDSM setting
this.apikey_label.grid(row=12, padx=PADX, sticky=tk.W)
this.apikey = nb.Entry(frame)
this.apikey.grid(row=12, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
prefs_cmdr_changed(cmdr, is_beta)
return frame
def prefs_cmdr_changed(cmdr, is_beta):
this.log_button['state'] = cmdr and not is_beta and tk.NORMAL or tk.DISABLED
this.user['state'] = tk.NORMAL
this.user.delete(0, tk.END)
this.apikey['state'] = tk.NORMAL
this.apikey.delete(0, tk.END)
if cmdr:
this.cmdr_text['text'] = cmdr + (is_beta and ' [Beta]' or '')
cred = credentials(cmdr)
if cred:
this.user.insert(0, cred[0])
this.apikey.insert(0, cred[1])
else:
this.cmdr_text['text'] = _('None') # No hotkey/shortcut currently defined
this.label['state'] = this.cmdr_label['state'] = this.cmdr_text['state'] = this.user_label['state'] = this.user['state'] = this.apikey_label['state'] = this.apikey['state'] = cmdr and not is_beta and this.log.get() and tk.NORMAL or tk.DISABLED
def prefsvarchanged():
this.user_label['state'] = this.user['state'] = this.apikey_label['state'] = this.log.get() and tk.NORMAL or tk.DISABLED
def prefs_changed(cmdr, is_beta):
this.system_label['text'] = _('System') + ':' # Main window
config.set('edsm_out', this.log.get())
if cmdr and not is_beta:
cmdrs = config.get('edsm_cmdrs')
usernames = config.get('edsm_usernames')
apikeys = config.get('edsm_apikeys')
if cmdr in cmdrs:
idx = cmdrs.index(cmdr)
usernames[idx] = this.user.get().strip()
apikeys[idx] = this.apikey.get().strip()
else:
config.set('edsm_cmdrs', cmdrs + [cmdr])
usernames.append(this.user.get().strip())
apikeys.append(this.apikey.get().strip())
config.set('edsm_usernames', usernames)
config.set('edsm_apikeys', apikeys)
def credentials(cmdr):
# Credentials for cmdr
if not cmdr:
return None
cmdrs = config.get('edsm_cmdrs')
if not cmdrs:
# Migrate from <= 2.25
cmdrs = [cmdr]
config.set('edsm_cmdrs', cmdrs)
if cmdr in cmdrs:
idx = cmdrs.index(cmdr)
return (config.get('edsm_usernames')[idx], config.get('edsm_apikeys')[idx])
else:
return None
def journal_entry(cmdr, is_beta, system, station, entry, state):
# Update display
if this.system['text'] != system:
this.system['text'] = system or ''
this.system['image'] = ''
if not system or system in FAKE:
this.system['url'] = None
this.lastlookup = True
else:
this.system['url'] = 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system)
this.lastlookup = False
this.system.update_idletasks()
this.multicrew = bool(state['Role'])
# Send interesting events to EDSM
if config.getint('edsm_out') and not is_beta and not multicrew and credentials(cmdr):
try:
# Send credits to EDSM on new game (but not on startup - data might be old)
if entry['event'] == 'LoadGame':
setcredits(cmdr, state['Credits'], state['Loan'])
# Send rank info to EDSM on startup or change
if entry['event'] in ['StartUp', 'Progress', 'Promotion'] and state['Rank']:
setranks(cmdr, state['Rank'])
# Send ship info to EDSM on startup or change
if entry['event'] in ['StartUp', 'Loadout', 'LoadGame', 'SetUserShipName'] and cmdr and state['ShipID']:
setshipid(cmdr, state['ShipID'])
props = []
if state['ShipIdent'] is not None:
props.append(('shipIdent', state['ShipIdent']))
if state['ShipName'] is not None:
props.append(('shipName', state['ShipName']))
if state['PaintJob'] is not None:
props.append(('paintJob', state['PaintJob']))
updateship(cmdr, state['ShipID'], state['ShipType'], props)
elif entry['event'] in ['ShipyardBuy', 'ShipyardSell']:
sellship(cmdr, entry.get('SellShipID'))
# Send materials info to EDSM on startup or change
if entry['event'] in ['StartUp', 'LoadGame', 'MaterialCollected', 'MaterialDiscarded', 'ScientificResearch', 'EngineerCraft', 'Synthesis']:
setmaterials(cmdr, state['Raw'], state['Manufactured'], state['Encoded'])
# Send paintjob info to EDSM on change
if entry['event'] in ['ModuleBuy', 'ModuleSell'] and entry['Slot'] == 'PaintJob':
updateship(cmdr, state['ShipID'], state['ShipType'], [('paintJob', state['PaintJob'])])
# Write EDSM log on startup and change
if system and entry['event'] in ['Location', 'FSDJump']:
this.lastlookup = False
writelog(cmdr, timegm(time.strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), system, 'StarPos' in entry and tuple(entry['StarPos']), state['ShipID'])
this.lastlookup = True
this.system.update_idletasks()
except Exception as e:
if __debug__: print_exc()
return unicode(e)
def cmdr_data(data, is_beta):
system = data['lastSystem']['name']
if not this.system['text']:
this.system['text'] = system
this.system['image'] = ''
if not system or system in FAKE:
this.system['url'] = None
this.lastlookup = True
else:
this.system['url'] = 'https://www.edsm.net/show-system?systemName=%s' % urllib2.quote(system)
this.lastlookup = False
this.system.update_idletasks()
if config.getint('edsm_out') and not is_beta and not multicrew and credentials(data['commander']['name']):
# Send flightlog to EDSM if FSDJump failed to do so
if not this.lastlookup:
try:
this.lastlookup = False
this.writelog(data['commander']['name'], int(time.time()), system, None, data['ship']['id'])
this.lastlookup = True
this.system.update_idletasks()
except Exception as e:
if __debug__: print_exc()
return unicode(e)
# Update credits and ship info and send to EDSM
try:
if data['commander'].get('credits') is not None:
setcredits(data['commander']['name'], data['commander']['credits'], data['commander'].get('debt', 0))
ship = companion.ship(data)
if ship != this.lastship:
updateship(data['commander']['name'],
data['ship']['id'],
data['ship']['name'].lower(),
[
('linkToCoriolis', coriolis.url(data, is_beta)),
('linkToEDShipyard', edshipyard.url(data, is_beta)),
])
this.lastship = ship
except Exception as e:
# Not particularly important so silent on failure
if __debug__: print_exc()
# Call an EDSM endpoint with args (which should be quoted)
def call(cmdr, endpoint, args, check_msgnum=True):
try:
(username, apikey) = credentials(cmdr)
url = 'https://www.edsm.net/%s?commanderName=%s&apiKey=%s&fromSoftware=%s&fromSoftwareVersion=%s' % (
endpoint,
urllib2.quote(username.encode('utf-8')),
urllib2.quote(apikey),
urllib2.quote(applongname),
urllib2.quote(appversion),
) + args
r = this.session.get(url, timeout=_TIMEOUT)
r.raise_for_status()
reply = r.json()
if not check_msgnum:
return reply
(msgnum, msg) = reply['msgnum'], reply['msg']
except:
if __debug__: print_exc()
raise Exception(_("Error: Can't connect to EDSM"))
# Message numbers: 1xx = OK, 2xx = fatal error, 3xx = error (but not generated in practice), 4xx = ignorable errors
if msgnum // 100 not in (1,4):
raise Exception(_('Error: EDSM {MSG}').format(MSG=msg))
else:
return reply
# Send flight log and also do lookup
def writelog(cmdr, timestamp, system_name, coordinates, shipid = None):
if system_name in FAKE:
return
args = '&systemName=%s&dateVisited=%s' % (
urllib2.quote(system_name),
urllib2.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(timestamp))),
)
if coordinates:
args += '&x=%.3f&y=%.3f&z=%.3f' % coordinates
if shipid is not None:
args += '&shipId=%d' % shipid
try:
reply = call(cmdr, 'api-logs-v1/set-log', args)
if reply.get('systemCreated'):
this.system['image'] = this._IMG_NEW
else:
this.system['image'] = this._IMG_KNOWN
this.syscache.add(system_name)
except:
this.system['image'] = this._IMG_ERROR
raise
def setranks(cmdr, ranks):
args = ''
if ranks:
for k,v in ranks.iteritems():
if v is not None:
args += '&%s=%s' % (k, urllib2.quote('%d;%d' % v))
if args:
call(cmdr, 'api-commander-v1/set-ranks', args)
def setcredits(cmdr, balance, loan):
if balance is not None:
call(cmdr, 'api-commander-v1/set-credits', '&balance=%d&loan=%d' % (balance, loan))
def setmaterials(cmdr, raw, manufactured, encoded):
call(cmdr, 'api-commander-v1/set-materials', "&type=data&values=%s" % json.dumps(encoded, separators = (',', ':')))
materials = {}
materials.update(raw)
materials.update(manufactured)
call(cmdr, 'api-commander-v1/set-materials', "&type=materials&values=%s" % json.dumps(materials, separators = (',', ':')))
def setshipid(cmdr, shipid):
if shipid is not None:
call(cmdr, 'api-commander-v1/set-ship-id', '&shipId=%d' % shipid)
def updateship(cmdr, shipid, shiptype, props=[]):
if shipid is not None and shiptype:
args = '&shipId=%d&type=%s' % (shipid, shiptype)
for (slot, thing) in props:
args += '&%s=%s' % (slot, urllib2.quote(unicode(thing)))
call(cmdr, 'api-commander-v1/update-ship', args)
def sellship(cmdr, shipid):
if shipid is not None:
call(cmdr, 'api-commander-v1/sell-ship', '&shipId=%d' % shipid)

View File

@ -182,36 +182,6 @@ class PreferencesDialog(tk.Toplevel):
notebook.add(eddnframe, text='EDDN') # Not translated notebook.add(eddnframe, text='EDDN') # Not translated
edsmframe = nb.Frame(notebook)
edsmframe.columnconfigure(1, weight=1)
HyperlinkLabel(edsmframe, text='Elite Dangerous Star Map', background=nb.Label().cget('background'), url='https://www.edsm.net/', underline=True).grid(columnspan=2, padx=PADX, sticky=tk.W) # Don't translate
self.edsm_log = tk.IntVar(value = (output & config.OUT_SYS_EDSM) and 1)
self.edsm_log_button = nb.Checkbutton(edsmframe, text=_('Send flight log to Elite Dangerous Star Map'), variable=self.edsm_log, command=self.outvarchanged)
self.edsm_log_button.grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W)
nb.Label(edsmframe).grid(sticky=tk.W) # big spacer
self.edsm_label = HyperlinkLabel(edsmframe, text=_('Elite Dangerous Star Map credentials'), background=nb.Label().cget('background'), url='https://www.edsm.net/settings/api', underline=True) # Section heading in settings
self.edsm_label.grid(columnspan=2, padx=PADX, sticky=tk.W)
self.edsm_cmdr_label = nb.Label(edsmframe, text=_('Cmdr')) # Main window
self.edsm_cmdr_label.grid(row=10, padx=PADX, sticky=tk.W)
self.edsm_cmdr_text = nb.Label(edsmframe)
self.edsm_cmdr_text.grid(row=10, column=1, padx=PADX, pady=PADY, sticky=tk.W)
self.edsm_user_label = nb.Label(edsmframe, text=_('Commander Name')) # EDSM setting
self.edsm_user_label.grid(row=11, padx=PADX, sticky=tk.W)
self.edsm_user = nb.Entry(edsmframe)
self.edsm_user.grid(row=11, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
self.edsm_apikey_label = nb.Label(edsmframe, text=_('API Key')) # EDSM setting
self.edsm_apikey_label.grid(row=12, padx=PADX, sticky=tk.W)
self.edsm_apikey = nb.Entry(edsmframe)
self.edsm_apikey.grid(row=12, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
notebook.add(edsmframe, text='EDSM') # Not translated
# build plugin prefs tabs # build plugin prefs tabs
for plugin in plug.PLUGINS: for plugin in plug.PLUGINS:
plugframe = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta) plugframe = plugin.get_prefs(notebook, monitor.cmdr, monitor.is_beta)
@ -406,22 +376,14 @@ class PreferencesDialog(tk.Toplevel):
self.username.delete(0, tk.END) self.username.delete(0, tk.END)
self.password['state'] = tk.NORMAL self.password['state'] = tk.NORMAL
self.password.delete(0, tk.END) self.password.delete(0, tk.END)
self.edsm_user['state'] = tk.NORMAL
self.edsm_user.delete(0, tk.END)
self.edsm_apikey['state'] = tk.NORMAL
self.edsm_apikey.delete(0, tk.END)
if monitor.cmdr and config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'): if monitor.cmdr and config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'):
config_idx = config.get('cmdrs').index(monitor.cmdr) config_idx = config.get('cmdrs').index(monitor.cmdr)
self.username.insert(0, config.get('fdev_usernames')[config_idx] or '') self.username.insert(0, config.get('fdev_usernames')[config_idx] or '')
self.password.insert(0, config.get_password(config.get('fdev_usernames')[config_idx]) or '') self.password.insert(0, config.get_password(config.get('fdev_usernames')[config_idx]) or '')
self.edsm_user.insert(0, config.get('edsm_usernames')[config_idx] or '')
self.edsm_apikey.insert(0, config.get('edsm_apikeys')[config_idx] or '')
elif monitor.cmdr and not config.get('cmdrs') and config.get('username') and config.get('password'): elif monitor.cmdr and not config.get('cmdrs') and config.get('username') and config.get('password'):
# migration from <= 2.25 # migration from <= 2.25
self.username.insert(0, config.get('username') or '') self.username.insert(0, config.get('username') or '')
self.password.insert(0, config.get('password') or '') self.password.insert(0, config.get('password') or '')
self.edsm_user.insert(0,config.get('edsm_cmdrname') or '')
self.edsm_apikey.insert(0, config.get('edsm_apikey') or '')
if self.cmdr is not False: # Don't notify on first run if self.cmdr is not False: # Don't notify on first run
plug.notify_prefs_cmdr_changed(monitor.cmdr, monitor.is_beta) plug.notify_prefs_cmdr_changed(monitor.cmdr, monitor.is_beta)
self.cmdr = monitor.cmdr self.cmdr = monitor.cmdr
@ -452,11 +414,6 @@ class PreferencesDialog(tk.Toplevel):
self.eddn_system_button['state']= logvalid and tk.NORMAL or tk.DISABLED self.eddn_system_button['state']= logvalid and tk.NORMAL or tk.DISABLED
self.eddn_delay_button['state'] = logvalid and eddn.replayfile and self.eddn_system.get() and tk.NORMAL or tk.DISABLED self.eddn_delay_button['state'] = logvalid and eddn.replayfile and self.eddn_system.get() and tk.NORMAL or tk.DISABLED
self.edsm_log_button['state'] = logvalid and tk.NORMAL or tk.DISABLED
edsm_state = logvalid and monitor.cmdr and self.edsm_log.get() and tk.NORMAL or tk.DISABLED
self.edsm_label['state'] = self.edsm_cmdr_label['state'] = self.edsm_user_label['state'] = self.edsm_apikey_label['state'] = edsm_state
self.edsm_cmdr_text['state'] = self.edsm_user['state'] = self.edsm_apikey['state'] = edsm_state
def filebrowse(self, title, pathvar): def filebrowse(self, title, pathvar):
if platform != 'win32': if platform != 'win32':
import tkFileDialog import tkFileDialog
@ -598,14 +555,10 @@ class PreferencesDialog(tk.Toplevel):
if not config.get('cmdrs'): if not config.get('cmdrs'):
config.set('cmdrs', [self.cmdr]) config.set('cmdrs', [self.cmdr])
config.set('fdev_usernames', [self.username.get().strip()]) config.set('fdev_usernames', [self.username.get().strip()])
config.set('edsm_usernames', [self.edsm_user.get().strip()])
config.set('edsm_apikeys', [self.edsm_apikey.get().strip()])
else: else:
idx = config.get('cmdrs').index(self.cmdr) if self.cmdr in config.get('cmdrs') else -1 idx = config.get('cmdrs').index(self.cmdr) if self.cmdr in config.get('cmdrs') else -1
_putfirst('cmdrs', idx, self.cmdr) _putfirst('cmdrs', idx, self.cmdr)
_putfirst('fdev_usernames', idx, self.username.get().strip()) _putfirst('fdev_usernames', idx, self.username.get().strip())
_putfirst('edsm_usernames', idx, self.edsm_user.get().strip())
_putfirst('edsm_apikeys', idx, self.edsm_apikey.get().strip())
config.set('output', config.set('output',
(self.out_td.get() and config.OUT_MKT_TD) + (self.out_td.get() and config.OUT_MKT_TD) +
@ -614,8 +567,7 @@ class PreferencesDialog(tk.Toplevel):
(self.out_ship.get() and config.OUT_SHIP) + (self.out_ship.get() and config.OUT_SHIP) +
(self.eddn_station.get() and config.OUT_MKT_EDDN) + (self.eddn_station.get() and config.OUT_MKT_EDDN) +
(self.eddn_system.get() and config.OUT_SYS_EDDN) + (self.eddn_system.get() and config.OUT_SYS_EDDN) +
(self.eddn_delay.get() and config.OUT_SYS_DELAY) + (self.eddn_delay.get() and config.OUT_SYS_DELAY))
(self.edsm_log.get() and config.OUT_SYS_EDSM))
config.set('outdir', self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get()) config.set('outdir', self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get())
logdir = self.logdir.get() logdir = self.logdir.get()
@ -764,12 +716,8 @@ def migrate(current_cmdr):
config.set_password(config.get('username'), config.get('password')) # Can fail on Linux config.set_password(config.get('username'), config.get('password')) # Can fail on Linux
config.set('cmdrs', [current_cmdr]) config.set('cmdrs', [current_cmdr])
config.set('fdev_usernames', [config.get('username')]) config.set('fdev_usernames', [config.get('username')])
config.set('edsm_usernames', [config.get('edsm_cmdrname') or ''])
config.set('edsm_apikeys', [config.get('edsm_apikey') or ''])
config.delete('username') config.delete('username')
config.delete('password') config.delete('password')
config.delete('edsm_cmdrname')
config.delete('edsm_apikey')
# Put current Cmdr first in the lists # Put current Cmdr first in the lists
def make_current(current_cmdr): def make_current(current_cmdr):
@ -777,8 +725,6 @@ def make_current(current_cmdr):
idx = config.get('cmdrs').index(current_cmdr) idx = config.get('cmdrs').index(current_cmdr)
_putfirst('cmdrs', idx) _putfirst('cmdrs', idx)
_putfirst('fdev_usernames', idx) _putfirst('fdev_usernames', idx)
_putfirst('edsm_usernames', idx)
_putfirst('edsm_apikeys', idx)
def _putfirst(setting, config_idx, new_value=None): def _putfirst(setting, config_idx, new_value=None):
assert config_idx>=0 or new_value is not None, (setting, config_idx, new_value) assert config_idx>=0 or new_value is not None, (setting, config_idx, new_value)

View File

@ -65,7 +65,7 @@ if sys.platform=='darwin':
APP = 'EDMarketConnector.py' APP = 'EDMarketConnector.py'
APPCMD = 'EDMC.py' APPCMD = 'EDMC.py'
SHORTVERSION = ''.join(VERSION.split('.')[:3]) SHORTVERSION = ''.join(VERSION.split('.')[:3])
PLUGINS = [ 'plugins/eddb.py' ] PLUGINS = [ 'plugins/eddb.py', 'plugins/edsm.py' ]
if sys.platform=='darwin': if sys.platform=='darwin':
OPTIONS = { 'py2app': OPTIONS = { 'py2app':