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

Switch eddb integration to a plugin

This commit is contained in:
Jonathan Harris 2017-07-12 23:21:27 +01:00
parent b794e19d75
commit fe0835be10
10 changed files with 93 additions and 79 deletions

View File

@ -24,15 +24,12 @@ import loadout
import edshipyard
import coriolis
import shipyard
import eddb
import eddn
import stats
import prefs
from config import appcmdname, appversion, update_feed, config
EDDB = eddb.EDDB()
SERVER_RETRY = 5 # retry pause for Companion servers [s]
EXIT_SUCCESS, EXIT_SERVER, EXIT_CREDENTIALS, EXIT_VERIFICATION, EXIT_NOT_DOCKED, EXIT_SYS_ERR = range(6)
@ -127,7 +124,6 @@ try:
# Finally - the data looks sane and we're docked at a station
print '%s,%s' % (data['lastSystem']['name'], data['lastStarport']['name'])
(station_id, has_market, has_outfitting, has_shipyard) = EDDB.station(data['lastSystem']['name'], data['lastStarport']['name'])
if (args.m or args.o or args.s) and not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')): # Ignore possibly missing shipyard info
sys.stderr.write("Station doesn't have anything!\n")
@ -155,13 +151,11 @@ try:
sys.stderr.write("Station doesn't supply outfitting\n")
if args.s:
if has_shipyard and not data['lastStarport'].get('ships') and not args.j:
if not data['lastStarport'].get('ships') and not args.j:
sleep(SERVER_RETRY)
data = session.query()
if data['lastStarport'].get('ships'):
shipyard.export(data, args.s)
elif has_shipyard:
sys.stderr.write("Couldn't retrieve shipyard info\n")
else:
sys.stderr.write("Station doesn't have a shipyard\n")

View File

