mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-08 05:20:03 +03:00
Add support for saving in Trade Dangerous .prices format.
This commit is contained in:
parent
41958801af
commit
434b82de4b
@ -15,6 +15,7 @@ if __debug__:
|
||||
|
||||
import companion
|
||||
import bpc
|
||||
import td
|
||||
import eddn
|
||||
import prefs
|
||||
from config import appname, applongname, config
|
||||
@ -136,11 +137,19 @@ class AppWindow:
|
||||
config.write('querytime', querytime)
|
||||
self.holdofftime = querytime + companion.holdoff
|
||||
|
||||
if not data.get('commander') or not data.get('commander').get('docked'):
|
||||
# Validation
|
||||
if not data.get('commander') or not data['commander'].get('name','').strip():
|
||||
raise Exception("Who are you?!") # Shouldn't happen
|
||||
elif not data['commander'].get('docked'):
|
||||
raise Exception("You're not docked at a station!")
|
||||
elif not data.get('lastStarport') or not data.get('lastStarport').get('commodities'):
|
||||
elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip():
|
||||
raise Exception("Where are you?!") # Shouldn't happen
|
||||
elif not data.get('lastStarport') or not data['lastStarport'].get('commodities'):
|
||||
raise Exception("Station doesn't have a market!")
|
||||
|
||||
if config.read('output') & config.OUT_TD:
|
||||
td.export(data)
|
||||
|
||||
if config.read('output') & config.OUT_BPC:
|
||||
bpc.export(data)
|
||||
|
||||
|
@ -4,9 +4,9 @@ Elite: Dangerous Market Connector
|
||||
This app downloads commodity market data from the game [Elite: Dangerous](https://www.elitedangerous.com/) and, at your choice, either:
|
||||
|
||||
* transmits the data to the Elite Dangerous Data Network ("EDDN") from where you and others can use it via online trading tools such as [eddb](http://eddb.io/).
|
||||
* saves the data to files on your disk which you can load into trading tools such as [Slopey's BPC Market Tool](https://forums.frontier.co.uk/showthread.php?t=76081).
|
||||
* saves the data to files on your disk which you can load into trading tools such as [Slopey's BPC Market Tool](https://forums.frontier.co.uk/showthread.php?t=76081) and [Trade Dangerous](https://bitbucket.org/kfsone/tradedangerous/wiki/Home).
|
||||
|
||||
The user-interface is deliberately minimal - just press the "Update" button to download and automatically transmit/save the commodity market data for the station where you're currently docked in-game:
|
||||
The user-interface is deliberately minimal - just press the "Update" button when you land at a station to automatically download and transmit or save the station's commodity market data:
|
||||
|
||||
 
|
||||
|
||||
|
42
bpc.py
42
bpc.py
@ -3,54 +3,34 @@
|
||||
|
||||
from os.path import join
|
||||
import codecs
|
||||
import datetime
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
from config import config
|
||||
|
||||
commoditymap = { 'Agricultural Medicines': 'Agri-Medicines',
|
||||
'Atmospheric Extractors': 'Atmospheric Processors',
|
||||
'Auto Fabricators': 'Auto-Fabricators',
|
||||
'Basic Narcotics': 'Narcotics',
|
||||
'Bio Reducing Lichen': 'Bioreducing Lichen',
|
||||
'Hazardous Environment Suits': 'H.E. Suits',
|
||||
'Heliostatic Furnaces': 'Microbial Furnaces',
|
||||
'Marine Supplies': 'Marine Equipment',
|
||||
'Non Lethal Weapons': 'Non-Lethal Weapons',
|
||||
'Terrain Enrichment Systems': 'Land Enrichment Systems' }
|
||||
|
||||
bracketmap = { 0: '',
|
||||
1: 'Low',
|
||||
2: 'Med',
|
||||
3: 'High' }
|
||||
|
||||
from companion import commoditymap, bracketmap
|
||||
|
||||
def export(data):
|
||||
|
||||
querytime = config.read('querytime') or int(time.time())
|
||||
|
||||
filename = join(config.read('outdir'), '%s.%s.%s.bpc' % (data.get('lastSystem').get('name').strip(), data.get('lastStarport').get('name').strip(), time.strftime('%Y-%m-%dT%H.%M.%S', time.localtime(querytime))))
|
||||
filename = join(config.read('outdir'), '%s.%s.%s.bpc' % (data['lastSystem']['name'].strip(), data['lastStarport']['name'].strip(), time.strftime('%Y-%m-%dT%H.%M.%S', time.localtime(querytime))))
|
||||
|
||||
timestamp = datetime.datetime.utcfromtimestamp(querytime).isoformat()
|
||||
rowheader = '%s;%s;%s' % (data.get('commander').get('name').replace(';',':'), data.get('lastSystem').get('name').strip(), data.get('lastStarport').get('name').strip())
|
||||
timestamp = time.strftime('%Y-%m-%dT%H.%M.%S', time.gmtime(querytime))
|
||||
rowheader = '%s;%s;%s' % (data['commander']['name'].replace(';',':').strip(), data['lastSystem']['name'].strip(), data['lastStarport']['name'].strip())
|
||||
|
||||
h = codecs.open(filename, 'w', 'utf-8')
|
||||
h.write('userID;System;Station;Commodity;Sell;Buy;Demand;;Supply;;Date;\r\n')
|
||||
|
||||
for commodity in data.get('lastStarport').get('commodities'):
|
||||
if commodity.get('categoryname') and commodity.get('categoryname') != 'NonMarketable':
|
||||
for commodity in data['lastStarport']['commodities']:
|
||||
if commodity.get('categoryname') and commodity['categoryname'] != 'NonMarketable':
|
||||
h.write('%s;%s;%s;%s;%s;%s;%s;%s;%s;\r\n' % (
|
||||
rowheader,
|
||||
commoditymap.get(commodity.get('name').strip(), commodity.get('name').strip()),
|
||||
commodity.get('sellPrice') and int(commodity.get('sellPrice')) or '',
|
||||
commodity.get('buyPrice') and int(commodity.get('buyPrice')) or '',
|
||||
commodity.get('demandBracket') and int(commodity.get('demand')) or '',
|
||||
commoditymap.get(commodity['name'].strip(), commodity['name'].strip()),
|
||||
commodity.get('sellPrice') and int(commodity['sellPrice']) or '',
|
||||
commodity.get('buyPrice') and int(commodity['buyPrice']) or '',
|
||||
int(commodity['demand']) if commodity.get('demandBracket') else '',
|
||||
bracketmap.get(commodity.get('demandBracket'), ''),
|
||||
commodity.get('stockBracket') and int(commodity.get('stock')) or '',
|
||||
int(commodity['stock']) if commodity.get('stockBracket') else '',
|
||||
bracketmap.get(commodity.get('stockBracket'), ''),
|
||||
timestamp))
|
||||
elif __debug__:
|
||||
print 'Skipping %s : %s' % (commodity.get('name'), commodity.get('categoryname'))
|
||||
|
||||
h.close()
|
||||
|
21
companion.py
21
companion.py
@ -19,6 +19,27 @@ from config import config
|
||||
holdoff = 120 # be nice
|
||||
|
||||
|
||||
# Map values reported by the Companion interface to names displayed in-game and recognized by trade tools
|
||||
|
||||
categorymap = { 'Narcotics': 'Legal Drugs',
|
||||
'Slaves': 'Slavery', }
|
||||
|
||||
commoditymap= { 'Agricultural Medicines': 'Agri-Medicines',
|
||||
'Atmospheric Extractors': 'Atmospheric Processors',
|
||||
'Auto Fabricators': 'Auto-Fabricators',
|
||||
'Basic Narcotics': 'Narcotics',
|
||||
'Bio Reducing Lichen': 'Bioreducing Lichen',
|
||||
'Hazardous Environment Suits': 'H.E. Suits',
|
||||
'Heliostatic Furnaces': 'Microbial Furnaces',
|
||||
'Marine Supplies': 'Marine Equipment',
|
||||
'Non Lethal Weapons': 'Non-Lethal Weapons',
|
||||
'Terrain Enrichment Systems': 'Land Enrichment Systems', }
|
||||
|
||||
bracketmap = { 1: 'Low',
|
||||
2: 'Med',
|
||||
3: 'High', }
|
||||
|
||||
|
||||
class CredentialsError(Exception):
|
||||
def __str__(self):
|
||||
return 'Error: Invalid Credentials'
|
||||
|
@ -16,7 +16,8 @@ appversion = '1.0.0.0'
|
||||
class Config:
|
||||
|
||||
OUT_EDDN = 1
|
||||
OUT_BPC = 2
|
||||
OUT_BPC = 2
|
||||
OUT_TD = 4
|
||||
|
||||
if platform=='darwin':
|
||||
|
||||
|
37
eddn.py
37
eddn.py
@ -1,8 +1,6 @@
|
||||
# Export to EDDN
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import requests
|
||||
from platform import system
|
||||
@ -10,7 +8,7 @@ from sys import platform
|
||||
import time
|
||||
|
||||
from config import applongname, appversion, config
|
||||
from bpc import commoditymap, bracketmap
|
||||
from companion import commoditymap, bracketmap
|
||||
|
||||
upload = 'http://eddn-gateway.elite-markets.net:8080/upload/'
|
||||
schema = 'http://schemas.elite-markets.net/eddn/commodity/1'
|
||||
@ -19,44 +17,43 @@ def export(data, callback):
|
||||
|
||||
callback('Sending data to EDDN...')
|
||||
|
||||
querytime = config.read('querytime') or int(time.time())
|
||||
|
||||
header = { 'softwareName': '%s [%s]' % (applongname, platform=='darwin' and "Mac OS" or system()),
|
||||
'softwareVersion': appversion,
|
||||
'uploaderID': data.get('commander').get('name') } # was hashlib.md5(config.read('username')).hexdigest() }
|
||||
systemName = data.get('lastSystem').get('name').strip()
|
||||
stationName = data.get('lastStarport').get('name').strip()
|
||||
timestamp = datetime.datetime.utcfromtimestamp(config.read('querytime') or int(time.time())).isoformat()
|
||||
'uploaderID': data['commander']['name'].strip() }
|
||||
systemName = data['lastSystem']['name'].strip()
|
||||
stationName = data['lastStarport']['name'].strip()
|
||||
timestamp = time.strftime('%Y-%m-%dT%H.%M.%S', time.gmtime(querytime))
|
||||
|
||||
# route all requests through a session in the hope of using keep-alive
|
||||
session = requests.Session()
|
||||
session.headers['connection'] = 'keep-alive' # can help through a proxy?
|
||||
|
||||
commodities = data.get('lastStarport').get('commodities')
|
||||
commodities = data['lastStarport']['commodities']
|
||||
i=0
|
||||
for commodity in commodities:
|
||||
i = i+1
|
||||
callback('Sending %d/%d' % (i, len(commodities)))
|
||||
if commodity.get('categoryname') and commodity.get('categoryname') != 'NonMarketable':
|
||||
if commodity.get('categoryname') and commodity['categoryname'] != 'NonMarketable':
|
||||
msg = { '$schemaRef': schema,
|
||||
'header': header,
|
||||
'message': {
|
||||
'systemName': systemName,
|
||||
'stationName': stationName,
|
||||
'itemName': commoditymap.get(commodity.get('name').strip(), commodity.get('name').strip()),
|
||||
'buyPrice': int(commodity.get('buyPrice')),
|
||||
'stationStock': int(commodity.get('stock')),
|
||||
'sellPrice': int(commodity.get('sellPrice')),
|
||||
'demand': int(commodity.get('demand')),
|
||||
'itemName': commoditymap.get(commodity['name'].strip(), commodity['name'].strip()),
|
||||
'buyPrice': int(commodity.get('buyPrice', 0)),
|
||||
'stationStock': int(commodity.get('stock', 0)),
|
||||
'sellPrice': int(commodity.get('sellPrice', 0)),
|
||||
'demand': int(commodity.get('demand', 0)),
|
||||
'timestamp': timestamp,
|
||||
}
|
||||
}
|
||||
if commodity.get('stockBracket'):
|
||||
msg['message']['supplyLevel'] = bracketmap.get(commodity.get('stockBracket'))
|
||||
msg['message']['supplyLevel'] = bracketmap.get(commodity['stockBracket'])
|
||||
if commodity.get('demandBracket'):
|
||||
msg['message']['demandLevel'] = bracketmap.get(commodity.get('demandBracket'))
|
||||
msg['message']['demandLevel'] = bracketmap.get(commodity['demandBracket'])
|
||||
|
||||
r = requests.post(upload, data=json.dumps(msg), verify=True)
|
||||
|
||||
elif __debug__:
|
||||
print 'Skipping %s : %s' % (commodity.get('name'), commodity.get('categoryname'))
|
||||
r = requests.post(upload, data=json.dumps(msg))
|
||||
|
||||
session.close()
|
||||
|
25
prefs.py
25
prefs.py
@ -41,7 +41,7 @@ class PreferencesDialog(tk.Toplevel):
|
||||
credframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
credframe.columnconfigure(1, weight=1)
|
||||
|
||||
ttk.Label(credframe, text="Please log in with your Elite:Dangerous account details.").grid(row=0, columnspan=2, sticky=tk.W)
|
||||
ttk.Label(credframe, text="Please log in with your Elite:Dangerous account details").grid(row=0, columnspan=2, sticky=tk.W)
|
||||
ttk.Label(credframe, text="Username (Email)").grid(row=1, sticky=tk.W)
|
||||
ttk.Label(credframe, text="Password").grid(row=2, sticky=tk.W)
|
||||
|
||||
@ -53,26 +53,27 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.password.insert(0, config.read('password') or '')
|
||||
self.password.grid(row=2, column=1, sticky=tk.NSEW)
|
||||
|
||||
for child in credframe.winfo_children():
|
||||
child.grid_configure(padx=5, pady=3)
|
||||
|
||||
outframe = ttk.LabelFrame(frame, text='Output')
|
||||
outframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
outframe.columnconfigure(1, weight=1)
|
||||
outframe.columnconfigure(0, weight=1)
|
||||
|
||||
self.outvar = tk.IntVar()
|
||||
self.outvar.set(config.read('output') or config.OUT_EDDN)
|
||||
ttk.Label(outframe, text="Please choose where you want the market data saved.").grid(row=0, columnspan=3, sticky=tk.W)
|
||||
ttk.Radiobutton(outframe, text="Online to the Elite Dangerous Data Network (EDDN)", variable=self.outvar, value=config.OUT_EDDN, command=self.outvarchanged).grid(row=1, columnspan=3, sticky=tk.W)
|
||||
ttk.Radiobutton(outframe, text="Offline to Slopey's BPC files in folder:", variable=self.outvar, value=config.OUT_BPC, command=self.outvarchanged).grid(row=2, columnspan=3, sticky=tk.W)
|
||||
ttk.Label(outframe, width=-1).grid(row=3, column=0)
|
||||
ttk.Label(outframe, text="Please choose where you want the market data saved").grid(row=0, columnspan=2, padx=5, pady=3, sticky=tk.W)
|
||||
ttk.Radiobutton(outframe, text="Online to the Elite Dangerous Data Network (EDDN)", variable=self.outvar, value=config.OUT_EDDN, command=self.outvarchanged).grid(row=1, columnspan=2, padx=5, sticky=tk.W)
|
||||
ttk.Radiobutton(outframe, text="Offline in Slopey's BPC format", variable=self.outvar, value=config.OUT_BPC, command=self.outvarchanged).grid(row=2, columnspan=2, padx=5, sticky=tk.W)
|
||||
ttk.Radiobutton(outframe, text="Offline in Trade Dangerous format", variable=self.outvar, value=config.OUT_TD, command=self.outvarchanged).grid(row=3, columnspan=2, padx=5, sticky=tk.W)
|
||||
ttk.Label(outframe, text=(platform=='darwin' and 'Where:' or 'File location:')).grid(row=4, padx=5, pady=(5,0), sticky=tk.NSEW)
|
||||
self.outbutton = ttk.Button(outframe, text=(platform=='darwin' and 'Browse...' or 'Choose...'), command=self.outbrowse)
|
||||
self.outbutton.grid(row=2, column=2, sticky=tk.E)
|
||||
self.outbutton.grid(row=4, column=1, padx=5, pady=(5,0), sticky=tk.NSEW)
|
||||
self.outdir = ttk.Entry(outframe)
|
||||
self.outdir.insert(0, config.read('outdir'))
|
||||
self.outdir.grid(row=3, column=1, columnspan=2, sticky=tk.NSEW)
|
||||
self.outdir.grid(row=5, columnspan=2, padx=5, pady=5, sticky=tk.EW)
|
||||
self.outvarchanged()
|
||||
|
||||
for child in credframe.winfo_children() + outframe.winfo_children():
|
||||
child.grid_configure(padx=5, pady=3)
|
||||
|
||||
if platform=='darwin':
|
||||
self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes
|
||||
else:
|
||||
@ -149,7 +150,7 @@ class AuthenticationDialog(tk.Toplevel):
|
||||
self.button.grid(row=1, column=3, sticky=tk.E)
|
||||
|
||||
for child in frame.winfo_children():
|
||||
child.grid_configure(padx=5, pady=3)
|
||||
child.grid_configure(padx=5, pady=5)
|
||||
|
||||
# wait for window to appear on screen before calling grab_set
|
||||
self.wait_visibility()
|
||||
|
46
td.py
Normal file
46
td.py
Normal file
@ -0,0 +1,46 @@
|
||||
# Export to Trade Dangerous
|
||||
|
||||
from os.path import join
|
||||
from collections import defaultdict
|
||||
import codecs
|
||||
from platform import system
|
||||
from sys import platform
|
||||
import time
|
||||
|
||||
from config import applongname, appversion, config
|
||||
from companion import categorymap, commoditymap, bracketmap
|
||||
|
||||
|
||||
def export(data):
|
||||
|
||||
querytime = config.read('querytime') or int(time.time())
|
||||
|
||||
filename = join(config.read('outdir'), '%s.%s.%s.prices' % (data['lastSystem']['name'].strip(), data['lastStarport']['name'].strip(), time.strftime('%Y-%m-%dT%H.%M.%S', time.localtime(querytime))))
|
||||
|
||||
timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(querytime))
|
||||
|
||||
# Format described here: https://bitbucket.org/kfsone/tradedangerous/wiki/Price%20Data
|
||||
h = open(filename, 'wt') # codecs can't automatically handle line endings, so encode manually where required
|
||||
h.write(('#! trade.py import -\n# Created by %s %s on %s for Cmdr %s.\n#\n# <item name> <sellCR> <buyCR> <demand> <stock> <timestamp>\n\n@ %s/%s\n' % (applongname, appversion, platform=='darwin' and "Mac OS" or system(), data['commander']['name'].strip(), data['lastSystem']['name'].strip(), data['lastStarport']['name'].strip())).encode('utf-8'))
|
||||
|
||||
# sort commodities by category
|
||||
bycategory = defaultdict(list)
|
||||
for commodity in data['lastStarport']['commodities']:
|
||||
if commodity.get('categoryname') and commodity.get('categoryname') != 'NonMarketable':
|
||||
bycategory[categorymap.get(commodity['categoryname'], commodity['categoryname'])].append(commodity)
|
||||
|
||||
for category in sorted(bycategory):
|
||||
h.write(' + %s\n' % category)
|
||||
# corrections to commodity names can change the sort order
|
||||
for commodity in sorted(bycategory[category], key=lambda x:commoditymap.get(x['name'].strip(),x['name'])):
|
||||
h.write(' %-23s %7d %7d %9s%c %8s%c %s\n' % (
|
||||
commoditymap.get(commodity['name'].strip(), commodity['name'].strip()),
|
||||
commodity.get('sellPrice', 0),
|
||||
commodity.get('buyPrice', 0),
|
||||
int(commodity.get('demand')) if commodity.get('demandBracket') else '',
|
||||
bracketmap.get(commodity.get('demandBracket'), '?')[0],
|
||||
int(commodity.get('stock')) if commodity.get('stockBracket') else '',
|
||||
bracketmap.get(commodity.get('stockBracket'), '-')[0],
|
||||
timestamp))
|
||||
|
||||
h.close()
|
Loading…
x
Reference in New Issue
Block a user