1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-05-31 23:59:38 +03:00

Make system and station names clickable and send to EDSM and eddb respectively.

This commit is contained in:
Jonathan Harris 2015-09-05 12:23:15 +01:00
parent edcda94e0f
commit b82c186d34
8 changed files with 126 additions and 7 deletions

View File

@ -8,6 +8,8 @@ from os.path import expanduser, isdir, join
import re import re
import requests import requests
from time import time, localtime, strftime from time import time, localtime, strftime
import urllib
import webbrowser
import Tkinter as tk import Tkinter as tk
import ttk import ttk
@ -24,14 +26,49 @@ import eddn
import loadout import loadout
import coriolis import coriolis
import flightlog import flightlog
import eddb
import prefs import prefs
from config import appname, applongname, config from config import appname, applongname, config
l10n.Translations().install() l10n.Translations().install()
EDDB = eddb.EDDB()
SHIPYARD_RETRY = 5 # retry pause for shipyard data [s] SHIPYARD_RETRY = 5 # retry pause for shipyard data [s]
class HyperlinkLabel(ttk.Label):
def __init__(self, master=None, **kw):
self.urlfn = kw.pop('urlfn', None)
ttk.Label.__init__(self, master, **kw)
self.font_n = kw.get('font', ttk.Style().lookup('TLabel', 'font'))
self.font_u = tkFont.Font(self, self.font_n)
self.font_u.configure(underline = True)
self.bind('<Enter>', self._enter)
self.bind('<Leave>', self._leave)
self.bind('<Button-1>', self._click)
# Make blue and clickable if setting non-empty text
def __setitem__(self, key, value):
if key=='text':
if self.urlfn and value:
self.configure({key: value}, foreground = 'blue', cursor = platform=='darwin' and 'pointinghand' or 'hand2')
else:
self.configure({key: value}, foreground = '', cursor = 'arrow')
else:
self.configure({key: value})
def _enter(self, event):
self.configure(font = self.font_u)
def _leave(self, event):
self.configure(font = self.font_n)
def _click(self, event):
if self.urlfn and self['text']:
webbrowser.open(self.urlfn(self['text']))
class AppWindow: class AppWindow:
def __init__(self, master): def __init__(self, master):
@ -73,8 +110,8 @@ class AppWindow:
ttk.Label(frame, text=_('Station:')).grid(row=2, column=0, sticky=tk.W) # Main window ttk.Label(frame, text=_('Station:')).grid(row=2, column=0, sticky=tk.W) # Main window
self.cmdr = ttk.Label(frame, width=-20) self.cmdr = ttk.Label(frame, width=-20)
self.system = ttk.Label(frame, width=-20) self.system = HyperlinkLabel(frame, width=-20, urlfn = self.system_url)
self.station = ttk.Label(frame, width=-20) self.station = HyperlinkLabel(frame, width=-20, urlfn = self.station_url)
self.button = ttk.Button(frame, text=_('Update'), command=self.getandsend, default=tk.ACTIVE, state=tk.DISABLED) # Update button in main window self.button = ttk.Button(frame, text=_('Update'), command=self.getandsend, default=tk.ACTIVE, state=tk.DISABLED) # Update button in main window
self.status = ttk.Label(frame, width=-25) self.status = ttk.Label(frame, width=-25)
self.w.bind('<Return>', self.getandsend) self.w.bind('<Return>', self.getandsend)
@ -201,7 +238,7 @@ class AppWindow:
self.cmdr['text'] = data.get('commander') and data.get('commander').get('name') or '' self.cmdr['text'] = data.get('commander') and data.get('commander').get('name') or ''
self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or '' self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or ''
self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or '-' self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or (EDDB.system(self.system['text'] and '-' or ''))
config.set('querytime', querytime) config.set('querytime', querytime)
self.holdofftime = querytime + companion.holdoff self.holdofftime = querytime + companion.holdoff
@ -295,6 +332,21 @@ class AppWindow:
self.cooldown() self.cooldown()
def system_url(self, text):
return text and 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(text)
def station_url(self, text):
if text:
station_id = EDDB.station(self.system['text'], self.station['text'])
if station_id:
return 'http://eddb.io/station/%d' % station_id
system_id = EDDB.system(self.system['text'])
if system_id:
return 'http://eddb.io/system/%d' % system_id
return None
def cooldown(self): def cooldown(self):
if time() < self.holdofftime: if time() < self.holdofftime:
self.button['text'] = _('cooldown {SS}s').format(SS = int(self.holdofftime - time())) # Update button in main window self.button['text'] = _('cooldown {SS}s').format(SS = int(self.holdofftime - time())) # Update button in main window

View File