@ -56,7 +56,6 @@ import td
import eddn
import edsm
import coriolis
import eddb
import edshipyard
import loadout
import stats
@ -67,7 +66,6 @@ from monitor import monitor
from interactions import interactions
from theme import theme
EDDB = eddb.EDDB()
SERVER_RETRY = 5 # retry pause for Companion servers [s]
EDSM_POLL = 0.1
@ -80,8 +78,6 @@ CLOCK_THRESHOLD = 11 * 60 * 60 + TZ_THRESHOLD
class AppWindow:
STATION_UNDOCKED = u'×' # "Station" name to display when not docked = U+00D7
# Tkinter Event types
EVENT_KEYPRESS = 2
EVENT_BUTTON = 4
@ -118,22 +114,18 @@ class AppWindow:
self.cmdr_label = tk.Label(frame)
self.ship_label = tk.Label(frame)
self.system_label = tk.Label(frame)
self.station_label = tk.Label(frame)
self.cmdr_label.grid(row=1, 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.station_label.grid(row=4, column=0, sticky=tk.W)
self.cmdr = tk.Label(frame, anchor=tk.W)
self.ship = HyperlinkLabel(frame, url = self.shipyard_url)
self.system = HyperlinkLabel(frame, compound=tk.RIGHT, url = self.system_url, popup_copy = True)
self.station = HyperlinkLabel(frame, url = self.station_url, popup_copy = lambda x: x!=self.STATION_UNDOCKED)
self.cmdr.grid(row=1, 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)
self.station.grid(row=4, column=1, sticky=tk.EW)
for plugin in plug.PLUGINS:
appitem = plugin.get_app(frame)
@ -355,7 +347,6 @@ class AppWindow:
self.ship_label['text'] = (monitor.captain and _('Role') or # Multicrew role label in main window
_('Ship')) + ':' # Main window
self.system_label['text'] = _('System') + ':' # Main window
self.station_label['text'] = _('Station') + ':' # Main window
self.button['text'] = self.theme_button['text'] = _('Update') # Update button in main window
if platform == 'darwin':
self.menubar.entryconfigure(1, label=_('File')) # Menu title
@ -480,7 +471,6 @@ class AppWindow:
if not monitor.system:
self.system['text'] = data['lastSystem']['name']
self.system['image'] = ''
self.station['text'] = data['commander'].get('docked') and data.get('lastStarport') and data['lastStarport'].get('name') or (EDDB.system(self.system['text']) and self.STATION_UNDOCKED or '')
self.status['text'] = ''
self.edit_menu.entryconfigure(0, state=tk.NORMAL) # Copy
@ -515,7 +505,6 @@ class AppWindow:
else:
# Finally - the data looks sane and we're docked at a station
(station_id, has_market, has_outfitting, has_shipyard) = EDDB.station(self.system['text'], self.station['text'])
# No EDDN output?
if (config.getint('output') & config.OUT_MKT_EDDN) and not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')): # Ignore possibly missing shipyard info
@ -544,7 +533,7 @@ class AppWindow:
self.w.update_idletasks()
self.eddn.export_commodities(data, monitor.is_beta)
self.eddn.export_outfitting(data, monitor.is_beta)
if has_shipyard and not data['lastStarport'].get('ships'):
if monitor.stationtype != 'Outpost' and not data['lastStarport'].get('ships'):
# API is flakey about shipyard info - silently retry if missing (<1s is usually sufficient - 5s for margin).
self.w.after(int(SERVER_RETRY * 1000), self.retry_for_shipyard)
else:
@ -634,7 +623,6 @@ class AppWindow:
return
system_changed = monitor.system and self.system['text'] != monitor.system
station_changed = monitor.station and self.station['text'] != monitor.station
# Update main window
if monitor.cmdr and monitor.captain:
@ -656,7 +644,6 @@ class AppWindow:
self.ship_label['text'] = _('Ship') + ':' # Main window
self.ship['text'] = ''
self.station['text'] = monitor.station or (EDDB.system(monitor.system) and self.STATION_UNDOCKED or '')
if self.system['text'] != monitor.system:
self.system['text'] = monitor.system or ''
self.edsm.link(monitor.system)
@ -747,7 +734,7 @@ class AppWindow:
plug.notify_system_changed(timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')), monitor.system, monitor.coordinates)
# Auto-Update after docking
if station_changed and monitor.mode and not config.getint('output') & config.OUT_MKT_MANUAL and config.getint('output') & config.OUT_STATION_ANY:
if monitor.mode and monitor.station and entry['event'] in ['StartUp', 'Location', 'Docked'] and not config.getint('output') & config.OUT_MKT_MANUAL and config.getint('output') & config.OUT_STATION_ANY:
self.w.after(int(SERVER_RETRY * 1000), self.getandsend)
# Send interesting events to EDDN
@ -863,18 +850,6 @@ class AppWindow:
def system_url(self, text):
return text and self.edsm.result['url']
def station_url(self, text):
if text:
(station_id, has_market, has_outfitting, has_shipyard) = EDDB.station(self.system['text'], self.station['text'])
if station_id:
return 'https://eddb.io/station/%d' % station_id
system_id = EDDB.system(self.system['text'])
if system_id:
return 'https://eddb.io/system/%d' % system_id
return None
def cooldown(self):
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
@ -888,9 +863,9 @@ class AppWindow:
self.w.wm_attributes('-topmost', self.always_ontop.get())
def copy(self, event=None):
if self.system['text']:
if monitor.system:
self.w.clipboard_clear()
self.w.clipboard_append(self.station['text'] == self.STATION_UNDOCKED and self.system['text'] or '%s,%s' % (self.system['text'], self.station['text']))
self.w.clipboard_append(monitor.station and '%s,%s' % (monitor.system, monitor.station) or monitor.system)
def help_general(self, event=None):
webbrowser.open('https://github.com/Marginal/EDMarketConnector/wiki')

View File

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

View File

@ -457,7 +457,7 @@
/* Empire rank. [stats.py] */
"Squire" = "Squire";
/* Main window. [EDMarketConnector.py] */
/* Main window. [eddb.py] */
"Station" = "Station";
/* [EDMarketConnector.py] */

45
eddb.py
View File

@ -1,47 +1,16 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# eddb.io station database
# build databases from files systems.csv and stations.json from http://eddb.io/api
#
import cPickle
import csv
import os
from os.path import dirname, join, normpath
import sys
from sys import platform
import json
import requests
from config import config
class EDDB:
HAS_MARKET = 1
HAS_OUTFITTING = 2
HAS_SHIPYARD = 4
def __init__(self):
with open(join(config.respath, 'systems.p'), 'rb') as h:
self.system_ids = cPickle.load(h)
with open(join(config.respath, 'stations.p'), 'rb') as h:
self.station_ids = cPickle.load(h)
# system_name -> system_id or 0
def system(self, system_name):
return self.system_ids.get(system_name, 0) # return 0 on failure (0 is not a valid id)
# (system_name, station_name) -> (station_id, has_market, has_outfitting, has_shipyard)
def station(self, system_name, station_name):
(station_id, flags) = self.station_ids.get((self.system_ids.get(system_name), station_name), (0,0))
return (station_id, bool(flags & EDDB.HAS_MARKET), bool(flags & EDDB.HAS_OUTFITTING), bool(flags & EDDB.HAS_SHIPYARD))
#
# build databases from files systems.csv and stations.json from http://eddb.io/api
#
if __name__ == "__main__":
import json
import requests
def download(filename):
r = requests.get('https://eddb.io/archive/v5/' + filename, stream=True)
@ -153,9 +122,7 @@ if __name__ == "__main__":
print '%-20s%8d %8d %11.5f %11.5f %11.5f' % (s['name'], system_ids[s['name']], k, s['x'], s['y'], s['z'])
# Hack - ensure duplicate system names are pointing at the more interesting system
system_ids['Almar'] = 750
system_ids['Amo'] = 866
system_ids['Arti'] = 60342
system_ids['Ogmar'] = 14915 # in bubble, not Colonia
system_ids['Ratri'] = 16001 # "
system_ids['K Carinae'] = 375886 # both unpopulated
@ -179,11 +146,7 @@ if __name__ == "__main__":
# station_id by (system_id, station_name)
stations = json.loads(download('stations.json').content) # let json do the utf-8 decode
station_ids = {
(x['system_id'], str(x['name'])) :
(x['id'],
(EDDB.HAS_MARKET if x['has_market'] else 0) |
(EDDB.HAS_OUTFITTING if x['has_outfitting'] else 0) |
(EDDB.HAS_SHIPYARD if x['has_shipyard'] else 0))
(x['system_id'], str(x['name'])) : x['id']
for x in stations if x['max_landing_pad_size']
}

View File

@ -130,6 +130,7 @@ class EDLogs(FileSystemEventHandler):
self.body = None
self.system = None
self.station = None
self.stationtype = None
self.coordinates = None
self.started = None # Timestamp of the LoadGame event
@ -197,7 +198,7 @@ class EDLogs(FileSystemEventHandler):
if __debug__:
print 'Stopping monitoring Journal'
self.currentdir = None
self.version = self.mode = self.group = self.cmdr = self.body = self.system = self.station = self.coordinates = None
self.version = self.mode = self.group = self.cmdr = self.body = self.system = self.station = self.stationtype = self.coordinates = None
self.is_beta = False
if self.observed:
self.observed = None
@ -306,6 +307,7 @@ class EDLogs(FileSystemEventHandler):
self.body = None
self.system = None
self.station = None
self.stationtype = None
self.coordinates = None
self.started = None
self.state = {
@ -332,6 +334,7 @@ class EDLogs(FileSystemEventHandler):
self.body = None
self.system = None
self.station = None
self.stationtype = None
self.coordinates = None
self.started = timegm(strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ'))
self.state.update({
@ -374,6 +377,7 @@ class EDLogs(FileSystemEventHandler):
self.state['PaintJob'] = self.canonicalise(entry.get('BuyItem'))
elif entry['event'] in ['Undocked']:
self.station = None
self.stationtype = None
elif entry['event'] in ['Location', 'FSDJump', 'Docked']:
if entry['event'] != 'Docked':
self.body = None
@ -383,6 +387,7 @@ class EDLogs(FileSystemEventHandler):
self.coordinates = None # Docked event doesn't include coordinates
self.system = entry['StarSystem'] == 'ProvingGround' and 'CQC' or entry['StarSystem']
self.station = entry.get('StationName') # May be None
self.stationtype = entry.get('StationType') # May be None
elif entry['event'] == 'SupercruiseExit':
self.body = entry.get('BodyType') == 'Planet' and entry.get('Body')
elif entry['event'] == 'SupercruiseEntry':
@ -454,6 +459,7 @@ class EDLogs(FileSystemEventHandler):
self.body = None
self.system = None
self.station = None
self.stationtype = None
self.coordinates = None
elif entry['event'] == 'ChangeCrewRole':
self.role = entry['Role'] != 'Idle' and entry['Role'] or None
@ -463,6 +469,7 @@ class EDLogs(FileSystemEventHandler):
self.body = None
self.system = None
self.station = None
self.stationtype = None
self.coordinates = None
return entry

68
plugins/eddb.py Normal file
View File

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
#
# Station display and eddb.io lookup
#
import cPickle
import csv
import os
from os.path import dirname, join, normpath
import sys
import Tkinter as tk
from ttkHyperlinkLabel import HyperlinkLabel
from config import config
STATION_UNDOCKED = u'×' # "Station" name to display when not docked = U+00D7
this = sys.modules[__name__] # For holding module globals
this.system = None # name of current system
with open(join(config.respath, 'systems.p'), 'rb') as h:
this.system_ids = cPickle.load(h)
with open(join(config.respath, 'stations.p'), 'rb') as h:
this.station_ids = cPickle.load(h)
# system_name -> system_id or 0
def system_id(system_name):
return this.system_ids.get(system_name, 0) # return 0 on failure (0 is not a valid id)
# (system_name, station_name) -> station_id or 0
def station_id(system_name, station_name):
return this.station_ids.get((this.system_ids.get(system_name), station_name), 0)
def station_url(text):
if text:
station = station_id(this.system, text)
if station:
return 'https://eddb.io/station/%d' % station
system = system_id(this.system)
if system:
return 'https://eddb.io/system/%d' % system
return None
def plugin_start():
return '~eddb'
def plugin_app(parent):
this.station_label = tk.Label(parent, text = _('Station') + ':') # Main window
this.station = HyperlinkLabel(parent, url = station_url, popup_copy = lambda x: x != STATION_UNDOCKED)
return (this.station_label, this.station)
def prefs_changed():
this.station_label['text'] = _('Station') + ':'
def journal_entry(cmdr, system, station, entry, state):
this.system = system
this.station['text'] = station or (system_id(system) and STATION_UNDOCKED or '')
def cmdr_data(data):
this.station['text'] = data['commander']['docked'] and data['lastStarport']['name'] or (system_id(data['lastSystem']['name']) and STATION_UNDOCKED or '')

View File

@ -65,6 +65,7 @@ if sys.platform=='darwin':
APP = 'EDMarketConnector.py'
APPCMD = 'EDMC.py'
SHORTVERSION = ''.join(VERSION.split('.')[:3])
PLUGINS = [ 'plugins/eddb.py' ]
if sys.platform=='darwin':
OPTIONS = { 'py2app':
@ -74,6 +75,7 @@ if sys.platform=='darwin':
'frameworks': [ 'Sparkle.framework' ],
'excludes': [ 'certifi', 'PIL', 'simplejson' ],
'iconfile': '%s.icns' % APPNAME,
'extra_scripts': PLUGINS,
'resources': ['snd_good.wav', 'snd_bad.wav', 'modules.p', 'ships.p', 'stations.p', 'systems.p'],
'semi_standalone': True,
'site_packages': False,
@ -117,6 +119,7 @@ elif sys.platform=='win32':
'systems.p',
'%s.VisualElementsManifest.xml' % APPNAME,
'%s.ico' % APPNAME ] +
PLUGINS +
[join('L10n',x) for x in os.listdir('L10n') if x.endswith('.strings')] ) ]
setup(

Binary file not shown.

BIN
systems.p

Binary file not shown.