@ -98,6 +98,12 @@
<Component Guid="{9DBAB544-E815-40A5-866A-391B68919344}"> <Component Guid="{9DBAB544-E815-40A5-866A-391B68919344}">
<File KeyPath="yes" Source="SourceDir\select.pyd" /> <File KeyPath="yes" Source="SourceDir\select.pyd" />
</Component> </Component>
<Component Guid="*">
<File KeyPath="yes" Source="SourceDir\stations.p" />
</Component>
<Component Guid="*">
<File KeyPath="yes" Source="SourceDir\systems.p" />
</Component>
<Component Guid="{30EEAD30-A43B-4A31-A209-450A8AD17AC2}"> <Component Guid="{30EEAD30-A43B-4A31-A209-450A8AD17AC2}">
<File KeyPath="yes" Source="SourceDir\tcl85.dll" /> <File KeyPath="yes" Source="SourceDir\tcl85.dll" />
</Component> </Component>
@ -344,6 +350,8 @@
<ComponentRef Id="pyexpat.pyd" /> <ComponentRef Id="pyexpat.pyd" />
<ComponentRef Id="python27.dll" /> <ComponentRef Id="python27.dll" />
<ComponentRef Id="select.pyd" /> <ComponentRef Id="select.pyd" />
<ComponentRef Id="stations.p" />
<ComponentRef Id="systems.p" />
<ComponentRef Id="tcl85.dll" /> <ComponentRef Id="tcl85.dll" />
<ComponentRef Id="tk85.dll" /> <ComponentRef Id="tk85.dll" />
<ComponentRef Id="unicodedata.pyd" /> <ComponentRef Id="unicodedata.pyd" />

View File

@ -9,6 +9,10 @@ This app downloads commodity market and other data from the game [Elite: Dangero
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 automatically 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.
Click on the station name to go to its [Elite: Dangerous Database](http://eddb.io/) (“eddb”) entry in your web broswer.
![Windows screenshot](img/win.png) ![Mac screenshot](img/mac.png) ![Windows screenshot](img/win.png) ![Mac screenshot](img/mac.png)

View File

@ -1,7 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import json
import requests import requests
from collections import defaultdict from collections import defaultdict
from cookielib import LWPCookieJar from cookielib import LWPCookieJar
@ -193,7 +192,7 @@ class Session:
r.raise_for_status() r.raise_for_status()
try: try:
data = json.loads(r.text) data = r.json()
except: except:
self.dump(r) self.dump(r)
raise ServerError() raise ServerError()

53
eddb.py Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/python
#
# eddb.io station database
#
import cPickle
from os.path import dirname, join, normpath
import sys
from sys import platform
class EDDB:
def __init__(self):
self.system_ids = cPickle.load(open(join(self.respath(), 'systems.p'), 'rb'))
self.station_ids = cPickle.load(open(join(self.respath(), 'stations.p'), 'rb'))
# system_name -> system_id
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
def station(self, system_name, station_name):
return self.station_ids.get((self.system_ids.get(system_name), station_name), 0) # return 0 on failure (0 is not a valid id)
def respath(self):
if getattr(sys, 'frozen', False):
if platform=='darwin':
return normpath(join(dirname(sys.executable), os.pardir, 'Resources'))
else:
return dirname(sys.executable)
elif __file__:
return dirname(__file__)
else:
return '.'
# build system & station database from files systems.json and stations_lite.json from http://eddb.io/api
if __name__ == "__main__":
import json
# system_name by system_id
systems = dict([(x['id'], str(x['name'])) for x in json.loads(open('systems.json').read())])
stations = json.loads(open('stations_lite.json').read())
# system_id by system_name - populated systems only
system_ids = dict([(systems[x['system_id']], x['system_id']) for x in stations])
cPickle.dump(system_ids, open('systems.p', 'wb'), protocol = cPickle.HIGHEST_PROTOCOL)
# station_id by (system_id, station_name)
station_ids = dict([((x['system_id'], str(x['name'])), x['id']) for x in stations])
cPickle.dump(station_ids, open('stations.p', 'wb'), protocol = cPickle.HIGHEST_PROTOCOL)

View File

@ -57,13 +57,14 @@ VERSION = re.search(r"^appversion\s*=\s*'(.+)'", file('config.py').read(), re.MU
SHORTVERSION = ''.join(VERSION.split('.')[:3]) SHORTVERSION = ''.join(VERSION.split('.')[:3])
if sys.platform=='darwin': if sys.platform=='darwin':
OPTIONS = { 'py2app': OPTIONS = { 'py2app':
{'dist_dir': dist_dir, {'dist_dir': dist_dir,
'optimize': 2, 'optimize': 2,
'packages': [ 'requests' ], 'packages': [ 'requests' ],
'frameworks': [ 'Sparkle.framework' ], 'frameworks': [ 'Sparkle.framework' ],
'excludes': [ 'PIL', 'simplejson' ], 'excludes': [ 'PIL', 'simplejson' ],
'iconfile': '%s.icns' % APPNAME, 'iconfile': '%s.icns' % APPNAME,
'resources': ['stations.p', 'systems.p'],
'semi_standalone': True, 'semi_standalone': True,
'site_packages': False, 'site_packages': False,
'plist': { 'plist': {
@ -98,6 +99,8 @@ elif sys.platform=='win32':
DATA_FILES = [ ('', [requests.certs.where(), DATA_FILES = [ ('', [requests.certs.where(),
'WinSparkle.dll', 'WinSparkle.dll',
'WinSparkle.pdb', # For debugging - don't include in package 'WinSparkle.pdb', # For debugging - don't include in package
'stations.p',
'systems.p',
'%s.VisualElementsManifest.xml' % APPNAME, '%s.VisualElementsManifest.xml' % APPNAME,
'%s.ico' % APPNAME ] + '%s.ico' % APPNAME ] +
[join('L10n',x) for x in os.listdir('L10n') if x.endswith('.strings')] ) ] [join('L10n',x) for x in os.listdir('L10n') if x.endswith('.strings')] ) ]

BIN
stations.p Normal file

Binary file not shown.

BIN
systems.p Normal file

Binary file not shown.